diff --git a/README.md b/README.md index 5a99ac9..2d33f08 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,33 @@ Projet du groupe 01: - William Karpinski: Extension gestion des horaires - Léo Moulin: Extension inscription des étudiants +## Running + +Le projet peut être lancé grace à docker compose. + +```sh +$ docker compose up +``` + +Dans le cas ou vous modifiers des fichiers, pour éviter que les images de docker soient recrées avec les changement + +```sh +$ docker compose up --force-recreate --build +``` + ## Dévelopement -``` -$ ./gradlew backend:run frontend:run --parallel -``` +Dans le cas ou vous êtes dans une phase de développement, il est plus simple d'utiliser gradle pour lancer le backend et frontend dans un mode de développement. +**Attention**: Ce mode n'est pas fait pour être utilisé en production! +```sh +$ ./gradlew run --parallel +``` permet de lancer le frontend sur [http://localhost:5173](http://localhost:5173) ansi que le frontend sur [http://localhost:8080](http://localhost:8080) + +Ceci requière également docker pour lancer une instance de postgresql pris en charge par spring. + +Il est possible de se passer entièrement de docker en supprimant la dépendance dans le fichier `backend/build.gradle.kts`: ~~`developmentOnly("org.springframework.boot:spring-boot-docker-compose")`~~ +Il est alors nécéssaire d'avoir une instance de postgresql tournant sur `localhost:5432` avec une table `clyde`, utilisateur: `devel` et password: `devel` +(cette configuration peut également être changée dans le fichier resources/application.properties de spring) + diff --git a/backend/Dockerfile b/backend/Dockerfile index 5475dc9..1ed9969 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,6 +1,15 @@ +## Building phase +FROM gradle:jdk21-alpine AS BUILD +WORKDIR /backend + +COPY . . +RUN gradle build -x test + +## Running Phase FROM eclipse-temurin:21-jdk-alpine -VOLUME /tmp +WORKDIR /backend VOLUME /cdn -ENV SPRING_PROFILES_ACTIVE=prod -COPY build/libs/backend-0.0.1-SNAPSHOT.jar /app.jar -ENTRYPOINT ["java", "-jar", "/app.jar"] +# ENV SPRING_PROFILES_ACTIVE=prod +COPY --from=BUILD /backend/build/libs/Clyde-0.0.1-SNAPSHOT.jar /backend/app.jar +EXPOSE 8080 +ENTRYPOINT ["java", "-jar", "/backend/app.jar"] diff --git a/backend/settings.gradle.kts b/backend/settings.gradle.kts new file mode 100644 index 0000000..7d39fc5 --- /dev/null +++ b/backend/settings.gradle.kts @@ -0,0 +1,13 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.6/userguide/multi_project_builds.html in the Gradle documentation. + */ + +plugins { + // Apply the foojay-resolver plugin to allow automatic download of JDKs + id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.0" +} + +rootProject.name = "Clyde" diff --git a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/MockController.java b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/MockController.java index 2181da0..3d75d2a 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/EndPoints/MockController.java +++ b/backend/src/main/java/ovh/herisson/Clyde/EndPoints/MockController.java @@ -21,7 +21,7 @@ import java.util.Date; public class MockController { private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); - + public final UserService userService; public final UserRepository userRepo; public final TokenRepository tokenRepo; public final TokenService tokenService; @@ -39,7 +39,8 @@ public class MockController { public final ScholarshipRequestRepository scholarshipRequestRepository; public final UnregisterRequestRepository uninscriptionRequestRepository; - public MockController(UserRepository userRepo, TokenRepository tokenRepo, TokenService tokenService, CurriculumCourseService CurriculumCourseService, CurriculumService curriculumService, CourseService courseService, ExternalCurriculumRepository externalCurriculumRepository, InscriptionService inscriptionService, UserCurriculumRepository ucr, MinervalRepository minervalRepository, ScholarshipRequestRepository scholarshipRequestRepository, UnregisterRequestRepository unregisterRequestRepository){ + public MockController(UserService userService, UserRepository userRepo, TokenRepository tokenRepo, TokenService tokenService, CurriculumCourseService CurriculumCourseService, CurriculumService curriculumService, CourseService courseService, ExternalCurriculumRepository externalCurriculumRepository, InscriptionService inscriptionService, UserCurriculumRepository ucr, MinervalRepository minervalRepository, ScholarshipRequestRepository scholarshipRequestRepository, UnregisterRequestRepository unregisterRequestRepository){ + this.userService = userService; this.tokenRepo = tokenRepo; this.userRepo = userRepo; this.tokenService = tokenService; @@ -73,7 +74,7 @@ public class MockController { User popo = new User("Smith", "Paul", "paulsmith@gmail.com", "306 rue du poulet", "belgique", new Date(0), null, Role.Student, passwordEncoder.encode("jesuispaulleroi")); mockUsers = new ArrayList<>(Arrays.asList(herobrine,joe,meh,joke,lena,jojo, popo)); - userRepo.saveAll(mockUsers); + userService.saveAll(mockUsers); Minerval minerval = new Minerval(joe.getRegNo(), 0, 852, 2023); minervalRepository.save(minerval); diff --git a/backend/src/main/java/ovh/herisson/Clyde/JdbcConfig.java b/backend/src/main/java/ovh/herisson/Clyde/JdbcConfig.java deleted file mode 100644 index 801e549..0000000 --- a/backend/src/main/java/ovh/herisson/Clyde/JdbcConfig.java +++ /dev/null @@ -1,37 +0,0 @@ -package ovh.herisson.Clyde; - -import javax.sql.DataSource; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.jdbc.datasource.DriverManagerDataSource; -import org.springframework.scheduling.annotation.EnableScheduling; - -@Configuration -@EnableScheduling -public class JdbcConfig { - - @Bean - @Profile("!prod") - public DataSource psqlSource(){ - DriverManagerDataSource source = new DriverManagerDataSource(); - source.setDriverClassName("org.postgresql.Driver"); - source.setUrl("jdbc:postgresql://localhost:5442/clyde"); - source.setUsername("devel"); - source.setPassword("devel"); - - return source; - } - - @Bean - @Profile("prod") - public DataSource psqlSourceProd(){ - DriverManagerDataSource source = new DriverManagerDataSource(); - source.setDriverClassName("org.postgresql.Driver"); - source.setUrl("jdbc:postgresql:clyde?socketFactory=org.newsclub.net.unix.AFUNIXSocketFactory$FactoryArg&socketFactoryArg=/var/run/postgresql/.s.PGSQL.5432"); - source.setUsername("clyde"); - - return source; - } -} diff --git a/backend/src/main/java/ovh/herisson/Clyde/Services/Inscription/InscriptionService.java b/backend/src/main/java/ovh/herisson/Clyde/Services/Inscription/InscriptionService.java index a40f537..208471d 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/Services/Inscription/InscriptionService.java +++ b/backend/src/main/java/ovh/herisson/Clyde/Services/Inscription/InscriptionService.java @@ -6,6 +6,7 @@ import ovh.herisson.Clyde.Repositories.*; import ovh.herisson.Clyde.Repositories.Inscription.ExternalCurriculumRepository; import ovh.herisson.Clyde.Repositories.Inscription.InscriptionRepository; import ovh.herisson.Clyde.Repositories.Inscription.MinervalRepository; +import ovh.herisson.Clyde.Services.UserService; import ovh.herisson.Clyde.Tables.*; import ovh.herisson.Clyde.Tables.Inscription.ExternalCurriculum; import ovh.herisson.Clyde.Tables.Inscription.InscriptionRequest; @@ -28,14 +29,15 @@ public class InscriptionService { private final MinervalRepository minervalRepository; private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); private final ExternalCurriculumRepository externalCurriculumRepository; - - public InscriptionService(InscriptionRepository inscriptionRepo, UserRepository userRepo, UserCurriculumRepository userCurriculumRepo, CurriculumRepository curriculumRepo, MinervalRepository minervalRepository, ExternalCurriculumRepository externalCurriculumRepository){ + private final UserService userService; + public InscriptionService(InscriptionRepository inscriptionRepo, UserRepository userRepo, UserCurriculumRepository userCurriculumRepo, CurriculumRepository curriculumRepo, MinervalRepository minervalRepository, ExternalCurriculumRepository externalCurriculumRepository, UserService userService){ this.inscriptionRepo = inscriptionRepo; this.userRepo = userRepo; this.userCurriculumRepo = userCurriculumRepo; this.curriculumRepo = curriculumRepo; this.minervalRepository = minervalRepository; this.externalCurriculumRepository = externalCurriculumRepository; + this.userService = userService; } public InscriptionRequest save(InscriptionRequest inscriptionRequest){ @@ -85,7 +87,7 @@ public class InscriptionService { inscrRequest.getPassword() ); - userRepo.save(userFromRequest); + userService.save(userFromRequest); Calendar c = Calendar.getInstance(); userCurriculumRepo.save(new UserCurriculum(userFromRequest, curriculumRepo.findById(inscrRequest.getCurriculumId()),c.get(Calendar.YEAR), true)); diff --git a/backend/src/main/java/ovh/herisson/Clyde/Services/UserService.java b/backend/src/main/java/ovh/herisson/Clyde/Services/UserService.java index 72eabd5..9c6bd7f 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/Services/UserService.java +++ b/backend/src/main/java/ovh/herisson/Clyde/Services/UserService.java @@ -2,6 +2,7 @@ package ovh.herisson.Clyde.Services; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; +import ovh.herisson.Clyde.Tables.RegNoGenerator; import ovh.herisson.Clyde.Repositories.UserRepository; import ovh.herisson.Clyde.Tables.Role; import ovh.herisson.Clyde.Tables.User; @@ -106,10 +107,17 @@ public class UserService { } public User save(User user){ + RegNoGenerator.resetCount(); user.setPassword(passwordEncoder.encode(user.getPassword())); return userRepo.save(user); } + public void saveAll(ArrayList list){ + //S'assure que le compteur est bien a 0 + RegNoGenerator.resetCount(); + userRepo.saveAll(list); + } + public Iterable getAll(){ return userRepo.findAll(); } diff --git a/backend/src/main/java/ovh/herisson/Clyde/Tables/RegNoGenerator.java b/backend/src/main/java/ovh/herisson/Clyde/Tables/RegNoGenerator.java new file mode 100644 index 0000000..886cc09 --- /dev/null +++ b/backend/src/main/java/ovh/herisson/Clyde/Tables/RegNoGenerator.java @@ -0,0 +1,46 @@ +package ovh.herisson.Clyde.Tables; + +import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.id.IdentifierGenerator; + +import java.sql.*; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +public class RegNoGenerator implements IdentifierGenerator { + private static int count = 0; + @Override + public Object generate(SharedSessionContractImplementor session, Object object) { + try{ + JdbcConnectionAccess jdbccon = session.getJdbcConnectionAccess(); + Connection conn = jdbccon.obtainConnection(); + + Statement statement = conn.createStatement(); + + Calendar c = new GregorianCalendar(); + int y = c.get(Calendar.YEAR); + String query = "select count(reg_no) + "+count+" from Users where reg_no/10000 = " + y%1000; + + ResultSet set = statement.executeQuery(query); + long resp = 0; + if(set.next()){ + resp = set.getLong(1)+((y%1000)*10000); + count += 1; + } + + conn.close(); + statement.close(); + + return resp; + + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public static void resetCount(){ + count = 0; + } +} \ No newline at end of file diff --git a/backend/src/main/java/ovh/herisson/Clyde/Tables/User.java b/backend/src/main/java/ovh/herisson/Clyde/Tables/User.java index 9f088a8..b21738e 100644 --- a/backend/src/main/java/ovh/herisson/Clyde/Tables/User.java +++ b/backend/src/main/java/ovh/herisson/Clyde/Tables/User.java @@ -1,20 +1,22 @@ package ovh.herisson.Clyde.Tables; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OnDeleteAction; +import org.hibernate.annotations.GenericGenerator; import ovh.herisson.Clyde.Tables.Msg.Discussion; import ovh.herisson.Clyde.Tables.Msg.Message; import java.util.Date; import java.util.List; - @Entity @Table(name = "Users") public class User { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GenericGenerator(name = "userGen", type = ovh.herisson.Clyde.Tables.RegNoGenerator.class) + @GeneratedValue(generator = "userGen") private Long regNo; private String lastName; private String firstName; @@ -24,7 +26,9 @@ public class User { private String country; private Date birthDate; private String profilePictureUrl; - private ovh.herisson.Clyde.Tables.Role role; + private Role role; + + @JsonIgnore private String password; ////// Extension Messagerie ///// diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 5d00d8e..190c76b 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -1,3 +1,12 @@ spring.jpa.hibernate.ddl-auto=create-drop spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect -spring.sql.init.mode=always \ No newline at end of file +spring.sql.init.mode=always + +# spring.datasource.url=jdbc:postgresql://localhost:5442/clyde +spring.datasource.url=jdbc:postgresql://db:5432/clyde +spring.datasource.username=devel +spring.datasource.password=devel + +# spring.config.activate.on-profile=prod +# spring.datasource.url=jdbc:postgresql:clyde?socketFactory=org.newsclub.net.unix.AFUNIXSocketFactory$FactoryArg&socketFactoryArg=/var/run/postgresql/.s.PGSQL.5432 +# spring.datasource.username=clyde diff --git a/backend/src/test/java/ovh/herisson/Clyde/Repositories/UserRepoTest.java b/backend/src/test/java/ovh/herisson/Clyde/Repositories/UserRepoTest.java index f99ff2f..599ec60 100644 --- a/backend/src/test/java/ovh/herisson/Clyde/Repositories/UserRepoTest.java +++ b/backend/src/test/java/ovh/herisson/Clyde/Repositories/UserRepoTest.java @@ -24,6 +24,7 @@ public class UserRepoTest { @BeforeEach public void setup(){ + userRepo.deleteAll(); User herobrine = new User("brine","hero","admin@admin.com","in your WalLs","ShadowsLand", new GregorianCalendar(2005, 4, 3).getTime(), null, Role.Admin,"admin"); userRepo.save(herobrine); } @@ -34,8 +35,8 @@ public class UserRepoTest { } @Test public void usertest(){ - Assert.assertEquals("brine", userRepo.findById(1).getLastName()); - Assert.assertTrue(new GregorianCalendar(2005, 4, 3).getTime().equals(userRepo.findById(1).getBirthDate())); + Assert.assertEquals("brine", userRepo.findByEmail("admin@admin.com").getLastName()); + Assert.assertTrue(new GregorianCalendar(2005, 4, 3).getTime().equals(userRepo.findByEmail("admin@admin.com").getBirthDate())); } } diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..ec5f6bc --- /dev/null +++ b/compose.yaml @@ -0,0 +1,29 @@ +services: + db: + image: 'postgres:16' + environment: + - 'POSTGRES_DB=clyde' + - 'POSTGRES_USER=devel' + - 'POSTGRES_PASSWORD=devel' + # Uncomment this to allow connections to the db from outside the container + # ports: + # - '5442:5432' + back: + build: backend/. + ports: + - "8080:8080" + volumes: + - cdn:/backend/cdn + ulimits: + nofile: + soft: 65536 + hard: 65536 + front: + build: frontend/. + volumes: + - cdn:/app/front/dist/cdn + ports: + - "8000:8080" + +volumes: + cdn: diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..2df53ae --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,11 @@ +# https://v2.vuejs.org/v2/cookbook/dockerize-vuejs-app +FROM node:lts-alpine +RUN npm install -g http-server +WORKDIR /app/front +COPY package*.json ./ +RUN npm install +COPY . . +ENV VITE_CLYDE_MODE=container +RUN npm run build +EXPOSE 8080 +CMD [ "http-server", "dist" ] diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 485aaa8..0ab750a 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -96,20 +96,19 @@ window.addEventListener('hashchange', () => { height: 100%; width: 100%; display:grid; - grid-template-columns:[firstCol-start]70px[firstCol-end secondCol-start]auto[endCol]; - grid-template-rows:[firstRow-start]61px[firstRow-end secondRow-start] auto [endRow]; + + grid-template-columns:[firstCol-start]70px[firstCol-end secondCol-start] auto [endCol]; + grid-template-rows:[firstRow-start] var(--header-size) [firstRow-end secondRow-start] calc(100% - var(--header-size)) [endRow]; grid-template-areas: "topBar topBar" "leftBar page"; - row-gap:0px; - column-gap:0px; + } .page { grid-area:page; height: 100%; width: 100%; - place-self:center; } .topBar{ @@ -152,7 +151,7 @@ window.addEventListener('hashchange', () => { ul.vertical{ list-style-type: none; - margin-top: 61px; + margin-top: var(--header-size); top:0; left:0; padding: 25px 0 0; @@ -200,7 +199,7 @@ window.addEventListener('hashchange', () => { left:0; position: fixed; - height:61px; + height:var(--header-size); width: 100%; background-color: rgb(24, 24, 24); } diff --git a/frontend/src/assets/main.css b/frontend/src/assets/main.css index 54ce8d8..67f454e 100644 --- a/frontend/src/assets/main.css +++ b/frontend/src/assets/main.css @@ -1,3 +1,7 @@ +:root { + --header-size: 61px; +} + body { background-color: rgb(53, 25, 60); margin:0; diff --git a/frontend/src/rest/restConsumer.js b/frontend/src/rest/restConsumer.js index 2ac4cc3..1af979e 100644 --- a/frontend/src/rest/restConsumer.js +++ b/frontend/src/rest/restConsumer.js @@ -1,7 +1,7 @@ import { getCookie } from '../utils.js' import { toast } from 'vue3-toastify' -const restURL = import.meta.env.PROD ? "https://clyde.herisson.ovh/api" : "http://localhost:8080" +const restURL = import.meta.env.VITE_CLYDE_MODE === 'container' ? "http://localhost:8080": import.meta.env.DEV ? "http://localhost:8080" : "https://clyde.herisson.ovh/api" export async function restGet(endPoint) { return await _rest(endPoint, {method: "GET"});