Compare commits
130 Commits
front_test
...
6ff6ce5052
Author | SHA1 | Date | |
---|---|---|---|
6ff6ce5052 | |||
60ec920cff | |||
900a4c5bdc | |||
d0b615c59d | |||
eccf116f49 | |||
8491c9b3cf | |||
137bc84c21 | |||
3c61fdca93 | |||
5ee3755548 | |||
52511dd4c4 | |||
84b70f8f38 | |||
834d68949c | |||
fea8687664 | |||
c94d3654ce | |||
d5c89bf8f4 | |||
78c72bdd72 | |||
307c7e700b | |||
8d486dce89 | |||
653f923693 | |||
64da3c9ab0 | |||
419ceec1bc | |||
e011a5534e | |||
ef964c4d35 | |||
5608b12f84 | |||
467babab79 | |||
a2e2395cc2 | |||
e3393c8834 | |||
5f8fe4a374 | |||
c5e7736a16 | |||
04589392cb | |||
1106cf8478 | |||
215d80ad70 | |||
dded62c25a | |||
3de7ebe2b1 | |||
8153496a0f | |||
861e7495a7 | |||
d78e43f7e0 | |||
3ca97cf378 | |||
e6a8d98d63 | |||
8894fea6d4 | |||
236bb0d167 | |||
d4dcc95d9b | |||
dc843299eb | |||
f3eaf8fe34 | |||
628c61fb8b | |||
4880f3829c | |||
80b2d087e4 | |||
b5c03798fc | |||
1d970ce5f5 | |||
f9de5ed6bf | |||
e75a5c9d2c | |||
5c3b2b138d | |||
8d4dc7916d | |||
1a6db7c953 | |||
3890aed158 | |||
dd5ca2cbd7 | |||
024deeba41 | |||
1cebebf1a5 | |||
d8bc7cc9b6 | |||
067eeb9494 | |||
e66fa33577 | |||
b355463dd9 | |||
27e70ee109 | |||
153501c8d4 | |||
40afde89b7 | |||
4698aa549f | |||
79e949bdd4 | |||
04a73073c1 | |||
11ab5e1dc4 | |||
820757c836 | |||
730aa5f450 | |||
dda3e5fcfd | |||
5e8e875a37 | |||
86e7dc7c75 | |||
6235fe7e68 | |||
3cb12dab4f | |||
0a9d83655f | |||
ef8c8e896d | |||
fc73293122 | |||
e26f8da662 | |||
b4c05f8c59 | |||
ca282378ec | |||
746fa97cf3 | |||
8b24456b48 | |||
6befd10735 | |||
db094a8d86 | |||
c739b4d26d | |||
dacb0dd179 | |||
b00c28a02a | |||
208cbbfa1d | |||
d77f38b405 | |||
525f98a054 | |||
43aadac503 | |||
07f66f65ed | |||
6e5651c527 | |||
1ed976b039 | |||
013b97cec0 | |||
e7cb8cf469 | |||
184642a750 | |||
a8ae5f14d4 | |||
e6565275c8 | |||
f629fb4a4e | |||
7a9955b781 | |||
1e97177777 | |||
9e2ab9fa5a | |||
70b00a1996 | |||
720b19df93 | |||
1498b5908b | |||
45bbe51897 | |||
c715955758 | |||
0fc4be2008 | |||
c7ddc37bf9 | |||
93bb46b017 | |||
eed4e6f855 | |||
d2cc3e00e1 | |||
249d00177c | |||
36e4967394 | |||
c32eea8a40 | |||
30344a60b7 | |||
2465545b6b | |||
83cbeb7a2e | |||
645a10477d | |||
a859871265 | |||
0eab9a8063 | |||
1dff7573ff | |||
8af40bfe50 | |||
afa4d34ec8 | |||
c5fc5b600e | |||
a4939737fe | |||
e7ebcc0d3a |
18
.gitea/workflows/back.yaml
Normal file
18
.gitea/workflows/back.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
name: Format
|
||||
|
||||
on: [ push, pull_request ]
|
||||
|
||||
jobs:
|
||||
|
||||
formatting:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4 # v2 minimum required
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '21'
|
||||
|
||||
- uses: axel-op/googlejavaformat-action@v3
|
||||
with:
|
||||
args: "--set-exit-if-changed --skip-sorting-imports --skip-reflowing-long-strings --aosp -n"
|
33
.gitea/workflows/build-back.yaml
Normal file
33
.gitea/workflows/build-back.yaml
Normal file
@ -0,0 +1,33 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Load .env file
|
||||
uses: xom9ikk/dotenv@v2.3.0
|
||||
with:
|
||||
path: ./config/
|
||||
mode: dev
|
||||
load-mode: strict
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 21
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
with:
|
||||
cache-disabled: true # Once the code has been pushed once in main, this should be reenabled.
|
||||
|
||||
- name: init gradle
|
||||
working-directory: ./MyINPulse-back/
|
||||
run: ./gradlew build # todo: run test, currently fail because no database is present
|
24
.gitea/workflows/front.yaml
Normal file
24
.gitea/workflows/front.yaml
Normal file
@ -0,0 +1,24 @@
|
||||
name: CI
|
||||
on: push
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install everything
|
||||
working-directory: ./front/MyINPulse-front
|
||||
run: npm i
|
||||
|
||||
- name: Run ESLint
|
||||
working-directory: ./front/MyINPulse-front
|
||||
run: npx eslint
|
||||
|
||||
- name: Run prettier
|
||||
working-directory: ./front/MyINPulse-front
|
||||
run: npx prettier src --check
|
||||
|
||||
- name: Build frontend
|
||||
working-directory: ./front/MyINPulse-front
|
||||
run: npm run build
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -2,3 +2,6 @@
|
||||
.idea
|
||||
keycloak/CAS/target
|
||||
docker-compose.yaml
|
||||
node_modules
|
||||
.vscode
|
||||
postgres/data
|
||||
|
60
Makefile
60
Makefile
@ -1,13 +1,16 @@
|
||||
help:
|
||||
@echo "make [clean dev-front prod dev-back]"
|
||||
@echo "make [clean dev-front prod dev-back dev]"
|
||||
|
||||
clean:
|
||||
@cp config/frontdev.env front/MyINPulse-front/.env
|
||||
@cp config/frontdev.env .env
|
||||
@cp config/frontdev.env MyINPulse-back/.env
|
||||
@cp config/prod.docker-compose.yaml docker-compose.yaml
|
||||
@docker compose down
|
||||
@rm -f docker-compose.yaml
|
||||
@rm -f .env
|
||||
@rm -f front/MyINPulse-front/.env
|
||||
|
||||
@rm -f MyINPulse-back/.env
|
||||
|
||||
# Install npm packages
|
||||
front/MyINPulse-front/.installed:
|
||||
@ -16,26 +19,55 @@ front/MyINPulse-front/.installed:
|
||||
|
||||
vite: ./front/MyINPulse-front/.installed
|
||||
|
||||
keycloak: ./keycloak/.installed
|
||||
|
||||
dev-front: clean vite
|
||||
@cp config/frontdev.front.env front/MyINPulse-front/.env
|
||||
@cp config/frontdev.main.env .env
|
||||
keycloak/.installed:
|
||||
@echo "running one time install"
|
||||
@cd keycloak/CAS && sudo sh build.sh
|
||||
@touch ./keycloak/.installed
|
||||
|
||||
dev-front: clean vite keycloak
|
||||
@cp config/frontdev.env front/MyINPulse-front/.env
|
||||
@cp config/frontdev.env .env
|
||||
@cp config/frontdev.env MyINPulse-back/.env
|
||||
@cp config/frontdev.docker-compose.yaml docker-compose.yaml
|
||||
@docker compose up -d --build
|
||||
@cd ./front/MyINPulse-front/ && npm run dev
|
||||
|
||||
prod: clean
|
||||
@cp config/prod.front.env front/MyINPulse-front/.env
|
||||
@cp config/prod.main.env .env
|
||||
@cp config/frontdev.docker-compose.yaml docker-compose.yaml
|
||||
prod: clean keycloak
|
||||
@cp config/prod.env front/MyINPulse-front/.env
|
||||
@cp config/prod.env .env
|
||||
@cp config/prod.env .env
|
||||
@cp config/prod.docker-compose.yaml docker-compose.yaml
|
||||
@docker compose up -d --build
|
||||
|
||||
|
||||
|
||||
dev-back:
|
||||
@cp config/backdev.front.env front/MyINPulse-front/.env
|
||||
@cp config/backdev.main.env .env
|
||||
dev-back: keycloak
|
||||
@cp config/backdev.env front/MyINPulse-front/.env
|
||||
@cp config/backdev.env .env
|
||||
@cp config/backdev.env MyINPulse-back/.env
|
||||
@cp config/backdev.docker-compose.yaml docker-compose.yaml
|
||||
@docker compose up -d --build
|
||||
@echo "cd MyINPulse-back"
|
||||
@echo "./gradlew bootRun --args='--server.port=8081'"
|
||||
@echo "cd MyINPulse-back" && echo 'export $$(cat .env | xargs)'
|
||||
@echo "./gradlew bootRun --args='--server.port=8081'"
|
||||
|
||||
dev: clean vite keycloak
|
||||
@cp config/dev.env front/MyINPulse-front/.env
|
||||
@cp config/dev.env .env
|
||||
@cp config/dev.env MyINPulse-back/.env
|
||||
@cp config/dev.docker-compose.yaml docker-compose.yaml
|
||||
@docker compose up -d --build
|
||||
@echo "cd MyINPulse-back" && echo 'export $$(cat .env | xargs)'
|
||||
@echo "./gradlew bootRun --args='--server.port=8081'"
|
||||
@cd ./front/MyINPulse-front/ && npm run dev &
|
||||
|
||||
test-back: clean keycloak
|
||||
@cp config/dev.env front/MyINPulse-front/.env
|
||||
@cp config/dev.env .env
|
||||
@cp config/dev.env MyINPulse-back/.env
|
||||
@cp config/dev.docker-compose.yaml docker-compose.yaml
|
||||
@docker compose up -d --build
|
||||
@echo "cd MyINPulse-back" && echo 'export $$(cat .env | xargs)'
|
||||
@cd ./MyINPulse-back/ && ./gradlew test && ./gradlew jacocoTestReport
|
||||
@firefox ./MyINPulse-back/build/jacocoHtml/index.html
|
||||
|
@ -1,29 +1,59 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '3.4.2'
|
||||
id 'io.spring.dependency-management' version '1.1.7'
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '3.4.2'
|
||||
id 'io.spring.dependency-management' version '1.1.7'
|
||||
id 'jacoco'
|
||||
}
|
||||
|
||||
group = 'enseirb'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
}
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
|
||||
implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.+'
|
||||
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.+'
|
||||
implementation 'org.postgresql:postgresql'
|
||||
implementation group: 'com.itextpdf', name: 'itextpdf', version: '5.5.13.3'
|
||||
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
testImplementation 'com.h2database:h2'
|
||||
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
useJUnitPlatform()
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
|
||||
test {
|
||||
finalizedBy jacocoTestReport // report is always generated after tests run
|
||||
}
|
||||
jacocoTestReport {
|
||||
dependsOn test // tests are required to run before generating the report
|
||||
reports {
|
||||
xml.required = false
|
||||
csv.required = false
|
||||
html.outputLocation = layout.buildDirectory.dir('jacocoHtml')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
jacoco {
|
||||
toolVersion = "0.8.12"
|
||||
reportsDirectory = layout.buildDirectory.dir('customJacocoReportDir')
|
||||
}
|
||||
|
@ -1,29 +1,15 @@
|
||||
package enseirb.myinpulse;
|
||||
|
||||
import enseirb.myinpulse.security.KeycloakJwtRolesConverter;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.oauth2.jwt.*;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.springframework.security.authorization.AuthorityAuthorizationManager.hasRole;
|
||||
|
||||
@SpringBootApplication
|
||||
public class MyinpulseApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MyinpulseApplication.class, args);
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MyinpulseApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
package enseirb.myinpulse.api;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
@SpringBootApplication
|
||||
@RestController
|
||||
public class GetUserInfo {
|
||||
// TODO: understand how to get data
|
||||
@GetMapping("/getUserInfo")
|
||||
public Object user(Principal principal) {
|
||||
System.out.println("GetUserInfo + " + principal);
|
||||
System.out.println(SecurityContextHolder.getContext().getAuthentication());
|
||||
return SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
}
|
||||
|
||||
@CrossOrigin(methods = {RequestMethod.GET, RequestMethod.OPTIONS})
|
||||
@GetMapping("/random")
|
||||
public boolean rand(){
|
||||
System.err.println("HELLO");
|
||||
return Math.random() > 0.5;
|
||||
}
|
||||
|
||||
@CrossOrigin(methods = {RequestMethod.GET, RequestMethod.OPTIONS})
|
||||
@GetMapping("/random2")
|
||||
public boolean rand2(){
|
||||
System.err.println("HELLO2");
|
||||
return Math.random() > 0.5;
|
||||
}
|
||||
|
||||
@CrossOrigin(methods = {RequestMethod.GET, RequestMethod.OPTIONS})
|
||||
@GetMapping("/random3")
|
||||
public boolean rand3(){
|
||||
System.err.println("HELLO");
|
||||
return Math.random() > 0.5;
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class KeycloakJwtRolesConverter implements Converter<Jwt, AbstractAuthenticationToken> {
|
||||
/** Prefix used for realm level roles. */
|
||||
public static final String PREFIX_REALM_ROLE = "ROLE_REALM_";
|
||||
|
||||
/** Prefix used in combination with the resource (client) name for resource level roles. */
|
||||
public static final String PREFIX_RESOURCE_ROLE = "ROLE_";
|
||||
|
||||
/** Name of the claim containing the realm level roles */
|
||||
private static final String CLAIM_REALM_ACCESS = "realm_access";
|
||||
|
||||
/** Name of the claim containing the resources (clients) the user has access to. */
|
||||
private static final String CLAIM_RESOURCE_ACCESS = "resource_access";
|
||||
|
||||
/** Name of the claim containing roles. (Applicable to realm and resource level.) */
|
||||
private static final String CLAIM_ROLES = "roles";
|
||||
|
||||
@Override
|
||||
public AbstractAuthenticationToken convert(Jwt source) {
|
||||
return new JwtAuthenticationToken(
|
||||
source,
|
||||
Stream.concat(
|
||||
new JwtGrantedAuthoritiesConverter().convert(source).stream(),
|
||||
tokenRolesExtractor(source).stream())
|
||||
.collect(toSet()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the realm and resource level roles from a JWT token distinguishing between them
|
||||
* using prefixes.
|
||||
*/
|
||||
public Collection<GrantedAuthority> tokenRolesExtractor(Jwt jwt) {
|
||||
// Collection that will hold the extracted roles
|
||||
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
|
||||
|
||||
// Realm roles
|
||||
// Get the part of the access token that holds the roles assigned on realm level
|
||||
Map<String, Collection<String>> realmAccess = jwt.getClaim(CLAIM_REALM_ACCESS);
|
||||
|
||||
// Verify that the claim exists and is not empty
|
||||
if (realmAccess != null && !realmAccess.isEmpty()) {
|
||||
// From the realm_access claim get the roles
|
||||
Collection<String> roles = realmAccess.get(CLAIM_ROLES);
|
||||
// Check if any roles are present
|
||||
if (roles != null && !roles.isEmpty()) {
|
||||
// Iterate of the roles and add them to the granted authorities
|
||||
Collection<GrantedAuthority> realmRoles =
|
||||
roles.stream()
|
||||
// Prefix all realm roles with "ROLE_realm_"
|
||||
.map(role -> new SimpleGrantedAuthority(PREFIX_REALM_ROLE + role))
|
||||
.collect(Collectors.toList());
|
||||
grantedAuthorities.addAll(realmRoles);
|
||||
}
|
||||
}
|
||||
|
||||
// Resource (client) roles
|
||||
// A user might have access to multiple resources all containing their own roles. Therefore,
|
||||
// it is a map of
|
||||
// resource each possibly containing a "roles" property.
|
||||
Map<String, Map<String, Collection<String>>> resourceAccess =
|
||||
jwt.getClaim(CLAIM_RESOURCE_ACCESS);
|
||||
|
||||
// Check if resources are assigned
|
||||
if (resourceAccess != null && !resourceAccess.isEmpty()) {
|
||||
// Iterate of all the resources
|
||||
resourceAccess.forEach(
|
||||
(resource, resourceClaims) -> {
|
||||
// Iterate of the "roles" claim inside the resource claims
|
||||
resourceClaims
|
||||
.get(CLAIM_ROLES)
|
||||
.forEach(
|
||||
// Add the role to the granted authority prefixed with ROLE_
|
||||
// and the name of the resource
|
||||
role ->
|
||||
grantedAuthorities.add(
|
||||
new SimpleGrantedAuthority(
|
||||
PREFIX_RESOURCE_ROLE
|
||||
+ resource
|
||||
+ "_"
|
||||
+ role)));
|
||||
});
|
||||
}
|
||||
|
||||
return grantedAuthorities;
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package enseirb.myinpulse.config;
|
||||
|
||||
import enseirb.myinpulse.security.KeycloakJwtRolesConverter;
|
||||
import static org.springframework.security.authorization.AuthorityAuthorizationManager.hasRole;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
@ -12,39 +14,62 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.springframework.security.authorization.AuthorityAuthorizationManager.hasRole;
|
||||
|
||||
@Configuration
|
||||
public class WebSecurityCustomConfiguration {
|
||||
// CORS configuration
|
||||
// TODO: make sure to only accept our own domains
|
||||
|
||||
@Value("${VITE_APP_URL}")
|
||||
private String frontendUrl;
|
||||
|
||||
/**
|
||||
* Configure the CORS (Cross Origin Ressource Sharing -- a security feature) configuration. The
|
||||
* only allowed website is the frontend, defined in the .env file.
|
||||
*
|
||||
* @return the CORS configuration used by the backend
|
||||
*/
|
||||
@Bean
|
||||
public CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
configuration.setAllowedOrigins(List.of("*"));
|
||||
configuration.setAllowedOrigins(List.of(frontendUrl));
|
||||
configuration.setAllowedMethods(Arrays.asList("GET", "OPTIONS"));
|
||||
configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type",
|
||||
"x-auth-token")); // Do not remove, this fixes the CORS errors when unauthenticated
|
||||
UrlBasedCorsConfigurationSource source = new
|
||||
UrlBasedCorsConfigurationSource();
|
||||
configuration.setAllowedHeaders(
|
||||
Arrays.asList("authorization", "content-type", "x-auth-token"));
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", configuration);
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the authorisation required for each path.
|
||||
*
|
||||
* <p>admin endpoints are under /admin/* and entrepreneur are under /entrepreneur/*
|
||||
*
|
||||
* <p>If endpoints dont require authentication, they are under /unauth/
|
||||
*
|
||||
* @param http automatically filled in by spring.
|
||||
* @return a securityfilterchain, automatically used by spring.
|
||||
* @throws Exception TODO: figure out when the exception are raised
|
||||
*/
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeHttpRequests(authorize -> authorize
|
||||
.requestMatchers("/random2").access(hasRole("REALM_MyINPulse-entrepreneur"))
|
||||
.requestMatchers("/random").access(hasRole("REALM_MyINPulse-admin"))
|
||||
.requestMatchers("/random3").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.oauth2ResourceServer(oauth2 -> oauth2
|
||||
.jwt(jwt -> jwt.
|
||||
jwtAuthenticationConverter(new KeycloakJwtRolesConverter())));
|
||||
http.authorizeHttpRequests(
|
||||
authorize ->
|
||||
authorize
|
||||
.requestMatchers("/entrepreneur/**", "/shared/**")
|
||||
.access(hasRole("REALM_MyINPulse-entrepreneur"))
|
||||
.requestMatchers("/admin/**", "/shared/**")
|
||||
.access(hasRole("REALM_MyINPulse-admin"))
|
||||
.requestMatchers("/unauth/**")
|
||||
.permitAll()
|
||||
.anyRequest()
|
||||
.authenticated())
|
||||
.oauth2ResourceServer(
|
||||
oauth2 ->
|
||||
oauth2.jwt(
|
||||
jwt ->
|
||||
jwt.jwtAuthenticationConverter(
|
||||
new KeycloakJwtRolesConverter())));
|
||||
return http.build();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,102 @@
|
||||
package enseirb.myinpulse.controller;
|
||||
|
||||
import enseirb.myinpulse.model.*;
|
||||
import enseirb.myinpulse.service.AdminApiService;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@SpringBootApplication
|
||||
@RestController
|
||||
public class AdminApi {
|
||||
|
||||
private final AdminApiService adminApiService;
|
||||
|
||||
@Autowired
|
||||
AdminApi(AdminApiService adminApiService) {
|
||||
this.adminApiService = adminApiService;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: description
|
||||
*
|
||||
* @return a list of all project managed by the current admin user
|
||||
*/
|
||||
@GetMapping("/admin/projects")
|
||||
public Iterable<Project> getProjects(@AuthenticationPrincipal Jwt principal) {
|
||||
return adminApiService.getProjectsOfAdmin(principal.getClaimAsString("email"));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Why in admin instead of shared ? + desc
|
||||
*
|
||||
* @return a list of upcoming appointments for the current user
|
||||
*/
|
||||
@GetMapping("/admin/appointments/upcoming")
|
||||
public Iterable<Appointment> getUpcomingAppointments(@AuthenticationPrincipal Jwt principal) {
|
||||
return adminApiService.getUpcomingAppointments(principal.getClaimAsString("email"));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: description
|
||||
*
|
||||
* @return a list of current unvalidated projects, waiting to be accepted
|
||||
*/
|
||||
@GetMapping("/admin/projects/pending")
|
||||
public Iterable<Project> getPendingProjects() {
|
||||
return adminApiService.getPendingProjects();
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint used to make a decision about a project.
|
||||
*
|
||||
* <p>The decision must contain the administrator
|
||||
*
|
||||
* @return the status code of the request
|
||||
*/
|
||||
@PostMapping("/admin/projects/decision")
|
||||
public void validateProject(@RequestBody ProjectDecision decision) {
|
||||
adminApiService.validateProject(decision);
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint used to manually add a project by an admin
|
||||
*
|
||||
* @return the status code of the request
|
||||
*/
|
||||
@PostMapping("/admin/project/add")
|
||||
public void addNewProject(@RequestBody Project project) {
|
||||
adminApiService.addNewProject(project);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: shouldn't it be an PUT request ? / What is the rerun type
|
||||
*
|
||||
* <p>Endpoint used to add a new report to an appointment
|
||||
*
|
||||
* @return the status code of the request
|
||||
*/
|
||||
@PostMapping("/admin/appoitements/report/{appointmentId}")
|
||||
public void createAppointmentReport(
|
||||
@PathVariable long appointmentId,
|
||||
@RequestBody Report report,
|
||||
@AuthenticationPrincipal Jwt principal) {
|
||||
adminApiService.createAppointmentReport(
|
||||
appointmentId, report, principal.getClaimAsString("email"));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Shouldn't a project be kept in history ? 2 different endpoints ?
|
||||
*
|
||||
* <p>Endpoint used to completely remove a project.
|
||||
*
|
||||
* @return the status code of the request
|
||||
*/
|
||||
@DeleteMapping("/admin/projects/remove/{projectId}")
|
||||
public void deleteProject(@PathVariable long projectId) {
|
||||
adminApiService.deleteProject(projectId);
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package enseirb.myinpulse.controller;
|
||||
|
||||
import enseirb.myinpulse.model.SectionCell;
|
||||
import enseirb.myinpulse.model.Project;
|
||||
import enseirb.myinpulse.service.EntrepreneurApiService;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@SpringBootApplication
|
||||
@RestController
|
||||
public class EntrepreneurApi {
|
||||
|
||||
private final EntrepreneurApiService entrepreneurApiService;
|
||||
|
||||
@Autowired
|
||||
EntrepreneurApi(EntrepreneurApiService entrepreneurApiService) {
|
||||
this.entrepreneurApiService = entrepreneurApiService;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: check return type
|
||||
*
|
||||
* <p>Endpoint used to update a LC section.
|
||||
*
|
||||
* @return status code
|
||||
*/
|
||||
@PutMapping("/entrepreneur/lcsection/modify/{sectionId}")
|
||||
public void editSectionCell(
|
||||
@PathVariable Long sectionId,
|
||||
@RequestBody SectionCell sectionCell,
|
||||
@AuthenticationPrincipal Jwt principal) {
|
||||
entrepreneurApiService.editSectionCell(
|
||||
sectionId, sectionCell, principal.getClaimAsString("email"));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: checkReturn Type
|
||||
*
|
||||
* <p>Endpoint used to delete a LC section
|
||||
*
|
||||
* @return status code
|
||||
*/
|
||||
@DeleteMapping("/entrepreneur/lcsection/remove/{sectionId}")
|
||||
public void removeSectionCell(
|
||||
@PathVariable Long sectionId, @AuthenticationPrincipal Jwt principal) {
|
||||
entrepreneurApiService.removeSectionCell(sectionId, principal.getClaimAsString("email"));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: check return type
|
||||
*
|
||||
* <p>Endpoint used to create a new LC section
|
||||
*
|
||||
* @return status code
|
||||
*/
|
||||
@PostMapping("/entrepreneur/lcsection/add") // remove id from doc aswell
|
||||
public void addLCSection(
|
||||
@RequestBody SectionCell sectionCell, @AuthenticationPrincipal Jwt principal) {
|
||||
entrepreneurApiService.addSectionCell(sectionCell, principal.getClaimAsString("email"));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: check return type
|
||||
*
|
||||
* <p>Endpoint used to request the creation of a new project
|
||||
*
|
||||
* @return status code
|
||||
*/
|
||||
@PostMapping("/entrepreneur/project/request")
|
||||
public void requestNewProject(
|
||||
@RequestBody Project project, @AuthenticationPrincipal Jwt principal) {
|
||||
entrepreneurApiService.requestNewProject(project, principal.getClaimAsString("email"));
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
package enseirb.myinpulse.controller;
|
||||
|
||||
import com.itextpdf.text.DocumentException;
|
||||
|
||||
import enseirb.myinpulse.model.*;
|
||||
import enseirb.myinpulse.service.SharedApiService;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
@SpringBootApplication
|
||||
@RestController
|
||||
public class SharedApi {
|
||||
|
||||
private final SharedApiService sharedApiService;
|
||||
|
||||
@Autowired
|
||||
SharedApi(SharedApiService sharedApiService) {
|
||||
this.sharedApiService = sharedApiService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint used to get the data inside the lean canvas
|
||||
*
|
||||
* @return a list of lean canvas sections
|
||||
*/
|
||||
@GetMapping("/shared/project/lcsection/{projectId}/{sectionId}/{date}")
|
||||
public Iterable<SectionCell> getLCSection(
|
||||
@PathVariable("projectId") Long projectId,
|
||||
@PathVariable("sectionId") Long sectionId,
|
||||
@PathVariable("date") String date,
|
||||
@AuthenticationPrincipal Jwt principal) {
|
||||
return sharedApiService.getSectionCells(
|
||||
projectId, sectionId, date, principal.getClaimAsString("email"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint used to get entrepreneurs details
|
||||
*
|
||||
* @return a list of all entrepreneurs in a project
|
||||
*/
|
||||
@GetMapping("/shared/entrepreneurs/{projectId}")
|
||||
public Iterable<Entrepreneur> getEntrepreneursByProjectId(
|
||||
@PathVariable int projectId, @AuthenticationPrincipal Jwt principal) {
|
||||
return sharedApiService.getEntrepreneursByProjectId(
|
||||
projectId, principal.getClaimAsString("email"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint used to get the administrator of a project.
|
||||
*
|
||||
* @return the admin of a project
|
||||
*/
|
||||
@GetMapping("/shared/projects/admin/{projectId}")
|
||||
public Administrator getAdminByProjectId(
|
||||
@PathVariable int projectId, @AuthenticationPrincipal Jwt principal) {
|
||||
return sharedApiService.getAdminByProjectId(projectId, principal.getClaimAsString("email"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint used to get all appointments of a single project.
|
||||
*
|
||||
* @return a list of all appointments.
|
||||
*/
|
||||
@GetMapping("/shared/projects/appointments/{projectId}")
|
||||
public Iterable<Appointment> getAppointmentsByProjectId(
|
||||
@PathVariable int projectId, @AuthenticationPrincipal Jwt principal) {
|
||||
return sharedApiService.getAppointmentsByProjectId(
|
||||
projectId, principal.getClaimAsString("email"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint used to generate a PDF report
|
||||
*
|
||||
* @return a PDF file? TODO: how does that works ?
|
||||
*/
|
||||
@GetMapping("/shared/projects/appointments/report/{appointmentId}")
|
||||
public void getPDFReport(
|
||||
@PathVariable int appointmentId, @AuthenticationPrincipal Jwt principal) {
|
||||
try {
|
||||
sharedApiService.getPDFReport(appointmentId, principal.getClaimAsString("email"));
|
||||
} catch (DocumentException e) {
|
||||
System.out.println(e + "Document exception");
|
||||
} catch (URISyntaxException e) {
|
||||
System.out.println(e + "Error with URI");
|
||||
} catch (IOException e) {
|
||||
System.out.println(e + "Failed to access file");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TODO
|
||||
*/
|
||||
@PostMapping("/shared/appointment/request")
|
||||
public void createAppointmentRequest(
|
||||
@RequestBody Appointment appointment, @AuthenticationPrincipal Jwt principal) {
|
||||
sharedApiService.createAppointmentRequest(appointment, principal.getClaimAsString("email"));
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package enseirb.myinpulse.exception;
|
||||
|
||||
public class RoleNotFoudException extends RuntimeException {
|
||||
public RoleNotFoudException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package enseirb.myinpulse.exception;
|
||||
|
||||
public class UserNotFoundException extends RuntimeException {
|
||||
public UserNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package enseirb.myinpulse.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.persistence.PrimaryKeyJoinColumn;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table(name = "administrator")
|
||||
@PrimaryKeyJoinColumn(name = "idAdministrator", referencedColumnName = "idUser")
|
||||
public class Administrator extends User {
|
||||
|
||||
@OneToMany(mappedBy = "projectAdministrator", fetch = FetchType.LAZY, orphanRemoval = true)
|
||||
private final List<Project> listProject = new ArrayList<>();
|
||||
|
||||
/*@OneToMany(mappedBy = "administratorSectionCell", fetch = FetchType.LAZY, orphanRemoval = true)
|
||||
private List<SectionCell> listSectionCell = new ArrayList<>();*/
|
||||
// should now be useless
|
||||
|
||||
@OneToMany(mappedBy = "administratorAnnotation", fetch = FetchType.LAZY, orphanRemoval = true)
|
||||
private final List<Annotation> listAnnotation = new ArrayList<>();
|
||||
|
||||
/*@OneToMany(mappedBy = "administratorAppointment", fetch = FetchType.LAZY, orphanRemoval = true)
|
||||
private final List<Appointment> listAppointment = new ArrayList<>();*/
|
||||
// should now be useless
|
||||
|
||||
@OneToOne(mappedBy = "administratorAppointment", fetch = FetchType.LAZY, orphanRemoval = true)
|
||||
private MakeAppointment makeAppointment;
|
||||
|
||||
public Administrator() {}
|
||||
|
||||
public Administrator(
|
||||
String userSurname,
|
||||
String username,
|
||||
String primaryMail,
|
||||
String secondaryMail,
|
||||
String phoneNumber) {
|
||||
super(null, userSurname, username, primaryMail, secondaryMail, phoneNumber);
|
||||
}
|
||||
|
||||
public List<Project> getListProject() {
|
||||
return listProject;
|
||||
}
|
||||
|
||||
public void updateListProject(Project project) {
|
||||
listProject.add(project);
|
||||
}
|
||||
|
||||
public List<Annotation> getListAnnotation() {
|
||||
return listAnnotation;
|
||||
}
|
||||
|
||||
public void updateListAnnotation(Annotation annotation) {
|
||||
listAnnotation.add(annotation);
|
||||
}
|
||||
|
||||
public MakeAppointment getMakeAppointment() {
|
||||
return makeAppointment;
|
||||
}
|
||||
|
||||
public void setMakeAppointment(MakeAppointment makeAppointment) {
|
||||
this.makeAppointment = makeAppointment;
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package enseirb.myinpulse.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "annotation")
|
||||
public class Annotation {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long idAnnotation;
|
||||
|
||||
private String comment;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "idSectionCell")
|
||||
private SectionCell sectionCellAnnotation;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "idAdministrator")
|
||||
private Administrator administratorAnnotation;
|
||||
|
||||
public Annotation() {}
|
||||
|
||||
public Annotation(Long idAnnotation, String commentary) {
|
||||
this.idAnnotation = idAnnotation;
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
public void setComment(String comment) {
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
public Long getIdAnnotation() {
|
||||
return idAnnotation;
|
||||
}
|
||||
|
||||
public void setIdAnnotation(Long idAnnotation) {
|
||||
this.idAnnotation = idAnnotation;
|
||||
}
|
||||
|
||||
public SectionCell getSectionCellAnnotation() {
|
||||
return sectionCellAnnotation;
|
||||
}
|
||||
|
||||
public void setSectionCellAnnotation(SectionCell sectionCellAnnotation) {
|
||||
this.sectionCellAnnotation = sectionCellAnnotation;
|
||||
}
|
||||
|
||||
public Administrator getAdministratorAnnotation() {
|
||||
return administratorAnnotation;
|
||||
}
|
||||
|
||||
public void setAdministratorAnnotation(Administrator administratorAnnotation) {
|
||||
this.administratorAnnotation = administratorAnnotation;
|
||||
}
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
package enseirb.myinpulse.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table(name = "appointment")
|
||||
public class Appointment {
|
||||
|
||||
/*@OneToMany(mappedBy = "appointmentEntrepreneurs", fetch = FetchType.LAZY, orphanRemoval = true)
|
||||
private final List<Entrepreneur> listEntrepreneur =
|
||||
new ArrayList<>(); */
|
||||
// should now be useless
|
||||
|
||||
@ManyToMany(
|
||||
fetch = FetchType.LAZY,
|
||||
cascade = {CascadeType.ALL})
|
||||
@JoinTable(
|
||||
name = "concern",
|
||||
joinColumns = @JoinColumn(name = "idAppointment"),
|
||||
inverseJoinColumns = @JoinColumn(name = "idSectionCell"))
|
||||
List<SectionCell> listSectionCell = new ArrayList<>();
|
||||
|
||||
@OneToOne(mappedBy = "appointmentReport", fetch = FetchType.LAZY, orphanRemoval = true)
|
||||
private Report report;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long idAppointment;
|
||||
|
||||
private LocalDate appointmentDate;
|
||||
|
||||
private LocalTime appointmentTime;
|
||||
|
||||
private LocalTime appointmentDuration;
|
||||
|
||||
@Column(length = 255)
|
||||
private String appointmentPlace;
|
||||
|
||||
private String appointmentSubject;
|
||||
|
||||
public Appointment() {}
|
||||
|
||||
public Appointment(
|
||||
Long idAppointment,
|
||||
LocalDate appointmentDate,
|
||||
LocalTime appointmentTime,
|
||||
LocalTime appointmentDuration,
|
||||
String appointmentPlace,
|
||||
String appointmentSubject) {
|
||||
this.idAppointment = idAppointment;
|
||||
this.appointmentDate = appointmentDate;
|
||||
this.appointmentTime = appointmentTime;
|
||||
this.appointmentDuration = appointmentDuration;
|
||||
this.appointmentPlace = appointmentPlace;
|
||||
this.appointmentSubject = appointmentSubject;
|
||||
}
|
||||
|
||||
public Long getIdAppointment() {
|
||||
return idAppointment;
|
||||
}
|
||||
|
||||
public void setIdAppointment(Long idAppointment) {
|
||||
this.idAppointment = idAppointment;
|
||||
}
|
||||
|
||||
public LocalDate getAppointmentDate() {
|
||||
return appointmentDate;
|
||||
}
|
||||
|
||||
public void setAppointmentDate(LocalDate appointmentDate) {
|
||||
this.appointmentDate = appointmentDate;
|
||||
}
|
||||
|
||||
public LocalTime getAppointmentTime() {
|
||||
return appointmentTime;
|
||||
}
|
||||
|
||||
public void setAppointmentTime(LocalTime appointmentTime) {
|
||||
this.appointmentTime = appointmentTime;
|
||||
}
|
||||
|
||||
public LocalTime getAppointmentDuration() {
|
||||
return appointmentDuration;
|
||||
}
|
||||
|
||||
public void setAppointmentDuration(LocalTime appointmentDuration) {
|
||||
this.appointmentDuration = appointmentDuration;
|
||||
}
|
||||
|
||||
public String getAppointmentPlace() {
|
||||
return appointmentPlace;
|
||||
}
|
||||
|
||||
public void setAppointmentPlace(String appointmentPlace) {
|
||||
this.appointmentPlace = appointmentPlace;
|
||||
}
|
||||
|
||||
public String getAppointmentSubject() {
|
||||
return appointmentSubject;
|
||||
}
|
||||
|
||||
public void setAppointmentSubject(String appointmentSubject) {
|
||||
this.appointmentSubject = appointmentSubject;
|
||||
}
|
||||
|
||||
public List<SectionCell> getAppointmentListSectionCell() {
|
||||
return listSectionCell;
|
||||
}
|
||||
|
||||
public void updateListSectionCell(SectionCell sectionCell) {
|
||||
listSectionCell.add(sectionCell);
|
||||
}
|
||||
|
||||
public Report getAppointmentReport() {
|
||||
return report;
|
||||
}
|
||||
|
||||
public void setAppointmentReport(Report report) {
|
||||
this.report = report;
|
||||
}
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
package enseirb.myinpulse.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "entrepreneur")
|
||||
@PrimaryKeyJoinColumn(name = "idEntrepreneur", referencedColumnName = "idUser")
|
||||
public class Entrepreneur extends User {
|
||||
|
||||
@Column(length = 255)
|
||||
private String school;
|
||||
|
||||
@Column(length = 255)
|
||||
private String course;
|
||||
|
||||
private boolean sneeStatus;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "idProjectParticipation", referencedColumnName = "idProject")
|
||||
private Project projectParticipation;
|
||||
|
||||
// @Column(insertable=false, updatable=false)
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "idProjectProposed", referencedColumnName = "idProject")
|
||||
private Project projectProposed;
|
||||
|
||||
/*@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "idAppointment")
|
||||
private Appointment appointmentEntrepreneur;*/
|
||||
// should now be useless
|
||||
|
||||
@OneToOne(mappedBy = "entrepreneurAppointment", fetch = FetchType.LAZY, orphanRemoval = true)
|
||||
private MakeAppointment makeAppointment;
|
||||
|
||||
public Entrepreneur() {}
|
||||
|
||||
public Entrepreneur(
|
||||
String userSurname,
|
||||
String username,
|
||||
String primaryMail,
|
||||
String secondaryMail,
|
||||
String phoneNumber,
|
||||
String school,
|
||||
String course,
|
||||
boolean sneeStatus) {
|
||||
super(userSurname, username, primaryMail, secondaryMail, phoneNumber);
|
||||
this.school = school;
|
||||
this.course = course;
|
||||
this.sneeStatus = sneeStatus;
|
||||
}
|
||||
|
||||
public Entrepreneur(
|
||||
Long idUser,
|
||||
String userSurname,
|
||||
String userName,
|
||||
String primaryMail,
|
||||
String secondaryMail,
|
||||
String phoneNumber,
|
||||
String school,
|
||||
String course,
|
||||
boolean sneeStatus,
|
||||
Project projectParticipation,
|
||||
Project projectProposed,
|
||||
MakeAppointment makeAppointment) {
|
||||
super(idUser, userSurname, userName, primaryMail, secondaryMail, phoneNumber);
|
||||
this.school = school;
|
||||
this.course = course;
|
||||
this.sneeStatus = sneeStatus;
|
||||
this.projectParticipation = projectParticipation;
|
||||
this.projectProposed = projectProposed;
|
||||
this.makeAppointment = makeAppointment;
|
||||
}
|
||||
|
||||
public String getSchool() {
|
||||
return school;
|
||||
}
|
||||
|
||||
public void setSchool(String school) {
|
||||
this.school = school;
|
||||
}
|
||||
|
||||
public String getCourse() {
|
||||
return course;
|
||||
}
|
||||
|
||||
public void setCourse(String course) {
|
||||
this.course = course;
|
||||
}
|
||||
|
||||
public boolean isSneeStatus() {
|
||||
return sneeStatus;
|
||||
}
|
||||
|
||||
public void setSneeStatus(boolean statusSnee) {
|
||||
this.sneeStatus = sneeStatus;
|
||||
}
|
||||
|
||||
public Project getProjectParticipation() {
|
||||
return projectParticipation;
|
||||
}
|
||||
|
||||
public void setProjectParticipation(Project projectParticipation) {
|
||||
this.projectParticipation = projectParticipation;
|
||||
}
|
||||
|
||||
public Project getProjectProposed() {
|
||||
return projectProposed;
|
||||
}
|
||||
|
||||
public void setProjectProposed(Project projectProposed) {
|
||||
this.projectProposed = projectProposed;
|
||||
}
|
||||
|
||||
public MakeAppointment getMakeAppointment() {
|
||||
return makeAppointment;
|
||||
}
|
||||
|
||||
public void setMakeAppointment(MakeAppointment makeAppointment) {
|
||||
this.makeAppointment = makeAppointment;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package enseirb.myinpulse.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "make_appointment")
|
||||
public class MakeAppointment {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long idMakeAppointment;
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "idAdministrator")
|
||||
private Administrator administratorAppointment;
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "idEntrepreneur")
|
||||
private Entrepreneur entrepreneurAppointment;
|
||||
|
||||
public MakeAppointment() {}
|
||||
|
||||
public MakeAppointment(Long idMakeAppointment) {
|
||||
this.idMakeAppointment = idMakeAppointment;
|
||||
}
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
package enseirb.myinpulse.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table(name = "project")
|
||||
public class Project {
|
||||
|
||||
@OneToMany(mappedBy = "projectParticipation", fetch = FetchType.LAZY, orphanRemoval = true)
|
||||
private final List<Entrepreneur> listEntrepreneurParticipation = new ArrayList<>();
|
||||
|
||||
@OneToMany(mappedBy = "projectSectionCell", fetch = FetchType.LAZY, orphanRemoval = true)
|
||||
private final List<SectionCell> listSectionCell = new ArrayList<>();
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long idProject;
|
||||
|
||||
@Column(length = 255)
|
||||
private String projectName;
|
||||
|
||||
private byte[] logo;
|
||||
private LocalDate creationDate;
|
||||
|
||||
@Column private ProjectDecisionValue projectStatus;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "idAdministrator")
|
||||
private Administrator projectAdministrator;
|
||||
|
||||
@OneToOne(mappedBy = "projectProposed", fetch = FetchType.LAZY, orphanRemoval = true)
|
||||
private Entrepreneur entrepreneurProposed;
|
||||
|
||||
public Project() {}
|
||||
|
||||
public Project(
|
||||
String projectName,
|
||||
byte[] logo,
|
||||
LocalDate creationDate,
|
||||
ProjectDecisionValue projectStatus,
|
||||
Administrator projectAdministrator) {
|
||||
this.projectName = projectName;
|
||||
this.logo = logo;
|
||||
this.creationDate = creationDate;
|
||||
// this.projectStatus = (long) projectStatus.ordinal();
|
||||
this.projectStatus = projectStatus;
|
||||
this.projectAdministrator = projectAdministrator;
|
||||
}
|
||||
|
||||
public Project(
|
||||
String projectName,
|
||||
byte[] logo,
|
||||
LocalDate creationDate,
|
||||
ProjectDecisionValue projectStatus,
|
||||
Administrator projectAdministrator,
|
||||
Entrepreneur entrepreneurProposed) {
|
||||
this.projectName = projectName;
|
||||
this.logo = logo;
|
||||
this.creationDate = creationDate;
|
||||
this.projectStatus = projectStatus;
|
||||
this.projectAdministrator = projectAdministrator;
|
||||
this.entrepreneurProposed = entrepreneurProposed;
|
||||
}
|
||||
|
||||
public Long getIdProject() {
|
||||
return idProject;
|
||||
}
|
||||
|
||||
public void setIdProject(Long idProject) {
|
||||
this.idProject = idProject;
|
||||
}
|
||||
|
||||
public String getProjectName() {
|
||||
return projectName;
|
||||
}
|
||||
|
||||
public void setProjectName(String projectName) {
|
||||
this.projectName = projectName;
|
||||
}
|
||||
|
||||
public byte[] getLogo() {
|
||||
return logo;
|
||||
}
|
||||
|
||||
public void setLogo(byte[] logo) {
|
||||
this.logo = logo;
|
||||
}
|
||||
|
||||
public LocalDate getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
public void setCreationDate(LocalDate creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
|
||||
public ProjectDecisionValue getProjectStatus() {
|
||||
return projectStatus;
|
||||
}
|
||||
|
||||
public void setProjectStatus(ProjectDecisionValue projectStatus) {
|
||||
this.projectStatus = projectStatus;
|
||||
}
|
||||
|
||||
public List<Entrepreneur> getListEntrepreneurParticipation() {
|
||||
return listEntrepreneurParticipation;
|
||||
}
|
||||
|
||||
public void updateListEntrepreneurParticipation(Entrepreneur projectParticipant) {
|
||||
listEntrepreneurParticipation.add(projectParticipant);
|
||||
}
|
||||
|
||||
public List<SectionCell> getListSectionCell() {
|
||||
return listSectionCell;
|
||||
}
|
||||
|
||||
public void updateListSectionCell(SectionCell projectSectionCell) {
|
||||
listSectionCell.add(projectSectionCell);
|
||||
}
|
||||
|
||||
public Administrator getProjectAdministrator() {
|
||||
return projectAdministrator;
|
||||
}
|
||||
|
||||
public void setProjectAdministrator(Administrator projectAdministrator) {
|
||||
this.projectAdministrator = projectAdministrator;
|
||||
}
|
||||
|
||||
public Entrepreneur getEntrepreneurProposed() {
|
||||
return entrepreneurProposed;
|
||||
}
|
||||
|
||||
public void setEntrepreneurProposed(Entrepreneur entrepreneurProposed) {
|
||||
this.entrepreneurProposed = entrepreneurProposed;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package enseirb.myinpulse.model;
|
||||
|
||||
public class ProjectDecision {
|
||||
public long projectId;
|
||||
public long adminId;
|
||||
public long isAccepted;
|
||||
|
||||
public ProjectDecision(long projectId, long adminId, long isAccepted) {
|
||||
this.projectId = projectId;
|
||||
this.adminId = adminId;
|
||||
this.isAccepted = isAccepted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProjectDecision{"
|
||||
+ "projectId="
|
||||
+ projectId
|
||||
+ ", adminId="
|
||||
+ adminId
|
||||
+ ", isAccepted="
|
||||
+ isAccepted
|
||||
+ '}';
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package enseirb.myinpulse.model;
|
||||
|
||||
public enum ProjectDecisionValue {
|
||||
PENDING,
|
||||
ACTIVE,
|
||||
ENDED,
|
||||
ABORTED,
|
||||
REJECTED,
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package enseirb.myinpulse.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "report")
|
||||
public class Report {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long idReport;
|
||||
|
||||
private String reportContent;
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "idAppointment")
|
||||
private Appointment appointmentReport;
|
||||
|
||||
public Report() {}
|
||||
|
||||
public Report(Long idReport, String reportContent) {
|
||||
this.idReport = idReport;
|
||||
this.reportContent = reportContent;
|
||||
}
|
||||
|
||||
public Long getIdReport() {
|
||||
return idReport;
|
||||
}
|
||||
|
||||
public String getReportContent() {
|
||||
return reportContent;
|
||||
}
|
||||
|
||||
public void setReportContent(String reportContent) {
|
||||
this.reportContent = reportContent;
|
||||
}
|
||||
|
||||
public Appointment getAppointmentReport() {
|
||||
return appointmentReport;
|
||||
}
|
||||
|
||||
public void setAppointmentReport(Appointment appointmentReport) {
|
||||
this.appointmentReport = appointmentReport;
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package enseirb.myinpulse.model;
|
||||
|
||||
public class RoleRepresentation {
|
||||
public String id;
|
||||
public String name;
|
||||
public String description;
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package enseirb.myinpulse.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table(name = "section_cell")
|
||||
public class SectionCell {
|
||||
|
||||
@ManyToMany(mappedBy = "listSectionCell")
|
||||
private final List<Appointment> listAppointment = new ArrayList<>();
|
||||
|
||||
@OneToMany(mappedBy = "sectionCellAnnotation", fetch = FetchType.LAZY, orphanRemoval = true)
|
||||
private final List<Annotation> listAnnotation = new ArrayList<>();
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long idSectionCell;
|
||||
|
||||
@Column() private long sectionId;
|
||||
private String contentSectionCell;
|
||||
|
||||
/*@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "idAdministrator")
|
||||
private Administrator administratorSectionCell;*/
|
||||
// should now be useless
|
||||
private LocalDateTime modificationDate;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "idProject")
|
||||
private Project projectSectionCell;
|
||||
|
||||
public SectionCell() {}
|
||||
|
||||
public SectionCell(
|
||||
Long idSectionCell,
|
||||
Long sectionId,
|
||||
String contentSectionCell,
|
||||
LocalDateTime modificationDate,
|
||||
Project projectSectionCell) {
|
||||
this.idSectionCell = idSectionCell;
|
||||
this.sectionId = sectionId;
|
||||
this.contentSectionCell = contentSectionCell;
|
||||
this.modificationDate = modificationDate;
|
||||
this.projectSectionCell = projectSectionCell;
|
||||
}
|
||||
|
||||
public Long getIdSectionCell() {
|
||||
return idSectionCell;
|
||||
}
|
||||
|
||||
public void setIdSectionCell(Long idSectionCell) {
|
||||
this.idSectionCell = idSectionCell;
|
||||
}
|
||||
|
||||
public Long getSectionId() {
|
||||
return sectionId;
|
||||
}
|
||||
|
||||
public void setSectionId(Long sectionId) {
|
||||
this.sectionId = sectionId;
|
||||
}
|
||||
|
||||
public String getContentSectionCell() {
|
||||
return contentSectionCell;
|
||||
}
|
||||
|
||||
public void setContentSectionCell(String contentSectionCell) {
|
||||
this.contentSectionCell = contentSectionCell;
|
||||
}
|
||||
|
||||
public LocalDateTime getModificationDate() {
|
||||
return modificationDate;
|
||||
}
|
||||
|
||||
public void setModificationDate(LocalDateTime modificationDate) {
|
||||
this.modificationDate = modificationDate;
|
||||
}
|
||||
|
||||
public Project getProjectSectionCell() {
|
||||
return projectSectionCell;
|
||||
}
|
||||
|
||||
public List<Appointment> getAppointmentSectionCell() {
|
||||
return listAppointment;
|
||||
}
|
||||
|
||||
public void updateAppointmentSectionCell(Appointment appointment) {
|
||||
listAppointment.add(appointment);
|
||||
}
|
||||
|
||||
public List<Annotation> getListAnnotation() {
|
||||
return listAnnotation;
|
||||
}
|
||||
|
||||
public void updateListAnnotation(Annotation annotation) {
|
||||
listAnnotation.add(annotation);
|
||||
}
|
||||
|
||||
public void setSectionId(long sectionId) {
|
||||
this.sectionId = sectionId;
|
||||
}
|
||||
|
||||
public void setProjectSectionCell(Project projectSectionCell) {
|
||||
this.projectSectionCell = projectSectionCell;
|
||||
}
|
||||
}
|
108
MyINPulse-back/src/main/java/enseirb/myinpulse/model/User.java
Normal file
108
MyINPulse-back/src/main/java/enseirb/myinpulse/model/User.java
Normal file
@ -0,0 +1,108 @@
|
||||
package enseirb.myinpulse.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "user_inpulse")
|
||||
@Inheritance(strategy = InheritanceType.JOINED)
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long idUser;
|
||||
|
||||
@Column(length = 255)
|
||||
private String userSurname;
|
||||
|
||||
@Column(length = 255)
|
||||
private String userName;
|
||||
|
||||
@Column(length = 255)
|
||||
private String primaryMail;
|
||||
|
||||
@Column(length = 255)
|
||||
private String secondaryMail;
|
||||
|
||||
@Column(length = 20)
|
||||
private String phoneNumber;
|
||||
|
||||
public User() {}
|
||||
|
||||
// TODO: this should be removed as we shouldn't be able to chose the ID. Leaving it for
|
||||
// compatibility purposes, as soon as it's not used anymore, delete it
|
||||
public User(
|
||||
Long idUser,
|
||||
String userSurname,
|
||||
String userName,
|
||||
String primaryMail,
|
||||
String secondaryMail,
|
||||
String phoneNumber) {
|
||||
this.idUser = idUser;
|
||||
this.userSurname = userSurname;
|
||||
this.userName = userName;
|
||||
this.primaryMail = primaryMail;
|
||||
this.secondaryMail = secondaryMail;
|
||||
this.phoneNumber = phoneNumber;
|
||||
}
|
||||
|
||||
public User(
|
||||
String userSurname,
|
||||
String userName,
|
||||
String primaryMail,
|
||||
String secondaryMail,
|
||||
String phoneNumber) {
|
||||
this.userSurname = userSurname;
|
||||
this.userName = userName;
|
||||
this.primaryMail = primaryMail;
|
||||
this.secondaryMail = secondaryMail;
|
||||
this.phoneNumber = phoneNumber;
|
||||
}
|
||||
|
||||
public Long getIdUser() {
|
||||
return idUser;
|
||||
}
|
||||
|
||||
public void setIdUser(Long idUser) {
|
||||
this.idUser = idUser;
|
||||
}
|
||||
|
||||
public String getUserSurname() {
|
||||
return userSurname;
|
||||
}
|
||||
|
||||
public void setUserSurname(String userSurname) {
|
||||
userSurname = userSurname;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
userName = userName;
|
||||
}
|
||||
|
||||
public String getPrimaryMail() {
|
||||
return primaryMail;
|
||||
}
|
||||
|
||||
public void setPrimaryMail(String primaryMail) {
|
||||
this.primaryMail = primaryMail;
|
||||
}
|
||||
|
||||
public String getSecondaryMail() {
|
||||
return secondaryMail;
|
||||
}
|
||||
|
||||
public void setSecondaryMail(String secondaryMail) {
|
||||
this.secondaryMail = secondaryMail;
|
||||
}
|
||||
|
||||
public String getPhoneNumber() {
|
||||
return phoneNumber;
|
||||
}
|
||||
|
||||
public void setPhoneNumber(String phoneNumber) {
|
||||
phoneNumber = phoneNumber;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package enseirb.myinpulse.model;
|
||||
|
||||
public class UserRepresentation {
|
||||
public String id;
|
||||
public String name;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package enseirb.myinpulse.repository;
|
||||
|
||||
import enseirb.myinpulse.model.Administrator;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@RepositoryRestResource
|
||||
public interface AdministratorRepository extends JpaRepository<Administrator, Long> {
|
||||
|
||||
/* @Query("SELECT a from Administrators a")
|
||||
Administrator findAllAdministrator(); */
|
||||
|
||||
Optional<Administrator> findByPrimaryMail(String PrimaryMail);
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package enseirb.myinpulse.repository;
|
||||
|
||||
import enseirb.myinpulse.model.Annotation;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
|
||||
@RepositoryRestResource
|
||||
public interface AnnotationRepository extends JpaRepository<Annotation, Long> {}
|
@ -0,0 +1,9 @@
|
||||
package enseirb.myinpulse.repository;
|
||||
|
||||
import enseirb.myinpulse.model.Appointment;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
|
||||
@RepositoryRestResource
|
||||
public interface AppointmentRepository extends JpaRepository<Appointment, Long> {}
|
@ -0,0 +1,17 @@
|
||||
package enseirb.myinpulse.repository;
|
||||
|
||||
import enseirb.myinpulse.model.Entrepreneur;
|
||||
import enseirb.myinpulse.model.Project;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
|
||||
@RepositoryRestResource
|
||||
public interface EntrepreneurRepository extends JpaRepository<Entrepreneur, Long> {
|
||||
|
||||
Iterable<Entrepreneur> getEntrepreneurByProjectParticipation(Project project);
|
||||
|
||||
/* @Query("SELECT e from Entrepreneur e")
|
||||
Entrepreneur findAllEntrepreneurl(); */
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package enseirb.myinpulse.repository;
|
||||
|
||||
import enseirb.myinpulse.model.MakeAppointment;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
|
||||
@RepositoryRestResource
|
||||
public interface MakeAppointmentRepository extends JpaRepository<MakeAppointment, Long> {}
|
@ -0,0 +1,19 @@
|
||||
package enseirb.myinpulse.repository;
|
||||
|
||||
import enseirb.myinpulse.model.Administrator;
|
||||
import enseirb.myinpulse.model.Project;
|
||||
import enseirb.myinpulse.model.ProjectDecisionValue;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@RepositoryRestResource
|
||||
public interface ProjectRepository extends JpaRepository<Project, Long> {
|
||||
Iterable<Project> findByProjectAdministrator(Administrator administrator);
|
||||
|
||||
Iterable<Project> findByProjectStatus(ProjectDecisionValue status);
|
||||
|
||||
Optional<Project> findByProjectName(String projectName);
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package enseirb.myinpulse.repository;
|
||||
|
||||
import enseirb.myinpulse.model.Report;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
|
||||
@RepositoryRestResource
|
||||
public interface ReportRepository extends JpaRepository<Report, Long> {}
|
@ -0,0 +1,18 @@
|
||||
package enseirb.myinpulse.repository;
|
||||
|
||||
import enseirb.myinpulse.model.Project;
|
||||
import enseirb.myinpulse.model.SectionCell;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@RepositoryRestResource
|
||||
public interface SectionCellRepository extends JpaRepository<SectionCell, Long> {
|
||||
|
||||
Iterable<SectionCell> findByProjectSectionCellAndSectionId(Project project, long sectionId);
|
||||
|
||||
Iterable<SectionCell> findByProjectSectionCellAndSectionIdAndModificationDateBefore(
|
||||
Project project, long sectionId, LocalDateTime date);
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package enseirb.myinpulse.repository;
|
||||
|
||||
import enseirb.myinpulse.model.User;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@RepositoryRestResource
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
Optional<User> findByPrimaryMail(String email);
|
||||
|
||||
/* @Query("SELECT u from User u")
|
||||
User findAllUser(); */
|
||||
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
package enseirb.myinpulse.security;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
|
||||
public class KeycloakJwtRolesConverter implements Converter<Jwt, AbstractAuthenticationToken> {
|
||||
/**
|
||||
* Prefix used for realm level roles.
|
||||
*/
|
||||
public static final String PREFIX_REALM_ROLE = "ROLE_REALM_";
|
||||
/**
|
||||
* Prefix used in combination with the resource (client) name for resource level roles.
|
||||
*/
|
||||
public static final String PREFIX_RESOURCE_ROLE = "ROLE_";
|
||||
|
||||
/**
|
||||
* Name of the claim containing the realm level roles
|
||||
*/
|
||||
private static final String CLAIM_REALM_ACCESS = "realm_access";
|
||||
/**
|
||||
* Name of the claim containing the resources (clients) the user has access to.
|
||||
*/
|
||||
private static final String CLAIM_RESOURCE_ACCESS = "resource_access";
|
||||
/**
|
||||
* Name of the claim containing roles. (Applicable to realm and resource level.)
|
||||
*/
|
||||
private static final String CLAIM_ROLES = "roles";
|
||||
|
||||
@Override
|
||||
public AbstractAuthenticationToken convert(Jwt source)
|
||||
{
|
||||
return new JwtAuthenticationToken(source, Stream.concat(new JwtGrantedAuthoritiesConverter().convert(source)
|
||||
.stream(), TEMPORARNAME(source).stream())
|
||||
.collect(toSet()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the realm and resource level roles from a JWT token distinguishing between them using prefixes.
|
||||
*/
|
||||
public Collection<GrantedAuthority> TEMPORARNAME(Jwt jwt) {
|
||||
// Collection that will hold the extracted roles
|
||||
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
|
||||
|
||||
// Realm roles
|
||||
// Get the part of the access token that holds the roles assigned on realm level
|
||||
Map<String, Collection<String>> realmAccess = jwt.getClaim(CLAIM_REALM_ACCESS);
|
||||
|
||||
// Verify that the claim exists and is not empty
|
||||
if (realmAccess != null && !realmAccess.isEmpty()) {
|
||||
// From the realm_access claim get the roles
|
||||
Collection<String> roles = realmAccess.get(CLAIM_ROLES);
|
||||
// Check if any roles are present
|
||||
if (roles != null && !roles.isEmpty()) {
|
||||
// Iterate of the roles and add them to the granted authorities
|
||||
Collection<GrantedAuthority> realmRoles = roles.stream()
|
||||
// Prefix all realm roles with "ROLE_realm_"
|
||||
.map(role -> new SimpleGrantedAuthority(PREFIX_REALM_ROLE + role))
|
||||
.collect(Collectors.toList());
|
||||
grantedAuthorities.addAll(realmRoles);
|
||||
}
|
||||
}
|
||||
|
||||
// Resource (client) roles
|
||||
// A user might have access to multiple resources all containing their own roles. Therefore, it is a map of
|
||||
// resource each possibly containing a "roles" property.
|
||||
Map<String, Map<String, Collection<String>>> resourceAccess = jwt.getClaim(CLAIM_RESOURCE_ACCESS);
|
||||
|
||||
// Check if resources are assigned
|
||||
if (resourceAccess != null && !resourceAccess.isEmpty()) {
|
||||
// Iterate of all the resources
|
||||
resourceAccess.forEach((resource, resourceClaims) -> {
|
||||
// Iterate of the "roles" claim inside the resource claims
|
||||
resourceClaims.get(CLAIM_ROLES).forEach(
|
||||
// Add the role to the granted authority prefixed with ROLE_ and the name of the resource
|
||||
role -> grantedAuthorities.add(new SimpleGrantedAuthority(PREFIX_RESOURCE_ROLE + resource + "_" + role))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return grantedAuthorities;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,166 @@
|
||||
package enseirb.myinpulse.service;
|
||||
|
||||
import static enseirb.myinpulse.model.ProjectDecisionValue.ACTIVE;
|
||||
import static enseirb.myinpulse.model.ProjectDecisionValue.REJECTED;
|
||||
|
||||
import enseirb.myinpulse.model.*;
|
||||
import enseirb.myinpulse.service.database.*;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class AdminApiService {
|
||||
|
||||
protected static final Logger logger = LogManager.getLogger();
|
||||
|
||||
private final ProjectService projectService;
|
||||
private final UserService userService;
|
||||
private final AdministratorService administratorService;
|
||||
private final UtilsService utilsService;
|
||||
private final AppointmentService appointmentService;
|
||||
private final ReportService reportService;
|
||||
private final SectionCellService sectionCellService;
|
||||
|
||||
@Autowired
|
||||
AdminApiService(
|
||||
ProjectService projectService,
|
||||
UserService userService,
|
||||
AdministratorService administratorService,
|
||||
UtilsService utilsService,
|
||||
AppointmentService appointmentService,
|
||||
ReportService reportService,
|
||||
SectionCellService sectionCellService) {
|
||||
this.projectService = projectService;
|
||||
this.userService = userService;
|
||||
this.administratorService = administratorService;
|
||||
this.utilsService = utilsService;
|
||||
this.appointmentService = appointmentService;
|
||||
this.reportService = reportService;
|
||||
this.sectionCellService = sectionCellService;
|
||||
}
|
||||
|
||||
// TODO: check if tests are sufficient - peer verification required
|
||||
public Iterable<Project> getProjectsOfAdmin(String mail) {
|
||||
return projectService.getProjectsByAdminId(
|
||||
administratorService.getAdministratorById(
|
||||
this.userService.getUserByEmail(mail).getIdUser()));
|
||||
}
|
||||
|
||||
public Iterable<Appointment> getUpcomingAppointments(String mail) {
|
||||
logger.info("User {} check their upcoming appointments", mail);
|
||||
User user = this.userService.getUserByEmail(mail);
|
||||
List<Appointment> appointments = new ArrayList<>();
|
||||
if (user instanceof Administrator) {
|
||||
List<Project> projects = new ArrayList<>(((Administrator) user).getListProject());
|
||||
projects.forEach(
|
||||
project -> {
|
||||
project.getListSectionCell()
|
||||
.forEach(
|
||||
sectionCell -> {
|
||||
appointments.addAll(
|
||||
this.sectionCellService
|
||||
.getAppointmentsBySectionCellId(
|
||||
sectionCell
|
||||
.getIdSectionCell()));
|
||||
});
|
||||
});
|
||||
}
|
||||
if (user instanceof Entrepreneur) {
|
||||
Project project = ((Entrepreneur) user).getProjectParticipation();
|
||||
project.getListSectionCell()
|
||||
.forEach(
|
||||
sectionCell -> {
|
||||
appointments.addAll(
|
||||
this.sectionCellService.getAppointmentsBySectionCellId(
|
||||
sectionCell.getIdSectionCell()));
|
||||
});
|
||||
}
|
||||
return appointments;
|
||||
}
|
||||
|
||||
// TODO: check if tests are sufficient - peer verification required
|
||||
public Iterable<Project> getPendingProjects() {
|
||||
return this.projectService.getPendingProjects();
|
||||
}
|
||||
|
||||
// TODO: check if tests are sufficient - peer verification required
|
||||
public void validateProject(ProjectDecision decision) {
|
||||
projectService.updateProject(
|
||||
decision.projectId,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
(decision.isAccepted == 1) ? ACTIVE : REJECTED,
|
||||
this.administratorService.getAdministratorById(decision.adminId));
|
||||
}
|
||||
|
||||
// TODO: check if tests are sufficient - peer verification required
|
||||
public void addNewProject(Project project) {
|
||||
project.setIdProject(null);
|
||||
// We remove the ID from the request to be sure that it will be auto generated
|
||||
try {
|
||||
this.projectService.getProjectByName(project.getProjectName(), true);
|
||||
throw new ResponseStatusException(HttpStatus.CONFLICT, "Project already exists");
|
||||
} catch (ResponseStatusException e) {
|
||||
if (e.getStatusCode() == HttpStatus.CONFLICT) {
|
||||
throw new ResponseStatusException(HttpStatus.CONFLICT, "Project already exists");
|
||||
}
|
||||
}
|
||||
Project newProject = projectService.addNewProject(project);
|
||||
if (project.getProjectAdministrator() != null) {
|
||||
newProject.getProjectAdministrator().updateListProject(newProject);
|
||||
}
|
||||
if (newProject.getEntrepreneurProposed() != null) {
|
||||
Entrepreneur proposed = newProject.getEntrepreneurProposed();
|
||||
proposed.setProjectProposed(newProject);
|
||||
proposed.setProjectParticipation(newProject);
|
||||
}
|
||||
newProject
|
||||
.getListEntrepreneurParticipation()
|
||||
.forEach(
|
||||
participation -> {
|
||||
participation.setProjectParticipation(newProject);
|
||||
});
|
||||
newProject
|
||||
.getListSectionCell()
|
||||
.forEach(
|
||||
sectionCell -> {
|
||||
sectionCell.setProjectSectionCell(newProject);
|
||||
});
|
||||
}
|
||||
|
||||
public void createAppointmentReport(long appointmentId, Report report, String mail) {
|
||||
long projectId =
|
||||
this.appointmentService
|
||||
.getAppointmentById(appointmentId)
|
||||
.getAppointmentListSectionCell()
|
||||
.getFirst()
|
||||
.getProjectSectionCell()
|
||||
.getIdProject();
|
||||
if (!utilsService.isAllowedToCheckProject(mail, projectId)) {
|
||||
logger.warn(
|
||||
"User {} tried to add an report for appointment {} but is not allowed to.",
|
||||
mail,
|
||||
projectId);
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
|
||||
}
|
||||
logger.info("User {} added a report for appointment {}", mail, projectId);
|
||||
Report addedReport = this.reportService.addNewReport(report);
|
||||
addedReport.setAppointmentReport(this.appointmentService.getAppointmentById(appointmentId));
|
||||
this.appointmentService.getAppointmentById(appointmentId).setAppointmentReport(addedReport);
|
||||
}
|
||||
|
||||
// TODO: test
|
||||
public void deleteProject(long projectId) {
|
||||
this.projectService.deleteProjectById(projectId);
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
package enseirb.myinpulse.service;
|
||||
|
||||
import static enseirb.myinpulse.model.ProjectDecisionValue.PENDING;
|
||||
|
||||
import enseirb.myinpulse.model.Project;
|
||||
import enseirb.myinpulse.model.SectionCell;
|
||||
import enseirb.myinpulse.service.database.ProjectService;
|
||||
import enseirb.myinpulse.service.database.SectionCellService;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
@Service
|
||||
public class EntrepreneurApiService {
|
||||
|
||||
protected static final Logger logger = LogManager.getLogger();
|
||||
|
||||
private final SectionCellService sectionCellService;
|
||||
private final ProjectService projectService;
|
||||
private final UtilsService utilsService;
|
||||
|
||||
@Autowired
|
||||
EntrepreneurApiService(
|
||||
SectionCellService sectionCellService,
|
||||
ProjectService projectService,
|
||||
UtilsService utilsService) {
|
||||
this.sectionCellService = sectionCellService;
|
||||
this.projectService = projectService;
|
||||
this.utilsService = utilsService;
|
||||
}
|
||||
|
||||
public void editSectionCell(Long sectionCellId, SectionCell sectionCell, String mail) {
|
||||
SectionCell editSectionCell = sectionCellService.getSectionCellById(sectionCellId);
|
||||
if (editSectionCell == null) {
|
||||
System.err.println("Trying to edit unknown section cell");
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.NOT_FOUND, "Cette cellule de section n'existe pas");
|
||||
}
|
||||
if (!utilsService.isAllowedToCheckProject(
|
||||
mail, this.sectionCellService.getProjectId(sectionCellId))) {
|
||||
logger.warn(
|
||||
"User {} tried to edit section cells {} of the project {} but is not allowed to.",
|
||||
mail,
|
||||
sectionCellId,
|
||||
this.sectionCellService.getProjectId(sectionCellId));
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
|
||||
}
|
||||
logger.info(
|
||||
"User {} edited section cell {} of the project with id {}",
|
||||
mail,
|
||||
sectionCellId,
|
||||
this.sectionCellService.getProjectId(sectionCellId));
|
||||
sectionCellService.updateSectionCell(
|
||||
sectionCellId,
|
||||
sectionCell.getSectionId(),
|
||||
sectionCell.getContentSectionCell(),
|
||||
sectionCell.getModificationDate());
|
||||
}
|
||||
|
||||
public void removeSectionCell(Long sectionCellId, String mail) {
|
||||
SectionCell editSectionCell = sectionCellService.getSectionCellById(sectionCellId);
|
||||
if (editSectionCell == null) {
|
||||
System.err.println("Trying to remove unknown section cell");
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.NOT_FOUND, "Cette cellule de section n'existe pas");
|
||||
}
|
||||
if (!utilsService.isAllowedToCheckProject(
|
||||
mail, this.sectionCellService.getProjectId(sectionCellId))) {
|
||||
logger.warn(
|
||||
"User {} tried to remove section cells {} of the project {} but is not allowed to.",
|
||||
mail,
|
||||
sectionCellId,
|
||||
this.sectionCellService.getSectionCellById(sectionCellId));
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
|
||||
}
|
||||
logger.info(
|
||||
"User {} removed section cell {} of the project with id {}",
|
||||
mail,
|
||||
sectionCellId,
|
||||
this.sectionCellService.getProjectId(sectionCellId));
|
||||
sectionCellService.removeSectionCellById(sectionCellId);
|
||||
}
|
||||
|
||||
public void addSectionCell(SectionCell sectionCell, String mail) {
|
||||
if (sectionCell == null) {
|
||||
System.err.println("Trying to create an empty section cell");
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.BAD_REQUEST, "La cellule de section fournie est vide");
|
||||
}
|
||||
if (!utilsService.isAllowedToCheckProject(
|
||||
mail, this.sectionCellService.getProjectId(sectionCell.getIdSectionCell()))) {
|
||||
logger.warn(
|
||||
"User {} tried to add a section cell to the project {} but is not allowed to.",
|
||||
mail,
|
||||
this.sectionCellService.getProjectId(sectionCell.getIdSectionCell()));
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
|
||||
}
|
||||
logger.info(
|
||||
"User {} added a new section cell {} to the project with id {}",
|
||||
mail,
|
||||
sectionCell.getIdSectionCell(),
|
||||
this.sectionCellService.getProjectId(sectionCell.getIdSectionCell()));
|
||||
SectionCell newSectionCell = sectionCellService.addNewSectionCell(sectionCell);
|
||||
newSectionCell.getProjectSectionCell().updateListSectionCell(newSectionCell);
|
||||
newSectionCell
|
||||
.getAppointmentSectionCell()
|
||||
.forEach(
|
||||
appointment -> {
|
||||
appointment.updateListSectionCell(newSectionCell);
|
||||
});
|
||||
newSectionCell
|
||||
.getListAnnotation()
|
||||
.forEach(
|
||||
annotation -> {
|
||||
annotation.setSectionCellAnnotation(newSectionCell);
|
||||
});
|
||||
}
|
||||
|
||||
public void requestNewProject(Project project, String mail) {
|
||||
if (project == null) {
|
||||
logger.error("Trying to request the creation of a null project");
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Le projet fourni est vide");
|
||||
}
|
||||
logger.info("User {} created a new project with id {}", mail, project.getIdProject());
|
||||
project.setProjectStatus(PENDING);
|
||||
projectService.addNewProject(project);
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
package enseirb.myinpulse.service;
|
||||
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON;
|
||||
|
||||
import enseirb.myinpulse.exception.UserNotFoundException;
|
||||
import enseirb.myinpulse.model.RoleRepresentation;
|
||||
import enseirb.myinpulse.model.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();
|
||||
}
|
||||
}
|
@ -0,0 +1,252 @@
|
||||
package enseirb.myinpulse.service;
|
||||
|
||||
import com.itextpdf.text.*;
|
||||
import com.itextpdf.text.pdf.PdfWriter;
|
||||
|
||||
import enseirb.myinpulse.model.*;
|
||||
import enseirb.myinpulse.service.database.*;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class SharedApiService {
|
||||
|
||||
protected static final Logger logger = LogManager.getLogger();
|
||||
|
||||
private final ProjectService projectService;
|
||||
private final EntrepreneurService entrepreneurService;
|
||||
private final SectionCellService sectionCellService;
|
||||
private final AppointmentService appointmentService;
|
||||
|
||||
private final UtilsService utilsService;
|
||||
|
||||
@Autowired
|
||||
SharedApiService(
|
||||
ProjectService projectService,
|
||||
EntrepreneurService entrepreneurService,
|
||||
SectionCellService sectionCellService,
|
||||
AppointmentService appointmentService,
|
||||
UtilsService utilsService) {
|
||||
this.projectService = projectService;
|
||||
this.entrepreneurService = entrepreneurService;
|
||||
this.sectionCellService = sectionCellService;
|
||||
this.appointmentService = appointmentService;
|
||||
this.utilsService = utilsService;
|
||||
}
|
||||
|
||||
// TODO filter this with date
|
||||
public Iterable<SectionCell> getSectionCells(
|
||||
long projectId, long sectionId, String date, String mail) {
|
||||
|
||||
if (!utilsService.isAllowedToCheckProject(mail, projectId)) {
|
||||
logger.warn(
|
||||
"User {} tried to check section cells of the project {} but is not allowed to.",
|
||||
mail,
|
||||
projectId);
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
|
||||
}
|
||||
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
||||
LocalDateTime dateTime = LocalDateTime.parse(date, formatter);
|
||||
|
||||
Project project = this.projectService.getProjectById(projectId);
|
||||
return this.sectionCellService.getSectionCellsByProjectAndSectionIdBeforeDate(
|
||||
project, sectionId, dateTime);
|
||||
}
|
||||
|
||||
// TODO: test
|
||||
public Iterable<Entrepreneur> getEntrepreneursByProjectId(long projectId, String mail) {
|
||||
if (!utilsService.isAllowedToCheckProject(mail, projectId)) {
|
||||
logger.warn(
|
||||
"User {} tried to check the member of the project {} but is not allowed to.",
|
||||
mail,
|
||||
projectId);
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
|
||||
}
|
||||
Project project = this.projectService.getProjectById(projectId);
|
||||
return this.entrepreneurService.GetEntrepreneurByProject(project);
|
||||
}
|
||||
|
||||
// TODO: test
|
||||
public Administrator getAdminByProjectId(long projectId, String mail) {
|
||||
if (!utilsService.isAllowedToCheckProject(mail, projectId)) {
|
||||
logger.warn(
|
||||
"User {} tried to check the admin of the project {} but is not allowed to.",
|
||||
mail,
|
||||
projectId);
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
|
||||
}
|
||||
Project project = this.projectService.getProjectById(projectId);
|
||||
return project.getProjectAdministrator();
|
||||
}
|
||||
|
||||
public Iterable<Appointment> getAppointmentsByProjectId(long projectId, String mail) {
|
||||
if (!utilsService.isAllowedToCheckProject(mail, projectId)) {
|
||||
logger.warn(
|
||||
"User {} tried to check the appointments related to the project {} but is not allowed to.",
|
||||
mail,
|
||||
projectId);
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
|
||||
}
|
||||
logger.info(
|
||||
"User {} tried to check the appointments related to the project {}",
|
||||
mail,
|
||||
projectId);
|
||||
Iterable<SectionCell> sectionCells =
|
||||
this.sectionCellService.getSectionCellsByProject(
|
||||
projectService.getProjectById(projectId),
|
||||
2L); // sectionId useless in this function ?
|
||||
List<Appointment> appointments = new ArrayList<Appointment>();
|
||||
sectionCells.forEach(
|
||||
sectionCell -> {
|
||||
appointments.addAll(
|
||||
this.sectionCellService.getAppointmentsBySectionCellId(
|
||||
sectionCell.getIdSectionCell()));
|
||||
});
|
||||
return appointments;
|
||||
}
|
||||
|
||||
public void getPDFReport(long appointmentId, String mail)
|
||||
throws DocumentException, URISyntaxException, IOException {
|
||||
long projectId =
|
||||
this.appointmentService
|
||||
.getAppointmentById(appointmentId)
|
||||
.getAppointmentListSectionCell()
|
||||
.getFirst()
|
||||
.getProjectSectionCell()
|
||||
.getIdProject();
|
||||
if (!utilsService.isAllowedToCheckProject(mail, projectId)) {
|
||||
logger.warn(
|
||||
"User {} tried to generate the PDF report {} related to the appointment {} but is not allowed to.",
|
||||
mail,
|
||||
this.appointmentService
|
||||
.getAppointmentById(appointmentId)
|
||||
.getAppointmentReport()
|
||||
.getIdReport(),
|
||||
appointmentId);
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
|
||||
}
|
||||
logger.info(
|
||||
"User {} generated the PDF report related to appointment {}", mail, appointmentId);
|
||||
|
||||
String reportContent =
|
||||
this.appointmentService
|
||||
.getAppointmentById(appointmentId)
|
||||
.getAppointmentReport()
|
||||
.getReportContent();
|
||||
|
||||
// PDF generation
|
||||
Document document = new Document();
|
||||
PdfWriter.getInstance(document, new FileOutputStream("Report" + appointmentId + ".pdf"));
|
||||
document.open();
|
||||
|
||||
Paragraph title =
|
||||
new Paragraph(
|
||||
new Phrase(
|
||||
"Compte Rendu - Réunion du "
|
||||
+ this.appointmentService
|
||||
.getAppointmentById(appointmentId)
|
||||
.getAppointmentDate()
|
||||
.toString(),
|
||||
FontFactory.getFont(
|
||||
FontFactory.HELVETICA,
|
||||
20,
|
||||
Font.BOLDITALIC,
|
||||
BaseColor.BLACK)));
|
||||
title.setAlignment(Element.ALIGN_CENTER);
|
||||
document.add(title);
|
||||
|
||||
Font subsection =
|
||||
FontFactory.getFont(FontFactory.HELVETICA, 14, Font.UNDERLINE, BaseColor.DARK_GRAY);
|
||||
Font body = FontFactory.getFont(FontFactory.COURIER, 12, BaseColor.BLACK);
|
||||
|
||||
String[] split = reportContent.split(" ");
|
||||
|
||||
String tmp = "";
|
||||
int counter = 1;
|
||||
for (String s : split) {
|
||||
if (s.equals("//")) {
|
||||
Chunk chunk = new Chunk(tmp, body);
|
||||
document.add(chunk);
|
||||
document.add(new Paragraph("\n"));
|
||||
tmp = "";
|
||||
Paragraph paragraph = new Paragraph("Point n°" + counter + " : ", subsection);
|
||||
document.add(paragraph);
|
||||
document.add(new Paragraph("\n"));
|
||||
counter++;
|
||||
} else {
|
||||
tmp = tmp.concat(s + " ");
|
||||
}
|
||||
}
|
||||
Chunk chunk = new Chunk(tmp, body);
|
||||
document.add(chunk);
|
||||
document.add(new Paragraph("\n"));
|
||||
|
||||
document.close();
|
||||
|
||||
// Replace uri with website address
|
||||
Files.copy(
|
||||
new URI(
|
||||
"http://localhost:8080/shared/projects/appointments/report/"
|
||||
+ appointmentId)
|
||||
.toURL()
|
||||
.openStream(),
|
||||
Paths.get("Report" + appointmentId + ".pdf"),
|
||||
StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
// delete file, we don't want to stock all reports on the server
|
||||
File file = new File("Report" + appointmentId + ".pdf");
|
||||
if (!file.delete()) {
|
||||
logger.warn("Failed to delete report {}", file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
public void createAppointmentRequest(Appointment appointment, String mail) {
|
||||
long projectId =
|
||||
appointment
|
||||
.getAppointmentListSectionCell()
|
||||
.getFirst()
|
||||
.getProjectSectionCell()
|
||||
.getIdProject();
|
||||
if (!utilsService.isAllowedToCheckProject(mail, projectId)) {
|
||||
logger.warn(
|
||||
"User {} tried to create for the project {} but is not allowed to.",
|
||||
mail,
|
||||
projectId);
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
|
||||
}
|
||||
logger.info("User {} tried to create an appointment for project {}", mail, projectId);
|
||||
Appointment newAppointment = this.appointmentService.addNewAppointment(appointment);
|
||||
newAppointment
|
||||
.getAppointmentListSectionCell()
|
||||
.forEach(
|
||||
sectionCell -> {
|
||||
sectionCell.updateAppointmentSectionCell(newAppointment);
|
||||
});
|
||||
newAppointment.getAppointmentReport().setAppointmentReport(newAppointment);
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package enseirb.myinpulse.service;
|
||||
|
||||
import enseirb.myinpulse.model.Administrator;
|
||||
import enseirb.myinpulse.model.Entrepreneur;
|
||||
import enseirb.myinpulse.model.Project;
|
||||
import enseirb.myinpulse.model.User;
|
||||
import enseirb.myinpulse.service.database.AdministratorService;
|
||||
import enseirb.myinpulse.service.database.EntrepreneurService;
|
||||
import enseirb.myinpulse.service.database.ProjectService;
|
||||
import enseirb.myinpulse.service.database.UserService;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
@Service
|
||||
public class UtilsService {
|
||||
|
||||
protected static final Logger logger = LogManager.getLogger();
|
||||
|
||||
private final UserService userService;
|
||||
private final ProjectService projectService;
|
||||
private final EntrepreneurService entrepreneurService;
|
||||
private final AdministratorService administratorService;
|
||||
|
||||
@Autowired
|
||||
UtilsService(
|
||||
ProjectService projectService,
|
||||
UserService userService,
|
||||
EntrepreneurService entrepreneurService,
|
||||
AdministratorService administratorService) {
|
||||
this.userService = userService;
|
||||
this.projectService = projectService;
|
||||
this.entrepreneurService = entrepreneurService;
|
||||
this.administratorService = administratorService;
|
||||
}
|
||||
|
||||
// TODO: test?
|
||||
public Boolean isAllowedToCheckProject(String mail, long projectId) {
|
||||
if (isAnAdmin(mail)) {
|
||||
return true;
|
||||
}
|
||||
User user = this.userService.getUserByEmail(mail);
|
||||
Entrepreneur entrepreneur = this.entrepreneurService.getEntrepreneurById(user.getIdUser());
|
||||
Project project = this.projectService.getProjectById(projectId);
|
||||
return entrepreneur.getProjectParticipation() == project;
|
||||
}
|
||||
|
||||
// TODO: test
|
||||
Boolean isAnAdmin(String mail) {
|
||||
try {
|
||||
long userId = this.userService.getUserByEmail(mail).getIdUser();
|
||||
Administrator a = this.administratorService.getAdministratorById(userId);
|
||||
return true;
|
||||
} catch (ResponseStatusException e) {
|
||||
logger.info(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package enseirb.myinpulse.service.database;
|
||||
|
||||
import enseirb.myinpulse.model.Administrator;
|
||||
import enseirb.myinpulse.repository.AdministratorRepository;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class AdministratorService {
|
||||
protected static final Logger logger = LogManager.getLogger();
|
||||
|
||||
private final AdministratorRepository administratorRepository;
|
||||
|
||||
@Autowired
|
||||
AdministratorService(AdministratorRepository administratorRepository) {
|
||||
this.administratorRepository = administratorRepository;
|
||||
}
|
||||
|
||||
public Iterable<Administrator> allAdministrators() {
|
||||
return this.administratorRepository.findAll();
|
||||
}
|
||||
|
||||
public Administrator getAdministratorById(long id) {
|
||||
Optional<Administrator> administrator = this.administratorRepository.findById(id);
|
||||
if (administrator.isEmpty()) {
|
||||
logger.error("No administrator found with id {}", id);
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.NOT_FOUND, "Cet administrateur n'existe pas");
|
||||
}
|
||||
return administrator.get();
|
||||
}
|
||||
|
||||
public Administrator getAdministratorByPrimaryMain(String primaryMail) {
|
||||
Optional<Administrator> administrator =
|
||||
this.administratorRepository.findByPrimaryMail(primaryMail);
|
||||
if (administrator.isEmpty()) {
|
||||
logger.error("No administrator found with the mail {}", primaryMail);
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.NOT_FOUND, "Cet administrateur n'existe pas");
|
||||
}
|
||||
return administrator.get();
|
||||
}
|
||||
|
||||
public Administrator addAdministrator(Administrator administrator) {
|
||||
return this.administratorRepository.save(administrator);
|
||||
}
|
||||
|
||||
/*
|
||||
public Administrator getAdministratorByProject(Project project) {
|
||||
r
|
||||
}
|
||||
*/
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package enseirb.myinpulse.service.database;
|
||||
|
||||
import enseirb.myinpulse.model.Annotation;
|
||||
import enseirb.myinpulse.repository.AnnotationRepository;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class AnnotationService {
|
||||
|
||||
protected static final Logger logger = LogManager.getLogger();
|
||||
|
||||
private final AnnotationRepository annotationRepository;
|
||||
|
||||
@Autowired
|
||||
AnnotationService(AnnotationRepository annotationRepository) {
|
||||
this.annotationRepository = annotationRepository;
|
||||
}
|
||||
|
||||
public Iterable<Annotation> getAllAnnotations() {
|
||||
return annotationRepository.findAll();
|
||||
}
|
||||
|
||||
public Annotation getAnnotationById(Long id) {
|
||||
Optional<Annotation> annotation = annotationRepository.findById(id);
|
||||
if (annotation.isEmpty()) {
|
||||
logger.error("getAnnotationById : No annotation found with id {}", id);
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.NOT_FOUND, "Cette annotation n'existe pas");
|
||||
}
|
||||
return annotation.get();
|
||||
}
|
||||
|
||||
public Annotation addNewAnnotation(Annotation annotation) {
|
||||
return this.annotationRepository.save(annotation);
|
||||
}
|
||||
|
||||
public void deleteAnnotationById(Long id) {
|
||||
this.annotationRepository.deleteById(id);
|
||||
}
|
||||
|
||||
public Annotation updateAnnotation(Long id, String comment) {
|
||||
Optional<Annotation> annotation = annotationRepository.findById(id);
|
||||
if (annotation.isEmpty()) {
|
||||
logger.error("updateAnnotation : No annotation found with id {}", id);
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.NOT_FOUND, "Cette annotation n'existe pas");
|
||||
}
|
||||
if (comment != null) {
|
||||
annotation.get().setComment(comment);
|
||||
}
|
||||
return this.annotationRepository.save(annotation.get());
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package enseirb.myinpulse.service.database;
|
||||
|
||||
import enseirb.myinpulse.model.Appointment;
|
||||
import enseirb.myinpulse.repository.AppointmentRepository;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class AppointmentService {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(AppointmentService.class);
|
||||
|
||||
private AppointmentRepository appointmentRepository;
|
||||
|
||||
@Autowired
|
||||
AppointmentService(AppointmentRepository appointmentRepository) {
|
||||
this.appointmentRepository = appointmentRepository;
|
||||
}
|
||||
|
||||
public Iterable<Appointment> getallAppointments() {
|
||||
return this.appointmentRepository.findAll();
|
||||
}
|
||||
|
||||
public Appointment getAppointmentById(Long id) {
|
||||
Optional<Appointment> appointment = this.appointmentRepository.findById(id);
|
||||
if (appointment.isEmpty()) {
|
||||
logger.error("getAppointmentById : No appointment found with id {}", id);
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce rendez vous n'existe pas");
|
||||
}
|
||||
return appointment.get();
|
||||
}
|
||||
|
||||
public Appointment addNewAppointment(Appointment appointment) {
|
||||
return this.appointmentRepository.save(appointment);
|
||||
}
|
||||
|
||||
public void deleteAppointmentById(Long id) {
|
||||
this.appointmentRepository.deleteById(id);
|
||||
}
|
||||
|
||||
public Appointment updateAppointment(
|
||||
Long id,
|
||||
LocalDate appointmentDate,
|
||||
LocalTime appointmentTime,
|
||||
LocalTime appointmentDuration,
|
||||
String appointmentPlace,
|
||||
String appointmentSubject) {
|
||||
Optional<Appointment> appointment = this.appointmentRepository.findById(id);
|
||||
if (appointment.isEmpty()) {
|
||||
logger.error("updateAppointment : No appointment found with id {}", id);
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce rendez vous n'existe pas");
|
||||
}
|
||||
if (appointmentDate != null) {
|
||||
appointment.get().setAppointmentDate(appointmentDate);
|
||||
}
|
||||
if (appointmentTime != null) {
|
||||
appointment.get().setAppointmentTime(appointmentTime);
|
||||
}
|
||||
if (appointmentDuration != null) {
|
||||
appointment.get().setAppointmentDuration(appointmentDuration);
|
||||
}
|
||||
if (appointmentPlace != null) {
|
||||
appointment.get().setAppointmentPlace(appointmentPlace);
|
||||
}
|
||||
if (appointmentSubject != null) {
|
||||
appointment.get().setAppointmentSubject(appointmentSubject);
|
||||
}
|
||||
return this.appointmentRepository.save(appointment.get());
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package enseirb.myinpulse.service.database;
|
||||
|
||||
import enseirb.myinpulse.model.Entrepreneur;
|
||||
import enseirb.myinpulse.model.Project;
|
||||
import enseirb.myinpulse.repository.EntrepreneurRepository;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class EntrepreneurService {
|
||||
|
||||
protected static final Logger logger = LogManager.getLogger();
|
||||
|
||||
private final EntrepreneurRepository entrepreneurRepository;
|
||||
|
||||
EntrepreneurService(EntrepreneurRepository entrepreneurRepository) {
|
||||
this.entrepreneurRepository = entrepreneurRepository;
|
||||
}
|
||||
|
||||
public Iterable<Entrepreneur> getAllEntrepreneurs() {
|
||||
return this.entrepreneurRepository.findAll();
|
||||
}
|
||||
|
||||
public Entrepreneur getEntrepreneurById(Long id) {
|
||||
Optional<Entrepreneur> entrepreneur = entrepreneurRepository.findById(id);
|
||||
if (entrepreneur.isEmpty()) {
|
||||
logger.error("getEntrepreneurById : No entrepreneur found with id {}", id);
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.NOT_FOUND, "Cet entrepreneur n'existe pas");
|
||||
}
|
||||
return entrepreneur.get();
|
||||
}
|
||||
|
||||
public Entrepreneur addEntrepreneur(Entrepreneur entrepreneur) {
|
||||
return this.entrepreneurRepository.save(entrepreneur);
|
||||
}
|
||||
|
||||
public Entrepreneur updateEntrepreneur(
|
||||
Long id, String school, String course, Boolean sneeStatus) {
|
||||
Optional<Entrepreneur> entrepreneur = entrepreneurRepository.findById(id);
|
||||
if (entrepreneur.isEmpty()) {
|
||||
logger.error("updateEntrepreneur : No entrepreneur found with id {}", id);
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.NOT_FOUND, "Cet entrepreneur n'existe pas");
|
||||
}
|
||||
if (school != null) {
|
||||
entrepreneur.get().setSchool(school);
|
||||
}
|
||||
if (course != null) {
|
||||
entrepreneur.get().setCourse(course);
|
||||
}
|
||||
if (sneeStatus != null) {
|
||||
entrepreneur.get().setSneeStatus(sneeStatus);
|
||||
}
|
||||
return this.entrepreneurRepository.save(entrepreneur.get());
|
||||
}
|
||||
|
||||
public Iterable<Entrepreneur> GetEntrepreneurByProject(Project project) {
|
||||
return this.entrepreneurRepository.getEntrepreneurByProjectParticipation(project);
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
package enseirb.myinpulse.service.database;
|
||||
|
||||
import static enseirb.myinpulse.model.ProjectDecisionValue.PENDING;
|
||||
|
||||
import enseirb.myinpulse.model.Administrator;
|
||||
import enseirb.myinpulse.model.Project;
|
||||
import enseirb.myinpulse.model.ProjectDecisionValue;
|
||||
import enseirb.myinpulse.repository.ProjectRepository;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class ProjectService {
|
||||
|
||||
protected static final Logger logger = LogManager.getLogger();
|
||||
|
||||
private final ProjectRepository projectRepository;
|
||||
|
||||
@Autowired
|
||||
ProjectService(ProjectRepository projectRepository) {
|
||||
this.projectRepository = projectRepository;
|
||||
}
|
||||
|
||||
public Iterable<Project> getAllProjects() {
|
||||
return this.projectRepository.findAll();
|
||||
}
|
||||
|
||||
public Project getProjectById(Long id) {
|
||||
Optional<Project> project = this.projectRepository.findById(id);
|
||||
if (project.isEmpty()) {
|
||||
logger.error("No project found with id {}", id);
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce projet n'existe pas");
|
||||
}
|
||||
return project.get();
|
||||
}
|
||||
|
||||
public Iterable<Project> getProjectsByAdminId(Administrator administrator) {
|
||||
return this.projectRepository.findByProjectAdministrator(administrator);
|
||||
}
|
||||
|
||||
// TODO: validation
|
||||
public Project addNewProject(Project project) {
|
||||
return this.projectRepository.save(project);
|
||||
}
|
||||
|
||||
public Project updateProject(
|
||||
Long id,
|
||||
String projectName,
|
||||
byte[] logo,
|
||||
LocalDate creationDate,
|
||||
ProjectDecisionValue projectStatus,
|
||||
Administrator administrator) {
|
||||
Optional<Project> project = this.projectRepository.findById(id);
|
||||
|
||||
if (project.isEmpty()) {
|
||||
logger.error("Project with id {} not found.", id);
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce projet n'existe pas");
|
||||
}
|
||||
|
||||
if (projectName != null) {
|
||||
project.get().setProjectName(projectName);
|
||||
}
|
||||
|
||||
if (logo != null) {
|
||||
project.get().setLogo(logo);
|
||||
}
|
||||
|
||||
if (creationDate != null) {
|
||||
project.get().setCreationDate(creationDate);
|
||||
}
|
||||
|
||||
if (projectStatus != null) {
|
||||
// TODO: check if this is really useful
|
||||
/*
|
||||
if (!validateStatus(projectStatus)) {
|
||||
logger.error("updateProjectStatus: Invalid status {}", projectStatus);
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.NOT_ACCEPTABLE, "Ce status n'est pas accepté");
|
||||
}
|
||||
*/
|
||||
project.get().setProjectStatus(projectStatus);
|
||||
}
|
||||
|
||||
if (administrator != null) {
|
||||
project.get().setProjectAdministrator(administrator);
|
||||
}
|
||||
|
||||
return this.projectRepository.save(project.get());
|
||||
}
|
||||
|
||||
public Boolean validateStatus(String status) {
|
||||
return List.of("PENDING", "ACTIVE", "ENDED").contains(status);
|
||||
}
|
||||
|
||||
public Iterable<Project> getPendingProjects() {
|
||||
return this.projectRepository.findByProjectStatus(PENDING);
|
||||
}
|
||||
|
||||
public void deleteProjectById(Long id) {
|
||||
this.projectRepository.deleteById(id);
|
||||
}
|
||||
|
||||
public Project getProjectByName(String name, boolean noerror) {
|
||||
Optional<Project> project = this.projectRepository.findByProjectName(name);
|
||||
if (project.isEmpty()) {
|
||||
if (noerror) logger.error("No project found with name {}", name);
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce projet n'existe pas");
|
||||
}
|
||||
return project.get();
|
||||
}
|
||||
|
||||
public Project getProjectByName(String name) {
|
||||
return getProjectByName(name, false);
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package enseirb.myinpulse.service.database;
|
||||
|
||||
import enseirb.myinpulse.model.Report;
|
||||
import enseirb.myinpulse.repository.ReportRepository;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class ReportService {
|
||||
|
||||
protected static final Logger logger = LogManager.getLogger();
|
||||
|
||||
private final ReportRepository reportRepository;
|
||||
|
||||
@Autowired
|
||||
ReportService(ReportRepository reportRepository) {
|
||||
this.reportRepository = reportRepository;
|
||||
}
|
||||
|
||||
public Iterable<Report> getAllReports() {
|
||||
return this.reportRepository.findAll();
|
||||
}
|
||||
|
||||
public Report getReportById(Long id) {
|
||||
Optional<Report> report = this.reportRepository.findById(id);
|
||||
if (report.isEmpty()) {
|
||||
logger.error("getReportById : No report found with id {}", id);
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce compte rendu n'existe pas");
|
||||
}
|
||||
return report.get();
|
||||
}
|
||||
|
||||
// TODO: do some validation
|
||||
public Report addNewReport(Report report) {
|
||||
return this.reportRepository.save(report);
|
||||
}
|
||||
|
||||
public void deleteReportById(Long id) {
|
||||
this.reportRepository.deleteById(id);
|
||||
}
|
||||
|
||||
public Report updateReport(Long id, String reportContent) {
|
||||
Optional<Report> report = this.reportRepository.findById(id);
|
||||
if (report.isEmpty()) {
|
||||
logger.error("updateReport : No report found with id {}", id);
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce compte rendu n'existe pas");
|
||||
}
|
||||
if (reportContent != null) {
|
||||
report.get().setReportContent(reportContent);
|
||||
}
|
||||
return this.reportRepository.save(report.get());
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package enseirb.myinpulse.service.database;
|
||||
|
||||
import enseirb.myinpulse.model.Appointment;
|
||||
import enseirb.myinpulse.model.Project;
|
||||
import enseirb.myinpulse.model.SectionCell;
|
||||
import enseirb.myinpulse.repository.SectionCellRepository;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class SectionCellService {
|
||||
|
||||
protected static final Logger logger = LogManager.getLogger();
|
||||
|
||||
private final SectionCellRepository sectionCellRepository;
|
||||
|
||||
@Autowired
|
||||
SectionCellService(SectionCellRepository sectionCellRepository) {
|
||||
this.sectionCellRepository = sectionCellRepository;
|
||||
}
|
||||
|
||||
public Iterable<SectionCell> getAllSectionCells() {
|
||||
return this.sectionCellRepository.findAll();
|
||||
}
|
||||
|
||||
public SectionCell getSectionCellById(Long id) {
|
||||
Optional<SectionCell> sectionCell = this.sectionCellRepository.findById(id);
|
||||
if (sectionCell.isEmpty()) {
|
||||
logger.error("getSectionCellById : No sectionCell found with id {}", id);
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.NOT_FOUND, "Cette cellule de section n'existe pas");
|
||||
}
|
||||
return sectionCell.get();
|
||||
}
|
||||
|
||||
public SectionCell addNewSectionCell(SectionCell sectionCell) {
|
||||
return this.sectionCellRepository.save(sectionCell);
|
||||
}
|
||||
|
||||
public void removeSectionCellById(Long id) {
|
||||
this.sectionCellRepository.deleteById(id);
|
||||
}
|
||||
|
||||
public SectionCell updateSectionCell(
|
||||
Long id, Long sectionId, String contentSectionCell, LocalDateTime modificationDate) {
|
||||
Optional<SectionCell> sectionCell = this.sectionCellRepository.findById(id);
|
||||
if (sectionCell.isEmpty()) {
|
||||
logger.error("updateSectionCell : No sectionCell found with id {}", id);
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.NOT_FOUND, "Cette cellule de section n'existe pas");
|
||||
}
|
||||
if (sectionId != null) {
|
||||
sectionCell.get().setSectionId(sectionId);
|
||||
}
|
||||
if (contentSectionCell != null) {
|
||||
sectionCell.get().setContentSectionCell(contentSectionCell);
|
||||
}
|
||||
if (modificationDate != null) {
|
||||
sectionCell.get().setModificationDate(modificationDate);
|
||||
}
|
||||
return this.sectionCellRepository.save(sectionCell.get());
|
||||
}
|
||||
|
||||
public Iterable<SectionCell> getSectionCellsByProject(Project project, Long sectionId) {
|
||||
return this.sectionCellRepository.findByProjectSectionCellAndSectionId(project, sectionId);
|
||||
}
|
||||
|
||||
public Long getProjectId(Long sectionCellId) {
|
||||
SectionCell sectionCell = getSectionCellById(sectionCellId);
|
||||
Project sectionProject = sectionCell.getProjectSectionCell();
|
||||
return sectionProject.getIdProject();
|
||||
}
|
||||
|
||||
public List<Appointment> getAppointmentsBySectionCellId(Long sectionCellId) {
|
||||
SectionCell sectionCell = getSectionCellById(sectionCellId);
|
||||
return sectionCell.getAppointmentSectionCell();
|
||||
}
|
||||
|
||||
public Iterable<SectionCell> getSectionCellsByProjectAndSectionIdBeforeDate(
|
||||
Project project, long sectionId, LocalDateTime date) {
|
||||
return sectionCellRepository.findByProjectSectionCellAndSectionIdAndModificationDateBefore(
|
||||
project, sectionId, date);
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package enseirb.myinpulse.service.database;
|
||||
|
||||
import enseirb.myinpulse.model.User;
|
||||
import enseirb.myinpulse.repository.UserRepository;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class UserService {
|
||||
|
||||
protected static final Logger logger = LogManager.getLogger();
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
UserService(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
public Iterable<User> getAllUsers() {
|
||||
return this.userRepository.findAll();
|
||||
}
|
||||
|
||||
// TODO
|
||||
public User getUserByEmail(String email) {
|
||||
Optional<User> opt_user = this.userRepository.findByPrimaryMail(email);
|
||||
|
||||
if (opt_user.isEmpty()) {
|
||||
logger.error("getUserByEmail : No user found with email {}", email);
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Cet utilisateur n'existe pas");
|
||||
}
|
||||
return opt_user.get();
|
||||
}
|
||||
|
||||
public Iterable<User> allUsers() {
|
||||
return this.userRepository.findAll();
|
||||
}
|
||||
|
||||
public User addUser(@RequestBody User user) {
|
||||
return this.userRepository.save(user);
|
||||
}
|
||||
|
||||
public User updateUser(
|
||||
@PathVariable Long id,
|
||||
String userSurname,
|
||||
String userName,
|
||||
String primaryMail,
|
||||
String secondaryMail,
|
||||
String phoneNumber) {
|
||||
Optional<User> user = userRepository.findById(id);
|
||||
if (user.isEmpty()) {
|
||||
logger.error("updateUser : No user found with id {}", id);
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Cet utilisateur n'existe pas");
|
||||
}
|
||||
if (userName != null) {
|
||||
user.get().setUserName(userName);
|
||||
}
|
||||
if (userSurname != null) {
|
||||
user.get().setUserSurname(userSurname);
|
||||
}
|
||||
if (primaryMail != null) {
|
||||
user.get().setPrimaryMail(primaryMail);
|
||||
}
|
||||
if (secondaryMail != null) {
|
||||
user.get().setSecondaryMail(secondaryMail);
|
||||
}
|
||||
if (phoneNumber != null) {
|
||||
user.get().setPhoneNumber(phoneNumber);
|
||||
}
|
||||
return this.userRepository.save(user.get());
|
||||
}
|
||||
}
|
@ -1,4 +1,8 @@
|
||||
spring.application.name=myinpulse
|
||||
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://localhost:7080/realms/test/protocol/openid-connect/certs
|
||||
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:7080/realms/test
|
||||
logging.level.org.springframework.security=DEBUG
|
||||
spring.datasource.url=jdbc:postgresql://${DATABASE_URL}/${BACKEND_DB}
|
||||
spring.datasource.username=${BACKEND_USER}
|
||||
spring.datasource.password=${BACKEND_PASSWORD}
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
logging.pattern.console=%d{yyyy-MMM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n
|
99
MyINPulse-back/src/main/resources/data.sql
Normal file
99
MyINPulse-back/src/main/resources/data.sql
Normal file
@ -0,0 +1,99 @@
|
||||
TRUNCATE project, user_inpulse, entrepreneur, administrator, section_cell, appointment, report, annotation CASCADE;
|
||||
|
||||
SELECT setval('annotation_id_annotation_seq', 1, false);
|
||||
SELECT setval('appointment_id_appointment_seq', 1, false);
|
||||
SELECT setval('make_appointment_id_make_appointment_seq', 1, false);
|
||||
SELECT setval('project_id_project_seq', 1, false);
|
||||
SELECT setval('report_id_report_seq', 1, false);
|
||||
SELECT setval('section_cell_id_section_cell_seq', 1, false);
|
||||
SELECT setval('user_inpulse_id_user_seq', 1, false);
|
||||
|
||||
INSERT INTO user_inpulse (user_surname, user_name, primary_mail, secondary_mail, phone_number)
|
||||
VALUES ('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'),
|
||||
('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'),
|
||||
('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'),
|
||||
('Janine', 'Dave', 'janine@labri.fr', 'janine2@labri.fr', '06 87 12 45 95');
|
||||
|
||||
INSERT INTO administrator (id_administrator)
|
||||
VALUES (7);
|
||||
|
||||
INSERT INTO project (project_name, logo, creation_date, project_status, id_administrator)
|
||||
VALUES ('Eau du robinet', decode('013d7d16d7ad4fefb61bd95b765c8ceb', 'hex'), TO_DATE('01-OCT-2023', 'DD-MON-YYYY'),
|
||||
'En cours', 7),
|
||||
('Air oxygéné', decode('150647a0984e8f228cd14b54', 'hex'), TO_DATE('04-APR-2024', 'DD-MON-YYYY'), 'En cours', 7),
|
||||
('Débat concours', decode('022024abd5486e245c145dda65116f', 'hex'), TO_DATE('22-NOV-2023', 'DD-MON-YYYY'),
|
||||
'Suspendu', 7),
|
||||
('HDeirbMI', decode('ab548d6c1d595a2975e6476f544d14c55a', 'hex'), TO_DATE('07-DEC-2024', 'DD-MON-YYYY'),
|
||||
'Lancement', 7);
|
||||
|
||||
|
||||
INSERT INTO entrepreneur (school, course, snee_status, id_entrepreneur, id_project_participation, id_project_proposed)
|
||||
VALUES ('ENSEIRB-MATMECA', 'INFO', TRUE, 1, 4, 4),
|
||||
('ENSC', 'Cognitique', TRUE, 2, 2, null),
|
||||
('ENSEIRB-MATMECA', 'MATMECA', FALSE, 3, 3, 3),
|
||||
('SupOptique', 'Classique', TRUE, 4, 1, 1),
|
||||
('ENSEGID', 'Géoscience', FALSE, 5, 1, null),
|
||||
('ENSMAC', 'Matériaux composites - Mécanique', FALSE, 6, 2, 2);
|
||||
|
||||
|
||||
INSERT INTO section_cell (title, content_section_cell, modification_date, id_project)
|
||||
VALUES ('Problème', 'les problèmes...', TO_TIMESTAMP('15-JAN-2025 09:30:20', 'DD-MON-YYYY, HH24:MI:SS'), 2),
|
||||
('Segment de client', 'Le segment AB passant le client n°8 est de longueur 32mm.
|
||||
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'), 3),
|
||||
('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'), 2),
|
||||
('Solution', 'Un problème ? Une solution', TO_TIMESTAMP('08-FEB-2024 10:17:53', 'DD-MON-YYYY, HH24:MI:SS'), 1),
|
||||
('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'), 4),
|
||||
('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'), 1),
|
||||
('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'), 3),
|
||||
('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'), 4),
|
||||
('Avantages concurrentiel', 'On est meilleur', TO_TIMESTAMP('23-APR-2024 16:24:02', 'DD-MON-YYYY, HH24:MI:SS'),
|
||||
2);
|
||||
|
||||
INSERT INTO appointment (appointment_date, appointment_time, appointment_duration, appointment_place,
|
||||
appointment_subject)
|
||||
VALUES (TO_DATE('24-DEC-2023', 'DD-MON-YYYY'), '00:00:00', '00:37:53', 'À la maison', 'Ouvrir les cadeaux'),
|
||||
(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à ?)'),
|
||||
(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 !'),
|
||||
(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'),
|
||||
(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)');
|
||||
|
||||
INSERT INTO report (report_content, id_appointment)
|
||||
VALUES ('Ah oui ça c''est super, ah ouais j''aime bien, bien vu de penser à ça', 1),
|
||||
('Bonne réunion', 3),
|
||||
('Ouais, j''ai rien compris mais niquel on fait comme vous avez dit', 3),
|
||||
('Non non ça va pas du tout ce que tu me proposes, faut tout refaire', 4),
|
||||
('Réponse de la DSI : non', 2),
|
||||
('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',
|
||||
5);
|
||||
|
||||
INSERT INTO annotation (comment, id_administrator, id_section_cell)
|
||||
VALUES ('faut changer ça hein', 7, 5),
|
||||
('??? sérieusement, vous pensez que c''est une bonne idée ?', 7, 7),
|
||||
('ok donc ça c''est votre business plan, bah glhf la team', 7, 2);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
2
MyINPulse-back/src/main/resources/delete.sql
Normal file
2
MyINPulse-back/src/main/resources/delete.sql
Normal file
@ -0,0 +1,2 @@
|
||||
DROP TABLE IF EXISTS administrateurs, projets, utilisateurs, entrepreneurs, sections, rendez_vous, comptes_rendus, concerner CASCADE;
|
||||
DROP TABLE IF EXISTS administrator, project, user_inpulse, entrepreneur, section_cell, appointment, make_appointment, report, annotation, concern CASCADE;
|
@ -0,0 +1,224 @@
|
||||
package enseirb.myinpulse;
|
||||
|
||||
import static enseirb.myinpulse.model.ProjectDecisionValue.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import enseirb.myinpulse.model.Administrator;
|
||||
import enseirb.myinpulse.model.Entrepreneur;
|
||||
import enseirb.myinpulse.model.Project;
|
||||
import enseirb.myinpulse.model.ProjectDecision;
|
||||
import enseirb.myinpulse.service.AdminApiService;
|
||||
import enseirb.myinpulse.service.database.AdministratorService;
|
||||
import enseirb.myinpulse.service.database.EntrepreneurService;
|
||||
import enseirb.myinpulse.service.database.ProjectService;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SpringBootTest
|
||||
@Transactional
|
||||
public class AdminApiServiceTest {
|
||||
private static long administratorid;
|
||||
private static Administrator administrator;
|
||||
private static Entrepreneur entrepreneur;
|
||||
@Autowired private AdminApiService adminApiService;
|
||||
@Autowired private ProjectService projectService;
|
||||
|
||||
@BeforeAll
|
||||
static void setup(
|
||||
@Autowired AdministratorService administratorService,
|
||||
@Autowired ProjectService projectService,
|
||||
@Autowired EntrepreneurService entrepreneurService) {
|
||||
administratorService.addAdministrator(
|
||||
new Administrator(
|
||||
"admin",
|
||||
"admin",
|
||||
"testAdminEmpty@example.com",
|
||||
"testAdmin@example.com",
|
||||
""));
|
||||
administrator =
|
||||
administratorService.addAdministrator(
|
||||
new Administrator(
|
||||
"admin2",
|
||||
"admin2",
|
||||
"testAdminFull@example.com",
|
||||
"testAdmin@example.com",
|
||||
""));
|
||||
administratorid = administrator.getIdUser();
|
||||
entrepreneur =
|
||||
new Entrepreneur(
|
||||
"JeSuisUnEntrepreneurDeCompet",
|
||||
"EtUé",
|
||||
"Entrepreneur@inpulse.com",
|
||||
"mail2",
|
||||
"phone",
|
||||
"Ensimag nan jdeconne ENSEIRB (-matmeca mais on s'en fout)",
|
||||
"info ofc",
|
||||
false);
|
||||
entrepreneurService.addEntrepreneur(entrepreneur);
|
||||
projectService.addNewProject(
|
||||
new Project(
|
||||
"sampleProjectAdminApiService",
|
||||
null,
|
||||
LocalDate.now(),
|
||||
ACTIVE,
|
||||
administratorService.getAdministratorByPrimaryMain(
|
||||
"testAdminFull@example.com")));
|
||||
}
|
||||
|
||||
private <T> List<T> IterableToList(Iterable<T> iterable) {
|
||||
List<T> l = new ArrayList<>();
|
||||
iterable.forEach(l::add);
|
||||
return l;
|
||||
}
|
||||
|
||||
@Test
|
||||
void getProjectOfAdminIsEmpty() {
|
||||
Iterable<Project> projects =
|
||||
adminApiService.getProjectsOfAdmin("testAdminEmpty@example.com");
|
||||
assertEquals(0, IterableToList(projects).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getProjectOfInexistantAdminFails() {
|
||||
String nonExistentAdminEmail = "testInexistantAdmin@example.com";
|
||||
|
||||
assertThrows(
|
||||
ResponseStatusException.class,
|
||||
() -> {
|
||||
adminApiService.getProjectsOfAdmin(nonExistentAdminEmail);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void getProjectOfAdminNotEmpty() {
|
||||
Iterable<Project> projects =
|
||||
adminApiService.getProjectsOfAdmin("testAdminFull@example.com");
|
||||
List<Project> l = IterableToList(projects);
|
||||
assertEquals(1, l.size());
|
||||
Project p = l.getFirst();
|
||||
assertEquals(p.getProjectName(), "sampleProjectAdminApiService");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPendingProjectsEmpty() {
|
||||
assertEquals(0, IterableToList(this.adminApiService.getPendingProjects()).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPendingProjectsNotEmpty() {
|
||||
this.projectService.addNewProject(
|
||||
new Project(
|
||||
"PendingProjectAdminApiService1", null, LocalDate.now(), PENDING, null));
|
||||
this.projectService.addNewProject(
|
||||
new Project(
|
||||
"PendingProjectAdminApiService2", null, LocalDate.now(), PENDING, null));
|
||||
Iterable<Project> pendingProjects = this.adminApiService.getPendingProjects();
|
||||
List<Project> pendingProjectsList = IterableToList(pendingProjects);
|
||||
assertEquals(2, pendingProjectsList.size());
|
||||
assertTrue(
|
||||
List.of("PendingProjectAdminApiService1", "PendingProjectAdminApiService2")
|
||||
.contains(pendingProjectsList.getFirst().getProjectName()));
|
||||
assertTrue(
|
||||
List.of("PendingProjectAdminApiService1", "PendingProjectAdminApiService2")
|
||||
.contains(pendingProjectsList.getLast().getProjectName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void validateInexistantProject() {
|
||||
ProjectDecision d = new ProjectDecision(-1, 0, 1);
|
||||
assertThrows(ResponseStatusException.class, () -> this.adminApiService.validateProject(d));
|
||||
}
|
||||
|
||||
@Test
|
||||
void validateExistantProject() {
|
||||
Project p =
|
||||
new Project("PendingProjectAdminApiService2", null, LocalDate.now(), PENDING, null);
|
||||
this.projectService.addNewProject(p);
|
||||
assertEquals(PENDING, p.getProjectStatus());
|
||||
ProjectDecision d = new ProjectDecision(p.getIdProject(), administratorid, 1);
|
||||
this.adminApiService.validateProject(d);
|
||||
assertEquals(ACTIVE, p.getProjectStatus());
|
||||
|
||||
// Check if the project was really updated in the database
|
||||
assertEquals(0, IterableToList(this.adminApiService.getPendingProjects()).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void refuseExistantProject() {
|
||||
Project p =
|
||||
new Project("PendingProjectAdminApiService2", null, LocalDate.now(), PENDING, null);
|
||||
this.projectService.addNewProject(p);
|
||||
assertEquals(PENDING, p.getProjectStatus());
|
||||
ProjectDecision d = new ProjectDecision(p.getIdProject(), administratorid, 0);
|
||||
this.adminApiService.validateProject(d);
|
||||
assertEquals(REJECTED, p.getProjectStatus());
|
||||
|
||||
// Check if the project was really updated in the database
|
||||
assertEquals(0, IterableToList(this.adminApiService.getPendingProjects()).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void addProject() {
|
||||
assertEquals(0, IterableToList(this.adminApiService.getPendingProjects()).size());
|
||||
Project p1 =
|
||||
new Project("PendingProjectAdminApiService2", null, LocalDate.now(), PENDING, null);
|
||||
this.adminApiService.addNewProject(p1);
|
||||
|
||||
assertEquals(1, IterableToList(this.adminApiService.getPendingProjects()).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void addProjectToAdmin() {
|
||||
assertEquals(0, administrator.getListProject().size());
|
||||
Project p1 = new Project("assProjectToAdmin", null, LocalDate.now(), ACTIVE, administrator);
|
||||
this.adminApiService.addNewProject(p1);
|
||||
assertEquals(1, administrator.getListProject().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void addProjectToUser() {
|
||||
assertNull(entrepreneur.getProjectParticipation());
|
||||
Project p1 =
|
||||
new Project("assProjectToAdmin", null, LocalDate.now(), ACTIVE, null, entrepreneur);
|
||||
this.adminApiService.addNewProject(p1);
|
||||
assertEquals(p1, entrepreneur.getProjectParticipation());
|
||||
}
|
||||
|
||||
@Test
|
||||
void addProjectWithManyUsers() {
|
||||
Entrepreneur e1 = new Entrepreneur();
|
||||
Entrepreneur e2 = new Entrepreneur();
|
||||
Entrepreneur e3 = new Entrepreneur();
|
||||
assertNull(e1.getProjectParticipation());
|
||||
assertNull(e2.getProjectParticipation());
|
||||
assertNull(e3.getProjectParticipation());
|
||||
Project p1 = new Project("assProjectToAdmin", null, LocalDate.now(), ACTIVE, null, null);
|
||||
p1.updateListEntrepreneurParticipation(e1);
|
||||
p1.updateListEntrepreneurParticipation(e2);
|
||||
p1.updateListEntrepreneurParticipation(e3);
|
||||
this.adminApiService.addNewProject(p1);
|
||||
assertEquals(p1, e1.getProjectParticipation());
|
||||
assertEquals(p1, e2.getProjectParticipation());
|
||||
assertEquals(p1, e3.getProjectParticipation());
|
||||
}
|
||||
|
||||
@Test
|
||||
void addDuplicateProject() {
|
||||
Project p1 =
|
||||
new Project("PendingProjectAdminApiService2", null, LocalDate.now(), PENDING, null);
|
||||
Project p2 =
|
||||
new Project("PendingProjectAdminApiService2", null, LocalDate.now(), PENDING, null);
|
||||
this.adminApiService.addNewProject(p1);
|
||||
assertThrows(ResponseStatusException.class, () -> this.adminApiService.addNewProject(p2));
|
||||
}
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
package enseirb.myinpulse;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class MyinpulseApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("contextLoad => Test if the context can load, i.e. the application can start")
|
||||
void contextLoads() {}
|
||||
}
|
||||
|
10
MyINPulse-back/src/test/resources/application.properties
Normal file
10
MyINPulse-back/src/test/resources/application.properties
Normal file
@ -0,0 +1,10 @@
|
||||
spring.datasource.driver-class-name=org.h2.Driver
|
||||
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
|
||||
spring.datasource.username=sa
|
||||
spring.datasource.password=sa
|
||||
spring.sql.init.mode=never
|
||||
spring.application.name=myinpulse-test
|
||||
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://localhost:7080/realms/test/protocol/openid-connect/certs
|
||||
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:7080/realms/test
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
logging.pattern.console=%d{yyyy-MMM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n
|
22
config/.env.dev
Normal file
22
config/.env.dev
Normal file
@ -0,0 +1,22 @@
|
||||
POSTGRES_DB=postgres_db
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres_db_user_password
|
||||
|
||||
KEYCLOAK_ADMIN=admin
|
||||
KEYCLOAK_ADMIN_PASSWORD=admin
|
||||
KEYCLOAK_HOSTNAME=localhost
|
||||
KEYCLOAK_DB=keycloak_db
|
||||
KEYCLOAK_USER=keycloak_db_user
|
||||
KEYCLOAK_PASSWORD=keycloak_db_user_password
|
||||
|
||||
BACKEND_DB=backend_db
|
||||
BACKEND_USER=backend_db_user
|
||||
BACKEND_PASSWORD=backend_db_user_password
|
||||
|
||||
DATABASE_URL=localhost:5433
|
||||
|
||||
VITE_KEYCLOAK_URL=http://localhost:7080
|
||||
VITE_KEYCLOAK_CLIENT_ID=myinpulse-dev
|
||||
VITE_KEYCLOAK_REALM=test
|
||||
VITE_APP_URL=http://localhost:5173
|
||||
VITE_BACKEND_URL=http://localhost:8081/
|
@ -1,15 +1,14 @@
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:latest
|
||||
env_file: .env
|
||||
build:
|
||||
context: postgres/
|
||||
dockerfile: Dockerfile
|
||||
container_name: MyINPulse-DB
|
||||
#ports:
|
||||
# - 5432:5432
|
||||
ports:
|
||||
- 5433:5432
|
||||
volumes:
|
||||
- ./postgres:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB}
|
||||
POSTGRES_USER: ${POSTGRES_USER}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
- ./postgres/data:/var/lib/postgresql/data
|
||||
|
||||
keycloak:
|
||||
container_name: MyINPulse-keycloak
|
||||
|
22
config/backdev.env
Normal file
22
config/backdev.env
Normal file
@ -0,0 +1,22 @@
|
||||
POSTGRES_DB=postgres_db
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres_db_user_password
|
||||
|
||||
KEYCLOAK_ADMIN=admin
|
||||
KEYCLOAK_ADMIN_PASSWORD=admin
|
||||
KEYCLOAK_HOSTNAME=localhost
|
||||
KEYCLOAK_DB=keycloak_db
|
||||
KEYCLOAK_USER=keycloak_db_user
|
||||
KEYCLOAK_PASSWORD=keycloak_db_user_password
|
||||
|
||||
BACKEND_DB=backend_db
|
||||
BACKEND_USER=backend_db_user
|
||||
BACKEND_PASSWORD=backend_db_user_password
|
||||
|
||||
DATABASE_URL=localhost:5433
|
||||
|
||||
VITE_KEYCLOAK_URL=http://localhost:7080
|
||||
VITE_KEYCLOAK_CLIENT_ID=myinpulse
|
||||
VITE_KEYCLOAK_REALM=test
|
||||
VITE_APP_URL=http://localhost:8080
|
||||
VITE_BACKEND_URL=http://localhost:8081/
|
@ -1,5 +0,0 @@
|
||||
VITE_KEYCLOAK_URL=http://localhost:7080
|
||||
VITE_KEYCLOAK_CLIENT_ID=myinpulse
|
||||
VITE_KEYCLOAK_REALM=test
|
||||
VITE_APP_URL=http://localhost:8080
|
||||
VITE_BACKEND_URL=http://localhost:8081/
|
@ -1,6 +0,0 @@
|
||||
POSTGRES_DB=keycloak_db
|
||||
POSTGRES_USER=keycloak_db_user
|
||||
POSTGRES_PASSWORD=keycloak_db_user_password
|
||||
KEYCLOAK_ADMIN=admin
|
||||
KEYCLOAK_ADMIN_PASSWORD=admin
|
||||
KEYCLOAK_HOSTNAME=localhost
|
52
config/dev.docker-compose.yaml
Normal file
52
config/dev.docker-compose.yaml
Normal file
@ -0,0 +1,52 @@
|
||||
services:
|
||||
postgres:
|
||||
env_file: .env
|
||||
build:
|
||||
context: postgres/
|
||||
dockerfile: Dockerfile
|
||||
container_name: MyINPulse-DB
|
||||
ports:
|
||||
- 5433:5432
|
||||
volumes:
|
||||
- ./postgres/data:/var/lib/postgresql/data
|
||||
|
||||
|
||||
keycloak:
|
||||
container_name: MyINPulse-keycloak
|
||||
build:
|
||||
context: ./keycloak
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
KC_DB: postgres
|
||||
KC_DB_URL: jdbc:postgresql://postgres/${POSTGRES_DB}
|
||||
KC_DB_USERNAME: ${POSTGRES_USER}
|
||||
KC_DB_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
environment:
|
||||
KC_HOSTNAME_PORT: 7080
|
||||
KC_HOSTNAME_STRICT_BACKCHANNEL: "true"
|
||||
KC_BOOTSTRAP_ADMIN_USERNAME: ${KEYCLOAK_ADMIN}
|
||||
KC_BOOTSTRAP_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
|
||||
KC_LOG_LEVEL: info
|
||||
command: ["start-dev", "--http-port", "7080", "--https-port", "7443", "--hostname", "${KEYCLOAK_HOSTNAME}"]
|
||||
ports:
|
||||
- "7080:7080"
|
||||
- "7443:7443"
|
||||
depends_on:
|
||||
- postgres
|
||||
|
||||
#front:
|
||||
# build:
|
||||
# context: ./front/
|
||||
# dockerfile: Dockerfile
|
||||
# container_name: MyINPulse-front
|
||||
# ports:
|
||||
# - "8080:80"
|
||||
|
||||
#back:
|
||||
# build:
|
||||
# context: ./MyINPulse-back/
|
||||
# dockerfile: Dockerfile
|
||||
# container_name: MyINPulse-back
|
||||
# ports:
|
||||
# - "8081:8080"
|
||||
|
22
config/dev.env
Normal file
22
config/dev.env
Normal file
@ -0,0 +1,22 @@
|
||||
POSTGRES_DB=postgres_db
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres_db_user_password
|
||||
|
||||
KEYCLOAK_ADMIN=admin
|
||||
KEYCLOAK_ADMIN_PASSWORD=admin
|
||||
KEYCLOAK_HOSTNAME=localhost
|
||||
KEYCLOAK_DB=keycloak_db
|
||||
KEYCLOAK_USER=keycloak_db_user
|
||||
KEYCLOAK_PASSWORD=keycloak_db_user_password
|
||||
|
||||
BACKEND_DB=backend_db
|
||||
BACKEND_USER=backend_db_user
|
||||
BACKEND_PASSWORD=backend_db_user_password
|
||||
|
||||
DATABASE_URL=localhost:5433
|
||||
|
||||
VITE_KEYCLOAK_URL=http://localhost:7080
|
||||
VITE_KEYCLOAK_CLIENT_ID=myinpulse-dev
|
||||
VITE_KEYCLOAK_REALM=test
|
||||
VITE_APP_URL=http://localhost:5173
|
||||
VITE_BACKEND_URL=http://localhost:8081/
|
@ -1,15 +1,15 @@
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:latest
|
||||
env_file: .env
|
||||
build:
|
||||
context: postgres/
|
||||
dockerfile: Dockerfile
|
||||
container_name: MyINPulse-DB
|
||||
#ports:
|
||||
# - 5432:5432
|
||||
volumes:
|
||||
- ./postgres:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB}
|
||||
POSTGRES_USER: ${POSTGRES_USER}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
- ./postgres/data:/var/lib/postgresql/data
|
||||
|
||||
|
||||
keycloak:
|
||||
container_name: MyINPulse-keycloak
|
||||
|
22
config/frontdev.env
Normal file
22
config/frontdev.env
Normal file
@ -0,0 +1,22 @@
|
||||
POSTGRES_DB=postgres_db
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres_db_user_password
|
||||
|
||||
KEYCLOAK_ADMIN=admin
|
||||
KEYCLOAK_ADMIN_PASSWORD=admin
|
||||
KEYCLOAK_HOSTNAME=localhost
|
||||
KEYCLOAK_DB=keycloak_db
|
||||
KEYCLOAK_USER=keycloak_db_user
|
||||
KEYCLOAK_PASSWORD=keycloak_db_user_password
|
||||
|
||||
BACKEND_DB=backend_db
|
||||
BACKEND_USER=backend_db_user
|
||||
BACKEND_PASSWORD=backend_db_user_password
|
||||
|
||||
DATABASE_URL=MyINPulse-DB
|
||||
|
||||
VITE_KEYCLOAK_URL=http://localhost:7080
|
||||
VITE_KEYCLOAK_CLIENT_ID=myinpulse-dev
|
||||
VITE_KEYCLOAK_REALM=test
|
||||
VITE_APP_URL=http://localhost:5173
|
||||
VITE_BACKEND_URL=http://localhost:8081/
|
@ -1,5 +0,0 @@
|
||||
VITE_KEYCLOAK_URL=http://localhost:7080
|
||||
VITE_KEYCLOAK_CLIENT_ID=myinpulse-dev
|
||||
VITE_KEYCLOAK_REALM=test
|
||||
VITE_APP_URL=http://localhost:5173
|
||||
VITE_BACKEND_URL=http://localhost:8081/
|
@ -1,6 +0,0 @@
|
||||
POSTGRES_DB=keycloak_db
|
||||
POSTGRES_USER=keycloak_db_user
|
||||
POSTGRES_PASSWORD=keycloak_db_user_password
|
||||
KEYCLOAK_ADMIN=admin
|
||||
KEYCLOAK_ADMIN_PASSWORD=admin
|
||||
KEYCLOAK_HOSTNAME=localhost
|
@ -1,11 +1,14 @@
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:latest
|
||||
env_file: .env
|
||||
build:
|
||||
context: postgres/
|
||||
dockerfile: Dockerfile
|
||||
container_name: MyINPulse-DB
|
||||
#ports:
|
||||
# - 5432:5432
|
||||
volumes:
|
||||
- ./postgres:/var/lib/postgresql/data
|
||||
- ./postgres/data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB}
|
||||
POSTGRES_USER: ${POSTGRES_USER}
|
||||
@ -27,10 +30,10 @@ services:
|
||||
KC_BOOTSTRAP_ADMIN_USERNAME: ${KEYCLOAK_ADMIN}
|
||||
KC_BOOTSTRAP_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
|
||||
KC_LOG_LEVEL: info
|
||||
command: ["start-dev", "--http-port", "7080", "--https-port", "7443", "--hostname", "${KEYCLOAK_HOSTNAME}"]
|
||||
ports:
|
||||
- "7080:7080"
|
||||
- "7443:7443"
|
||||
command: ["start-dev", "--http-port", "7080", "--https-port", "7443", "--hostname", "${KEYCLOAK_HOSTNAME}"] # TODO: remove start-dev
|
||||
#ports:
|
||||
# - "7080:7080"
|
||||
# - "7443:7443"
|
||||
depends_on:
|
||||
- postgres
|
||||
|
||||
@ -47,6 +50,6 @@ services:
|
||||
context: ./MyINPulse-back/
|
||||
dockerfile: Dockerfile
|
||||
container_name: MyINPulse-back
|
||||
ports:
|
||||
- "8081:8080"
|
||||
#ports:
|
||||
# - "8081:8080"
|
||||
|
22
config/prod.env
Normal file
22
config/prod.env
Normal file
@ -0,0 +1,22 @@
|
||||
POSTGRES_DB=postgres_db
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres_db_user_password
|
||||
|
||||
KEYCLOAK_ADMIN=admin
|
||||
KEYCLOAK_ADMIN_PASSWORD=admin
|
||||
KEYCLOAK_HOSTNAME=0549cd63f912d5dc9b31278d6f.eirb.fr
|
||||
KEYCLOAK_DB=keycloak_db
|
||||
KEYCLOAK_USER=keycloak_db_user
|
||||
KEYCLOAK_PASSWORD=keycloak_db_user_password
|
||||
|
||||
BACKEND_DB=backend_db
|
||||
BACKEND_USER=backend_db_user
|
||||
BACKEND_PASSWORD=backend_db_user_password
|
||||
|
||||
DATABASE_URL=MyINPulse-DB
|
||||
|
||||
VITE_KEYCLOAK_URL=https://0549cd63f912d5dc9b31278d6f.eirb.fr
|
||||
VITE_KEYCLOAK_CLIENT_ID=myinpulse-eirb
|
||||
VITE_KEYCLOAK_REALM=test
|
||||
VITE_APP_URL=https://0549cd63f912d5dc9b31278d6f.piair.dev
|
||||
VITE_BACKEND_URL=http://TODO/
|
@ -1,5 +0,0 @@
|
||||
VITE_KEYCLOAK_URL=https://0549cd63f912d5dc9b31278d6f.eirb.fr
|
||||
VITE_KEYCLOAK_CLIENT_ID=myinpulse-eirb
|
||||
VITE_KEYCLOAK_REALM=test
|
||||
VITE_APP_URL=https://0549cd63f912d5dc9b31278d6f.piair.dev
|
||||
VITE_BACKEND_URL=http://TODO/
|
@ -1,6 +0,0 @@
|
||||
POSTGRES_DB=keycloak_db
|
||||
POSTGRES_USER=keycloak_db_user
|
||||
POSTGRES_PASSWORD=keycloak_db_user_password
|
||||
KEYCLOAK_ADMIN=admin
|
||||
KEYCLOAK_ADMIN_PASSWORD=admin
|
||||
KEYCLOAK_HOSTNAME=0549cd63f912d5dc9b31278d6f.eirb.fr
|
12
documentation/Doc.txt
Normal file
12
documentation/Doc.txt
Normal file
@ -0,0 +1,12 @@
|
||||
Format des comptes rendus de réunion :
|
||||
Texte organisé par bullet point, chaque bullet point est séparé par "//" pour pouvoir être correctement généré.
|
||||
|
||||
Exemple :
|
||||
Le texte "// blablabla // oui bonjour"
|
||||
donne le résultat
|
||||
|
||||
Point n°1 :
|
||||
blablabla
|
||||
|
||||
Point n°2 :
|
||||
oui bonjour
|
47
documentation/openapi/notes.md
Normal file
47
documentation/openapi/notes.md
Normal file
@ -0,0 +1,47 @@
|
||||
## API Endpoints notes
|
||||
|
||||
### EntrepreneurApi and SharedApi
|
||||
#### Endpoint Name Changes
|
||||
- `/entrepreneur/lcsection/modify/{sectionId}` → `/entrepreneur/sectionCell/modify/{sectionId}`
|
||||
|
||||
### Admin api
|
||||
- `/admin/appointments/upcoming`: is shared not admin
|
||||
- `/admin/projects/decision`: instanciates classes with `adminId` instead of taking the id from the token
|
||||
- `/admin/project/add`:
|
||||
- point 1: the doc has this `projects` everywhere this should be `/admin/projects/add` to avoid confusion I think
|
||||
- point 2: this doesn't assiociate users with a project I need to add other endopint for that
|
||||
- `/admin/appoitements/report/{appointmentId}`:
|
||||
- typo: `appoitements` → `appointments`
|
||||
- `/admin/projects/remove/{projectId}`, `/admin/project/add`, `/admin/projects/decision`, `/admin/projects/pending`:
|
||||
- should need token to delete or add project
|
||||
|
||||
### Entrepreneur api
|
||||
- `/entrepreneur/sectionCell/modify/{sectionId}`:
|
||||
- the section-id because of the definition of `sectionCell` schema the `sectionId` is given twice possibly leading to inconsistency. Which is why the path var to be removed:
|
||||
- → `/entrepreneur/sectionCell/modify`
|
||||
|
||||
### Shared api
|
||||
- `/shared/project/sectionCell/{projectId}/{sectionId}/{date}`:
|
||||
- point 1:
|
||||
same point for `project` → `projects`
|
||||
- point 2:
|
||||
have yet to read `sharedApiService` to see how dates are handled and to see if we agree on values of `date` to make it so it gets the version relative to current date
|
||||
- `/shared/entrepreneurs/{projectId}`:
|
||||
- maybe change to `/shared/projects/entrepreneurs/{projectId}` to match other similair endpoints like `/shared/projects/admin/{projectId}`
|
||||
- `/shared/appointment/request`:
|
||||
- creates the apointement but don't know how it associates other users, potentially multiple classes in one request body, is that possible ?
|
||||
|
||||
## TODOs for me
|
||||
|
||||
### list 1:
|
||||
- add back-end server links (backend and auth) for interacting with api through swagger
|
||||
- get config for that set up in the project
|
||||
|
||||
### list 2:
|
||||
- see what to do about logo img
|
||||
- see format for date and add it in examples
|
||||
- ask the form of return of the json of iterables, for now I have put array
|
||||
- add endpoint for adding users to a project
|
||||
- update endpoint descriptions
|
||||
- add examples for values in schemas
|
||||
|
11
documentation/openapi/run_doc.sh
Executable file
11
documentation/openapi/run_doc.sh
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd ./swagger-ui
|
||||
|
||||
if [ ! -d "./node_modules/" ]
|
||||
then
|
||||
npm install
|
||||
npm install swagger-cli
|
||||
fi
|
||||
|
||||
npm start
|
214
documentation/openapi/src/adminApi.yaml
Normal file
214
documentation/openapi/src/adminApi.yaml
Normal file
@ -0,0 +1,214 @@
|
||||
# _ ____ __ __ ___ _ _ _ ____ ___
|
||||
# / \ | _ \| \/ |_ _| \ | | / \ | _ \_ _|
|
||||
# / _ \ | | | | |\/| || || \| | / _ \ | |_) | |
|
||||
# / ___ \| |_| | | | || || |\ | / ___ \| __/| |
|
||||
# /_/ \_\____/|_| |_|___|_| \_| /_/ \_\_| |___|
|
||||
#
|
||||
paths:
|
||||
/admin/projects:
|
||||
get:
|
||||
summary: Retourne la liste of projets associés à l'admin
|
||||
tags:
|
||||
- Admin API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
description:
|
||||
JSON array of who's elements are objects containing necessary information for the view
|
||||
(project name, entrepreneur names, etc..)
|
||||
of the projects an admin is watching over.
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "main.yaml#/components/schemas/project"
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is missing or invalid
|
||||
/admin/projects/pending/decision:
|
||||
post:
|
||||
summary: valider un projet en attente de validation
|
||||
tags:
|
||||
- Admin API
|
||||
description:
|
||||
if the request is accepted the status of the
|
||||
project is changed to ongoing, entrepreneur
|
||||
account is confirmed and the project is linked
|
||||
to the admin accepting the request and the
|
||||
entrepreneur requesting it. Else the pending
|
||||
project and user info are deleted.
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
pedingProjectId:
|
||||
type: integer
|
||||
decision:
|
||||
type: boolean
|
||||
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is
|
||||
missing or invalid
|
||||
|
||||
/admin/projects/add:
|
||||
post:
|
||||
summary: Ajout manuel d'un projet
|
||||
description:
|
||||
Adds a project with the
|
||||
inputed details
|
||||
tags:
|
||||
- Admin API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "main.yaml#/components/schemas/project"
|
||||
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is
|
||||
missing or invalid
|
||||
|
||||
/admin/appointments/report/{appointmentId}:
|
||||
put:
|
||||
summary: enregistrer un rapport du rendez-vous
|
||||
description:
|
||||
Generate a PDF file formatted
|
||||
from input text and links it
|
||||
to the appointement.
|
||||
tags:
|
||||
- Admin API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
parameters:
|
||||
- in: path
|
||||
name: appointmentId
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "main.yaml#/components/schemas/report"
|
||||
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is
|
||||
missing or invalid
|
||||
post:
|
||||
summary: modifier un rapport déja éxistant du rendez-vous
|
||||
description:
|
||||
Modifies the report file to input
|
||||
text and links it to the appointement.
|
||||
tags:
|
||||
- Admin API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
parameters:
|
||||
- in: path
|
||||
name: appointmentId
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "main.yaml#/components/schemas/report"
|
||||
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is
|
||||
missing or invalid
|
||||
|
||||
|
||||
/admin/projects/remove/{projectId}:
|
||||
delete:
|
||||
summary: supression d'un project
|
||||
description:
|
||||
Removes the project
|
||||
with the inputed id projectId
|
||||
tags:
|
||||
- Admin API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
parameters:
|
||||
- in: path
|
||||
name: projectId
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is
|
||||
missing or invalid
|
||||
|
||||
|
||||
/admin/projects/pending:
|
||||
get:
|
||||
summary: Retourne la liste des projets en attente de validation
|
||||
tags:
|
||||
- Admin API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
description:
|
||||
JSON array of who's elements are objects containing
|
||||
necessary information for the view (project name, etc..)
|
||||
of all pending projects.
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "main.yaml#/components/schemas/project"
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is missing or invalid
|
596
documentation/openapi/src/bundled.yaml
Normal file
596
documentation/openapi/src/bundled.yaml
Normal file
@ -0,0 +1,596 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: MyInpulse Backend Api
|
||||
description: this document servers as a documentation for the backend api.
|
||||
version: 0.2.0
|
||||
tags:
|
||||
- name: Entrepreneurs API
|
||||
description: La partie de l'api dédiée aux entrepreneurs
|
||||
- name: Admin API
|
||||
description: La partie de l'api dédiée aux entrepreneurs
|
||||
- name: Shared API
|
||||
description: La partie de l'api dédiée aux entrepreneurs et admins
|
||||
components:
|
||||
schemas:
|
||||
user:
|
||||
type: object
|
||||
properties:
|
||||
idUser:
|
||||
type: integer
|
||||
userSurname:
|
||||
type: string
|
||||
userName:
|
||||
type: string
|
||||
primaryMail:
|
||||
type: string
|
||||
example: example@exmaple.com
|
||||
secondaryMail:
|
||||
type: string
|
||||
example: example@exmaple.com
|
||||
phoneNumber:
|
||||
type: string
|
||||
example: 0612345678
|
||||
user-entrepreneur:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/user'
|
||||
- type: object
|
||||
properties:
|
||||
school:
|
||||
type: string
|
||||
example: enseirb
|
||||
course:
|
||||
type: string
|
||||
example: info
|
||||
sneeStatus:
|
||||
type: boolean
|
||||
example: false
|
||||
user-admin:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/user'
|
||||
sectionCell:
|
||||
type: object
|
||||
properties:
|
||||
idSectionCell:
|
||||
type: integer
|
||||
example: this the cell (postit id)
|
||||
sectionId:
|
||||
type: integer
|
||||
contentSectionCell:
|
||||
type: string
|
||||
modificationDate:
|
||||
type: string
|
||||
project:
|
||||
type: object
|
||||
properties:
|
||||
idProject:
|
||||
type: integer
|
||||
projectName:
|
||||
type: string
|
||||
creationDate:
|
||||
type: string
|
||||
logo:
|
||||
example: to be discussed not yet fixed
|
||||
type: string
|
||||
format: binary
|
||||
report:
|
||||
type: object
|
||||
properties:
|
||||
idReport:
|
||||
type: integer
|
||||
reportContent:
|
||||
type: string
|
||||
appointement:
|
||||
type: object
|
||||
properties:
|
||||
appointmentDate:
|
||||
type: string
|
||||
appointmentTime:
|
||||
type: string
|
||||
appointmentDuration:
|
||||
type: string
|
||||
appointmentPlace:
|
||||
type: string
|
||||
appointmentSubject:
|
||||
type: string
|
||||
securitySchemes:
|
||||
MyINPulse:
|
||||
type: oauth2
|
||||
flows:
|
||||
implicit:
|
||||
authorizationUrl: 'http://localhost:7080'
|
||||
scopes:
|
||||
MyINPulse-admin: Administrateur
|
||||
MyINPulse-entrepreneur: Utilisateur
|
||||
servers:
|
||||
- url: 'http://localhost:8081/'
|
||||
description: Backend developper server
|
||||
paths:
|
||||
/admin/projects:
|
||||
get:
|
||||
summary: Retourne la liste of projets associés à l'admin
|
||||
tags:
|
||||
- Admin API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
description: 'JSON array of who''s elements are objects containing necessary information for the view (project name, entrepreneur names, etc..) of the projects an admin is watching over.'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/project'
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
/admin/projects/pending/decision:
|
||||
post:
|
||||
summary: valider un projet en attente de validation
|
||||
tags:
|
||||
- Admin API
|
||||
description: 'if the request is accepted the status of the project is changed to ongoing, entrepreneur account is confirmed and the project is linked to the admin accepting the request and the entrepreneur requesting it. Else the pending project and user info are deleted.'
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
pedingProjectId:
|
||||
type: integer
|
||||
decision:
|
||||
type: boolean
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
/admin/projects/add:
|
||||
post:
|
||||
summary: Ajout manuel d'un projet
|
||||
description: Adds a project with the inputed details
|
||||
tags:
|
||||
- Admin API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/project'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
'/admin/appointments/report/{appointmentId}':
|
||||
put:
|
||||
summary: enregistrer un rapport du rendez-vous
|
||||
description: Generate a PDF file formatted from input text and links it to the appointement.
|
||||
tags:
|
||||
- Admin API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
parameters:
|
||||
- in: path
|
||||
name: appointmentId
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/report'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
post:
|
||||
summary: modifier un rapport déja éxistant du rendez-vous
|
||||
description: Modifies the report file to input text and links it to the appointement.
|
||||
tags:
|
||||
- Admin API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
parameters:
|
||||
- in: path
|
||||
name: appointmentId
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/report'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
'/admin/projects/remove/{projectId}':
|
||||
delete:
|
||||
summary: supression d'un project
|
||||
description: Removes the project with the inputed id projectId
|
||||
tags:
|
||||
- Admin API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
parameters:
|
||||
- in: path
|
||||
name: projectId
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
/admin/projects/pending:
|
||||
get:
|
||||
summary: Retourne la liste des projets en attente de validation
|
||||
tags:
|
||||
- Admin API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
description: 'JSON array of who''s elements are objects containing necessary information for the view (project name, etc..) of all pending projects.'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/project'
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
/shared/appointments/upcoming:
|
||||
get:
|
||||
summary: Retourne la list des prochains rendez-vous de l'utilisateur
|
||||
tags:
|
||||
- Shared API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
- MyINPulse-entrepreneur
|
||||
description: 'JSON array of upcoming appointment data (name, date, time etc..) for a user.'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/appointement'
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
'/shared/projects/sectionCell/{projectId}/{sectionId}/{date}':
|
||||
get:
|
||||
summary: Retourne la liste de sections de LC avec un titre donné
|
||||
tags:
|
||||
- Shared API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
- MyINPulse-entrepreneur
|
||||
description: JSON array containing Lean Canvas section data with a title for the current date (or given date if the date parameter is passed)
|
||||
parameters:
|
||||
- in: path
|
||||
required: true
|
||||
name: projectId
|
||||
schema:
|
||||
type: integer
|
||||
- in: path
|
||||
required: true
|
||||
description: 'this number can be 1, 2,...,8. It is associated with the title of the sectionCell'
|
||||
name: sectionId
|
||||
schema:
|
||||
type: integer
|
||||
enum:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- 4
|
||||
- 5
|
||||
- 6
|
||||
- 7
|
||||
- 8
|
||||
- in: path
|
||||
required: true
|
||||
name: date
|
||||
description: the date corresponding to the wanted version of lc section. "Nan" for the latest version
|
||||
example: NaN
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/sectionCell'
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
'/shared/projects/entrepreneurs/{projectId}':
|
||||
get:
|
||||
summary: Retourne la liste d'entrepreneurs associée à un projet donné
|
||||
tags:
|
||||
- Shared API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
- MyINPulse-entrepreneur
|
||||
description: JSON array of entrepreneur names associated with a project
|
||||
parameters:
|
||||
- in: path
|
||||
name: projectId
|
||||
schema:
|
||||
type: integer
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/user-entrepreneur'
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
'/shared/projects/admin/{projectId}':
|
||||
get:
|
||||
summary: Retourne les informations de l'admin qui accompagne le projet
|
||||
tags:
|
||||
- Shared API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
- MyINPulse-entrepreneur
|
||||
description: 'JSON object containing information (name, gmail, tel, etc..) the admin supervising the project with id projectID.'
|
||||
parameters:
|
||||
- in: path
|
||||
name: projectId
|
||||
schema:
|
||||
type: integer
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/user-admin'
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
'/shared/projects/appointments/{projectId}':
|
||||
get:
|
||||
summary: Retourne les rendez-vous du projet
|
||||
tags:
|
||||
- Shared API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
- MyINPulse-entrepreneur
|
||||
description: JSON array of upcoming and past appointment data for the project with id projectID.
|
||||
parameters:
|
||||
- in: path
|
||||
name: projectId
|
||||
schema:
|
||||
type: integer
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/appointement'
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
'/shared/projects/appointments/report/{appointmentId}':
|
||||
get:
|
||||
summary: Retourne le rapport pdf du rendez-vous
|
||||
tags:
|
||||
- Shared API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
- MyINPulse-entrepreneur
|
||||
description: PDF file containing the ap- pointment report
|
||||
parameters:
|
||||
- in: path
|
||||
name: apointementId
|
||||
schema:
|
||||
type: integer
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/pdf:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
/shared/appointments/request:
|
||||
post:
|
||||
summary: demander un rendez-vous
|
||||
description: will add an appointement request request by the applicant to have an appointment to be confirmed or denied by the specified participants of the appointement.
|
||||
tags:
|
||||
- Shared API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-entrepreneur
|
||||
- MyINPulse-admin
|
||||
requestBody:
|
||||
description: \"participants\" property is an array containing userids of the participants in the appointement
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
title:
|
||||
type: string
|
||||
start_time:
|
||||
type: string
|
||||
end_time:
|
||||
type: string
|
||||
place:
|
||||
type: string
|
||||
applicantId:
|
||||
type: integer
|
||||
participants:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
/entrepreneur/projects/request:
|
||||
post:
|
||||
summary: demander la création et validation d'un projet
|
||||
tags:
|
||||
- Entrepreneurs API
|
||||
description: Adds project to pending projects to then be accepted or rejected by an admin
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-entrepreneur
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
founder:
|
||||
$ref: '#/components/schemas/user-entrepreneur'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
/entrepreneur/sectionCell/add:
|
||||
post:
|
||||
summary: ajouter une sections au LC
|
||||
description: Adds input data to the user's LC with a specified title.
|
||||
tags:
|
||||
- Entrepreneurs API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-entrepreneur
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/sectionCell'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
/entrepreneur/sectionCell/modify:
|
||||
put:
|
||||
summary: modifier les données d'une section LC
|
||||
description: Modifies input Lean Canvas section by changing it to the information in the request body and changes the time stamp.
|
||||
tags:
|
||||
- Entrepreneurs API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-entrepreneur
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/sectionCell'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
||||
'/entrepreneur/sectionCell/remove/{sectionCellId}':
|
||||
delete:
|
||||
summary: supprimer une section LC.
|
||||
description: Deletes section from Lean Canvas
|
||||
tags:
|
||||
- Entrepreneurs API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-entrepreneur
|
||||
parameters:
|
||||
- in: path
|
||||
name: sectionCellId
|
||||
schema:
|
||||
type: integer
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'400':
|
||||
description: Bad request
|
||||
'401':
|
||||
description: Authorization information is missing or invalid
|
121
documentation/openapi/src/entrepreneurApi.yaml
Normal file
121
documentation/openapi/src/entrepreneurApi.yaml
Normal file
@ -0,0 +1,121 @@
|
||||
# _____ _ _ _____ ____ _____ ____ ____ _____ _ _ _____ _ _ ____
|
||||
# | ____| \ | |_ _| _ \| ____| _ \| _ \| ____| \ | | ____| | | | _ \
|
||||
# | _| | \| | | | | |_) | _| | |_) | |_) | _| | \| | _| | | | | |_) |
|
||||
# | |___| |\ | | | | _ <| |___| __/| _ <| |___| |\ | |___| |_| | _ <
|
||||
# |_____|_|_\_| |_| |_| \_\_____|_| |_| \_\_____|_| \_|_____|\___/|_| \_\
|
||||
# / \ | _ \_ _|
|
||||
# / _ \ | |_) | |
|
||||
# / ___ \| __/| |
|
||||
# /_/ \_\_| |___|
|
||||
#
|
||||
|
||||
paths:
|
||||
/entrepreneur/projects/request:
|
||||
post:
|
||||
summary: demander la création et validation d'un projet
|
||||
tags:
|
||||
- Entrepreneurs API
|
||||
description:
|
||||
Adds project to pending projects
|
||||
to then be accepted or rejected by
|
||||
an admin
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-entrepreneur
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
founder:
|
||||
$ref: "main.yaml#/components/schemas/user-entrepreneur"
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is
|
||||
missing or invalid
|
||||
|
||||
|
||||
/entrepreneur/sectionCell/add:
|
||||
post:
|
||||
summary: ajouter une sections au LC
|
||||
description:
|
||||
Adds input data to the user's LC
|
||||
with a specified title.
|
||||
tags:
|
||||
- Entrepreneurs API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-entrepreneur
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "main.yaml#/components/schemas/sectionCell"
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is
|
||||
missing or invalid
|
||||
/entrepreneur/sectionCell/modify:
|
||||
put:
|
||||
summary: modifier les données d'une section LC
|
||||
description:
|
||||
Modifies input Lean Canvas section by changing it to
|
||||
the information in the request body and changes the
|
||||
time stamp.
|
||||
tags:
|
||||
- Entrepreneurs API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-entrepreneur
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "main.yaml#/components/schemas/sectionCell"
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is
|
||||
missing or invalid
|
||||
|
||||
/entrepreneur/sectionCell/remove/{sectionCellId}:
|
||||
delete:
|
||||
summary: supprimer une section LC.
|
||||
description:
|
||||
Deletes section from Lean Canvas
|
||||
tags:
|
||||
- Entrepreneurs API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-entrepreneur
|
||||
parameters:
|
||||
- in: path
|
||||
name: sectionCellId
|
||||
schema:
|
||||
type: integer
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is
|
||||
missing or invalid
|
115
documentation/openapi/src/main.yaml
Normal file
115
documentation/openapi/src/main.yaml
Normal file
@ -0,0 +1,115 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: MyInpulse Backend Api
|
||||
description: this document servers as a documentation for the backend api.
|
||||
version: 0.2.0
|
||||
|
||||
tags:
|
||||
- name: Entrepreneurs API
|
||||
description: La partie de l'api dédiée aux entrepreneurs
|
||||
- name: Admin API
|
||||
description: La partie de l'api dédiée aux entrepreneurs
|
||||
- name: Shared API
|
||||
description: La partie de l'api dédiée aux entrepreneurs et admins
|
||||
|
||||
|
||||
components:
|
||||
schemas:
|
||||
user:
|
||||
$ref: "models.yaml#/user"
|
||||
user-entrepreneur:
|
||||
$ref: "models.yaml#/user-entrepreneur"
|
||||
user-admin:
|
||||
$ref: "models.yaml#/user-admin"
|
||||
sectionCell:
|
||||
$ref: "models.yaml#/sectionCell"
|
||||
project:
|
||||
$ref: "models.yaml#/project"
|
||||
report:
|
||||
$ref: "models.yaml#/report"
|
||||
appointement:
|
||||
$ref: "models.yaml#/appointement"
|
||||
|
||||
|
||||
securitySchemes:
|
||||
MyINPulse:
|
||||
type: oauth2
|
||||
flows:
|
||||
implicit:
|
||||
authorizationUrl: http://localhost:7080
|
||||
description: keycloak server
|
||||
scopes:
|
||||
MyINPulse-admin: Administrateur
|
||||
MyINPulse-entrepreneur: Utilisateur
|
||||
|
||||
servers:
|
||||
- url: http://localhost:8081/
|
||||
description: Backend server
|
||||
|
||||
|
||||
|
||||
paths:
|
||||
# _ ____ __ __ ___ _ _ _ ____ ___
|
||||
# / \ | _ \| \/ |_ _| \ | | / \ | _ \_ _|
|
||||
# / _ \ | | | | |\/| || || \| | / _ \ | |_) | |
|
||||
# / ___ \| |_| | | | || || |\ | / ___ \| __/| |
|
||||
# /_/ \_\____/|_| |_|___|_| \_| /_/ \_\_| |___|
|
||||
#
|
||||
/admin/projects:
|
||||
$ref: "./adminApi.yaml#/paths/~1admin~1projects"
|
||||
/admin/projects/pending/decision:
|
||||
$ref: "./adminApi.yaml#/paths/~1admin~1projects~1pending~1decision"
|
||||
/admin/projects/add:
|
||||
$ref: "./adminApi.yaml#/paths/~1admin~1projects~1add"
|
||||
/admin/appointments/report/{appointmentId}:
|
||||
$ref: "./adminApi.yaml#/paths/~1admin~1appointments~1report~1{appointmentId}"
|
||||
/admin/projects/remove/{projectId}:
|
||||
$ref: "./adminApi.yaml#/paths/~1admin~1projects~1remove~1{projectId}"
|
||||
/admin/projects/pending:
|
||||
$ref: "./adminApi.yaml#/paths/~1admin~1projects~1pending"
|
||||
|
||||
# ____ _ _ _ ____ ___
|
||||
# / ___|| |__ __ _ _ __ ___ __| | / \ | _ \_ _|
|
||||
# \___ \| '_ \ / _` | '__/ _ \/ _` | / _ \ | |_) | |
|
||||
# ___) | | | | (_| | | | __/ (_| | / ___ \| __/| |
|
||||
# |____/|_| |_|\__,_|_| \___|\__,_| /_/ \_\_| |___|
|
||||
#
|
||||
/shared/appointments/upcoming:
|
||||
$ref: "./sharedApi.yaml#/paths/~1shared~1appointments~1upcoming"
|
||||
/shared/projects/sectionCell/{projectId}/{sectionId}/{date}:
|
||||
$ref: "./sharedApi.yaml#/paths/~1shared~1projects~1sectionCell~1{projectId}~1{sectionId}~1{date}"
|
||||
/shared/projects/entrepreneurs/{projectId}:
|
||||
$ref: "./sharedApi.yaml#/paths/~1shared~1projects~1entrepreneurs~1{projectId}"
|
||||
/shared/projects/admin/{projectId}:
|
||||
$ref: "./sharedApi.yaml#/paths/~1shared~1projects~1admin~1{projectId}"
|
||||
/shared/projects/appointments/{projectId}:
|
||||
$ref: "./sharedApi.yaml#/paths/~1shared~1projects~1appointments~1{projectId}"
|
||||
/shared/projects/appointments/report/{appointmentId}:
|
||||
$ref: "./sharedApi.yaml#/paths/~1shared~1projects~1appointments~1report~1{appointmentId}"
|
||||
|
||||
/shared/appointments/request:
|
||||
$ref: "./sharedApi.yaml#/paths/~1shared~1appointments~1request"
|
||||
|
||||
# _____ _ _ _____ ____ _____ ____ ____ _____ _ _ _____ _ _ ____
|
||||
# | ____| \ | |_ _| _ \| ____| _ \| _ \| ____| \ | | ____| | | | _ \
|
||||
# | _| | \| | | | | |_) | _| | |_) | |_) | _| | \| | _| | | | | |_) |
|
||||
# | |___| |\ | | | | _ <| |___| __/| _ <| |___| |\ | |___| |_| | _ <
|
||||
# |_____|_|_\_| |_| |_| \_\_____|_| |_| \_\_____|_| \_|_____|\___/|_| \_\
|
||||
# / \ | _ \_ _|
|
||||
# / _ \ | |_) | |
|
||||
# / ___ \| __/| |
|
||||
# /_/ \_\_| |___|
|
||||
#
|
||||
/entrepreneur/projects/request:
|
||||
$ref: "./entrepreneurApi.yaml#/paths/~1entrepreneur~1projects~1request"
|
||||
/entrepreneur/sectionCell/add:
|
||||
$ref: "./entrepreneurApi.yaml#/paths/~1entrepreneur~1sectionCell~1add"
|
||||
/entrepreneur/sectionCell/modify:
|
||||
$ref: "./entrepreneurApi.yaml#/paths/~1entrepreneur~1sectionCell~1modify"
|
||||
/entrepreneur/sectionCell/remove/{sectionCellId}:
|
||||
$ref: "./entrepreneurApi.yaml#/paths/~1entrepreneur~1sectionCell~1remove~1{sectionCellId}"
|
||||
|
||||
|
||||
|
||||
|
||||
|
88
documentation/openapi/src/models.yaml
Normal file
88
documentation/openapi/src/models.yaml
Normal file
@ -0,0 +1,88 @@
|
||||
# models.yaml
|
||||
|
||||
user:
|
||||
type: object
|
||||
properties:
|
||||
idUser:
|
||||
type: integer
|
||||
userSurname:
|
||||
type: string
|
||||
userName:
|
||||
type: string
|
||||
primaryMail:
|
||||
type: string
|
||||
example: "example@exmaple.com"
|
||||
secondaryMail:
|
||||
type: string
|
||||
example: "example@exmaple.com"
|
||||
phoneNumber:
|
||||
type: string
|
||||
example: "0612345678"
|
||||
|
||||
user-entrepreneur:
|
||||
allOf:
|
||||
- $ref: "#/user"
|
||||
- type: object
|
||||
properties:
|
||||
school:
|
||||
type: string
|
||||
example: "enseirb"
|
||||
course:
|
||||
type: string
|
||||
example: "info"
|
||||
sneeStatus:
|
||||
type: boolean
|
||||
example: false
|
||||
|
||||
user-admin:
|
||||
allOf:
|
||||
- $ref: "#/user"
|
||||
|
||||
sectionCell:
|
||||
type: object
|
||||
properties:
|
||||
idSectionCell:
|
||||
type: integer
|
||||
example: this the cell (postit id)
|
||||
sectionId:
|
||||
type: integer
|
||||
contentSectionCell:
|
||||
type: string
|
||||
modificationDate:
|
||||
type: string
|
||||
|
||||
project:
|
||||
type: object
|
||||
properties:
|
||||
idProject:
|
||||
type: integer
|
||||
projectName:
|
||||
type: string
|
||||
creationDate:
|
||||
type: string
|
||||
logo:
|
||||
example: to be discussed not yet fixed
|
||||
type: string
|
||||
format: binary
|
||||
|
||||
report:
|
||||
type: object
|
||||
properties:
|
||||
idReport:
|
||||
type: integer
|
||||
reportContent:
|
||||
type: string
|
||||
|
||||
appointement:
|
||||
type: object
|
||||
properties:
|
||||
appointmentDate:
|
||||
type: string
|
||||
appointmentTime:
|
||||
type: string
|
||||
appointmentDuration:
|
||||
type: string
|
||||
appointmentPlace:
|
||||
type: string
|
||||
appointmentSubject:
|
||||
type: string
|
254
documentation/openapi/src/sharedApi.yaml
Normal file
254
documentation/openapi/src/sharedApi.yaml
Normal file
@ -0,0 +1,254 @@
|
||||
# ____ _ _ _ ____ ___
|
||||
# / ___|| |__ __ _ _ __ ___ __| | / \ | _ \_ _|
|
||||
# \___ \| '_ \ / _` | '__/ _ \/ _` | / _ \ | |_) | |
|
||||
# ___) | | | | (_| | | | __/ (_| | / ___ \| __/| |
|
||||
# |____/|_| |_|\__,_|_| \___|\__,_| /_/ \_\_| |___|
|
||||
#
|
||||
paths:
|
||||
/shared/appointments/upcoming:
|
||||
get:
|
||||
summary: Retourne la list des prochains rendez-vous de l'utilisateur
|
||||
tags:
|
||||
- Shared API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
- MyINPulse-entrepreneur
|
||||
description:
|
||||
JSON array of upcoming appointment data (name, date, time etc..) for a user.
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "main.yaml#/components/schemas/appointement"
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is missing or invalid
|
||||
|
||||
/shared/projects/sectionCell/{projectId}/{sectionId}/{date}:
|
||||
get:
|
||||
summary: Retourne la liste de sections de LC avec un titre donné
|
||||
tags:
|
||||
- Shared API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
- MyINPulse-entrepreneur
|
||||
description:
|
||||
JSON array containing Lean Canvas
|
||||
section data with a title for the
|
||||
current date (or given date if the
|
||||
date parameter is passed)
|
||||
parameters:
|
||||
- in: path
|
||||
required: true
|
||||
name: projectId
|
||||
schema:
|
||||
type: integer
|
||||
- in: path
|
||||
required: true
|
||||
description: this number can be 1, 2,...,8. It is associated with the title of the sectionCell
|
||||
name: sectionId
|
||||
schema:
|
||||
type: integer
|
||||
enum: [1, 2, 3, 4, 5, 6, 7, 8]
|
||||
- in: path
|
||||
required: true
|
||||
name: date
|
||||
description: the date corresponding to the wanted version of lc section. "Nan" for the latest version
|
||||
example: "NaN"
|
||||
schema:
|
||||
type: string
|
||||
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "main.yaml#/components/schemas/sectionCell"
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is missing or invalid
|
||||
|
||||
/shared/projects/entrepreneurs/{projectId}:
|
||||
get:
|
||||
summary: Retourne la liste d'entrepreneurs associée à un projet donné
|
||||
tags:
|
||||
- Shared API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
- MyINPulse-entrepreneur
|
||||
description:
|
||||
JSON array of entrepreneur
|
||||
names associated with a project
|
||||
parameters:
|
||||
- in: path
|
||||
name: projectId
|
||||
schema:
|
||||
type: integer
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "main.yaml#/components/schemas/user-entrepreneur"
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is missing or invalid
|
||||
|
||||
/shared/projects/admin/{projectId}:
|
||||
get:
|
||||
summary: Retourne les informations de l'admin qui accompagne le projet
|
||||
tags:
|
||||
- Shared API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
- MyINPulse-entrepreneur
|
||||
description:
|
||||
JSON object containing information (name, gmail, tel, etc..)
|
||||
the admin supervising the project with id projectID.
|
||||
parameters:
|
||||
- in: path
|
||||
name: projectId
|
||||
schema:
|
||||
type: integer
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "main.yaml#/components/schemas/user-admin"
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is
|
||||
missing or invalid
|
||||
|
||||
/shared/projects/appointments/{projectId}:
|
||||
get:
|
||||
summary: Retourne les rendez-vous du projet
|
||||
tags:
|
||||
- Shared API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
- MyINPulse-entrepreneur
|
||||
description:
|
||||
JSON array of upcoming and past appointment
|
||||
data for the project with id projectID.
|
||||
parameters:
|
||||
- in: path
|
||||
name: projectId
|
||||
schema:
|
||||
type: integer
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "main.yaml#/components/schemas/appointement"
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is
|
||||
missing or invalid
|
||||
/shared/projects/appointments/report/{appointmentId}:
|
||||
get:
|
||||
summary: Retourne le rapport pdf du rendez-vous
|
||||
tags:
|
||||
- Shared API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-admin
|
||||
- MyINPulse-entrepreneur
|
||||
description:
|
||||
PDF file containing the ap-
|
||||
pointment report
|
||||
parameters:
|
||||
- in: path
|
||||
name: apointementId
|
||||
schema:
|
||||
type: integer
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/pdf:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is
|
||||
missing or invalid
|
||||
|
||||
/shared/appointments/request:
|
||||
post:
|
||||
summary: demander un rendez-vous
|
||||
description:
|
||||
will add an appointement request request by the applicant
|
||||
to have an appointment to be confirmed or denied by the
|
||||
specified participants of the appointement.
|
||||
tags:
|
||||
- Shared API
|
||||
security:
|
||||
- MyINPulse:
|
||||
- MyINPulse-entrepreneur
|
||||
- MyINPulse-admin
|
||||
requestBody:
|
||||
description: \"participants\" property is an array containing userids of the participants in the appointement
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
title:
|
||||
type: string
|
||||
start_time:
|
||||
type: string
|
||||
end_time:
|
||||
type: string
|
||||
place:
|
||||
type: string
|
||||
applicantId:
|
||||
type: integer
|
||||
participants:
|
||||
#/* */
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
"400":
|
||||
description: Bad request
|
||||
"401":
|
||||
description: Authorization information is
|
||||
missing or invalid
|
||||
|
14
documentation/openapi/swagger-ui/main.js
Normal file
14
documentation/openapi/swagger-ui/main.js
Normal file
@ -0,0 +1,14 @@
|
||||
const express = require("express");
|
||||
const swaggerUi = require("swagger-ui-express");
|
||||
const yaml = require("js-yaml");
|
||||
const fs = require("fs");
|
||||
|
||||
const app = express();
|
||||
|
||||
const swaggerDocument = yaml.load(fs.readFileSync("../src/bundled.yaml", "utf8"));
|
||||
|
||||
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument));
|
||||
|
||||
app.listen(3000, () => {
|
||||
console.log("Swagger UI running at http://localhost:3000/api-docs");
|
||||
});
|
2179
documentation/openapi/swagger-ui/package-lock.json
generated
Normal file
2179
documentation/openapi/swagger-ui/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
documentation/openapi/swagger-ui/package.json
Normal file
21
documentation/openapi/swagger-ui/package.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "swagger-ui",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"bundle": "swagger-cli bundle -o ../src/bundled.yaml -t yaml ../src/main.yaml",
|
||||
"start": "npm run bundle; node main.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"express": "^4.21.2",
|
||||
"js-yaml": "^4.1.0",
|
||||
"package.json": "^2.0.1",
|
||||
"swagger-cli": "^4.0.4",
|
||||
"swagger-ui-express": "^5.0.1"
|
||||
}
|
||||
}
|
2
front/MyINPulse-front/.gitignore
vendored
2
front/MyINPulse-front/.gitignore
vendored
@ -36,4 +36,4 @@ playwright-report/
|
||||
# Custom
|
||||
|
||||
.installed
|
||||
package-lock.json
|
||||
./package-lock.json
|
7
front/MyINPulse-front/.prettierrc
Normal file
7
front/MyINPulse-front/.prettierrc
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"useTabs":false,
|
||||
"semi":true,
|
||||
"trailingComma":"es5",
|
||||
"arrowParens":"always",
|
||||
"tabWidth":4
|
||||
}
|
29
front/MyINPulse-front/eslint.config.js
Normal file
29
front/MyINPulse-front/eslint.config.js
Normal file
@ -0,0 +1,29 @@
|
||||
import eslint from "@eslint/js";
|
||||
import eslintConfigPrettier from "eslint-config-prettier";
|
||||
import eslintPluginVue from "eslint-plugin-vue";
|
||||
import globals from "globals";
|
||||
import typescriptEslint from "typescript-eslint";
|
||||
|
||||
export default typescriptEslint.config(
|
||||
{ ignores: ["*.d.ts", "**/coverage", "**/dist"] },
|
||||
{
|
||||
extends: [
|
||||
eslint.configs.recommended,
|
||||
...typescriptEslint.configs.recommended,
|
||||
...eslintPluginVue.configs["flat/recommended"],
|
||||
],
|
||||
files: ["**/*.{ts,vue}"],
|
||||
languageOptions: {
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
globals: globals.browser,
|
||||
parserOptions: {
|
||||
parser: typescriptEslint.parser,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
// your rules
|
||||
},
|
||||
},
|
||||
eslintConfigPrettier
|
||||
);
|
1397
front/MyINPulse-front/package-lock.json
generated
1397
front/MyINPulse-front/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -26,8 +26,15 @@
|
||||
"@types/node": "^22.10.7",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"eslint": "^9.20.0",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
"eslint-plugin-vue": "^9.32.0",
|
||||
"globals": "^15.14.0",
|
||||
"jiti": "^2.4.2",
|
||||
"npm-run-all2": "^7.0.2",
|
||||
"prettier": "3.5.0",
|
||||
"typescript": "~5.7.3",
|
||||
"typescript-eslint": "^8.23.0",
|
||||
"vite": "^6.0.11",
|
||||
"vite-plugin-vue-devtools": "^7.7.0",
|
||||
"vue-tsc": "^2.2.0"
|
||||
|
@ -1,50 +1,47 @@
|
||||
<script setup lang="ts">
|
||||
import { RouterLink, RouterView } from 'vue-router'
|
||||
import { RouterView } from "vue-router";
|
||||
import ErrorWrapper from "@/views/errorWrapper.vue";
|
||||
import ProjectComponent from "@/components/ProjectComponent.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Header />
|
||||
<error-wrapper></error-wrapper>
|
||||
<div id="main">
|
||||
<ProjectComp
|
||||
v-for="(project, index) in projects"
|
||||
:key="index"
|
||||
:projectName="project.name"
|
||||
/>
|
||||
<HeaderComponent />
|
||||
<error-wrapper></error-wrapper>
|
||||
<div id="main">
|
||||
<ProjectComponent
|
||||
v-for="(project, index) in projects"
|
||||
:key="index"
|
||||
:project-name="project.name"
|
||||
/>
|
||||
</div>
|
||||
<RouterView />
|
||||
<RouterView />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import Header from "@/components/Header.vue";
|
||||
import ProjectComp from "@/components/Project-comp.vue";
|
||||
import HeaderComponent from "@/components/HeaderComponent.vue";
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
Header,
|
||||
ProjectComp,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
projects: [
|
||||
{
|
||||
name: 'Projet Alpha',
|
||||
//link: './project-alpha.html',
|
||||
//members: ['Alice', 'Bob', 'Charlie'],
|
||||
},
|
||||
{
|
||||
name: 'Projet Beta',
|
||||
//link: './project-beta.html',
|
||||
//members: ['David', 'Eve', 'Frank'],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
name: "App",
|
||||
components: {
|
||||
HeaderComponent,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
projects: [
|
||||
{
|
||||
name: "Projet Alpha",
|
||||
//link: './project-alpha.html',
|
||||
//members: ['Alice', 'Bob', 'Charlie'],
|
||||
},
|
||||
{
|
||||
name: "Projet Beta",
|
||||
//link: './project-beta.html',
|
||||
//members: ['David', 'Eve', 'Frank'],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
</script>
|
||||
<style scoped></style>
|
||||
|
@ -1,26 +1,26 @@
|
||||
<template>
|
||||
<header>
|
||||
<img src="./icons/logo inpulse.png" alt="INPulse" />
|
||||
<img src="./icons/logo inpulse.png" alt="INPulse" />
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'Header',
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
header img {
|
||||
width: 100px;
|
||||
}
|
||||
</template>
|
||||
|
||||
header{
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "HeaderComponent",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
header img {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 20px;
|
||||
background-color: #fff;
|
||||
border-bottom: 2px solid #ddd;
|
||||
}
|
||||
</style>
|
||||
}
|
||||
</style>
|
@ -3,16 +3,19 @@
|
||||
<div class="project-header">
|
||||
<h2>{{ projectName }}</h2>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="ts">
|
||||
import type { PropType } from "vue";
|
||||
|
||||
export default {
|
||||
name: 'Project',
|
||||
name: "ProjectComponent",
|
||||
props: {
|
||||
projectName: String,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
projectName: {
|
||||
type: Object as PropType<string>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
@ -1,17 +1,43 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps(['data']);
|
||||
import { color } from "@/services/popupDisplayer.ts";
|
||||
import type { PropType } from "vue";
|
||||
|
||||
defineProps({
|
||||
errorMessage: {
|
||||
type: Object as PropType<string>,
|
||||
required: true,
|
||||
},
|
||||
errorColor: {
|
||||
type: Object as PropType<color>,
|
||||
default: color.Red,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class='["red", "yellow", "blue", "green"][data.type]' class="error-modal">
|
||||
<p>{{["Erreur :(", "Warning :|", "Info :)", "Succes ;)"][data.type]}}</p>
|
||||
<p>{{data.errorMessage}}</p>
|
||||
<div class="loading" :class='["red-loader", "yellow-loader", "blue-loader", "green-loader"][data.type]'></div>
|
||||
</div>
|
||||
<div
|
||||
:class="['red', 'yellow', 'blue', 'green'][errorColor]"
|
||||
class="error-modal"
|
||||
>
|
||||
<p>
|
||||
{{
|
||||
["Erreur :(", "Warning :|", "Info :)", "Succes ;)"][errorColor]
|
||||
}}
|
||||
</p>
|
||||
<p>{{ errorMessage }}</p>
|
||||
<div
|
||||
class="loading"
|
||||
:class="
|
||||
['red-loader', 'yellow-loader', 'blue-loader', 'green-loader'][
|
||||
errorColor
|
||||
]
|
||||
"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.error-modal{
|
||||
.error-modal {
|
||||
margin-bottom: 1em;
|
||||
padding: 1em;
|
||||
border-radius: 1em;
|
||||
@ -19,41 +45,45 @@ const props = defineProps(['data']);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
animation: disappear 5s linear forwards;
|
||||
}
|
||||
}
|
||||
|
||||
.red{
|
||||
.red {
|
||||
background-color: #ee6055;
|
||||
color: white;
|
||||
}
|
||||
.red-loader {
|
||||
}
|
||||
|
||||
.red-loader {
|
||||
background-color: #fa8383;
|
||||
}
|
||||
}
|
||||
|
||||
.yellow{
|
||||
background-color: #FF9D23;
|
||||
color: white;
|
||||
}
|
||||
.yellow-loader{
|
||||
.yellow {
|
||||
background-color: #ff9d23;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.yellow-loader {
|
||||
background-color: #ffbf81;
|
||||
}
|
||||
}
|
||||
|
||||
.blue {
|
||||
.blue {
|
||||
background-color: #809bce;
|
||||
color: white;
|
||||
}
|
||||
.blue-loader{
|
||||
background-color: #95b8d1;
|
||||
}
|
||||
}
|
||||
|
||||
.green {
|
||||
.blue-loader {
|
||||
background-color: #95b8d1;
|
||||
}
|
||||
|
||||
.green {
|
||||
background-color: green;
|
||||
color: white;
|
||||
}
|
||||
.green-loader {
|
||||
background-color: darkgreen;
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
.green-loader {
|
||||
background-color: darkgreen;
|
||||
}
|
||||
|
||||
.loading {
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
@ -62,33 +92,33 @@ const props = defineProps(['data']);
|
||||
height: 1em;
|
||||
width: 0;
|
||||
animation: loading 4s linear forwards;
|
||||
}
|
||||
}
|
||||
|
||||
/* Animation for the loading bar */
|
||||
@keyframes loading {
|
||||
/* Animation for the loading bar */
|
||||
@keyframes loading {
|
||||
0% {
|
||||
width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
100% {
|
||||
width: 0;
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes disappear {
|
||||
@keyframes disappear {
|
||||
0% {
|
||||
height: 100px;
|
||||
padding: 1em;
|
||||
margin: 1em;
|
||||
height: 100px;
|
||||
padding: 1em;
|
||||
margin: 1em;
|
||||
}
|
||||
80% {
|
||||
height: 100px;
|
||||
padding: 1em;
|
||||
margin: 1em;
|
||||
height: 100px;
|
||||
padding: 1em;
|
||||
margin: 1em;
|
||||
}
|
||||
100% {
|
||||
height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
}
|
||||
</style>
|
||||
|
18
front/MyINPulse-front/src/components/temp-modal.vue
Normal file
18
front/MyINPulse-front/src/components/temp-modal.vue
Normal file
@ -0,0 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import { addNewMessage } from "@/services/popupDisplayer.ts";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
@click="
|
||||
addNewMessage(
|
||||
'new error from another view',
|
||||
Math.floor(Math.random() * 4)
|
||||
)
|
||||
"
|
||||
>
|
||||
Add an error
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
@ -1,36 +1,31 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router/router.ts'
|
||||
import {createPinia} from "pinia";
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
|
||||
import AuthStorePlugin from './plugins/authStore';
|
||||
import keycloakService from './services/keycloak';
|
||||
import {useAuthStore} from "@/stores/authStore.ts";
|
||||
let store: any;
|
||||
import { createApp } from "vue";
|
||||
import App from "./App.vue";
|
||||
import router from "./router/router.ts";
|
||||
import { createPinia } from "pinia";
|
||||
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
|
||||
import keycloakService from "./services/keycloak";
|
||||
import { type AuthStore, useAuthStore } from "@/stores/authStore.ts";
|
||||
|
||||
let store: AuthStore;
|
||||
|
||||
keycloakService.CallInit(() => {
|
||||
try {
|
||||
const app = createApp(App)
|
||||
const app = createApp(App);
|
||||
|
||||
// Setup pinia store, allowing user to keep logged in status after refresh
|
||||
const pinia = createPinia();
|
||||
pinia.use(piniaPluginPersistedstate);
|
||||
app.use(pinia);
|
||||
app.use(AuthStorePlugin, { pinia });
|
||||
store = useAuthStore();
|
||||
app.use(router)
|
||||
keycloakService.CallInitStore(store);
|
||||
app.use(router);
|
||||
|
||||
app.mount('#app');
|
||||
app.mount("#app");
|
||||
} catch (e) {
|
||||
console.error("Error while initiating Keycloak.")
|
||||
console.error(e)
|
||||
createApp(App).mount('#app');
|
||||
console.error("Error while initiating Keycloak.");
|
||||
console.error(e);
|
||||
createApp(App).mount("#app");
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export {store};
|
||||
export { store };
|
||||
|
@ -1,14 +0,0 @@
|
||||
// file: src/plugins/authStore.js
|
||||
|
||||
import { useAuthStore } from "@/stores/authStore.ts";
|
||||
import keycloakService from '@/services/keycloak';
|
||||
// Setup auth store as a plugin so it can be accessed globally in our FE
|
||||
const authStorePlugin = {
|
||||
install(app: any, option: any) {
|
||||
const store = useAuthStore(option.pinia);
|
||||
app.config.globalProperties.$store = store;
|
||||
keycloakService.CallInitStore(store);
|
||||
}
|
||||
}
|
||||
|
||||
export default authStorePlugin;
|
@ -1,17 +1,17 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: '/test',
|
||||
name: 'test',
|
||||
// route level code-splitting
|
||||
// this generates a separate chunk (About.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
component: () => import('../views/test.vue'),
|
||||
},
|
||||
],
|
||||
})
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: "/test",
|
||||
name: "test",
|
||||
// route level code-splitting
|
||||
// this generates a separate chunk (About.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
component: () => import("../views/testComponent.vue"),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export default router
|
||||
export default router;
|
||||
|
@ -1,31 +1,37 @@
|
||||
import axios from "axios";
|
||||
import {store} from "@/main.ts";
|
||||
import {addNewMessage, color} from "@/services/popupDisplayer.ts";
|
||||
import axios, { type AxiosError, type AxiosResponse } from "axios";
|
||||
import { store } from "@/main.ts";
|
||||
import { addNewMessage, color } from "@/services/popupDisplayer.ts";
|
||||
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: import.meta.env.VITE_BACKEND_URL,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
axiosInstance.interceptors.response.use(
|
||||
response => response, // Directly return successful responses.
|
||||
async error => {
|
||||
(response) => response, // Directly return successful responses.
|
||||
async (error) => {
|
||||
const originalRequest = error.config;
|
||||
if (error.response.status === 401 && !originalRequest._retry && store.authenticated) {
|
||||
if (
|
||||
((error.response && error.response.status === 401) ||
|
||||
error.code == "ERR_NETWORK") &&
|
||||
!originalRequest._retry &&
|
||||
store.authenticated
|
||||
) {
|
||||
originalRequest._retry = true; // Mark the request as retried to avoid infinite loops.
|
||||
try {
|
||||
await store.refreshUserToken();
|
||||
// Update the authorization header with the new access token.
|
||||
axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${store.user.token}`;
|
||||
axiosInstance.defaults.headers.common["Authorization"] =
|
||||
`Bearer ${store.user.token}`;
|
||||
return axiosInstance(originalRequest); // Retry the original request with the new access token.
|
||||
} catch (refreshError) {
|
||||
// Handle refresh token errors by clearing stored tokens and redirecting to the login page.
|
||||
console.error('Token refresh failed:', refreshError);
|
||||
localStorage.removeItem('accessToken');
|
||||
localStorage.removeItem('refreshToken');
|
||||
window.location.href = '/login';
|
||||
console.error("Token refresh failed:", refreshError);
|
||||
localStorage.removeItem("accessToken");
|
||||
localStorage.removeItem("refreshToken");
|
||||
window.location.href = "/login";
|
||||
return Promise.reject(refreshError);
|
||||
}
|
||||
}
|
||||
@ -34,23 +40,29 @@ axiosInstance.interceptors.response.use(
|
||||
);
|
||||
|
||||
// TODO: spawn a error modal
|
||||
function defaultApiErrorHandler(err: string){
|
||||
addNewMessage(err, color.Red);
|
||||
function defaultApiErrorHandler(err: AxiosError) {
|
||||
addNewMessage(err.message, color.Red);
|
||||
}
|
||||
|
||||
function defaultApiSuccessHandler(response: any){
|
||||
addNewMessage(response.data, color.green)
|
||||
}
|
||||
function callApi(endpoint: string, onSuccessHandler?: any, onErrorHandler?: any): void {
|
||||
axiosInstance.get(endpoint).then(
|
||||
onSuccessHandler == null ? defaultApiSuccessHandler : onSuccessHandler
|
||||
).catch(
|
||||
(err) => {
|
||||
onErrorHandler == null ? defaultApiErrorHandler(err): onErrorHandler(err);
|
||||
throw err;
|
||||
}
|
||||
)
|
||||
function defaultApiSuccessHandler(response: AxiosResponse) {
|
||||
addNewMessage(response.data, color.Green);
|
||||
}
|
||||
|
||||
function callApi(
|
||||
endpoint: string,
|
||||
onSuccessHandler?: (response: AxiosResponse) => void,
|
||||
onErrorHandler?: (error: AxiosError) => void
|
||||
): void {
|
||||
axiosInstance
|
||||
.get(endpoint)
|
||||
.then(
|
||||
onSuccessHandler == null
|
||||
? defaultApiSuccessHandler
|
||||
: onSuccessHandler
|
||||
)
|
||||
.catch(
|
||||
onErrorHandler == null ? defaultApiErrorHandler : onErrorHandler
|
||||
);
|
||||
}
|
||||
|
||||
export {callApi}
|
||||
export { callApi };
|
||||
|
@ -1,33 +1,31 @@
|
||||
import Keycloak from 'keycloak-js';
|
||||
import Keycloak from "keycloak-js";
|
||||
import type { AuthStore } from "@/stores/authStore.ts";
|
||||
|
||||
const options = {
|
||||
url: import.meta.env.VITE_KEYCLOAK_URL,
|
||||
clientId: import.meta.env.VITE_KEYCLOAK_CLIENT_ID,
|
||||
realm: import.meta.env.VITE_KEYCLOAK_REALM
|
||||
}
|
||||
|
||||
realm: import.meta.env.VITE_KEYCLOAK_REALM,
|
||||
};
|
||||
|
||||
const keycloak = new Keycloak(options);
|
||||
let authenticated: boolean | undefined;
|
||||
let store = null;
|
||||
|
||||
async function login(){
|
||||
async function login() {
|
||||
try {
|
||||
await keycloak.login() // https://www.keycloak.org/securing-apps/javascript-adapter#:~:text=when%20initialization%20completes.-,login(options),-Redirects%20to%20login
|
||||
await keycloak.login(); // https://www.keycloak.org/securing-apps/javascript-adapter#:~:text=when%20initialization%20completes.-,login(options),-Redirects%20to%20login
|
||||
return keycloak;
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function signup(){
|
||||
async function signup() {
|
||||
try {
|
||||
await keycloak.login(
|
||||
{action: "register"}
|
||||
) // https://www.keycloak.org/securing-apps/javascript-adapter#:~:text=when%20initialization%20completes.-,login(options),-Redirects%20to%20login
|
||||
await keycloak.login({ action: "register" }); // https://www.keycloak.org/securing-apps/javascript-adapter#:~:text=when%20initialization%20completes.-,login(options),-Redirects%20to%20login
|
||||
return keycloak;
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,31 +40,33 @@ async function init(onInitCallback: () => void) {
|
||||
onLoad: "check-sso",
|
||||
silentCheckSsoRedirectUri: `${location.origin}/silent-check-sso.htm`,
|
||||
responseMode: "query",
|
||||
})
|
||||
onInitCallback()
|
||||
});
|
||||
onInitCallback();
|
||||
} catch (error) {
|
||||
console.error("Keycloak init failed")
|
||||
console.error(error)
|
||||
console.error("Keycloak init failed");
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes store with Keycloak user data
|
||||
*
|
||||
*/
|
||||
async function initStore(storeInstance: any) {
|
||||
async function initStore(storeInstance: AuthStore) {
|
||||
try {
|
||||
store = storeInstance
|
||||
console.log(keycloak)
|
||||
await store.initOauth(keycloak)
|
||||
store = storeInstance;
|
||||
console.log(keycloak);
|
||||
await store.initOauth(keycloak);
|
||||
|
||||
// Show alert if user is not authenticated
|
||||
if (!authenticated) { console.warn("not authenticated") }
|
||||
if (!authenticated) {
|
||||
console.warn("not authenticated");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Keycloak init failed")
|
||||
console.error(error)
|
||||
console.error("Keycloak init failed");
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout user
|
||||
@ -83,7 +83,7 @@ async function refreshToken() {
|
||||
await keycloak.updateToken(480);
|
||||
return keycloak;
|
||||
} catch (error) {
|
||||
console.error('Failed to refresh token');
|
||||
console.error("Failed to refresh token");
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
@ -97,4 +97,4 @@ const KeycloakService = {
|
||||
callSignup: signup,
|
||||
};
|
||||
|
||||
export default KeycloakService;
|
||||
export default KeycloakService;
|
||||
|
@ -1,19 +1,43 @@
|
||||
import {ref} from "vue";
|
||||
enum color {Red, Yellow, Blue, green}
|
||||
import { ref, type Ref } from "vue";
|
||||
|
||||
function addNewMessage(errorMessage: string, type?: color, timeout?: number){
|
||||
if (timeout == null){
|
||||
enum color {
|
||||
Red,
|
||||
Yellow,
|
||||
Blue,
|
||||
Green,
|
||||
}
|
||||
|
||||
type ErrorMessageContent = {
|
||||
message: string;
|
||||
color: color;
|
||||
id: number;
|
||||
timeout: number;
|
||||
};
|
||||
|
||||
let id: number = 0;
|
||||
const getId = () => {
|
||||
id = id + 1;
|
||||
return id;
|
||||
};
|
||||
|
||||
function addNewMessage(errorMessage: string, type?: color, timeout?: number) {
|
||||
if (timeout == null) {
|
||||
timeout = 5000;
|
||||
}
|
||||
if (type == null){
|
||||
if (type == null) {
|
||||
type = color.Red;
|
||||
}
|
||||
|
||||
const data = {errorMessage: errorMessage, timeout: timeout, type: type, uid: Math.random()*100000};
|
||||
errorList.value.push(data)
|
||||
setTimeout(() => errorList.value.slice(0, 1), timeout)
|
||||
const data: ErrorMessageContent = {
|
||||
message: errorMessage,
|
||||
timeout: timeout,
|
||||
color: type,
|
||||
id: getId(),
|
||||
};
|
||||
errorList.value.push(data);
|
||||
setTimeout(() => errorList.value.slice(0, 1), timeout);
|
||||
}
|
||||
|
||||
const errorList: any= ref([])
|
||||
const errorList: Ref<ErrorMessageContent[]> = ref([]);
|
||||
|
||||
export {addNewMessage, errorList, color}
|
||||
export { addNewMessage, errorList, color, type ErrorMessageContent };
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user