284 Commits

Author SHA1 Message Date
1fad792be7 Just to merge 2024-03-22 20:14:20 +01:00
3d6941ab93 adding cdn to CI
All checks were successful
Build and test backend / Build-backend (push) Successful in 1m57s
Build and test FrontEnd / Build-frontend (push) Successful in 23s
deploy to production / deploy-frontend (push) Successful in 27s
deploy to production / deploy-backend (push) Successful in 1m29s
2024-03-18 21:39:31 +01:00
de72bd800c CI fix
All checks were successful
Build and test backend / Build-backend (push) Successful in 1m53s
deploy to production / deploy-frontend (push) Successful in 26s
deploy to production / deploy-backend (push) Successful in 2m3s
Build and test FrontEnd / Build-frontend (push) Successful in 23s
2024-03-18 21:13:00 +01:00
b465dcfa92 Merge pull request 'Clean le projet' (#146) from Leo/Backend/Cleaning into master
Some checks failed
Build and test backend / Build-backend (push) Successful in 1m55s
deploy to production / deploy-frontend (push) Successful in 26s
deploy to production / deploy-backend (push) Failing after 2m51s
Build and test FrontEnd / Build-frontend (push) Successful in 24s
Reviewed-on: #146
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
2024-03-18 21:06:02 +01:00
73f3df0bc6 Clean le projet
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m46s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-18 20:54:16 +01:00
90a7b7b70e Merge pull request 'Link back and front all get' (#115) from wal/front/listingUsers into master
Some checks failed
Build and test backend / Build-backend (push) Successful in 1m53s
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Failing after 2m48s
Build and test FrontEnd / Build-frontend (push) Successful in 24s
Reviewed-on: #115
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
Reviewed-by: LeoMoulin <leomoulin125@gmail.com>
2024-03-18 20:20:35 +01:00
4f002a29e1 Merge pull request 'added delete self' (#145) from Max/Backend/UserDelete into master
Some checks failed
deploy to production / deploy-frontend (push) Waiting to run
deploy to production / deploy-backend (push) Waiting to run
Build and test FrontEnd / Build-frontend (push) Waiting to run
Build and test backend / Build-backend (push) Has been cancelled
Reviewed-on: #145
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: LeoMoulin <leomoulin125@gmail.com>
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
2024-03-18 20:19:41 +01:00
66d090d045 Merge pull request 'Leo/Backend/UnitTest' (#138) from Leo/Backend/UnitTest into master
Some checks failed
Build and test backend / Build-backend (push) Successful in 1m56s
deploy to production / deploy-frontend (push) Successful in 26s
deploy to production / deploy-backend (push) Failing after 2m53s
Build and test FrontEnd / Build-frontend (push) Successful in 25s
Reviewed-on: #138
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
Reviewed-by: Maxime <231026@umons.ac.be>
2024-03-18 19:21:54 +01:00
4715441afd FINAL COMMIT
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-18 18:47:00 +01:00
77ac771b8f Merge remote-tracking branch 'origin/Max/Backend/UserDelete' into wal/front/listingUsers
Some checks failed
Build and test backend / Build-backend (pull_request) Failing after 1m31s
Build and test backend / Test-backend (pull_request) Failing after 1m31s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-18 17:36:07 +01:00
3762750968 Tempo 2024-03-18 17:34:35 +01:00
a276c24f8f added delete self
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 2m0s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-18 17:30:04 +01:00
25c5c1b018 Nearly finish
Some checks failed
Build and test backend / Build-backend (pull_request) Failing after 1m31s
Build and test backend / Test-backend (pull_request) Failing after 1m31s
Build and test FrontEnd / Build-frontend (pull_request) Failing after 20s
2024-03-18 17:28:14 +01:00
c7f37b0854 Fix le truc de max et ajoute le test du delete
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m44s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-18 15:55:38 +01:00
c35f675a11 Manage course + delete course END
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m3s
Build and test backend / Test-backend (pull_request) Successful in 1m57s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-18 15:47:04 +01:00
a9e5e45872 Merge branch 'master' into wal/front/listingUsers
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m5s
Build and test backend / Test-backend (pull_request) Successful in 2m1s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-18 14:57:49 +01:00
73d50f3f50 Merge remote-tracking branch 'refs/remotes/origin/wal/front/listingUsers' into wal/front/listingUsers
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m59s
Build and test backend / Test-backend (pull_request) Successful in 2m2s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 26s
2024-03-18 14:52:29 +01:00
0871d2971d manage Course finished 2024-03-18 14:51:27 +01:00
9744bd973f Resolve conflicts and adapt tests
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m49s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-18 14:29:30 +01:00
ecaa0af24a Merge remote-tracking branch 'origin/master' into Leo/Backend/UnitTest
# Conflicts:
#	backend/src/main/java/ovh/herisson/Clyde/Services/AuthenticatorService.java
#	backend/src/main/java/ovh/herisson/Clyde/Services/UserService.java
2024-03-18 13:55:45 +01:00
a762b6875d removing cdn
Some checks failed
Build and test backend / Build-backend (pull_request) Failing after 1m34s
Build and test backend / Test-backend (pull_request) Failing after 1m32s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-18 13:54:31 +01:00
4e6c4ecf38 Merge pull request 'added GET /user/{id}' (#143) from Max/Backend/GetUserById into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m13s
deploy to production / deploy-frontend (push) Successful in 24s
Build and test FrontEnd / Build-frontend (push) Successful in 25s
Build and test backend / Test-backend (push) Successful in 1m21s
deploy to production / deploy-backend (push) Successful in 2m22s
Reviewed-on: #143
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
Reviewed-by: LeoMoulin <leomoulin125@gmail.com>
Reviewed-by: Wal <karpinskiwal@gmail.com>
2024-03-18 13:48:07 +01:00
ec3c912847 Merge remote-tracking branch 'origin/master' into Max/Backend/GetUserById
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m0s
Build and test backend / Test-backend (pull_request) Successful in 2m1s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-18 13:45:47 +01:00
5636d96478 Merge pull request 'Max/Backend/UserDelete' (#144) from Max/Backend/UserDelete into master
Some checks failed
Build and test FrontEnd / Build-frontend (push) Waiting to run
deploy to production / deploy-frontend (push) Waiting to run
deploy to production / deploy-backend (push) Waiting to run
Build and test backend / Test-backend (push) Has been cancelled
Build and test backend / Build-backend (push) Successful in 2m12s
Reviewed-on: #144
Reviewed-by: LeoMoulin <leomoulin125@gmail.com>
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
2024-03-18 13:45:04 +01:00
d40ceff2ba disable test on ci, problem for later
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m42s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-18 12:41:18 +01:00
fd357ba938 GET /curriculum returns user's curriculum
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-18 12:15:13 +01:00
92079c5a47 Merge remote-tracking branch 'origin/Max/Backend/UserDelete' into wal/front/listingUsers
Some checks failed
Build and test backend / Build-backend (pull_request) Failing after 1m32s
Build and test backend / Test-backend (pull_request) Failing after 1m33s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-18 11:59:44 +01:00
753af3874e Login and register ok and starting requests 2024-03-18 11:55:51 +01:00
e03a01ec89 oups forgot somthing 2024-03-18 11:53:33 +01:00
fd18df7c3a added a InscriptionRequest to POST /mock
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 1m59s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-18 11:33:50 +01:00
93c161be4c added every delete endpoint required
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m16s
Build and test backend / Test-backend (pull_request) Successful in 1m59s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-18 11:22:21 +01:00
853a3a42d2 Small improvement
Some checks failed
Build and test backend / Build-backend (pull_request) Successful in 1m45s
Build and test backend / Test-backend (pull_request) Failing after 3m25s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-18 02:14:36 +01:00
a80fb2b297 added DELETE user and prepared tables for cascade deletion
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-18 00:14:48 +01:00
f484fb095e added protection for inscription requests 2024-03-18 00:14:26 +01:00
8ff29ca34e Register
Some checks failed
Build and test backend / Build-backend (pull_request) Successful in 2m3s
Build and test backend / Test-backend (pull_request) Successful in 1m57s
Build and test FrontEnd / Build-frontend (pull_request) Failing after 23s
2024-03-17 23:19:36 +01:00
611e7167f9 CI -> build no test and trying to fix test
Some checks failed
Build and test backend / Build-backend (pull_request) Successful in 1m50s
Build and test backend / Test-backend (pull_request) Failing after 2m38s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 26s
2024-03-17 22:40:22 +01:00
ee37dc79a7 Fixing the CI
Some checks failed
Build and test backend / Build-backend (pull_request) Failing after 2m45s
Build and test backend / Test-backend (pull_request) Failing after 2m37s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
Moving the dev test and build to port 5442 from 5432 to avoid
conflicting with the running postgresql
2024-03-17 22:02:12 +01:00
2fb6aef67c added GET /user/{id} 2024-03-17 22:01:48 +01:00
7e7cec2f6c Merge branch 'Max/Backend/GetUserById' into wal/front/listingUsers
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 1m57s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-17 22:00:56 +01:00
345599888d added GET /user/{id}
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m59s
Build and test backend / Test-backend (pull_request) Successful in 1m56s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-17 21:48:58 +01:00
19b4950be4 Merge branch 'master' into wal/front/listingUsers
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m4s
Build and test backend / Test-backend (pull_request) Successful in 1m57s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-17 21:39:04 +01:00
d9307753c4 trop de truc
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m58s
Build and test backend / Test-backend (pull_request) Successful in 1m56s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-17 21:38:10 +01:00
7a23dcc96a Merge pull request 'Max/Backend/ReturnUserPasswordIssue' (#137) from Max/Backend/ReturnUserPasswordIssue into master
All checks were successful
Build and test backend / Test-backend (push) Successful in 1m20s
deploy to production / deploy-frontend (push) Successful in 23s
Build and test backend / Build-backend (push) Successful in 2m12s
deploy to production / deploy-backend (push) Successful in 2m18s
Build and test FrontEnd / Build-frontend (push) Successful in 23s
Reviewed-on: #137
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: LeoMoulin <leomoulin125@gmail.com>
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
2024-03-17 21:36:53 +01:00
f2b80ba89f Resolve conflicts and resolve condition bug in isNotSecretaryOrAdmin
Some checks failed
Build and test backend / Build-backend (pull_request) Failing after 2m27s
Build and test backend / Test-backend (pull_request) Failing after 2m25s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-17 19:17:38 +01:00
114116b97c Merge remote-tracking branch 'origin/master' into Leo/Backend/UnitTest
# Conflicts:
#	backend/src/main/java/ovh/herisson/Clyde/EndPoints/UserController.java
2024-03-17 19:14:25 +01:00
924faca13f Add testing for file uploading and correct minors bugs in service
Some checks failed
Build and test backend / Build-backend (pull_request) Failing after 3m14s
Build and test backend / Test-backend (pull_request) Failing after 2m30s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 26s
2024-03-17 19:06:27 +01:00
ea4a0745e0 creation of the user when request accepted
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m42s
Build and test backend / Test-backend (pull_request) Successful in 2m30s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 33s
2024-03-17 17:15:33 +01:00
76f5a39a8f GET /users doesn't return Admins if the poster isn't an admin
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m1s
Build and test backend / Test-backend (pull_request) Successful in 2m0s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-17 16:26:30 +01:00
37f8a3ac4e removed an unused variable 2024-03-17 16:25:00 +01:00
ea46dd664c added a todo to send an email for every state changement of request
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m58s
Build and test backend / Test-backend (pull_request) Successful in 1m59s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-17 16:02:30 +01:00
b2d0be014c UserList and Student List part1
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 1m56s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-17 15:59:12 +01:00
571d27c230 Add test for user patch
Some checks failed
Build and test backend / Build-backend (pull_request) Failing after 2m24s
Build and test backend / Test-backend (pull_request) Failing after 2m22s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-17 15:53:50 +01:00
37a9eb46ae Add tests for UserController get and post
Some checks failed
Build and test backend / Build-backend (pull_request) Failing after 2m22s
Build and test backend / Test-backend (pull_request) Failing after 2m24s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-17 15:42:43 +01:00
bfc4f6567b Merge remote-tracking branch 'origin/Leo/Backend/UnitTest' into Leo/Backend/UnitTest
# Conflicts:
#	backend/src/main/java/ovh/herisson/Clyde/EndPoints/UserController.java
2024-03-17 15:40:45 +01:00
d423a57fa0 Add tests for UserController get and post 2024-03-17 15:40:14 +01:00
210fda0401 Merge branch 'master' into wal/front/listingUsers 2024-03-17 13:33:47 +01:00
b67b25b4a4 Login Finished, add curricula and apps
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 2m0s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-17 13:24:24 +01:00
385290d1a2 Merge branch 'master' into Max/Backend/ReturnUserPasswordIssue
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m4s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-17 13:07:20 +01:00
cf2deb983d added security to assistant posting and Get courses/owned for owners
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m0s
Build and test backend / Test-backend (pull_request) Successful in 1m57s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-17 12:13:03 +01:00
dcec45acf5 Merge pull request 'added /students endpoint' (#135) from Max/Backend/StudentEndPoin into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m11s
Build and test backend / Test-backend (push) Successful in 1m19s
deploy to production / deploy-frontend (push) Successful in 24s
deploy to production / deploy-backend (push) Successful in 2m20s
Build and test FrontEnd / Build-frontend (push) Successful in 24s
Reviewed-on: #135
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
Reviewed-by: Wal <karpinskiwal@gmail.com>
2024-03-17 12:00:57 +01:00
008af10d0e Merge branch 'master' into Leo/Backend/UnitTest
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m17s
Build and test backend / Test-backend (pull_request) Successful in 2m17s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-17 10:36:00 +01:00
f7df234312 moved portective method to Static ProtectiveService
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 1m57s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-17 03:06:19 +01:00
d855bbe911 Merge branch 'Max/Backend/CourseInCurriculum' into Max/Backend/ReturnUserPasswordIssue 2024-03-17 02:50:12 +01:00
f2507ddcdd forgot the return statement 2024-03-17 02:46:33 +01:00
a70b05a0ef protected course'owner password 2024-03-17 02:45:49 +01:00
1d793cef4e moved UserWithouPaswword to authenticatorService 2024-03-17 02:40:05 +01:00
4cf2ac1aa8 fixed an issue with the getting of curriculums
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m1s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-17 02:34:00 +01:00
6e6bd285af added security to the post of course and GET /courses 2024-03-17 02:15:08 +01:00
474a8d3f31 added POST /curriculum/{id} endopoint to post courses 2024-03-17 02:00:42 +01:00
4379794dba added /students endpoint
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m1s
Build and test backend / Test-backend (pull_request) Successful in 1m56s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-16 23:05:26 +01:00
c5d7ce4178 cleaned the Entities
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m4s
Build and test backend / Test-backend (pull_request) Successful in 2m1s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-16 20:31:03 +01:00
382d3c203a cleaned the services 2024-03-16 20:25:35 +01:00
5a7934b2a3 Merge branch 'master' into wal/front/listingUsers
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m14s
Build and test backend / Test-backend (pull_request) Successful in 2m7s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 27s
2024-03-16 19:57:53 +01:00
8476563678 profil part3 2024-03-16 19:54:42 +01:00
97b57b361d cleaned all controllers 2024-03-16 19:13:57 +01:00
069466ef5f Max/Backend/CoursesEndpoints (#129)
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m16s
Build and test backend / Test-backend (push) Successful in 1m24s
deploy to production / deploy-frontend (push) Successful in 26s
deploy to production / deploy-backend (push) Successful in 2m22s
Build and test FrontEnd / Build-frontend (push) Successful in 26s
PLZ FIX

Reviewed-on: #129
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
Co-authored-by: Bartha Maxime <231026@umons.ac.be>
Co-committed-by: Bartha Maxime <231026@umons.ac.be>
2024-03-16 17:17:07 +01:00
d5f6656e2b added the GET /teachers (#130)
Some checks failed
Build and test backend / Build-backend (push) Has been cancelled
Build and test backend / Test-backend (push) Waiting to run
deploy to production / deploy-frontend (push) Waiting to run
deploy to production / deploy-backend (push) Waiting to run
Build and test FrontEnd / Build-frontend (push) Waiting to run
had to fix the mock and the UserController isAdminOrSecretary

Reviewed-on: #130
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
Co-authored-by: Bartha Maxime <231026@umons.ac.be>
Co-committed-by: Bartha Maxime <231026@umons.ac.be>
2024-03-16 17:16:46 +01:00
32e26f35cb Merge pull request 'show apps by role' (#131) from tonitch/front/apps into master
Some checks failed
Build and test backend / Build-backend (push) Has been cancelled
Build and test backend / Test-backend (push) Waiting to run
deploy to production / deploy-frontend (push) Waiting to run
deploy to production / deploy-backend (push) Waiting to run
Build and test FrontEnd / Build-frontend (push) Waiting to run
Reviewed-on: #131
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: Maxime <231026@umons.ac.be>
2024-03-16 17:16:34 +01:00
36fc33c3e9 Profil part.2/?
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m4s
Build and test backend / Test-backend (pull_request) Successful in 2m4s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-16 17:01:26 +01:00
17ab241250 show map by role
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m7s
Build and test backend / Test-backend (pull_request) Successful in 2m4s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-16 16:57:52 +01:00
36ce5a553b Profil, merge Master and corrections
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m0s
Build and test backend / Test-backend (pull_request) Successful in 1m59s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-16 15:21:10 +01:00
a5807148e1 And again we continue
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m59s
Build and test backend / Test-backend (pull_request) Successful in 1m57s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-16 15:06:21 +01:00
53e478b05c Merge pull request 'added ApplicationController and Application enum' (#119) from Max/Backend/AppsController into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m12s
Build and test backend / Test-backend (push) Successful in 1m19s
deploy to production / deploy-backend (push) Successful in 2m18s
Build and test FrontEnd / Build-frontend (push) Successful in 25s
deploy to production / deploy-frontend (push) Successful in 26s
Reviewed-on: #119
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
Reviewed-by: Wal <karpinskiwal@gmail.com>
2024-03-16 14:51:56 +01:00
182be8ac7b Merge branch 'master' into Max/Backend/AppsController
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m58s
Build and test backend / Test-backend (pull_request) Successful in 1m59s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-16 14:48:03 +01:00
beba199f60 Merge pull request 'Login indication' (#127) from tonitch/front/loginIndication into master
All checks were successful
Build and test backend / Test-backend (push) Successful in 1m17s
deploy to production / deploy-frontend (push) Successful in 24s
Build and test FrontEnd / Build-frontend (push) Successful in 24s
deploy to production / deploy-backend (push) Successful in 2m21s
Build and test backend / Build-backend (push) Successful in 2m12s
Reviewed-on: #127
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: Maxime <231026@umons.ac.be>
2024-03-16 14:45:02 +01:00
767a83d1d6 Merge pull request 'Max/Backend/BackendClean' (#121) from Max/Backend/BackendClean into master
Some checks failed
deploy to production / deploy-frontend (push) Successful in 26s
deploy to production / deploy-backend (push) Has been cancelled
Build and test FrontEnd / Build-frontend (push) Waiting to run
Build and test backend / Build-backend (push) Successful in 2m12s
Build and test backend / Test-backend (push) Successful in 1m20s
Reviewed-on: #121
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
2024-03-16 14:38:19 +01:00
da3f8c47f9 Fix merge because i'm bad
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m3s
Build and test backend / Test-backend (pull_request) Successful in 2m0s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 22s
2024-03-16 14:34:11 +01:00
8d1235be92 again links
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m0s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-16 14:31:44 +01:00
1546fc6d47 Merge branch 'master' into Max/Backend/BackendClean
Some checks failed
Build and test backend / Build-backend (pull_request) Failing after 1m34s
Build and test backend / Test-backend (pull_request) Failing after 1m31s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-16 14:13:47 +01:00
04f64f505e Indicated that you are logged by coloring the icon in orange and disconnect if clicked on it
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 1m57s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-16 13:56:29 +01:00
e84e34d735 login 2024-03-16 12:47:49 +01:00
c955fbf5f8 Merge pull request 'fix tokens characters' (#126) from tonitch/back/fixTokens into master
All checks were successful
Build and test backend / Test-backend (push) Successful in 1m19s
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Successful in 2m20s
Build and test FrontEnd / Build-frontend (push) Successful in 24s
Build and test backend / Build-backend (push) Successful in 2m11s
Reviewed-on: #126
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: Maxime <231026@umons.ac.be>
2024-03-16 12:42:54 +01:00
847936b799 fix tokens characters
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m6s
Build and test backend / Test-backend (pull_request) Successful in 2m0s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-16 12:36:17 +01:00
0b27d2e8d8 Merge branch 'master' into tonitch/front/pagesAPI
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 1m59s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-16 12:35:15 +01:00
45fbef52ed fix tokens characters
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m59s
Build and test backend / Test-backend (pull_request) Successful in 2m1s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-16 12:29:51 +01:00
Wal
ca6f676fb7 Merge pull request 'tonitch/front/manageCourses/LinkToBackend' (#125) from tonitch/front/manageCourses/LinkToBackend into wal/front/listingUsers
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m59s
Build and test backend / Test-backend (pull_request) Successful in 1m57s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 26s
Reviewed-on: #125
2024-03-16 12:26:57 +01:00
cc8530621d Merge branch 'master' into tonitch/front/manageCourses/LinkToBackend
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m0s
Build and test backend / Test-backend (pull_request) Successful in 1m56s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-16 12:01:44 +01:00
abff9aef3a Merge branch 'master' into Max/Backend/AppsController
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m59s
Build and test backend / Test-backend (pull_request) Successful in 1m56s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-16 11:58:03 +01:00
41288258c9 Merge branch 'master' into wal/front/listingUsers
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m1s
Build and test backend / Test-backend (pull_request) Successful in 2m2s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-16 11:56:37 +01:00
47a0c97f3d small commit but its for the big merge+ verif psswrd and confirm in login
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m1s
Build and test backend / Test-backend (pull_request) Successful in 2m1s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-16 11:52:31 +01:00
3ea6c7886a Merge pull request 'rename Cursus -> Curriculum' (#120) from Max/Backend/CurriculumRename into master
All checks were successful
deploy to production / deploy-frontend (push) Successful in 25s
Build and test backend / Build-backend (push) Successful in 2m9s
Build and test backend / Test-backend (push) Successful in 1m20s
deploy to production / deploy-backend (push) Successful in 2m22s
Build and test FrontEnd / Build-frontend (push) Successful in 25s
Reviewed-on: #120
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
Reviewed-by: Wal <karpinskiwal@gmail.com>
2024-03-16 11:50:49 +01:00
17d0ae7ccc Refactoring: cursus -> curriculum frontend
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m3s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
I hope I didn't missed anything, this commit is following the previous
one in this branch
2024-03-16 10:17:04 +01:00
8f2fb04112 I pressed tab by accident
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 2m0s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-16 09:03:03 +01:00
c6198b7220 cleaned Services + added private final to all repos
Some checks failed
Build and test backend / Build-backend (pull_request) Failing after 1m35s
Build and test backend / Test-backend (pull_request) Failing after 1m30s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 26s
2024-03-16 09:02:08 +01:00
13fd048cd2 added a inscriptionService mock user 2024-03-16 09:01:36 +01:00
b7b2eafb93 removed the GET /Apps/{id} frontend just iterates on the /apps list
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m3s
Build and test backend / Test-backend (pull_request) Successful in 2m2s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-16 00:44:11 +01:00
0860567e1b fixed the GetAuthorizedApps method
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m4s
Build and test backend / Test-backend (pull_request) Successful in 1m59s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-16 00:42:46 +01:00
25009ba149 Enum in CamelCase
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m58s
Build and test backend / Test-backend (pull_request) Successful in 1m56s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-16 00:34:20 +01:00
208c6c63e8 moved the isSecretaryOrAdmin method 2024-03-16 00:31:03 +01:00
e2da7271af rename Cursus -> Curriculum
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m3s
Build and test backend / Test-backend (pull_request) Successful in 2m0s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-15 23:53:15 +01:00
d5e4387303 Merge branch 'master' into wal/front/listingUsers
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m59s
Build and test backend / Test-backend (pull_request) Successful in 2m0s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-15 22:49:26 +01:00
1903a6c9be "trying functions"
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m4s
Build and test backend / Test-backend (pull_request) Successful in 2m1s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-15 22:47:40 +01:00
77a170be6d Merge branch 'master' into tonitch/front/pagesAPI
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m1s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-15 22:37:37 +01:00
9f02207eb0 Merge pull request 'Max/Backend/Curriculum' (#106) from Max/Backend/Curriculum into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m12s
deploy to production / deploy-frontend (push) Successful in 26s
Build and test FrontEnd / Build-frontend (push) Successful in 24s
Build and test backend / Test-backend (push) Successful in 1m21s
deploy to production / deploy-backend (push) Successful in 2m21s
Reviewed-on: #106
Reviewed-by: LeoMoulin <leomoulin125@gmail.com>
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
2024-03-15 22:33:25 +01:00
ae4ad036a8 Merge remote-tracking branch 'origin/master' into tonitch/front/manageCourses/LinkToBackend 2024-03-15 22:32:21 +01:00
3996765c8a Simple hook for when the backend is ready
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 1m59s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-15 22:25:26 +01:00
b047c4de35 Listing users and students
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-15 20:23:33 +01:00
1f14890d43 added ApplicationController and Application enum
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m3s
Build and test backend / Test-backend (pull_request) Successful in 2m0s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-15 18:54:53 +01:00
2ea6ed16bb removed missclick
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m6s
Build and test backend / Test-backend (pull_request) Successful in 2m2s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-15 18:53:58 +01:00
189e664f37 Add tests for Storage system
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m53s
Build and test backend / Test-backend (pull_request) Successful in 2m17s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-15 18:49:41 +01:00
f33a421aee Merge branch 'master' into Max/Backend/Curriculum
Some checks failed
Build and test backend / Build-backend (pull_request) Successful in 2m3s
Build and test backend / Test-backend (pull_request) Successful in 2m0s
Build and test FrontEnd / Build-frontend (pull_request) Failing after 21s
2024-03-15 17:40:42 +01:00
017235cccf fixed inscription in the backend
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m8s
Build and test backend / Test-backend (pull_request) Successful in 2m0s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-15 17:29:45 +01:00
1bff48a4b9 changed the frontend API calls
to better suit the backend and logic (register => list and register => single item)
2024-03-15 17:09:18 +01:00
385640c10e Merge branch 'master' into wal/front/listingUsers
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m59s
Build and test backend / Test-backend (pull_request) Successful in 1m59s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-15 15:14:18 +01:00
a0c38a8d59 adding list of user PROTO 2024-03-15 15:12:01 +01:00
198ee8a4ce Register API and form optimization [depend: backend /register] (#93)
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m7s
Build and test backend / Test-backend (push) Successful in 1m18s
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Successful in 2m20s
Build and test FrontEnd / Build-frontend (push) Successful in 25s
Made the register api following the backend

refactored the register form for more ergonomy

**PS: Waiting for the backend to catch up**

Reviewed-on: #93
Reviewed-by: Maxime <231026@umons.ac.be>
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: LeoMoulin <leomoulin125@gmail.com>
Co-authored-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
Co-committed-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
2024-03-15 14:46:39 +01:00
08c662a65f Fetch inscription on backend
Some checks failed
Build and test FrontEnd / Build-frontend (push) Waiting to run
Build and test backend / Build-backend (push) Successful in 2m14s
Build and test backend / Test-backend (push) Successful in 1m17s
deploy to production / deploy-frontend (push) Successful in 26s
deploy to production / deploy-backend (push) Has been cancelled
This commit is waiting for the backend implementation to be merged.

The list of field expected is writen in comment
2024-03-15 14:41:21 +01:00
c8b7930a8e Setup unit tests and implements test for the token limit and trivial tests for userRepository 2024-03-15 11:20:23 +01:00
20d52b2b21 Merge pull request 'Max/Backend/RegisterEndPoint' (#105) from Max/Backend/RegisterEndPoint into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m11s
deploy to production / deploy-frontend (push) Successful in 24s
Build and test backend / Test-backend (push) Successful in 1m20s
deploy to production / deploy-backend (push) Successful in 2m21s
Build and test FrontEnd / Build-frontend (push) Successful in 23s
Reviewed-on: #105
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
Reviewed-by: LeoMoulin <leomoulin125@gmail.com>
Reviewed-by: Wal <karpinskiwal@gmail.com>
2024-03-14 23:30:13 +01:00
1502cc871c Merge pull request 'UploadAPI and profilePicture' (#102) from tonitch/front/apiUpload into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m13s
deploy to production / deploy-backend (push) Successful in 2m21s
Build and test FrontEnd / Build-frontend (push) Successful in 24s
Build and test backend / Test-backend (push) Successful in 1m24s
deploy to production / deploy-frontend (push) Successful in 26s
Reviewed-on: #102
Reviewed-by: LeoMoulin <leomoulin125@gmail.com>
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: Maxime <231026@umons.ac.be>
2024-03-14 22:37:30 +01:00
826bbf5990 Create the directory if not exists
Some checks are pending
Build and test backend / Build-backend (push) Waiting to run
Build and test backend / Test-backend (push) Waiting to run
deploy to production / deploy-frontend (push) Waiting to run
deploy to production / deploy-backend (push) Waiting to run
Build and test FrontEnd / Build-frontend (push) Waiting to run
2024-03-14 22:36:48 +01:00
c26972369f Putting the right configuration for cors
Some checks are pending
Build and test backend / Build-backend (push) Waiting to run
Build and test backend / Test-backend (push) Waiting to run
deploy to production / deploy-frontend (push) Waiting to run
deploy to production / deploy-backend (push) Waiting to run
Build and test FrontEnd / Build-frontend (push) Waiting to run
2024-03-14 22:35:57 +01:00
Wal
4c5cae7ff5 Merge pull request 'Translations' (#104) from wal/front/Translations into master
Some checks are pending
Build and test backend / Build-backend (push) Waiting to run
Build and test backend / Test-backend (push) Waiting to run
deploy to production / deploy-frontend (push) Waiting to run
deploy to production / deploy-backend (push) Waiting to run
Build and test FrontEnd / Build-frontend (push) Waiting to run
Reviewed-on: #104
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
Reviewed-by: LeoMoulin <leomoulin125@gmail.com>
Reviewed-by: Maxime <231026@umons.ac.be>
2024-03-14 22:34:45 +01:00
59c3442647 lil corrections
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m6s
Build and test backend / Test-backend (pull_request) Successful in 2m5s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-14 22:33:16 +01:00
12846ed83d added cursus/course interactions
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m0s
Build and test backend / Test-backend (pull_request) Successful in 2m2s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-14 21:53:43 +01:00
bb4ee784fa Merge pull request 'Max/Backend/UserControllerUpdate' (#94) from Max/Backend/UserControllerUpdate into master
All checks were successful
deploy to production / deploy-frontend (push) Successful in 25s
Build and test backend / Build-backend (push) Successful in 2m16s
Build and test backend / Test-backend (push) Successful in 1m22s
deploy to production / deploy-backend (push) Successful in 2m24s
Build and test FrontEnd / Build-frontend (push) Successful in 26s
Reviewed-on: #94
Reviewed-by: LeoMoulin <leomoulin125@gmail.com>
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
2024-03-14 21:53:33 +01:00
1777e894e9 removing spaces
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m0s
Build and test backend / Test-backend (pull_request) Successful in 2m2s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-14 21:33:36 +01:00
3c3659c056 Merge branch 'master' into wal/front/Translations 2024-03-14 21:31:22 +01:00
e05492f4a8 Adding all translations 2024-03-14 21:27:03 +01:00
97a2c8a9f6 Fix the "error" bug
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m34s
deploy to production / deploy-frontend (push) Successful in 27s
deploy to production / deploy-backend (push) Successful in 2m21s
Build and test FrontEnd / Build-frontend (push) Successful in 24s
Build and test backend / Test-backend (push) Successful in 1m21s
Even when the requests was sucessfull, the "error" toast was
appearing... now it should do a "success" when adequate
2024-03-14 21:06:33 +01:00
9aa425d1c3 changed details 2024-03-14 20:04:27 +01:00
f0a411c031 added InscriptionController
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 1m59s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-14 16:36:09 +01:00
6228e21d38 easter is coming (dont look it's not fun)
All checks were successful
deploy to production / deploy-frontend (push) Successful in 26s
Build and test backend / Build-backend (push) Successful in 2m13s
Build and test backend / Test-backend (push) Successful in 1m23s
deploy to production / deploy-backend (push) Successful in 2m20s
Build and test FrontEnd / Build-frontend (push) Successful in 25s
2024-03-13 23:28:25 +01:00
64e7f8dc6b modifying the frontend to send the image and getting the data
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 2m2s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-13 22:33:39 +01:00
a0285e700d Modifying backend so it send the full entry of a file upload 2024-03-13 22:28:59 +01:00
68e55e8355 Putting the right configuration for cors 2024-03-13 20:42:06 +01:00
157e5951fc ups je change un copié collé 2024-03-13 19:14:22 +01:00
4241f15731 j'ai envie de me pendre 2024-03-13 19:12:46 +01:00
cead1188ab Merge pull request 'Leo/Backend' (#95) from Leo/Backend into master
All checks were successful
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Successful in 2m19s
Build and test backend / Build-backend (push) Successful in 2m15s
Build and test backend / Test-backend (push) Successful in 1m22s
Build and test FrontEnd / Build-frontend (push) Successful in 23s
Reviewed-on: #95
Reviewed-by: Maxime <231026@umons.ac.be>
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
2024-03-13 18:06:33 +01:00
5c7147bb17 fixing the double throw before the merge
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m3s
Build and test backend / Test-backend (pull_request) Successful in 1m57s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
Signed-off-by: Debucquoy Anthony <d.tonitch@gmail.com>
2024-03-13 18:05:35 +01:00
7d8e1113cc Remove course
All checks were successful
deploy to production / deploy-frontend (push) Successful in 28s
Build and test backend / Build-backend (push) Successful in 2m13s
Build and test backend / Test-backend (push) Successful in 1m22s
Build and test FrontEnd / Build-frontend (push) Successful in 26s
deploy to production / deploy-backend (push) Successful in 2m21s
2024-03-13 17:54:57 +01:00
354793a29f Create Course 2024-03-13 17:54:57 +01:00
d5b1df32b6 course management 2024-03-13 17:54:57 +01:00
2a58c335f2 Apply les trucs de l'exception
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m1s
Build and test backend / Test-backend (pull_request) Successful in 1m55s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-13 15:48:28 +01:00
4f511bf066 Merge pull request 'HUUUUGE CHANGE' (#97) from Max/Backend/ServiceInscription into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m15s
Build and test backend / Test-backend (push) Successful in 1m19s
deploy to production / deploy-frontend (push) Successful in 26s
deploy to production / deploy-backend (push) Successful in 2m24s
Build and test FrontEnd / Build-frontend (push) Successful in 26s
Reviewed-on: #97
2024-03-13 15:44:16 +01:00
62f64eed60 HUUUUGE CHANGE
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m0s
Build and test backend / Test-backend (pull_request) Successful in 2m2s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-13 15:36:13 +01:00
4b1db883e2 updated tonitch's reviews
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m0s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-13 15:28:17 +01:00
58a4c87661 Removing test gradle
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m13s
Build and test backend / Test-backend (push) Successful in 1m20s
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Successful in 2m18s
Build and test FrontEnd / Build-frontend (push) Successful in 24s
2024-03-13 14:39:34 +01:00
f52cb31189 Adding info about self (#88)
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m13s
deploy to production / deploy-backend (push) Successful in 2m24s
Build and test FrontEnd / Build-frontend (push) Successful in 25s
Build and test backend / Test-backend (push) Successful in 1m21s
deploy to production / deploy-frontend (push) Successful in 27s
Reviewed-on: #88
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: Maxime <231026@umons.ac.be>
Reviewed-by: LeoMoulin <leomoulin125@gmail.com>
Co-authored-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
Co-committed-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
2024-03-13 09:54:56 +01:00
044648674c Merge branch 'master' into Max/Backend/UserControllerUpdate
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m0s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-12 23:16:35 +01:00
4b0ea8cf40 added the post /user Endpoint
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m23s
Build and test backend / Test-backend (pull_request) Successful in 1m59s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-12 23:08:18 +01:00
dae59f67ce encoding the password before saving it
oups I Forgor
2024-03-12 22:35:25 +01:00
66282bce9f Create new constructor for ReinscriptionRequest so you don't have to worry about the type of the request
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m15s
Build and test backend / Test-backend (pull_request) Successful in 1m59s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-12 17:53:52 +01:00
b7a574a312 Merge branch 'master' into Leo/Backend
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m57s
Build and test backend / Test-backend (pull_request) Successful in 1m55s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-12 11:17:14 +01:00
8fbfb36958 Remove the bad link between users and file. Add a delete function for storageFile entities and clean things.
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m0s
Build and test backend / Test-backend (pull_request) Successful in 1m57s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-12 10:48:13 +01:00
86f1a6f17b Little corrections
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m16s
Build and test backend / Test-backend (push) Successful in 1m18s
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Successful in 2m20s
Build and test FrontEnd / Build-frontend (push) Successful in 24s
2024-03-12 09:55:26 +01:00
68df9f99fa modify profil strating setup 2024-03-12 09:55:26 +01:00
2fe6153705 Translation correction 2024-03-12 09:55:26 +01:00
042553c123 Profil Teacher and examples 2024-03-12 09:55:26 +01:00
3cf5153e79 Profil Student Prototype 2024-03-12 09:55:26 +01:00
07e5fb3a73 profil menu base 2024-03-12 09:55:26 +01:00
c14d0a9d21 option language settings start 2024-03-12 09:55:26 +01:00
5c728098df protected post /user and get/users and return without password
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m58s
Build and test backend / Test-backend (pull_request) Successful in 1m55s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-12 00:03:32 +01:00
28d252279a added a small description 2024-03-11 22:33:53 +01:00
ab91a39a63 Create exception for file deletion.
Add user/inscriptionrequest connection to StorageFile entity.
Create a prototype of the delete for file function
2024-03-11 20:23:45 +01:00
d4c48ee9f1 Leo/Backend (#82)
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m11s
Build and test backend / Test-backend (push) Successful in 1m21s
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Successful in 2m17s
Build and test FrontEnd / Build-frontend (push) Successful in 24s
Ce merge enverra dans main : le timeout des token, la limite de 5 token par user, les nouvelles tables pour les demandes d'inscriptions

Co-authored-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
Reviewed-on: #82
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
Reviewed-by: Maxime <231026@umons.ac.be>
Reviewed-by: Wal <karpinskiwal@gmail.com>
Co-authored-by: LeoMoulin <leomoulin125@gmail.com>
Co-committed-by: LeoMoulin <leomoulin125@gmail.com>
2024-03-11 19:16:19 +01:00
5325d6e3ae Storage System (#92)
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m17s
Build and test backend / Test-backend (push) Successful in 1m19s
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Successful in 2m20s
Build and test FrontEnd / Build-frontend (push) Successful in 25s
First idea of the storage system

Reviewed-on: #92
Co-authored-by: Bartha Maxime <231026@umons.ac.be>
Co-committed-by: Bartha Maxime <231026@umons.ac.be>
2024-03-11 17:52:08 +01:00
ce2efb61c8 fixed some issue for the token authorization (#87)
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m11s
Build and test backend / Test-backend (push) Successful in 1m20s
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Successful in 2m21s
Build and test FrontEnd / Build-frontend (push) Successful in 23s
Reviewed-on: #87
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
Co-authored-by: Bartha Maxime <231026@umons.ac.be>
Co-committed-by: Bartha Maxime <231026@umons.ac.be>
2024-03-10 23:28:13 +01:00
b7c97ead2b Merge pull request 'Reactive Translations' (#86) from tonitch/front/Reactive_Translations into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m8s
Build and test backend / Test-backend (push) Successful in 1m21s
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Successful in 2m19s
Build and test FrontEnd / Build-frontend (push) Successful in 25s
Reviewed-on: #86
Reviewed-by: Maxime <231026@umons.ac.be>
Reviewed-by: Wal <karpinskiwal@gmail.com>
2024-03-10 20:35:32 +01:00
84fe1df671 Reactive Translations
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m59s
Build and test backend / Test-backend (pull_request) Successful in 2m1s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
Make Translated text reactive so that when switching lang, text is
reload on the fly

Fixes: #77
2024-03-09 19:14:57 +01:00
8fdfb470cb fixing the origin requests once and for all
All checks were successful
Build and test backend / Test-backend (push) Successful in 1m20s
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Successful in 2m21s
Build and test backend / Build-backend (push) Successful in 2m13s
Build and test FrontEnd / Build-frontend (push) Successful in 26s
2024-03-09 18:54:46 +01:00
160cfb0bbf Page api stub
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m1s
Build and test backend / Test-backend (pull_request) Successful in 1m55s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-09 18:41:20 +01:00
31159ebb5c Merge pull request 'Fixing the cross origine on the frontend side + request in json' (#79) from tonitch/front/fix/crossOrigine into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m15s
Build and test backend / Test-backend (push) Successful in 1m22s
deploy to production / deploy-frontend (push) Successful in 26s
deploy to production / deploy-backend (push) Successful in 2m23s
Build and test FrontEnd / Build-frontend (push) Successful in 23s
Reviewed-on: #79
Reviewed-by: Maxime <231026@umons.ac.be>
2024-03-09 18:18:15 +01:00
ac88307036 fix expiration date and frontend requests
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m1s
Build and test backend / Test-backend (pull_request) Successful in 2m1s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-09 16:22:38 +01:00
847b1ca419 Solve crossOrigin Finally
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 2m0s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-09 16:20:55 +01:00
5bda05925c Merge pull request 'Removing more useless stuff' (#81) from tonitch/front/fix/removeComponents into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m13s
Build and test backend / Test-backend (push) Successful in 1m20s
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Successful in 2m19s
Build and test FrontEnd / Build-frontend (push) Successful in 26s
Reviewed-on: #81
2024-03-09 14:58:01 +01:00
be084cfd12 Removing more useless stuff
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m58s
Build and test backend / Test-backend (pull_request) Successful in 1m59s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-09 12:32:07 +01:00
0b4b38f6c5 Fix typo
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m1s
Build and test backend / Test-backend (pull_request) Successful in 1m56s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
Merci javascript pour ces erreurs de qualitée...
2024-03-09 10:36:20 +01:00
21de520175 Fixing the cross origine on the frontend side
Some checks failed
Build and test backend / Build-backend (pull_request) Successful in 1m59s
Build and test backend / Test-backend (pull_request) Successful in 1m59s
Build and test FrontEnd / Build-frontend (pull_request) Failing after 21s
2024-03-09 10:29:32 +01:00
b88d820c12 Merge pull request 'fixed a token encoding issue' (#70) from Max/backend/loginFix into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m13s
Build and test backend / Test-backend (push) Successful in 1m21s
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Successful in 2m17s
Build and test FrontEnd / Build-frontend (push) Successful in 26s
Reviewed-on: #70
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
Reviewed-by: LeoMoulin <leomoulin125@gmail.com>
2024-03-09 09:57:52 +01:00
521c98fdc2 token is now an writable char thanks to the modulos !
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m3s
Build and test backend / Test-backend (pull_request) Successful in 1m57s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 22s
2024-03-09 00:46:40 +01:00
ba8b32160d Lots of refactoring
Some checks failed
Build and test backend / Build-backend (pull_request) Successful in 2m3s
Build and test backend / Test-backend (pull_request) Successful in 2m1s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 26s
Build and test FrontEnd / Build-frontend (push) Waiting to run
Build and test backend / Build-backend (push) Successful in 2m13s
Build and test backend / Test-backend (push) Successful in 1m18s
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Has been cancelled
- Removing test mentions in readme
- moving login page as an app
- removing vite broken config
- removing auto-generated and unused vite configuration (base.css)

Overall simplification

(sorry @Wal I kinda destroyed your login page a bit but seems fixable 👉👈)
2024-03-08 23:35:11 +01:00
3571b96cfc Merge pull request 'Fix lang toggle' (#72) from tonitch/front/fix/langSwitch into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m14s
Build and test backend / Test-backend (push) Successful in 1m24s
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Successful in 2m24s
Build and test FrontEnd / Build-frontend (push) Successful in 27s
Reviewed-on: #72
Reviewed-by: Wal <karpinskiwal@gmail.com>
2024-03-08 22:22:19 +01:00
619d2601f1 Fix lang toggle
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m3s
Build and test backend / Test-backend (pull_request) Successful in 2m4s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
This is not perfect as the toggle is not set to the right position when
the site is reload but as @Wal_ said he would refactor, I just made a
working sample good enough imo
2024-03-08 22:00:15 +01:00
03ff0c0568 Merge pull request 'Ajout register + quelques options' (#63) from wal/frontend/Register into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m15s
Build and test backend / Test-backend (push) Successful in 1m22s
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Successful in 2m21s
Build and test FrontEnd / Build-frontend (push) Successful in 27s
Reviewed-on: #63
Reviewed-by: Maxime <231026@umons.ac.be>
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
2024-03-08 21:24:10 +01:00
82a3b152f2 put the params in the body and fixed token issue
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m0s
Build and test backend / Test-backend (pull_request) Successful in 2m0s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 20s
2024-03-08 20:54:23 +01:00
d2a697904e Merge branch 'master' into wal/frontend/Register
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m2s
Build and test backend / Test-backend (pull_request) Successful in 1m59s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
2024-03-08 20:53:10 +01:00
fe34ff4705 Merge pull request 'wtf is it doing there ?' (#71) from tonitch/front/fix/stupidLine into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m10s
Build and test backend / Test-backend (push) Successful in 1m20s
deploy to production / deploy-frontend (push) Successful in 23s
deploy to production / deploy-backend (push) Successful in 2m21s
Build and test FrontEnd / Build-frontend (push) Successful in 21s
Reviewed-on: #71
Reviewed-by: Maxime <231026@umons.ac.be>
Reviewed-by: Wal <karpinskiwal@gmail.com>
2024-03-08 20:46:59 +01:00
de7774047f Merge pull request '[Journal de bord] tokens et authentifications' (#65) from maxonitch/jdb/Authentication into master
Some checks failed
Build and test backend / Test-backend (push) Waiting to run
deploy to production / deploy-frontend (push) Waiting to run
deploy to production / deploy-backend (push) Waiting to run
Build and test FrontEnd / Build-frontend (push) Waiting to run
Build and test backend / Build-backend (push) Has been cancelled
Reviewed-on: #65
Reviewed-by: Maxime <231026@umons.ac.be>
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: LeoMoulin <leomoulin125@gmail.com>
2024-03-08 20:46:27 +01:00
a524845d06 First draft of the register requests api.
Some checks failed
Build and test backend / Test-backend (push) Waiting to run
deploy to production / deploy-frontend (push) Waiting to run
deploy to production / deploy-backend (push) Waiting to run
Build and test FrontEnd / Build-frontend (push) Waiting to run
Build and test backend / Build-backend (push) Has been cancelled
I don't think it's currently usable but it serve as a stub for when
backend will support it
2024-03-08 20:45:22 +01:00
8e40638b5e adding the right dependencies
Some checks failed
Build and test backend / Test-backend (push) Waiting to run
deploy to production / deploy-frontend (push) Waiting to run
deploy to production / deploy-backend (push) Waiting to run
Build and test FrontEnd / Build-frontend (push) Waiting to run
Build and test backend / Build-backend (push) Has been cancelled
2024-03-08 20:43:47 +01:00
13d9020c7d stub for cursus 2024-03-08 20:43:47 +01:00
8a544515d0 Merge branch 'master' into wal/frontend/Register
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m1s
Build and test backend / Test-backend (pull_request) Successful in 1m56s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-08 20:23:13 +01:00
481c96bec2 i18n added but not usable
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m0s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-08 20:22:00 +01:00
1383814e34 change ASCII to ISO_8859_1
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m1s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 20s
2024-03-08 19:57:38 +01:00
7ff47b6e9c wtf is it doing there ?
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m0s
Build and test backend / Test-backend (pull_request) Successful in 2m4s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 20s
2024-03-08 19:23:59 +01:00
fba30cff9e fixed a token encoding issue
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m33s
Build and test backend / Test-backend (pull_request) Successful in 1m59s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-08 18:52:10 +01:00
875cfb8b7c Merge pull request 'Max/Backend/loginApi Ajout mock Users et Tokens' (#62) from Max/Backend/loginApi into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m16s
Build and test backend / Test-backend (push) Successful in 1m24s
deploy to production / deploy-frontend (push) Successful in 22s
deploy to production / deploy-backend (push) Successful in 2m20s
Build and test FrontEnd / Build-frontend (push) Successful in 21s
Reviewed-on: #62
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: LeoMoulin <leomoulin125@gmail.com>
2024-03-08 16:50:22 +01:00
0ca5640564 Merge branch 'master' into wal/frontend/Register
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m0s
Build and test backend / Test-backend (pull_request) Successful in 1m56s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 26s
2024-03-08 16:37:00 +01:00
acfd366fc8 fixed the user constructor issue
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m3s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 20s
2024-03-08 12:00:56 +01:00
4111839852 Requests setup
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m59s
Build and test backend / Test-backend (pull_request) Successful in 1m54s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-08 11:54:10 +01:00
e69ece23d0 adding set cookie and set lang (#68)
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m9s
Build and test backend / Test-backend (push) Successful in 1m19s
deploy to production / deploy-frontend (push) Successful in 21s
deploy to production / deploy-backend (push) Successful in 2m20s
Build and test FrontEnd / Build-frontend (push) Successful in 21s
simple set cookie (je deteste javascript) et un setlang pour le syntastic sugar

Reviewed-on: #68
Reviewed-by: Maxime <231026@umons.ac.be>
Reviewed-by: Wal <karpinskiwal@gmail.com>
Co-authored-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
Co-committed-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
2024-03-08 11:23:32 +01:00
b42324987b stub for courses (#60)
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m5s
Build and test backend / Test-backend (push) Successful in 1m20s
deploy to production / deploy-frontend (push) Successful in 22s
deploy to production / deploy-backend (push) Successful in 2m17s
Build and test FrontEnd / Build-frontend (push) Successful in 20s
base for the courses api

Reviewed-on: #60
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: Maxime <231026@umons.ac.be>
Co-authored-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
Co-committed-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
2024-03-07 22:29:07 +01:00
3b31fa794f Merge branch 'Leo/Backend' into Max/Backend/loginApi
Some checks failed
Build and test backend / Build-backend (pull_request) Failing after 1m36s
Build and test backend / Test-backend (pull_request) Failing after 1m35s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 20s
2024-03-07 20:53:33 +01:00
c33b73a114 - Ajout de "l'url" de l'image dans User 2024-03-07 19:12:48 +01:00
2f2a72bfa0 added the possibility to remove the mocks
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m6s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 21s
2024-03-07 17:29:31 +01:00
6b58c852a2 cleaning
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m57s
Build and test backend / Test-backend (pull_request) Successful in 1m56s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 21s
2024-03-07 17:02:19 +01:00
8b35b3dc01 cleaned the login process 2024-03-07 17:01:50 +01:00
93144d0f90 added what is the token and justifications
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m56s
Build and test backend / Test-backend (pull_request) Successful in 1m57s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 20s
2024-03-07 15:43:16 +01:00
3c08022c20 toggle for language(base) + starting inscription menu
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m55s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 23s
2024-03-07 15:42:36 +01:00
204e6a9505 Base oauth et spring sessions
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m0s
Build and test backend / Test-backend (pull_request) Successful in 1m55s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 20s
2024-03-07 15:24:22 +01:00
Wal
d639fa5ee3 Merge pull request 'fixing top level await' (#64) from tonitch/front/fix/top-level-await into wal/frontend/Register
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m59s
Build and test backend / Test-backend (pull_request) Successful in 1m57s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
Reviewed-on: #64
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: Maxime <231026@umons.ac.be>
2024-03-07 15:21:12 +01:00
e1d8e37c52 Merge branch 'master' into Max/Backend/loginApi
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m1s
Build and test backend / Test-backend (pull_request) Successful in 2m1s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 20s
2024-03-07 15:15:32 +01:00
8e932b1b67 fixing top level await 2024-03-07 14:51:36 +01:00
dbbf74f2c3 Merge pull request 'tonitch/front/User_API' (#56) from tonitch/front/User_API into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m11s
Build and test backend / Test-backend (push) Successful in 1m22s
deploy to production / deploy-frontend (push) Successful in 22s
deploy to production / deploy-backend (push) Successful in 2m18s
Build and test FrontEnd / Build-frontend (push) Successful in 21s
Reviewed-on: #56
Reviewed-by: Maxime <231026@umons.ac.be>
Reviewed-by: Wal <karpinskiwal@gmail.com>
2024-03-07 14:12:49 +01:00
4aa15ec72a Merge branch 'master' into wal/frontend/Register
Some checks failed
Build and test backend / Build-backend (pull_request) Successful in 1m59s
Build and test backend / Test-backend (pull_request) Successful in 1m57s
Build and test FrontEnd / Build-frontend (pull_request) Failing after 21s
2024-03-07 14:11:32 +01:00
2938707f0f added mocks users with their role as password and token
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m58s
Build and test backend / Test-backend (pull_request) Successful in 1m58s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 21s
2024-03-07 00:55:07 +01:00
0e7c18e088 Base for rest api utilisation (#53)
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m11s
Build and test backend / Test-backend (push) Successful in 1m23s
deploy to production / deploy-frontend (push) Successful in 23s
deploy to production / deploy-backend (push) Successful in 2m18s
Build and test FrontEnd / Build-frontend (push) Successful in 21s
The restConsumer will be the base, then I will create a js file per
"object" (for instance there will be users.js with all endpoints for
users using the restConsumer.js)

Reviewed-on: #53
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: Maxime <231026@umons.ac.be>
Co-authored-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
Co-committed-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
2024-03-06 21:38:09 +01:00
886077349c Adding menu button + Cursus
Some checks failed
Build and test backend / Build-backend (pull_request) Successful in 1m56s
Build and test backend / Test-backend (pull_request) Successful in 2m0s
Build and test FrontEnd / Build-frontend (pull_request) Failing after 20s
2024-03-06 21:00:35 +01:00
434cc8dd2b - On objectise tout
- Ajout des relation
2024-03-06 20:05:24 +01:00
d9ec085d2c Inputs setup 2024-03-06 17:41:18 +01:00
4a85a55290 added Token and User Services 2024-03-06 17:38:09 +01:00
37d24c59e7 add generic HttpResponse 2024-03-06 17:37:38 +01:00
5acca4d10d added foreign key to user 2024-03-06 17:37:06 +01:00
b050a74b75 added LoginController Post(/login) 2024-03-06 17:35:49 +01:00
010f9200a7 removed useless line 2024-03-06 17:35:27 +01:00
6a39464f61 /bin/bash: line 1: q: command not found 2024-03-06 17:34:18 +01:00
7222bca6e2 added spring boot security without the login page 2024-03-06 17:30:13 +01:00
6df81a66f2 Fixing i18n path
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m58s
Build and test backend / Test-backend (pull_request) Successful in 1m56s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 19s
Build and test backend / Build-backend (push) Successful in 2m5s
Build and test backend / Test-backend (push) Successful in 1m17s
deploy to production / deploy-frontend (push) Successful in 21s
deploy to production / deploy-backend (push) Successful in 2m17s
Build and test FrontEnd / Build-frontend (push) Successful in 20s
2024-03-06 14:41:03 +01:00
34a36f8b1e i18n try 2024-03-06 14:35:58 +01:00
2a558e40cb Merge branch 'master' into wal/frontend/Register 2024-03-06 14:23:24 +01:00
3350533e74 Register proto 2024-03-06 14:20:32 +01:00
aaaba0ddf3 User api first draft finished
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m55s
Build and test backend / Test-backend (pull_request) Successful in 1m52s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 19s
2024-03-06 14:08:39 +01:00
a253a5152d My life is a potato
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m9s
Build and test backend / Test-backend (push) Successful in 1m20s
deploy to production / deploy-frontend (push) Successful in 22s
deploy to production / deploy-backend (push) Successful in 2m17s
Build and test FrontEnd / Build-frontend (push) Successful in 20s
2024-03-06 11:20:29 +01:00
38ed249150 using unix socket
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m9s
Build and test backend / Test-backend (push) Successful in 1m18s
Build and test FrontEnd / Build-frontend (push) Successful in 21s
deploy to production / deploy-frontend (push) Successful in 20s
deploy to production / deploy-backend (push) Successful in 1m33s
2024-03-06 10:52:11 +01:00
212ab638a2 allow unix socket connection for database in prod
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m3s
Build and test backend / Test-backend (push) Successful in 1m16s
deploy to production / deploy-frontend (push) Successful in 22s
deploy to production / deploy-backend (push) Successful in 2m17s
Build and test FrontEnd / Build-frontend (push) Successful in 21s
2024-03-06 10:01:55 +01:00
e158fa1f87 backbone for login
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m58s
Build and test backend / Test-backend (pull_request) Successful in 1m52s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 32s
2024-03-06 09:00:55 +01:00
6289be529a package-lock was forgoten 2024-03-06 08:59:08 +01:00
1f69040436 adding patch to restConsumer 2024-03-06 08:59:08 +01:00
56a14a3e8a adding toast on requests 2024-03-06 08:59:06 +01:00
b72c0a8e17 Merge pull request 'LeoMoulin/Backend/Leo' (#55) from LeoMoulin/Backend/Leo into master
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m2s
Build and test backend / Test-backend (push) Successful in 1m19s
deploy to production / deploy-frontend (push) Successful in 21s
deploy to production / deploy-backend (push) Successful in 2m13s
Build and test FrontEnd / Build-frontend (push) Successful in 19s
Reviewed-on: #55
2024-03-05 23:41:59 +01:00
bb0e6783ec correction commit
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m3s
Build and test backend / Test-backend (pull_request) Successful in 1m53s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 19s
2024-03-05 23:34:49 +01:00
57de070eb1 Merge branch 'master' into LeoMoulin/Backend/Leo
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m55s
Build and test backend / Test-backend (pull_request) Successful in 1m52s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 24s
2024-03-05 20:30:00 +01:00
24a54bdee4 removing useless function & calling reloadLang properly (#52)
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m8s
Build and test backend / Test-backend (push) Successful in 1m25s
deploy to production / deploy-frontend (push) Successful in 32s
deploy to production / deploy-backend (push) Successful in 2m17s
Build and test FrontEnd / Build-frontend (push) Successful in 25s
Reviewed-on: #52
Reviewed-by: Maxime <231026@umons.ac.be>
Reviewed-by: Wal <karpinskiwal@gmail.com>
Co-authored-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
Co-committed-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
2024-03-05 20:28:23 +01:00
d1b4023d92 adding register 2024-03-05 14:58:56 +01:00
c27c3ac9fb - Ajout des champs password et salt dans user
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 2m25s
Build and test backend / Test-backend (pull_request) Successful in 2m1s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 25s
Build and test FrontEnd / Test-frontend (pull_request) Successful in 23s
- Ajout de la table token
- Ajout des foreign keys
2024-03-05 14:14:56 +01:00
837db9aba9 backbone for login 2024-03-05 14:10:13 +01:00
09d5e1c293 Document rest
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m55s
Build and test backend / Test-backend (pull_request) Successful in 1m50s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 19s
2024-03-05 11:48:04 +01:00
dcd1fad6ac solve access to /login
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m55s
Build and test backend / Test-backend (pull_request) Successful in 1m49s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 20s
Build and test backend / Build-backend (push) Successful in 2m6s
Build and test backend / Test-backend (push) Successful in 1m23s
deploy to production / deploy-frontend (push) Successful in 22s
deploy to production / deploy-backend (push) Successful in 2m16s
Build and test FrontEnd / Build-frontend (push) Successful in 20s
Vite won't export not specified page, so I specified it in the config.
2024-03-05 10:57:48 +01:00
8c2397c4cf Base for rest api utilisation
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m54s
Build and test backend / Test-backend (pull_request) Successful in 1m52s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 20s
The restConsumer will be the base, then I will create a js file per
"object" (for instance there will be users.js with all endpoints for
users using the restConsumer.js)
2024-03-05 00:15:52 +01:00
cc89d7f5b7 added ResponseEntity and TODOs 2024-03-04 23:35:15 +01:00
36f1ab3203 added .idea/ to .gitignore
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m8s
Build and test backend / Test-backend (push) Successful in 1m17s
deploy to production / deploy-frontend (push) Successful in 21s
deploy to production / deploy-backend (push) Successful in 2m13s
Build and test FrontEnd / Build-frontend (push) Successful in 21s
2024-03-04 21:30:16 +01:00
45bfe08c9a added .idea/ to .gitignore 2024-03-04 21:27:22 +01:00
6c688dab59 added Admin and Secretary 2024-03-04 21:25:44 +01:00
516fc0d5e6 fix last commit
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m7s
deploy to production / deploy-frontend (push) Successful in 22s
Build and test backend / Test-backend (push) Successful in 1m21s
deploy to production / deploy-backend (push) Successful in 2m19s
Build and test FrontEnd / Build-frontend (push) Successful in 20s
2024-03-04 20:42:10 +01:00
7abd2a001f relatives position for static api
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m9s
Build and test backend / Test-backend (push) Successful in 1m18s
deploy to production / deploy-frontend (push) Successful in 22s
deploy to production / deploy-backend (push) Successful in 2m20s
Build and test FrontEnd / Build-frontend (push) Successful in 21s
2024-03-04 20:15:12 +01:00
9850f2145c Fixing the login page availability
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m8s
Build and test backend / Test-backend (push) Successful in 1m24s
deploy to production / deploy-frontend (push) Successful in 23s
deploy to production / deploy-backend (push) Successful in 2m20s
Build and test FrontEnd / Build-frontend (push) Successful in 20s
To access the login page you need login.html. Then this page loads the
login.js that generate the login.vue in the div#app (with the '#app')
2024-03-04 19:42:57 +01:00
25fe568148 Convert login.html to Login.vue 2024-03-04 19:42:57 +01:00
672d17cf0e New file for login's style 2024-03-04 19:42:57 +01:00
49196caccc Grid setup frontend 2024-03-04 19:42:57 +01:00
0b0fe9ae78 Table for navigation bars 2024-03-04 19:42:57 +01:00
057d8ff001 Login prototype 2024-03-04 19:42:57 +01:00
21a42737a2 adding api definition in static files
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m4s
Build and test backend / Test-backend (push) Successful in 1m17s
deploy to production / deploy-frontend (push) Successful in 22s
deploy to production / deploy-backend (push) Successful in 2m14s
Build and test FrontEnd / Build-frontend (push) Successful in 20s
2024-03-02 22:19:10 +01:00
2d43707aca Changing name because it's cool...
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m6s
Build and test backend / Test-backend (push) Successful in 1m17s
deploy to production / deploy-frontend (push) Successful in 22s
deploy to production / deploy-backend (push) Successful in 2m12s
Build and test FrontEnd / Build-frontend (push) Successful in 20s
Honestly this commit can be skipped but I want to show-off ^^
2024-03-02 20:09:19 +01:00
f1b3b0dd45 Adding favicon plus perfect clyde
The clyde was good but i'm authistic so I made it perfect (16x16 scaled
up so proportions are perfectly perfect)
2024-03-02 20:09:19 +01:00
512e8a41dd removing action for frontend test
Some checks are pending
Build and test backend / Build-backend (push) Waiting to run
Build and test backend / Test-backend (push) Waiting to run
deploy to production / deploy-frontend (push) Waiting to run
deploy to production / deploy-backend (push) Waiting to run
Build and test FrontEnd / Build-frontend (push) Waiting to run
2024-03-02 20:09:02 +01:00
1a5f3cf65e Removing vitest 2024-03-02 20:09:02 +01:00
298cdcaae0 Implementation of i18n with documentation
Some checks are pending
Build and test backend / Build-backend (push) Waiting to run
Build and test backend / Test-backend (push) Waiting to run
deploy to production / deploy-frontend (push) Waiting to run
deploy to production / deploy-backend (push) Waiting to run
Build and test FrontEnd / Build-frontend (push) Waiting to run
Build and test FrontEnd / Test-frontend (push) Waiting to run
All files are documented. For further details please read them.
2024-03-02 20:08:02 +01:00
dbe24dbc5f typo
Some checks are pending
Build and test backend / Build-backend (push) Waiting to run
Build and test backend / Test-backend (push) Waiting to run
deploy to production / deploy-frontend (push) Waiting to run
deploy to production / deploy-backend (push) Waiting to run
Build and test FrontEnd / Build-frontend (push) Waiting to run
Build and test FrontEnd / Test-frontend (push) Waiting to run
maxed
2024-03-02 20:07:16 +01:00
1a1baccddd idea of internationalisation in JDB 2024-03-02 20:07:16 +01:00
ba7e9599de Premire journal de bord base
Some checks failed
Build and test backend / Test-backend (push) Waiting to run
deploy to production / deploy-frontend (push) Waiting to run
deploy to production / deploy-backend (push) Waiting to run
Build and test FrontEnd / Build-frontend (push) Waiting to run
Build and test FrontEnd / Test-frontend (push) Waiting to run
Build and test backend / Build-backend (push) Has been cancelled
Contient le choix des technologies
ainsi que la répartition des taches
2024-03-02 20:04:47 +01:00
fa522eabd3 fixing db
Some checks failed
Build and test backend / Build-backend (push) Successful in 2m6s
Build and test backend / Test-backend (push) Has been cancelled
Build and test FrontEnd / Build-frontend (push) Has been cancelled
Build and test FrontEnd / Test-frontend (push) Has been cancelled
deploy to production / deploy-frontend (push) Successful in 24s
deploy to production / deploy-backend (push) Has been cancelled
2024-03-02 19:30:26 +01:00
caf11b5b19 Refactoring backend (#42)
All checks were successful
Build and test backend / Build-backend (push) Successful in 2m7s
Build and test backend / Test-backend (push) Successful in 1m22s
Build and test FrontEnd / Build-frontend (push) Successful in 22s
Build and test FrontEnd / Test-frontend (push) Successful in 22s
deploy to production / deploy-frontend (push) Successful in 24s
deploy to production / deploy-backend (push) Successful in 1m28s
removing cors fails.
refactoring ping as a proposal for rest endpoints locations

Reviewed-on: #42
Reviewed-by: Maxime <231026@umons.ac.be>
Co-authored-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
Co-committed-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
2024-03-01 18:43:56 +01:00
0de7b69b1b enable jpa library for managing data
All checks were successful
Build and test backend / Build-backend (pull_request) Successful in 1m57s
Build and test backend / Test-backend (pull_request) Successful in 1m57s
Build and test FrontEnd / Build-frontend (pull_request) Successful in 22s
Build and test FrontEnd / Test-frontend (pull_request) Successful in 22s
Build and test backend / Build-backend (push) Successful in 2m19s
Build and test backend / Test-backend (push) Successful in 1m18s
deploy to production / deploy-frontend (push) Successful in 25s
deploy to production / deploy-backend (push) Successful in 2m16s
Build and test FrontEnd / Build-frontend (push) Successful in 23s
Build and test FrontEnd / Test-frontend (push) Successful in 23s
2024-02-29 08:53:33 +01:00
118 changed files with 7173 additions and 2038 deletions

View File

View File

@ -17,15 +17,16 @@ jobs:
distribution: 'temurin'
- uses: gradle/gradle-build-action@v3
- name: building
run: ./gradlew backend:build
Test-backend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
java-version: '21'
distribution: 'temurin'
- uses: gradle/gradle-build-action@v3
- name: building
run: ./gradlew backend:test
run: ./gradlew backend:build -x test
# Test-backend:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - uses: actions/setup-java@v3
# with:
# java-version: '21'
# distribution: 'temurin'
# - run: curl -fsSL https://get.docker.com | sh
# - uses: gradle/gradle-build-action@v3
# - name: testing
# run: ./gradlew backend:test

View File

@ -45,7 +45,7 @@ jobs:
distribution: 'temurin'
- uses: gradle/gradle-build-action@v3
- name: building
run: ./gradlew backend:build
run: ./gradlew backend:build -x test
- name: pushing to the server
run: |
echo "${{ secrets.SSH_KEY }}" > key
@ -53,5 +53,5 @@ jobs:
scp -o "StrictHostKeyChecking=no" -o "LogLevel=ERROR" -i key -r * ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:api/
- name: restarting the backend
run: |
ssh -o "StrictHostKeyChecking=no" -o "LogLevel=ERROR" -i key ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "cd api/backend && docker build -t clyde/backend . && docker rm clyde_backend_prod -f || true && docker run --rm -d --name clyde_backend_prod -p 4000:8080 clyde/backend && docker image prune -f"
ssh -o "StrictHostKeyChecking=no" -o "LogLevel=ERROR" -i key ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} 'cd api/backend && docker build -t clyde/backend . && docker rm clyde_backend_prod -f || true && docker run --rm -d -u $(id -u clyde):$(id -g clyde) -v /var/run/postgresql:/var/run/postgresql --name clyde_backend_prod -p 4000:8080 clyde/backend && docker image prune -f'
- run: echo "The backend has been deployed. running at https://clyde.herisson.ovh/api"

View File

@ -20,16 +20,3 @@ jobs:
- run: npm run build --if-present
name: build
working-directory: ./frontend
Test-frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
working-directory: ./frontend
- run: npm ci
name: clean install
working-directory: ./frontend
- run: npm run test:unit
name: test
working-directory: ./frontend

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ build
.project
.settings
.idea/

View File

@ -0,0 +1,48 @@
# Journal de bord du 29 février
Ce premier journal de bord permet d'initier une tendance a garder une trace des choix fait lors du dévelopement du
projet de génie logiciel. Ces journaux pourront alors être consultés par la suite, pour la rédaction du rapport.
## Choix des technologies utilisées
### Backend: spring.io
Le backend est imposé, nous devons utiliser spring boots. La courbe d'aprentisage nous semble difficile mais après de
longues documentations nous commençons à comprendre son fonctionnement.
### Frontend: Vue.js
Le frontend n'est pas imposé, nous devons utiliser javascript mais le choix du framework (si utilisé) est libre. Nous
avons pris la recomendation du cours: vue.js qui est un framework simple d'aprentisage et très performant.
#### Librairies
- **Vue3-toastify:** Nous avons opté pour l'utilisation d'une librarie de "notification". cette librairie permet
d'afficher des notifications sur la page. Elle nous est utile autant pour l'application finale que pour le
dévelopement.
### Database: postgresql
C'est une base de données très efficace qui est déjà installé
### VCS: Gitea
C'est une alternative a github mais self-hosted. Nous avons accés à un serveur sur lequel gitea est installé
(https://git.herisson.ovh/).
### CI/CD: Gitea Actions
Gitea a récement implémenter l'équivalent de github actions dans gitea et qui est complètement compatible avec github
actions. Nous avons donc implémentés les test et build en continu lors des pr et merge. Lorsqu'un merge est fait avec la
branche master, le site est instentanément mis à jours (après une dernière verification du build et test) sur l'adresse
http://clyde.herisson.ovh pour le frontent et http://clyde.herisson.ovh/api pour le backend.
## Répartition des taches
Nous nous répartisons les taches par familiarité et préférences avec les différentes partie du projet.
- Wiliam: Frontend visuel
- Anthony: Frontend technique
- Max: Backend Endpoints
- Léo: Backend Data

View File

@ -0,0 +1,36 @@
# Authentification
## Contexte
Le projet demande de pouvoir authentifier les utilisateurs présents. Le but étant de leurs associer un "contexte"
(cours, informations personnelles, ...). Pour que ceux-ci puissent accomplir différentes actions nécéssitantes une
identification (permission, info personelles, ...).
## Méthode
Lorsque qu'un utilisateur se connecte au serveur, nous lui envoyons un token qui sera stocké dans le
navigateur. Ce token est unique à l'utilisateur et pourra être ré-envoyé dans les futures requêtes
pour identifier l'utilisateur.
Ce token est donc une chaine de 64 caractères suivant la norme ISO_8859_1(8bits par cararctère) aléatoires,ce qui est d'après nos recherches suffisant.
De plus une limite de 5 token par utilisateur sera ajoutée de sorte à
1) S'assurer qu'une personne ne noie la base de donnée de tokens.
2) Ajouter une protection supplémentaire pour assurer qu'un token est bien unique à un utilisateur.
## Autres méthodes envisagée
### Oauth2
C'est un protocol d'identification vastement utilisé permettant, en plus d'identifier les requettes,
de gérer leurs permissions. Un utilisateur créen un token peut lui attribuer des permissions
spécifique qui restrainderaients les permissions d'utilisation de ce token. C'est très utile pour
déployer des api de site pouvant notament être accédé par des ordinateurs / bots. Ca n'est en
revanche pas l'objectif du projet et l'option n'a donc pas été retenue
### Spring Sessions / Tomcat sessions
Il aurait été possible de laisser une librairie automatiser les sessions. Malheuresement, celà
implique de devoir se plier au format de la dite librairie. L'implémentation d'un système de gestion
de token maison semblai à la fois, non-imposible et interessant à notre apprentisage. C'est pourquoi
nous n'avons pas utilisé cette option.

View File

@ -0,0 +1,45 @@
# Internationalization (i18n)
L'un des critère du projet est de donner la possibilité aux utilisateur de choisir entre différentes
langues. Minimum 2 sont a implémenter, le français et l'anglais.
## Intention
La gestion des langue au niveau backend peut sembler être une bonne idée aux premier abord car celà
permeterais de laisser la possibilité a différents frontend utilisant la meme api de traduction.
cependant, peu d'éléments venant de la base de données sont traduisible. Nous alons alors opter pour
une internationalization au niveau du frontend. Dans le cas ou un éléments venant du frontend
devrait être traduit, Il suffirait alors de le faire traduire par le frontend directement
## Implémentation
Le frontend va se voir équiper d'une collection de fonctions permettant la traduction. notament
`i18n(key: str) -> str` qui prendrait en entrée une "clé" identifiant la traduction à aller
chercher. Cette clé serait sous la forme : `<context>.<element>`. La fonctions retournera alors la
traduction du texte dans la langue choisie par l'utilisateur. cette langue sera stockée dans les
cookies pour qu'un utilisateur non enregistré puisse naviguer sur le site sans problèmes. Si
l'utilisateur est enregistré elle pourra également être ajouter à son profil pour que la langue soit
mise à jours lors de son prochain passage.
### Base de données de traduction
Les traductions seront rassembler dans fichier txt. Une langue sera présente par fichier et une
traduction par ligne. (Ce format semble être utilisé par certaines librairies de spring. Malgré le
fait que nous ne l'utiliserons finalement pas, ce format semble efficace est facile à utilsier).
Chaque ligne commence par la clé. suivi immédiatement d'un "=". le contenu après ce égale est la
traduction jusqu'au égale.
## Considérations
- Il existe certainemnt des librairies prète à l'emploi de traduction mais celà semble être
relativement simple à implémenter manuellement.
- Dans l'éventualité où nous voudrions implémenter des éléments au milieu d'une traduction (example:
Veuillez vérifier votre addresse mail: `tonitch@herisson.ovh` puis revenir sur le site!). Dans ce
cas nous pouvons utiliser le regex et simplement renseigner ces éléments par \1, \2, \3, ... puis
créer une fonction qui s'occuperais de remplacer ces éléments dans le texte avant de le mettre en
avant.
- Il ne devrait pas etre trop compliqué d'écrire un script qui vérifie que toutes les traductions
sont présente dans tout les fichiers en vérifiant que toutes les clés d'un fichiers sont présente.

2
backend/.gitignore vendored
View File

@ -35,3 +35,5 @@ out/
### VS Code ###
.vscode/
/cdn

View File

@ -1,5 +1,6 @@
FROM eclipse-temurin:21-jdk-alpine
VOLUME /tmp
VOLUME /cdn
ENV SPRING_PROFILES_ACTIVE=prod
COPY build/libs/backend-0.0.1-SNAPSHOT.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

View File

@ -17,9 +17,12 @@ repositories {
dependencies {
implementation("org.springframework.boot:spring-boot-starter-jdbc")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-mail")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("com.kohlschutter.junixsocket:junixsocket-core:2.9.0")
// implementation("org.springframework.session:spring-session-jdbc")
developmentOnly("org.springframework.boot:spring-boot-devtools")
developmentOnly("org.springframework.boot:spring-boot-docker-compose")
@ -28,8 +31,11 @@ dependencies {
testImplementation("org.springframework.boot:spring-boot-testcontainers")
testImplementation("org.testcontainers:junit-jupiter")
testImplementation("org.testcontainers:postgresql")
testImplementation("io.rest-assured:rest-assured")
testImplementation("org.hamcrest:hamcrest")
}
tasks.register("run") {
dependsOn(tasks.bootRun)
}
@ -38,3 +44,4 @@ tasks.register("run") {
tasks.withType<Test> {
useJUnitPlatform()
}

View File

@ -6,4 +6,4 @@ services:
- 'POSTGRES_USER=devel'
- 'POSTGRES_PASSWORD=devel'
ports:
- '5432:5432'
- '5442:5432'

View File

@ -2,8 +2,9 @@ package ovh.herisson.Clyde;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
@SpringBootApplication
@SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
public class ClydeApplication {
public static void main(String[] args) {

View File

@ -0,0 +1,75 @@
package ovh.herisson.Clyde.EndPoints;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import ovh.herisson.Clyde.Services.AuthenticatorService;
import ovh.herisson.Clyde.Tables.Applications;
import ovh.herisson.Clyde.Tables.Role;
import ovh.herisson.Clyde.Tables.User;
import java.util.ArrayList;
@RestController
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
public class ApplicationsController {
AuthenticatorService authServ;
public ApplicationsController(AuthenticatorService authServ){
this.authServ = authServ;
}
/** return a list of authorized applications.
* depends on the token
*/
@GetMapping("/apps")
public ResponseEntity<Iterable<Applications>> getAuthorizedApps(@RequestHeader("Authorization") String token){
return new ResponseEntity<>(getAuthorizedApplications(token), HttpStatus.OK);
}
@GetMapping("/apps/{identifier}")
public ResponseEntity<Boolean> getAppAuthorization(@PathVariable Applications identifier, @RequestHeader("Authorization") String token){
if (getAuthorizedApplications(token).contains(identifier)){
return new ResponseEntity<>(true, HttpStatus.OK);
}
return new ResponseEntity<>(false, HttpStatus.OK);
}
public ArrayList<Applications> getAuthorizedApplications(String token){
ArrayList<Applications> authorizedApps = new ArrayList<>();
//if unAuthed
authorizedApps.add(Applications.Login);
User user = authServ.getUserFromToken(token);
if(user == null)
return authorizedApps;
// if authed
authorizedApps.add(Applications.Profile);
if (!authServ.isNotIn(new Role[]{Role.Teacher,Role.Student,Role.Admin},token)) {
authorizedApps.add(Applications.Msg);
authorizedApps.add(Applications.Forum);
authorizedApps.add(Applications.Rdv);
}
//if Teacher or Secretary or Admin add ManageCourses App
if (!authServ.isNotIn(new Role[]{Role.Teacher,Role.Secretary,Role.Admin},token))
authorizedApps.add(Applications.ManageCourses);
if (!authServ.isNotIn(new Role[]{Role.InscriptionService,Role.Admin},token)){
authorizedApps.add(Applications.Inscription);
authorizedApps.add(Applications.StudentsList);}
if (!authServ.isNotIn(new Role[]{Role.Secretary,Role.Admin},token)){
authorizedApps.add(Applications.UsersList);}
return authorizedApps;
}
}

View File

@ -0,0 +1,138 @@
package ovh.herisson.Clyde.EndPoints;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import ovh.herisson.Clyde.Responses.UnauthorizedResponse;
import ovh.herisson.Clyde.Services.AuthenticatorService;
import ovh.herisson.Clyde.Services.CourseService;
import ovh.herisson.Clyde.Services.ProtectionService;
import ovh.herisson.Clyde.Services.TeacherCourseService;
import ovh.herisson.Clyde.Tables.Course;
import ovh.herisson.Clyde.Tables.Role;
import ovh.herisson.Clyde.Tables.User;
import java.util.HashMap;
import java.util.Map;
@RestController
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
public class CourseController {
private final CourseService courseServ;
private final TeacherCourseService teacherCourseServ;
private final AuthenticatorService authServ;
public CourseController(CourseService courseServ, TeacherCourseService teacherCourseServ, AuthenticatorService authServ) {
this.courseServ = courseServ;
this.teacherCourseServ = teacherCourseServ;
this.authServ = authServ;
}
@GetMapping("/course/{id}")
public ResponseEntity<HashMap<String,Object>> getCourse(@RequestHeader("Authorization") String token, @PathVariable long id){
if (authServ.getUserFromToken(token) == null)
return new UnauthorizedResponse<>(null);
Course foundCourse = courseServ.findById(id);
if (foundCourse == null)
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
return new ResponseEntity<>(ProtectionService.courseWithoutPassword(foundCourse), HttpStatus.OK);
}
@GetMapping("/courses")
public ResponseEntity<Iterable<HashMap<String,Object>>> getAllCourses(@RequestHeader("Authorization") String token){
if (authServ.isNotIn(new Role[]{Role.Admin,Role.Secretary},token))
return new UnauthorizedResponse<>(null);
return new ResponseEntity<>(ProtectionService.coursesWithoutPasswords(courseServ.findAll()),HttpStatus.OK);
}
@GetMapping("/courses/owned")
public ResponseEntity<Iterable<HashMap<String ,Object>>> getOwnedCourses(@RequestHeader("Authorization") String token){
if (authServ.isNotIn(new Role[]{Role.Admin,Role.Teacher},token))
return new UnauthorizedResponse<>(null);
return new ResponseEntity<>(ProtectionService.coursesWithoutPasswords(courseServ.findOwnedCourses(authServ.getUserFromToken(token))),HttpStatus.OK);
}
@GetMapping("/course/{id}/assistants")
public ResponseEntity<Iterable<HashMap<String,Object>>> getCourseAssistants(@RequestHeader("Authorization")String token, @PathVariable long id){
if (authServ.getUserFromToken(token) == null)
return new UnauthorizedResponse<>(null);
Iterable<User> assistants = teacherCourseServ.findCourseAssistants(courseServ.findById(id));
return new ResponseEntity<>(ProtectionService.usersWithoutPasswords(assistants),HttpStatus.OK);
}
@PostMapping("/course")
public ResponseEntity<Map<String ,Object>> postCourse(@RequestHeader("Authorization") String token,
@RequestBody Course course)
{
System.out.println(course);
System.out.println(token);
if (authServ.isNotIn(new Role[]{Role.Secretary,Role.Admin},token))
return new UnauthorizedResponse<>(null);
Course createdCourse = courseServ.save(course);
if (createdCourse == null)
return new ResponseEntity<>(null,HttpStatus.BAD_REQUEST);
return new ResponseEntity<>(ProtectionService.courseWithoutPassword(createdCourse), HttpStatus.CREATED);
}
@PatchMapping("/course/{id}")
public ResponseEntity<Course> patchCourse(@RequestHeader("Authorization") String token,
@RequestBody Map<String,Object> updates,
@PathVariable long id)
{
if (authServ.isNotIn(new Role[]{Role.Admin,Role.Teacher,Role.Secretary}, token))
return new UnauthorizedResponse<>(null);
if (!courseServ.modifyData(id, updates, authServ.getUserFromToken(token).getRole()))
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
return new ResponseEntity<>(HttpStatus.OK);
}
@PostMapping("/course/{id}")
public ResponseEntity<String> postTeachers(@RequestHeader("Authorization") String token,
@RequestBody Iterable<Long> teacherIds,
@PathVariable Long id)
{
if (authServ.isNotIn(new Role[]{Role.Admin,Role.Secretary}, token))
return new UnauthorizedResponse<>(null);
if (!teacherCourseServ.saveAll(teacherIds,courseServ.findById(id)))
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
return new ResponseEntity<>(HttpStatus.OK);
}
@DeleteMapping("course/{id}")
public ResponseEntity<String> deleteUser(@RequestHeader("Authorization") String token, @PathVariable Long id){
if (authServ.isNotIn(new Role[]{Role.Admin,Role.Secretary}, token))
return new UnauthorizedResponse<>(null);
Course toDelete = courseServ.findById(id);
if (toDelete == null)
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
courseServ.delete(courseServ.findById(id));
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@ -0,0 +1,97 @@
package ovh.herisson.Clyde.EndPoints;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import ovh.herisson.Clyde.Responses.UnauthorizedResponse;
import ovh.herisson.Clyde.Services.*;
import ovh.herisson.Clyde.Tables.Curriculum;
import ovh.herisson.Clyde.Tables.Role;
import java.util.Map;
@RestController
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
public class CurriculumController {
private final CurriculumService curriculumServ;
private final AuthenticatorService authServ;
private final UserCurriculumService userCurriculumServ;
private final CurriculumCourseService curriculumCourseServ;
public CurriculumController(CurriculumService curriculumServ, AuthenticatorService authServ, UserCurriculumService userCurriculumServ, CurriculumCourseService curriculumCourseServ){
this.curriculumServ = curriculumServ;
this.authServ = authServ;
this.userCurriculumServ = userCurriculumServ;
this.curriculumCourseServ = curriculumCourseServ;
}
@GetMapping("/curriculum/{id}")
public ResponseEntity<Map<String,Object>> findById(@PathVariable long id){
Curriculum foundCurriculum = curriculumServ.findById(id);
if (foundCurriculum == null)
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
return new ResponseEntity<>(curriculumCourseServ.getDepthCurriculum(foundCurriculum), HttpStatus.OK);
}
@GetMapping("/curriculum")
public ResponseEntity<Map<String ,Object>> findSelfCurriculum(@RequestHeader("Authorization") String token){
if (authServ.getUserFromToken(token) == null)
return new UnauthorizedResponse<>(null);
Curriculum curriculum = userCurriculumServ.findByUser(authServ.getUserFromToken(token));
if (curriculum == null)
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
return new ResponseEntity<>(curriculumCourseServ.getDepthCurriculum(curriculum),HttpStatus.OK);
}
@GetMapping("/curriculums")
public ResponseEntity<Iterable<Map<String, Object>>> findAllIndDepth(){
return new ResponseEntity<>(curriculumCourseServ.getAllDepthCurriculum(),HttpStatus.OK);
}
@PostMapping("/curriculum")
public ResponseEntity<Curriculum> postCurriculum(@RequestHeader("Authorization") String token,@RequestBody Curriculum curriculum){
if (authServ.isNotIn(new Role[]{Role.Secretary,Role.Admin},token))
return new UnauthorizedResponse<>(null);
return new ResponseEntity<>(curriculumServ.save(curriculum),HttpStatus.CREATED);
}
@PostMapping("/curriculum/{id}")
public ResponseEntity<String> postCoursesToCurriculum(@RequestHeader("Authorization") String token,
@RequestBody Iterable<Long> coursesIds,
@PathVariable long id)
{
if (authServ.isNotIn(new Role[]{Role.Admin,Role.Secretary},token))
return new UnauthorizedResponse<>(null);
if (!curriculumCourseServ.saveAll(coursesIds, curriculumServ.findById(id)))
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
return new ResponseEntity<>(HttpStatus.OK);
}
@DeleteMapping("/curriculum/{id}")
public ResponseEntity<String > deleteCurriculum(@RequestHeader("Authorization") String token, @PathVariable Long id){
if (authServ.isNotIn(new Role[]{Role.Admin,Role.Secretary}, token))
return new UnauthorizedResponse<>(null);
Curriculum toDelete = curriculumServ.findById(id);
if (toDelete == null)
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
curriculumServ.delete(toDelete);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@ -0,0 +1,82 @@
package ovh.herisson.Clyde.EndPoints;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import ovh.herisson.Clyde.Responses.UnauthorizedResponse;
import ovh.herisson.Clyde.Services.AuthenticatorService;
import ovh.herisson.Clyde.Services.InscriptionService;
import ovh.herisson.Clyde.Services.ProtectionService;
import ovh.herisson.Clyde.Tables.InscriptionRequest;
import ovh.herisson.Clyde.Tables.RequestState;
import ovh.herisson.Clyde.Tables.Role;
import java.util.Map;
@RestController
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
public class InscriptionController {
private final InscriptionService inscriptionServ;
private final AuthenticatorService authServ;
public InscriptionController(InscriptionService inscriptionServ, AuthenticatorService authServ){
this.inscriptionServ = inscriptionServ;
this.authServ = authServ;
}
@GetMapping("/requests/register")
public ResponseEntity<Iterable<Map<String,Object>>> getAllRequests(@RequestHeader("Authorization") String token){
if (authServ.isNotIn(new Role[]{Role.Admin,Role.InscriptionService},token))
return new UnauthorizedResponse<>(null);
Iterable<InscriptionRequest> inscriptionRequests = inscriptionServ.getAll();
return new ResponseEntity<>(ProtectionService.requestsWithoutPasswords(inscriptionRequests), HttpStatus.OK);
}
@GetMapping("/request/register/{id}")
public ResponseEntity<Map<String,Object>> getById(@RequestHeader("Authorization") String token, @PathVariable long id){
if (authServ.isNotIn(new Role[]{Role.Admin,Role.InscriptionService},token))
return new UnauthorizedResponse<>(null);
InscriptionRequest foundInscriptionRequest = inscriptionServ.getById(id);
if (foundInscriptionRequest == null)
return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
return new ResponseEntity<>(ProtectionService.requestWithoutPassword(foundInscriptionRequest), HttpStatus.OK);
}
@PatchMapping("/request/register/{id}")
public ResponseEntity<InscriptionRequest> changeRequestState(@PathVariable long id,
@RequestHeader("Authorization") String token,
@RequestBody RequestState state)
{
if (authServ.isNotIn(new Role[]{Role.InscriptionService,Role.Admin},token))
return new UnauthorizedResponse<>(null);
if (!inscriptionServ.modifyState(id, state))
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
return new ResponseEntity<>(HttpStatus.OK);
}
@DeleteMapping("/request/register/{id}")
public ResponseEntity<String > deleteRequest(@RequestHeader("Authorization") String token, @PathVariable Long id){
if (authServ.isNotIn(new Role[]{Role.Admin,Role.InscriptionService}, token))
return new UnauthorizedResponse<>(null);
InscriptionRequest toDelete = inscriptionServ.getById(id);
if (toDelete == null)
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
inscriptionServ.delete(toDelete);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@ -0,0 +1,56 @@
package ovh.herisson.Clyde.EndPoints;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import ovh.herisson.Clyde.Responses.UnauthorizedResponse;
import ovh.herisson.Clyde.Services.AuthenticatorService;
import ovh.herisson.Clyde.Services.ProtectionService;
import ovh.herisson.Clyde.Tables.InscriptionRequest;
import java.util.Date;
import java.util.Map;
@RestController
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
public class LoginController {
private final AuthenticatorService authServ;
static public class RequestLogin{
private final String identifier;
private final String password;
@JsonFormat(pattern="yyyy-MM-dd'T'HH:mm:ss")
private final Date expirationDate;
public RequestLogin(String identifier, String password, Date expirationDate){
this.identifier = identifier;
this.password = password;
this.expirationDate = expirationDate;
}
}
public LoginController(AuthenticatorService authServ){
this.authServ = authServ;
}
@PostMapping(value = "/login")
public ResponseEntity<String> login(@RequestBody RequestLogin requestLogin){
String sessionToken = authServ.login(requestLogin.identifier,requestLogin.password,requestLogin.expirationDate);
if (sessionToken == null){
return new UnauthorizedResponse<>("Identifier or Password incorrect");
}
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("Set-Cookie",String.format("session_token=%s",sessionToken));
return ResponseEntity.ok().headers(responseHeaders).build();
}
@PostMapping("/register")
public ResponseEntity<Map<String,Object>> register(@RequestBody InscriptionRequest inscriptionRequest){
InscriptionRequest returnedInscriptionRequest = authServ.register(inscriptionRequest);
return new ResponseEntity<>(ProtectionService.requestWithoutPassword(returnedInscriptionRequest), HttpStatus.CREATED);
}
}

View File

@ -0,0 +1,101 @@
package ovh.herisson.Clyde.EndPoints;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;
import ovh.herisson.Clyde.Repositories.TokenRepository;
import ovh.herisson.Clyde.Repositories.UserRepository;
import ovh.herisson.Clyde.Services.*;
import ovh.herisson.Clyde.Tables.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
@RestController
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
public class MockController {
private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
public final UserRepository userRepo;
public final TokenRepository tokenRepo;
public final TokenService tokenService;
public final CurriculumCourseService CurriculumCourseService;
public final CurriculumService curriculumService;
public final CourseService courseService;
public final InscriptionService inscriptionService;
ArrayList<User> mockUsers;
public MockController(UserRepository userRepo, TokenRepository tokenRepo, TokenService tokenService, CurriculumCourseService CurriculumCourseService, CurriculumService curriculumService, CourseService courseService, InscriptionService inscriptionService){
this.tokenRepo = tokenRepo;
this.userRepo = userRepo;
this.tokenService = tokenService;
this.CurriculumCourseService = CurriculumCourseService;
this.curriculumService = curriculumService;
this.courseService = courseService;
this.inscriptionService = inscriptionService;
}
/** Saves an example of each user type by :
* email : FooRole@FooRole.com, password : FooRole and token : FooRole
* For example the admin as "admin@admin.com" as email and "admin" as both password and token
* They all have silly names
*/
@PostMapping("/mock")
public void postMock(){
// user part
User herobrine = new User("brine","hero","admin@admin.com","behind","ShadowsLand",new Date(0), null,Role.Admin,passwordEncoder.encode("admin"));
User joe = new User("Mama","Joe","student@student.com","roundabout","England",new Date(0), null,Role.Student,passwordEncoder.encode("student"));
User meh = new User("Polo","Marco","secretary@secretary.com","a Box","Monaco",new Date(0), null,Role.Secretary,passwordEncoder.encode("secretary"));
User joke = new User("Gaillard","Corentin","teacher@teacher.com","lab","faculty",new Date(0), null,Role.Teacher,passwordEncoder.encode("teacher"));
User jojo = new User("Bridoux","Justin","teacher2@teacher2.com","lab","faculty",new Date(0), null,Role.Teacher,passwordEncoder.encode("teacher"));
User lena = new User("Louille","Lena","inscriptionService@InscriptionService.com","no","yes",new Date(0), null,Role.InscriptionService,passwordEncoder.encode("inscriptionService"));
mockUsers = new ArrayList<>(Arrays.asList(herobrine,joe,meh,joke,lena,jojo));
userRepo.saveAll(mockUsers);
// Course / Curriculum part
Curriculum infoBab1 = new Curriculum(1,"info");
Curriculum chemistryBab1 = new Curriculum(1,"chemistry");
Curriculum psychologyBab1 = new Curriculum(1,"psychology");
curriculumService.save(infoBab1);
curriculumService.save(chemistryBab1);
curriculumService.save(psychologyBab1);
Course progra1 = new Course(5,"Programmation et algorithmique 1",joke);
Course chemistry1 = new Course(12, "Thermochimie",joke);
Course psycho1 = new Course(21, "Neuroreaction of isolated brain cells",joke);
Course commun = new Course(2, "cours commun",joke);
courseService.save(progra1);
courseService.save(chemistry1);
courseService.save(psycho1);
courseService.save(commun);
CurriculumCourseService.save(new CurriculumCourse(infoBab1,progra1));
CurriculumCourseService.save(new CurriculumCourse(infoBab1,commun));
CurriculumCourseService.save(new CurriculumCourse(psychologyBab1,psycho1));
CurriculumCourseService.save(new CurriculumCourse(psychologyBab1,commun));
CurriculumCourseService.save(new CurriculumCourse(chemistryBab1,commun));
CurriculumCourseService.save(new CurriculumCourse(chemistryBab1,chemistry1));
InscriptionRequest inscriptionRequest = new InscriptionRequest("helen","prenom","non","helen@gmail.com","america",new Date(),(long) 1,RequestState.Pending,"yes.png","password");
inscriptionService.save(inscriptionRequest);
}
}

View File

@ -4,15 +4,15 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RestController;
import ovh.herisson.Clyde.Ping;
import ovh.herisson.Clyde.Responses.PingResponse;
@RestController
@CrossOrigin(origins = "http://localhost:5173")
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
public class PingController {
@GetMapping("/ping")
public Ping ping(){
return new Ping(1, "pong");
public PingResponse ping(){
return new PingResponse(1, "pong");
}
}

View File

@ -0,0 +1,36 @@
package ovh.herisson.Clyde.EndPoints;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import ovh.herisson.Clyde.Services.StorageService;
import ovh.herisson.Clyde.Tables.FileType;
import ovh.herisson.Clyde.Tables.StorageFile;
@RestController
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
public class StorageController {
private final StorageService storageServ;
public StorageController(StorageService storageServ){
this.storageServ= storageServ;
}
@PostMapping("/upload/{fileType}")
public ResponseEntity<StorageFile> handleFileUpload(@RequestParam("file") MultipartFile file, @PathVariable FileType fileType) {
StorageFile fileEntry;
try {
fileEntry = storageServ.store(file,fileType);
} catch(Exception e){
e.printStackTrace();
return new ResponseEntity<>(null,HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(fileEntry, HttpStatus.OK);
}
}

View File

@ -0,0 +1,37 @@
package ovh.herisson.Clyde.EndPoints;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import ovh.herisson.Clyde.Responses.UnauthorizedResponse;
import ovh.herisson.Clyde.Services.AuthenticatorService;
import ovh.herisson.Clyde.Services.TokenService;
import ovh.herisson.Clyde.Tables.Role;
import ovh.herisson.Clyde.Tables.Token;
@RestController
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
public class TokenController {
private final TokenService tokenServ;
private final AuthenticatorService authServ;
public TokenController(TokenService tokenServ, AuthenticatorService authServ){
this.tokenServ = tokenServ;
this.authServ = authServ;
}
@GetMapping("/tokens")
public ResponseEntity<Iterable<Token>> getTokens(@RequestHeader("Authorization")String token){
if (authServ.isNotIn(new Role[]{Role.Admin},token))
return new UnauthorizedResponse<>(null);
return new ResponseEntity<>(tokenServ.getAllTokens(), HttpStatus.OK);
}
}

View File

@ -1,27 +1,139 @@
package ovh.herisson.Clyde.EndPoints;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import ovh.herisson.Clyde.Repositories.UserRepository;
import ovh.herisson.Clyde.Responses.UnauthorizedResponse;
import ovh.herisson.Clyde.Services.AuthenticatorService;
import ovh.herisson.Clyde.Services.ProtectionService;
import ovh.herisson.Clyde.Services.UserService;
import ovh.herisson.Clyde.Tables.Role;
import ovh.herisson.Clyde.Tables.User;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@RestController
@CrossOrigin(origins = "http://localhost:5173")
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
public class UserController {
private final UserRepository userRepo;
private final UserService userService;
private final AuthenticatorService authServ;
public UserController(UserService userService, AuthenticatorService authServ){
this.userService = userService;
this.authServ = authServ;
}
public UserController(UserRepository userRepo){
this.userRepo = userRepo;
/** returns information about the connected user
*
* @param token the session token of the user
* @return the user information except his password
*/
@GetMapping("/user")
public ResponseEntity<HashMap<String,Object>> getUser(@RequestHeader("Authorization") String token){
User user = authServ.getUserFromToken(token);
if (user == null) return new UnauthorizedResponse<>(null);
return new ResponseEntity<>(ProtectionService.userWithoutPassword(user), HttpStatus.OK);
}
@GetMapping("/user/{id}")
public ResponseEntity<HashMap<String ,Object>> getUserById(@RequestHeader("Authorization") String token, @PathVariable Long id){
if (authServ.isNotIn(new Role[]{Role.Admin,Role.Secretary,Role.InscriptionService},token))
return new UnauthorizedResponse<>(null);
return new ResponseEntity<>(ProtectionService.userWithoutPassword(userService.getUserById(id)), HttpStatus.OK);
}
@PostMapping("/user")
public ResponseEntity<Map<String ,Object>> postUser(@RequestBody User user,@RequestHeader("Authorization") String token){
if (authServ.isNotIn(new Role[]{Role.Admin,Role.InscriptionService,Role.Secretary},token))
return new UnauthorizedResponse<>(null);
return new ResponseEntity<>(ProtectionService.userWithoutPassword(userService.save(user)),HttpStatus.CREATED);
}
@GetMapping("/users")
public Iterable<User> getUsers(){
return userRepo.findAll();
public ResponseEntity<Iterable<HashMap<String,Object>>> getAllUsers(@RequestHeader("Authorization") String token){
if (authServ.isNotIn(new Role[]{Role.Admin,Role.Secretary},token))
return new UnauthorizedResponse<>(null);
Role posterRole = authServ.getUserFromToken(token).getRole();
Iterable<User> users = new ArrayList<>();
if (posterRole == Role.Admin)
users = userService.getAll();
else if (posterRole == Role.Secretary)
users = userService.getAllExceptAdmins();
return new ResponseEntity<>(ProtectionService.usersWithoutPasswords(users), HttpStatus.OK);
}
@PostMapping("/users")
public void postUser(@RequestBody User user ){
userRepo.save(user);
/** changes the specified user's information
*
* @param updates the changes to be made
* @param token the session token of the user posting the change
* @param id the id of the user to change
* @return a string clarifying the issue (if there is any)
*/
@PatchMapping("/user/{id}")
public ResponseEntity<String> patchUser(@RequestHeader("Authorization") String token,
@RequestBody Map<String,Object> updates,
@PathVariable Long id) {
if (token == null) return new UnauthorizedResponse<>(null);
User poster = authServ.getUserFromToken(token);
if (poster == null) {return new UnauthorizedResponse<>("bad token");}
if (!userService.modifyData(id, updates, poster))
return new UnauthorizedResponse<>("there was an issue with the updates requested");
return new ResponseEntity<>(null, HttpStatus.OK);
}
@GetMapping("/teachers")
public ResponseEntity<Iterable<HashMap<String,Object>>> getAllTeachers(@RequestHeader("Authorization") String token){
if (authServ.getUserFromToken(token) == null)
return new UnauthorizedResponse<>(null);
Iterable<User> teachers = userService.getAllTeachers();
return new ResponseEntity<>(ProtectionService.usersWithoutPasswords(teachers), HttpStatus.OK);
}
@GetMapping("/students")
public ResponseEntity<Iterable<HashMap<String,Object>>> getAllStudent(@RequestHeader("Authorization") String token){
if (authServ.getUserFromToken(token) == null)
return new UnauthorizedResponse<>(null);
Iterable<User> students = userService.getAllStudents();
return new ResponseEntity<>(ProtectionService.usersWithoutPasswords(students), HttpStatus.OK);
}
@DeleteMapping("/user/{id}")
public ResponseEntity<String> deleteStudent(@RequestHeader("Authorization") String token, @PathVariable Long id){
if (authServ.isNotIn(new Role[]{Role.Admin,Role.Secretary},token) && !id.equals(authServ.getUserFromToken(token).getRegNo()))
return new UnauthorizedResponse<>(null);
User toDelete = userService.getUserById(id);
if (toDelete == null)
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
userService.delete(toDelete);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@ -6,10 +6,10 @@ 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.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.scheduling.annotation.EnableScheduling;
@Configuration
@EnableScheduling
public class JdbcConfig {
@Bean
@ -17,7 +17,7 @@ public class JdbcConfig {
public DataSource psqlSource(){
DriverManagerDataSource source = new DriverManagerDataSource();
source.setDriverClassName("org.postgresql.Driver");
source.setUrl("jdbc:postgresql://localhost:5432/clyde");
source.setUrl("jdbc:postgresql://localhost:5442/clyde");
source.setUsername("devel");
source.setPassword("devel");
@ -29,21 +29,9 @@ public class JdbcConfig {
public DataSource psqlSourceProd(){
DriverManagerDataSource source = new DriverManagerDataSource();
source.setDriverClassName("org.postgresql.Driver");
source.setUrl("jdbc:postgresql://localhost:5432/clyde");
source.setUrl("jdbc:postgresql:clyde?socketFactory=org.newsclub.net.unix.AFUNIXSocketFactory$FactoryArg&socketFactoryArg=/var/run/postgresql/.s.PGSQL.5432");
source.setUsername("clyde");
return source;
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/greeting-javaconfig").allowedOrigins("*");
}
};
}
}

View File

@ -1,3 +0,0 @@
package ovh.herisson.Clyde;
public record Ping(int id, String txt){};

View File

@ -0,0 +1,15 @@
package ovh.herisson.Clyde.Repositories;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import ovh.herisson.Clyde.Tables.Course;
import ovh.herisson.Clyde.Tables.User;
public interface CourseRepository extends CrudRepository<Course,Long> {
Course findById(long id);
@Query("select c from Course c where c.owner = ?1")
Iterable<Course> findAllOwnedCoures(User teacher);
}

View File

@ -0,0 +1,17 @@
package ovh.herisson.Clyde.Repositories;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import ovh.herisson.Clyde.Tables.Course;
import ovh.herisson.Clyde.Tables.Curriculum;
import ovh.herisson.Clyde.Tables.CurriculumCourse;
public interface CurriculumCourseRepository extends CrudRepository<CurriculumCourse,Long> {
@Query("select distinct cc.course from CurriculumCourse cc where cc.curriculum = ?1")
Iterable<Course> findCoursesByCurriculum(Curriculum curriculum);
@Query("select distinct cc.curriculum from CurriculumCourse cc")
Iterable<Curriculum> findDistinctCurriculums();
}

View File

@ -0,0 +1,8 @@
package ovh.herisson.Clyde.Repositories;
import org.springframework.data.repository.CrudRepository;
import ovh.herisson.Clyde.Tables.Curriculum;
public interface CurriculumRepository extends CrudRepository<Curriculum,Long> {
Curriculum findById(long id);
}

View File

@ -0,0 +1,14 @@
package ovh.herisson.Clyde.Repositories;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import ovh.herisson.Clyde.Tables.StorageFile;
import java.util.ArrayList;
public interface FileRepository extends CrudRepository<StorageFile,Long> {
public StorageFile getStorageFileByName(String name);
}

View File

@ -0,0 +1,10 @@
package ovh.herisson.Clyde.Repositories;
import org.springframework.data.repository.CrudRepository;
import ovh.herisson.Clyde.Tables.InscriptionRequest;
public interface InscriptionRepository extends CrudRepository<InscriptionRequest,Long> {
InscriptionRequest findById(long aLong);
}

View File

@ -0,0 +1,14 @@
package ovh.herisson.Clyde.Repositories;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import ovh.herisson.Clyde.Tables.Course;
import ovh.herisson.Clyde.Tables.TeacherCourse;
import ovh.herisson.Clyde.Tables.User;
public interface TeacherCourseRepository extends CrudRepository<TeacherCourse, Long> {
@Query("select tc.user from TeacherCourse tc where tc.course = ?1")
Iterable<User> findAllAssistantOfCourse(Course course);
}

View File

@ -0,0 +1,14 @@
package ovh.herisson.Clyde.Repositories;
import org.springframework.data.repository.CrudRepository;
import ovh.herisson.Clyde.Tables.Token;
import ovh.herisson.Clyde.Tables.User;
import java.util.ArrayList;
public interface TokenRepository extends CrudRepository<Token,Long> {
Token getByToken(String token);
ArrayList <Token> getByUserOrderByExpirationDate(User user);
}

View File

@ -0,0 +1,13 @@
package ovh.herisson.Clyde.Repositories;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import ovh.herisson.Clyde.Tables.Curriculum;
import ovh.herisson.Clyde.Tables.User;
import ovh.herisson.Clyde.Tables.UserCurriculum;
public interface UserCurriculumRepository extends CrudRepository<UserCurriculum, Long> {
@Query("select uc.curriculum from UserCurriculum uc where uc.user = ?1")
Curriculum findByUser(User student);
}

View File

@ -4,13 +4,20 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import ovh.herisson.Clyde.Tables.User;
import java.util.List;
public interface UserRepository extends CrudRepository<User, Long> {
User findById(long id);
/**
@Query(value = "select a.* from Users a ",nativeQuery = true)
Iterable<User> findAllUsers();**/
User findByEmail(String email);
@Query("select u from User u where u.role = ovh.herisson.Clyde.Tables.Role.Teacher")
Iterable<User> findAllTeachers();
@Query("select u from User u where u.role = ovh.herisson.Clyde.Tables.Role.Student")
Iterable<User> findAllStudents();
@Query("select u from User u where u.role <> ovh.herisson.Clyde.Tables.Role.Admin")
Iterable<User> findAllExceptAdmins();
}

View File

@ -0,0 +1,3 @@
package ovh.herisson.Clyde.Responses;
public record PingResponse(int id, String txt){};

View File

@ -0,0 +1,12 @@
package ovh.herisson.Clyde.Responses;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
public class UnauthorizedResponse<T> extends ResponseEntity<T> {
public UnauthorizedResponse(T message) {
super(message,HttpStatus.UNAUTHORIZED);
}
}

View File

@ -0,0 +1,53 @@
package ovh.herisson.Clyde.Services;
import org.springframework.stereotype.Service;
import ovh.herisson.Clyde.Tables.*;
import java.util.Date;
@Service
public class AuthenticatorService {
private final TokenService tokenService;
private final UserService userService;
private final InscriptionService inscriptionService;
public AuthenticatorService(TokenService tokenService, UserService userService, InscriptionService inscriptionService){
this.tokenService = tokenService;
this.userService = userService;
this.inscriptionService = inscriptionService;
}
public User getUserFromToken(String token){
return tokenService.getUserFromToken(token);
}
public String login(String identifier, String password, Date expirationDate){
User user = userService.getUser(identifier);
if (user == null){return null;}
if (!userService.checkPassword(user,password)){return null;}
String token = tokenService.generateNewToken();
tokenService.saveToken(new Token(user, token,expirationDate));
return token;
}
public InscriptionRequest register(InscriptionRequest inscriptionRequest) {
inscriptionRequest.setState(RequestState.Pending);
return inscriptionService.save(inscriptionRequest);
}
public boolean isNotIn(Role[] roles, String token){
if (token == null)
return true;
User poster = getUserFromToken(token);
if (poster == null) return true;
for (Role r:roles){
if (poster.getRole() == r)
return false;
}
return true;
}
}

View File

@ -0,0 +1,83 @@
package ovh.herisson.Clyde.Services;
import org.springframework.stereotype.Service;
import ovh.herisson.Clyde.Repositories.CourseRepository;
import ovh.herisson.Clyde.Tables.Course;
import ovh.herisson.Clyde.Tables.Role;
import ovh.herisson.Clyde.Tables.User;
import java.util.Map;
@Service
public class CourseService {
private final CourseRepository courseRepo;
public CourseService(CourseRepository courseRepo) {
this.courseRepo = courseRepo;
}
public Course save(Course course){
if (course.getOwner().getRole() != Role.Teacher)
return null;
return courseRepo.save(course);
}
public Course findById(long id){
return courseRepo.findById(id);
}
public Iterable<Course> findAll() {
return courseRepo.findAll();
}
public Iterable<Course> findOwnedCourses(User userFromToken) {
return courseRepo.findAllOwnedCoures(userFromToken);
}
public boolean modifyData(long id, Map<String, Object> updates, Role role) {
Course target = courseRepo.findById(id);
if (target == null)
return false;
if (role == Role.Teacher){
for (Map.Entry<String, Object> entry : updates.entrySet()){
if (entry.getKey().equals("title")){
target.setTitle((String) entry.getValue());
courseRepo.save(target);
return true;
}
}
}
if (role != Role.Secretary)
return false;
for (Map.Entry<String ,Object> entry: updates.entrySet()){
switch (entry.getKey()){
case "title":
target.setTitle((String) entry.getValue());
break;
case "credits":
target.setCredits((Integer) entry.getValue());
break;
case "owner":
if (((User) entry.getValue() ).getRole() != Role.Teacher)
break;
target.setOwner((User) entry.getValue());
break;
}
}
courseRepo.save(target);
return true;
}
public void delete(Course course) {
courseRepo.delete(course);
}
}

View File

@ -0,0 +1,93 @@
package ovh.herisson.Clyde.Services;
import org.springframework.stereotype.Service;
import ovh.herisson.Clyde.Repositories.CourseRepository;
import ovh.herisson.Clyde.Repositories.CurriculumCourseRepository;
import ovh.herisson.Clyde.Repositories.CurriculumRepository;
import ovh.herisson.Clyde.Tables.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@Service
public class CurriculumCourseService {
private final CurriculumCourseRepository curriculumCourseRepo;
private final CourseRepository courseRepo;
private final CurriculumRepository curriculumRepo;
public CurriculumCourseService(CurriculumCourseRepository curriculumCourseRepository, CourseRepository courseRepo, CurriculumRepository curriculumRepo) {
this.curriculumCourseRepo = curriculumCourseRepository;
this.courseRepo = courseRepo;
this.curriculumRepo = curriculumRepo;
}
public void save(CurriculumCourse curriculumCourse){
curriculumCourseRepo.save(curriculumCourse);
}
public Map<String, Object> getDepthCurriculum(Curriculum curriculum){
if (curriculum == null)
return null;
HashMap<String ,Object> toReturn = new HashMap<>();
ArrayList<Map<String ,Object>> courses = new ArrayList<>();
Iterable<Course> foundCourses = curriculumCourseRepo.findCoursesByCurriculum(curriculum);
for (Course c: foundCourses){
courses.add(ProtectionService.courseWithoutPassword(c));
}
toReturn.put("courses",courses);
toReturn.put("curriculumId", curriculum.getCurriculumId());
toReturn.put("year", curriculum.getYear());
toReturn.put("option", curriculum.getOption());
return toReturn;
}
public Iterable<Map<String, Object>> getAllDepthCurriculum(){
ArrayList<Map<String,Object>> toReturn = new ArrayList<>();
for (Curriculum curriculum : curriculumRepo.findAll()){
toReturn.add(getDepthCurriculum(curriculum));
}
return toReturn;
}
/** tries to add all courses to the curriculum
*
* @param coursesIds the ids of the courses to be added
* @param curriculum the curriculum to add the courses to
* @return if the changes were made
*/
public boolean saveAll(Iterable<Long> coursesIds, Curriculum curriculum) {
if (curriculum == null || coursesIds == null)
return false;
ArrayList<Course> toAdd = new ArrayList<>();
for (Long courseId : coursesIds){
Course course = courseRepo.findById((long) courseId);
if (course == null)
return false;
if (!toAdd.contains(course))
toAdd.add(course);
}
for (Course course : toAdd){
curriculumCourseRepo.save(new CurriculumCourse(curriculum,course));
}
return true;
}
}

View File

@ -0,0 +1,25 @@
package ovh.herisson.Clyde.Services;
import org.springframework.stereotype.Service;
import ovh.herisson.Clyde.Repositories.CurriculumRepository;
import ovh.herisson.Clyde.Tables.Curriculum;
@Service
public class CurriculumService {
private final CurriculumRepository curriculumRepo;
public CurriculumService(CurriculumRepository curriculumRepo){
this.curriculumRepo = curriculumRepo;
}
public Curriculum save(Curriculum curriculum){
return curriculumRepo.save(curriculum);
}
public Curriculum findById(long id){
return curriculumRepo.findById(id);
}
public void delete(Curriculum curriculum) {
curriculumRepo.delete(curriculum);
}
}

View File

@ -0,0 +1,94 @@
package ovh.herisson.Clyde.Services;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import ovh.herisson.Clyde.Repositories.CurriculumRepository;
import ovh.herisson.Clyde.Repositories.InscriptionRepository;
import ovh.herisson.Clyde.Repositories.UserCurriculumRepository;
import ovh.herisson.Clyde.Repositories.UserRepository;
import ovh.herisson.Clyde.Tables.InscriptionRequest;
import ovh.herisson.Clyde.Tables.RequestState;
import ovh.herisson.Clyde.Tables.User;
import ovh.herisson.Clyde.Tables.UserCurriculum;
@Service
public class InscriptionService {
private final InscriptionRepository inscriptionRepo;
private final UserRepository userRepo;
private final UserCurriculumRepository userCurriculumRepo;
private final CurriculumRepository curriculumRepo;
private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
public InscriptionService(InscriptionRepository inscriptionRepo, UserRepository userRepo, UserCurriculumRepository userCurriculumRepo, CurriculumRepository curriculumRepo){
this.inscriptionRepo = inscriptionRepo;
this.userRepo = userRepo;
this.userCurriculumRepo = userCurriculumRepo;
this.curriculumRepo = curriculumRepo;
}
public InscriptionRequest save(InscriptionRequest inscriptionRequest){
inscriptionRequest.setPassword(passwordEncoder.encode(inscriptionRequest.getPassword()));
return inscriptionRepo.save(inscriptionRequest);
}
public InscriptionRequest getById(long id){
return inscriptionRepo.findById(id);
}
public Iterable<InscriptionRequest> getAll(){
return inscriptionRepo.findAll();
}
public boolean modifyState(long id, RequestState requestState) {
InscriptionRequest inscrRequest = getById(id);
if (inscrRequest == null)
return false;
// if th state is the same we don't send an email
if (requestState == inscrRequest.getState())
return false;
/** todo send an email to tell the poster of the inscrRequest (inscrRequest.getEmail())
* to notify them that the state of their request changed
* FooEmailFormat toSend = (String.format("Your request state changed from %s to %s"),
* inscrRequest.getState(), requestState)
* FooEmailSender.send(toSend, inscrRequest.getEmail())
*/
//saves the user from the request if accepted
if (requestState == RequestState.Accepted)
{
if (curriculumRepo.findById(inscrRequest.getCurriculumId()) == null)
return false;
User userFromRequest = new User(
inscrRequest.getLastName(),
inscrRequest.getFirstName(),
inscrRequest.getEmail(),
inscrRequest.getAddress(),
inscrRequest.getCountry(),
inscrRequest.getBirthDate(),
inscrRequest.getProfilePicture(),
inscrRequest.getPassword()
);
userRepo.save(userFromRequest);
userCurriculumRepo.save(new UserCurriculum(userFromRequest, curriculumRepo.findById(inscrRequest.getCurriculumId())));
}
inscrRequest.setState(requestState);
save(inscrRequest);
return true;
}
public void delete(InscriptionRequest toDelete) {
inscriptionRepo.delete(toDelete);
}
}

View File

@ -0,0 +1,105 @@
package ovh.herisson.Clyde.Services;
import ovh.herisson.Clyde.Tables.Course;
import ovh.herisson.Clyde.Tables.InscriptionRequest;
import ovh.herisson.Clyde.Tables.User;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class ProtectionService {
/** return user's data except password
* @param user the user to return
* @return all the user data without the password
*/
public static HashMap<String,Object> userWithoutPassword(User user){
if (user ==null)
return null;
HashMap<String,Object> toReturn = new HashMap<>();
toReturn.put("regNo",user.getRegNo());
toReturn.put("lastName",user.getLastName());
toReturn.put("firstName",user.getFirstName());
toReturn.put("email", user.getEmail());
toReturn.put("address",user.getAddress());
toReturn.put("birthDate",user.getBirthDate());
toReturn.put("country",user.getCountry());
toReturn.put("profilePictureUrl",user.getProfilePictureUrl());
toReturn.put("role",user.getRole());
return toReturn;
}
public static Iterable<HashMap<String ,Object>>usersWithoutPasswords(Iterable<User> users){
ArrayList<HashMap<String,Object>> toReturn = new ArrayList<>();
for (User u : users){
toReturn.add(userWithoutPassword(u));
}
return toReturn;
}
public static HashMap<String,Object> courseWithoutPassword(Course course){
if (course == null)
return null;
HashMap<String ,Object> toReturn = new HashMap<>();
toReturn.put("courseId",course.getCourseID());
toReturn.put("credits",course.getCredits());
toReturn.put("title", course.getTitle());
toReturn.put("owner", userWithoutPassword(course.getOwner()));
return toReturn;
}
public static Iterable<HashMap<String ,Object>> coursesWithoutPasswords(Iterable<Course> courses){
ArrayList<HashMap<String,Object>> toReturn = new ArrayList<>();
for (Course course: courses){
toReturn.add(ProtectionService.courseWithoutPassword(course));
}
return toReturn;
}
public static Map<String, Object> requestWithoutPassword(InscriptionRequest inscriptionRequest) {
if (inscriptionRequest == null)
return null;
Map<String, Object> toReturn = new HashMap<>();
toReturn.put("id", inscriptionRequest.getId());
toReturn.put("lastName", inscriptionRequest.getLastName());
toReturn.put("firstName", inscriptionRequest.getFirstName());
toReturn.put("address", inscriptionRequest.getAddress());
toReturn.put("email",inscriptionRequest.getEmail());
toReturn.put("birthDate", inscriptionRequest.getBirthDate());
toReturn.put("country", inscriptionRequest.getCountry());
toReturn.put("curriculum", inscriptionRequest.getCurriculumId());
toReturn.put("state", inscriptionRequest.getState());
toReturn.put("profilePictureUrl", inscriptionRequest.getProfilePicture());
return toReturn;
}
public static Iterable<Map<String ,Object>> requestsWithoutPasswords(Iterable<InscriptionRequest> inscriptionRequests){
ArrayList<Map<String,Object>> toReturn = new ArrayList<>();
for (InscriptionRequest i:inscriptionRequests){
toReturn.add(requestWithoutPassword(i));
}
return toReturn;
}
}

View File

@ -0,0 +1,69 @@
package ovh.herisson.Clyde.Services;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import ovh.herisson.Clyde.Repositories.FileRepository;
import ovh.herisson.Clyde.Tables.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Objects;
import java.util.UUID;
@Service
public class StorageService {
private final Path rootLocation = Paths.get("cdn/");
private final FileRepository fileRepo;
public StorageService(FileRepository filerepo){
this.fileRepo = filerepo;
if(!Files.exists(rootLocation)){
try {
Files.createDirectories(rootLocation);
} catch(IOException e){
e.printStackTrace();
}
}
}
public StorageFile store(MultipartFile file, FileType fileType) {
if (file == null || file.getOriginalFilename() == null)
return null;
if (file.getOriginalFilename().isEmpty()){return null;}
UUID uuid = UUID.randomUUID();
String stringUuid = uuid + "." + file.getOriginalFilename().split("\\.",2)[1];
try {
if (file.isEmpty()) {
return null;
}
Path destinationFile = this.rootLocation.resolve(Paths.get(stringUuid));
Files.copy(file.getInputStream(), destinationFile,StandardCopyOption.REPLACE_EXISTING);
}
catch (IOException e) {
return null;
}
String url = this.rootLocation.resolve(Paths.get(Objects.requireNonNull(stringUuid)))
.normalize().toString();
return fileRepo.save(new StorageFile(file.getOriginalFilename(),url, fileType));
}
public void delete(StorageFile file) throws SecurityException {
File f = new File(file.getUrl());
f.delete();
//Delete l'entité
fileRepo.delete(file);
}
}

View File

@ -0,0 +1,53 @@
package ovh.herisson.Clyde.Services;
import org.springframework.stereotype.Controller;
import ovh.herisson.Clyde.Repositories.TeacherCourseRepository;
import ovh.herisson.Clyde.Repositories.UserRepository;
import ovh.herisson.Clyde.Tables.Course;
import ovh.herisson.Clyde.Tables.Role;
import ovh.herisson.Clyde.Tables.TeacherCourse;
import ovh.herisson.Clyde.Tables.User;
import java.util.ArrayList;
@Controller
public class TeacherCourseService {
private final TeacherCourseRepository teacherCourseRepo;
private final UserRepository userRepo;
public TeacherCourseService(TeacherCourseRepository teacherCourseRepo, UserRepository userRepo) {
this.teacherCourseRepo = teacherCourseRepo;
this.userRepo = userRepo;
}
public Iterable<User> findCourseAssistants(Course course) {
if (course == null)
return null;
return teacherCourseRepo.findAllAssistantOfCourse(course);
}
public boolean saveAll(Iterable<Long> teacherIds, Course course){
if (course == null || teacherIds == null)
return false;
ArrayList<User> toAdd = new ArrayList<>();
for (Long teacherId : teacherIds){
User teacher = userRepo.findById((long) teacherId);
if ( teacher== null){
return false;
}
if (!toAdd.contains(teacher) && teacher.getRole() == Role.Teacher)
{
toAdd.add(teacher);
}
}
for (User teacher: toAdd){
teacherCourseRepo.save(new TeacherCourse(teacher,course));
}
return true;
}
}

View File

@ -0,0 +1,74 @@
package ovh.herisson.Clyde.Services;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import ovh.herisson.Clyde.Repositories.TokenRepository;
import ovh.herisson.Clyde.Tables.Token;
import ovh.herisson.Clyde.Tables.User;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Calendar;
@Service
public class TokenService {
private final TokenRepository tokenRepo;
public TokenService(TokenRepository tokenRepo){
this.tokenRepo = tokenRepo;
}
public Iterable<Token> getAllTokens() {
return tokenRepo.findAll();
}
public String generateNewToken(){
byte[] bytes = new byte[64];
new SecureRandom().nextBytes(bytes);
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) (((bytes[i]+256)%256 %95+ 32));
}
// will never end up in the catch because of the way that SecureRandom.nextBytes is implemented
try {
return new String(Base64.getEncoder().encode(bytes),"ISO_8859_1");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
public User getUserFromToken(String token) {
Token tokenRep = tokenRepo.getByToken(token);
if (tokenRep == null)
return null;
return tokenRep.getUser();
}
public void saveToken(Token token){
//Si l'utilisateur a déja 5 token delete celui qui devait expirer le plus vite
ArrayList<Token> tokenList = tokenRepo.getByUserOrderByExpirationDate(token.getUser());
while(tokenList.size() >= 5){
tokenRepo.delete(tokenList.getFirst());
tokenList.remove(tokenList.getFirst());
}
tokenRepo.save(token);
}
//Tous les jours a minuit
@Scheduled(cron = "0 0 0 * * ?")
public void autoDeleteToken() {
for (Token t: tokenRepo.findAll()){
Calendar cal = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal2.setTime(t.getExpirationDate());
if (cal.compareTo(cal2) >= 0){
tokenRepo.delete(t);
}
}
}
}

View File

@ -0,0 +1,20 @@
package ovh.herisson.Clyde.Services;
import org.springframework.stereotype.Service;
import ovh.herisson.Clyde.Repositories.UserCurriculumRepository;
import ovh.herisson.Clyde.Tables.Curriculum;
import ovh.herisson.Clyde.Tables.User;
@Service
public class UserCurriculumService {
private final UserCurriculumRepository userCurriculumRepository;
public UserCurriculumService(UserCurriculumRepository userCurriculumRepository) {
this.userCurriculumRepository = userCurriculumRepository;
}
public Curriculum findByUser(User student){
return userCurriculumRepository.findByUser(student);
}
}

View File

@ -0,0 +1,134 @@
package ovh.herisson.Clyde.Services;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import ovh.herisson.Clyde.Repositories.UserRepository;
import ovh.herisson.Clyde.Tables.Role;
import ovh.herisson.Clyde.Tables.User;
import java.util.*;
@Service
public class UserService {
private final UserRepository userRepo;
private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
public UserService(UserRepository userRepo){
this.userRepo = userRepo;
}
/** return the user identified by th identifier
*
* @param identifier can be an email or the RegNo
* @return the identified user
*/
public User getUser(String identifier){
if (identifier == null)
return null;
try {
int id = Integer.parseInt(identifier);
return userRepo.findById(id);
}
catch (NumberFormatException nfe){
return userRepo.findByEmail(identifier);
}
}
/** modify the target data
* verify the permission of modifying from the poster
*
* @param poster the user wanting to modify target's data
* @param updates the changes to be made
* @param targetId the id of the user to update
* @return if the changes were done or not
*/
public boolean modifyData(long targetId, Map<String ,Object> updates, User poster){
User target = userRepo.findById(targetId);
if (target == null)
return false;
if (poster.getRegNo().equals(target.getRegNo())){
for (Map.Entry<String, Object> entry : updates.entrySet()){
switch (entry.getKey()){
case "firstName":
target.setFirstName((String) entry.getValue());
break;
case "lastName":
target.setLastName((String) entry.getValue());
break;
case "email":
target.setEmail((String) entry.getValue());
break;
case "address":
target.setAddress((String) entry.getValue());
break;
case "country":
target.setCountry((String) entry.getValue());
break;
case "birthDate":
target.setBirthDate((Date) entry.getValue());
break;
case "profilePictureUrl":
target.setProfilePictureUrl((String) entry.getValue());
break;
case "password":
target.setPassword(passwordEncoder.encode((String) entry.getValue()));
break;
}
}
userRepo.save(target);
return true;
}
// the secretary can change roles (for example if a student becomes a teacher)
else if (poster.getRole() == Role.Secretary)
{
for (Map.Entry<String, Object> entry : updates.entrySet()){
if ( entry.getKey().equals("role")) {
if (entry.getValue() == Role.Admin) {return false;}
target.setRole((Role) entry.getValue());
userRepo.save(target);
return true;
}
}
}
return false;
}
public boolean checkPassword(User user, String tryingPassword){
return passwordEncoder.matches(tryingPassword, user.getPassword());
}
public User save(User user){
user.setPassword(passwordEncoder.encode(user.getPassword()));
return userRepo.save(user);
}
public Iterable<User> getAll(){
return userRepo.findAll();
}
public Iterable<User> getAllExceptAdmins(){
return userRepo.findAllExceptAdmins();
}
public Iterable<User> getAllTeachers (){return userRepo.findAllTeachers();}
public Iterable<User> getAllStudents(){return userRepo.findAllStudents();}
public User getUserById(long id) {
return userRepo.findById(id);
}
public void delete(User user) {
userRepo.delete(user);
}
}

View File

@ -0,0 +1,23 @@
package ovh.herisson.Clyde.Tables;
public enum Applications {
// without any token
Login,
// with any token
Profile,
// Students and higher authorization
Msg,
Forum,
Rdv,
// teachers and Secretary authorization
ManageCourses,
UsersList,
// InscriptionService authorization
Inscription,
StudentsList
}

View File

@ -1,9 +1,8 @@
package ovh.herisson.Clyde.Tables;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.*;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
@Entity
public class Course {
@ -12,12 +11,16 @@ public class Course {
private int courseID;
private int credits;
private String title;
private String faculty;
public Course(int credits, String title, String faculty){
@ManyToOne(fetch = FetchType.EAGER)
@OnDelete(action = OnDeleteAction.SET_NULL)
@JoinColumn(name = "Users")
private User owner;
public Course(int credits, String title, User owner){
this.credits = credits;
this.title = title;
this.faculty = faculty;
this.owner = owner;
}
public Course() {}
@ -34,14 +37,6 @@ public class Course {
this.credits = credits;
}
public String getFaculty() {
return faculty;
}
public void setFaculty(String faculty){
this.faculty = faculty;
}
public String getTitle() {
return title;
}
@ -49,4 +44,12 @@ public class Course {
public void setTitle(String title){
this.title = title;
}
public User getOwner() {
return owner;
}
public void setOwner(User owner) {
this.owner = owner;
}
}

View File

@ -6,22 +6,21 @@ import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Cursus {
public class Curriculum {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int cursusId;
private int curriculumId;
private int year;
private String option;
public Cursus(int year, String option){
public Curriculum(int year, String option){
this.year = year;
this.option = option;
}
public Cursus() {}
public Curriculum() {}
public int getCursusId(){
return this.cursusId;
public int getCurriculumId(){
return this.curriculumId;
}
public int getYear(){

View File

@ -0,0 +1,49 @@
package ovh.herisson.Clyde.Tables;
import jakarta.persistence.*;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
@Entity
public class CurriculumCourse {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "Curriculum")
@OnDelete(action = OnDeleteAction.CASCADE)
private Curriculum curriculum;
@ManyToOne(fetch = FetchType.EAGER)
@OnDelete(action = OnDeleteAction.CASCADE)
@JoinColumn(name = "Course")
private Course course;
public CurriculumCourse(Curriculum curriculum, Course course){
this.curriculum = curriculum;
this.course = course;
}
public CurriculumCourse() {}
public int getId() {
return id;
}
public Course getCourse() {
return course;
}
public void setCourse(Course course){
this.course = course;
}
public Curriculum getCurriculum() {
return curriculum;
}
public void setCurriculum(Curriculum curriculum) {
this.curriculum = curriculum;
}
}

View File

@ -1,42 +0,0 @@
package ovh.herisson.Clyde.Tables;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class CursusCourse {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private int cursusId;
private int courseId;
public CursusCourse(int cursusId, int courseId){
this.cursusId = cursusId;
this.courseId = courseId;
}
public CursusCourse() {}
public int getId() {
return id;
}
public int getCourseId() {
return courseId;
}
public void setCourseId(int courseId){
this.courseId = courseId;
}
public int getCursusId() {
return cursusId;
}
public void setCursusId(int cursusId) {
this.cursusId = cursusId;
}
}

View File

@ -0,0 +1,8 @@
package ovh.herisson.Clyde.Tables;
public enum FileType {
ProfilePicture,
EducationCertificate
}

View File

@ -0,0 +1,121 @@
package ovh.herisson.Clyde.Tables;
import jakarta.persistence.*;
import java.util.Date;
@Entity
public class InscriptionRequest {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String firstName;
private String lastName;
private String address;
private String email;
private String country;
private Date birthDate;
private Long curriculumId;
private RequestState state;
private String profilePicture;
private String password;
public InscriptionRequest(){}
public InscriptionRequest(String lastName, String firstName, String address, String email, String country, Date birthDate,Long curriculumId, RequestState state, String profilePicture, String password){
this.lastName = lastName;
this.firstName = firstName;
this.address = address;
this.email = email;
this.country = country;
this.birthDate = birthDate;
this.curriculumId = curriculumId;
this.state = state;
this.profilePicture = profilePicture;
this.password = password;
}
public int getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public Date getBirthDate() {
return birthDate;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
public long getCurriculumId() {
return curriculumId;
}
public void setCurriculumId(long curriculum) {
this.curriculumId = curriculum;
}
public RequestState getState() {
return state;
}
public void setState(RequestState state) {
this.state = state;
}
public String getProfilePicture() {
return profilePicture;
}
public void setProfilePicture(String profilePicture) {
this.profilePicture = profilePicture;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

View File

@ -0,0 +1,78 @@
package ovh.herisson.Clyde.Tables;
import jakarta.persistence.*;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
@Entity
public class ReInscriptionRequest {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@ManyToOne
@JoinColumn(name = "Users")
@OnDelete(action = OnDeleteAction.CASCADE)
private User user;
@ManyToOne
@JoinColumn(name = "Curriculum")
@OnDelete(action = OnDeleteAction.CASCADE)
private Curriculum newCurriculum;
private RequestState state;
//Permet de différencier les demandes de changement et une réinscription dans le même Curriculum
//Pour la réinscription on va le mettre a 0
private boolean type = false;
public ReInscriptionRequest(){}
public ReInscriptionRequest(User user, Curriculum newCurriculum, RequestState state, boolean type){
this.user = user;
this.newCurriculum = newCurriculum;
this.state = state;
this.type = type;
}
public ReInscriptionRequest(User user, Curriculum newCurriculum, RequestState state){
this.user = user;
this.newCurriculum = newCurriculum;
this.state = state;
}
public int getId() {
return id;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Curriculum getNewCurriculum() {
return newCurriculum;
}
public void setNewCurriculum(Curriculum newCurriculum) {
this.newCurriculum = newCurriculum;
}
public RequestState getState() {
return state;
}
public void setState(RequestState state) {
this.state = state;
}
public boolean isType() {
return type;
}
public void setType(boolean type) {
this.type = type;
}
}

View File

@ -0,0 +1,7 @@
package ovh.herisson.Clyde.Tables;
public enum RequestState {
Accepted,
Refused,
Pending
}

View File

@ -2,6 +2,8 @@ package ovh.herisson.Clyde.Tables;
public enum Role {
Teacher,
Student;
}
Student,
Admin,
InscriptionService,
Secretary
}

View File

@ -1,42 +0,0 @@
package ovh.herisson.Clyde.Tables;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Secretary {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private int regNo;
private String faculty;
public Secretary(int regNo, String faculty){
this.regNo = regNo;
this.faculty = faculty;
}
public Secretary() {}
public int getId() {
return id;
}
public int getRegNo() {
return regNo;
}
public void setRegNo(int regNo) {
this.regNo = regNo;
}
public String getFaculty() {
return faculty;
}
public void setFaculty(String faculty) {
this.faculty = faculty;
}
}

View File

@ -0,0 +1,59 @@
package ovh.herisson.Clyde.Tables;
import jakarta.persistence.*;
@Entity
public class StorageFile {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String url;
private FileType fileType;
public StorageFile(String name, String url, FileType fileType){
this.name = name;
this.url = url;
this.fileType = fileType;
}
public StorageFile(){}
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public FileType getFileType() {
return fileType;
}
public void setFileType(FileType fileType) {
this.fileType = fileType;
}
}

View File

@ -0,0 +1,51 @@
package ovh.herisson.Clyde.Tables;
import jakarta.persistence.*;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
@Entity
public class TeacherCourse {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@ManyToOne(fetch = FetchType.EAGER)
@OnDelete(action = OnDeleteAction.CASCADE)
@JoinColumn(name = "Users")
private User user;
@ManyToOne(fetch = FetchType.EAGER)
@OnDelete(action = OnDeleteAction.CASCADE)
@JoinColumn(name = "Course")
private Course course;
public TeacherCourse(User user, Course course){
this.user = user;
this.course = course;
}
public TeacherCourse() {}
public int getId() {
return id;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}
}

View File

@ -1,54 +0,0 @@
package ovh.herisson.Clyde.Tables;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class TeacherGivenCourse {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private int regNo;
private int courseId;
//This flag helps make the difference between an assistant or a Teacher (who owns the course)
private boolean owned;
public TeacherGivenCourse(int regNo, int courseId, boolean owned){
this.regNo = regNo;
this.courseId = courseId;
this.owned = owned;
}
public TeacherGivenCourse() {}
public int getId() {
return id;
}
public int getRegNo() {
return regNo;
}
public void setRegNo(int regNo) {
this.regNo = regNo;
}
public int getCourseId() {
return courseId;
}
public void setCourseId(int courseId) {
this.courseId = courseId;
}
public boolean isOwned() {
return owned;
}
public void setOwned(boolean owned) {
this.owned = owned;
}
}

View File

@ -0,0 +1,56 @@
package ovh.herisson.Clyde.Tables;
import jakarta.persistence.*;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import java.util.Date;
@Entity
public class Token {
@GeneratedValue(strategy = GenerationType.AUTO)
@Id
private int id;
@ManyToOne(fetch = FetchType.EAGER)
@OnDelete(action = OnDeleteAction.CASCADE)
@JoinColumn(name ="Users")
private User user;
private String token;
private Date expirationDate;
public Token(User user, String token, Date expirationDate){
this.user = user;
this.token = token;
this.expirationDate = expirationDate;
}
public Token(){}
public int getId() {
return id;
}
public User getUser() {
return user;
}
public void setUser(User regNo) {
this.user = regNo;
}
public String getToken(){
return token;
}
public void setToken(String data) {
this.token = data;
}
public void setExpirationDate(Date date){
this.expirationDate = date;
}
public Date getExpirationDate(){
return expirationDate;
}
}

View File

@ -1,41 +1,55 @@
package ovh.herisson.Clyde.Tables;
import jakarta.persistence.*;
import java.util.Date;
//Classe représentant un utilisateur l'attribut password demande surement un peu de rafinement niveau sécurité
//et l'attribut tokenApi doit encore être ajouté vu qu'il faut en discuter
@Entity
//Je rajoute un s au nom de la table pour éviter les conflits avec les mots réservés
@Table(name = "Users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int regNo;
private Long regNo;
private String lastName;
private String firstName;
@Column(unique = true)
private String email;
private String adress;
private String address;
private String country;
private Date birthDate;
private String profilePictureUrl;
private ovh.herisson.Clyde.Tables.Role role;
private String password;
public User(String lastName, String firstName, String email, String adress, String country, Date birthDate, Role role){
public User(String lastName, String firstName, String email, String address,
String country, Date birthDate, String profilePictureUrl, Role role, String password)
{
this.lastName = lastName;
this.firstName = firstName;
this.email = email;
this.adress = adress;
this.address = address;
this.country = country;
this.birthDate = birthDate;
this.profilePictureUrl = profilePictureUrl;
this.role = role;
this.password = password;
}
public User(String lastName, String firstName, String email, String address,
String country, Date birthDate, String profilePictureUrl, String password)
{
this.lastName = lastName;
this.firstName = firstName;
this.email = email;
this.address = address;
this.country = country;
this.birthDate = birthDate;
this.profilePictureUrl = profilePictureUrl;
this.password = password;
this.role = Role.Student;
}
public User() {}
public int getRegNo(){
public Long getRegNo(){
return this.regNo;
}
public String getLastName() {
@ -62,12 +76,12 @@ public class User {
this.email = email;
}
public String getAdress() {
return adress;
public String getAddress() {
return address;
}
public void setAdress(String adress) {
this.adress = adress;
public void setAddress(String address) {
this.address = address;
}
public String getCountry() {
@ -86,6 +100,11 @@ public class User {
this.birthDate = birthDate;
}
public String getProfilePictureUrl(){return this.profilePictureUrl;}
public void setProfilePictureUrl(String profilePictureUrl){
this.profilePictureUrl = profilePictureUrl;
}
public ovh.herisson.Clyde.Tables.Role getRole() {
return role;
}
@ -93,4 +112,11 @@ public class User {
public void setRole(ovh.herisson.Clyde.Tables.Role role) {
this.role = role;
}
public String getPassword(){
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

View File

@ -0,0 +1,50 @@
package ovh.herisson.Clyde.Tables;
import jakarta.persistence.*;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
@Entity
public class UserCurriculum {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
//Un étudiant peut avoir plusieurs curriculums
@ManyToOne(fetch = FetchType.EAGER)
@OnDelete(action = OnDeleteAction.CASCADE)
@JoinColumn(name = "Users")
private User user;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "Curriculum")
@OnDelete(action = OnDeleteAction.CASCADE)
private Curriculum curriculum;
public UserCurriculum(User user, Curriculum curriculum){
this.user = user;
this.curriculum = curriculum;
}
public UserCurriculum() {}
public int getId() {
return id;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Curriculum getCurriculum() {
return curriculum;
}
public void setCurriculum(Curriculum curriculum) {
this.curriculum = curriculum;
}
}

View File

@ -1,40 +0,0 @@
package ovh.herisson.Clyde.Tables;
import jakarta.persistence.*;
@Entity
@Table(name = "User_Cursus")
public class UserCursus {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private int regNo;
private int cursusId;
public UserCursus(int regNo, int cursusId){
this.regNo = regNo;
this.cursusId = cursusId;
}
public UserCursus() {}
public int getId() {
return id;
}
public int getRegNo() {
return regNo;
}
public void setRegNo(int regNo) {
this.regNo = regNo;
}
public int getCursusId() {
return cursusId;
}
public void setCursusId(int cursusId) {
this.cursusId = cursusId;
}
}

View File

@ -1,2 +1,3 @@
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.sql.init.mode=always

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,12 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Clyde's api</title>
<script type="module" crossorigin src="assets/index-BP8s9Pse.js"></script>
<link rel="stylesheet" crossorigin href="assets/index-rZb_qAw7.css">
</head>
<body>
<div id="app"></div>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@ class ClydeApplicationTests {
@Test
void contextLoads() {
}
}

View File

@ -0,0 +1,105 @@
package ovh.herisson.Clyde.Endpoints;
import com.github.dockerjava.api.model.ExposedPort;
import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.PortBinding;
import com.github.dockerjava.api.model.Ports;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import org.junit.Assert;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.ActiveProfiles;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import ovh.herisson.Clyde.ClydeApplication;
import ovh.herisson.Clyde.EndPoints.StorageController;
import ovh.herisson.Clyde.Repositories.FileRepository;
import ovh.herisson.Clyde.Services.StorageService;
import ovh.herisson.Clyde.Tables.FileType;
import ovh.herisson.Clyde.Tables.StorageFile;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import static io.restassured.RestAssured.with;
@Testcontainers
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles(value ="dev")
public class StorageControllerTest {
@LocalServerPort
private Integer port;
@Autowired
private ClydeApplication controller;
@Autowired
private StorageController storageController;
@Autowired
private StorageService storageService;
@Autowired
private FileRepository fileRepository;
@Container
@ServiceConnection
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:alpine")
.withDatabaseName("clyde")
.withUsername("devel")
.withPassword("devel")
.withCreateContainerCmdModifier(cmd -> cmd.withHostConfig(new HostConfig().withPortBindings(new PortBinding(Ports.Binding.bindPort(5442), new ExposedPort(5432)))));
@BeforeAll
static void beforeAll(){
postgres.start();
}
@AfterAll
static void afterAll(){
postgres.stop();
}
@BeforeEach
void setup(){
RestAssured.baseURI = "http://localhost:" + port;
}
@AfterEach
void afterEach(){
fileRepository.deleteAll();
}
@Test
public void uploadFileTest() throws IOException {
File mmf = new File("test.txt");
mmf.createNewFile();
FileWriter fw = new FileWriter(mmf);
fw.write("Ceci est un test");
fw.close();
with().multiPart("file", mmf).pathParam("fileType", FileType.ProfilePicture).when().request("POST", "/upload/{fileType}").then().statusCode(200);
StorageFile sf = fileRepository.getStorageFileByName("test.txt");
//On vérifie que le fichier a bien été stocké dans la db
Assert.assertFalse(sf == null);
//On vérifie que le fichier a bel et bien été stocké dans le dossier cdn
File extFile = new File(sf.getUrl());
Assert.assertTrue(extFile.exists());
Assert.assertEquals("cdn", extFile.getParent());
//On delete tranquillement les fichiers (la méthode delete a déja été testée dans StorageServiceTest)
storageService.delete(sf);
mmf.delete();
}
}

View File

@ -0,0 +1,149 @@
package ovh.herisson.Clyde.Endpoints;
import com.github.dockerjava.api.model.ExposedPort;
import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.PortBinding;
import com.github.dockerjava.api.model.Ports;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import org.junit.Assert;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.test.context.ActiveProfiles;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import ovh.herisson.Clyde.ClydeApplication;
import ovh.herisson.Clyde.Repositories.TokenRepository;
import ovh.herisson.Clyde.Repositories.UserRepository;
import ovh.herisson.Clyde.Responses.UnauthorizedResponse;
import ovh.herisson.Clyde.Services.TokenService;
import ovh.herisson.Clyde.Tables.Role;
import ovh.herisson.Clyde.Tables.Token;
import ovh.herisson.Clyde.Tables.User;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import static io.restassured.RestAssured.with;
import static org.hamcrest.Matchers.equalTo;
@Testcontainers
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles(value = "dev")
public class UserControllerTest {
@LocalServerPort
private Integer port;
@Autowired
private ClydeApplication controller;
@Autowired
private TokenService tokenService;
@Autowired
private UserRepository userRepository;
@Autowired
private TokenRepository tokenRepository;
@Container
@ServiceConnection
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:alpine")
.withDatabaseName("clyde")
.withUsername("devel")
.withPassword("devel")
.withCreateContainerCmdModifier(cmd -> cmd.withHostConfig(new HostConfig().withPortBindings(new PortBinding(Ports.Binding.bindPort(5442), new ExposedPort(5432)))));
@BeforeAll
static void beforeAll(){
postgres.start();
}
@AfterAll
static void afterAll(){
postgres.stop();
}
@BeforeEach
void setup(){
RestAssured.baseURI = "http://localhost:" + port;
}
@AfterEach
void aftereach(){
tokenRepository.deleteAll();
userRepository.deleteAll();
}
@Test
//Verifie qu'un user qui n'a pas les permissions admin ou secretaire ne peut pas post
public void userPostTest(){
User god = new User("god","god","admin@admin.com","everywhere","every",new Date(0), null, Role.Admin,"goddoesntneedpassword");
Token godToken = new Token(god, tokenService.generateNewToken(), new Date());
userRepository.save(god);
tokenService.saveToken(godToken);
//Can god post herobrine himself ?
User herobrine = new User("brine","hero","herobrine@student.com","in your WalLs","ShadowsLand",new Date(0), null,Role.Student,"test");
with().body(herobrine).contentType(ContentType.JSON).header("Authorization", godToken.getToken()).when().request("POST", "/user").then().statusCode(201);
userRepository.delete(herobrine);
//Can noob post herobrine without authorizations (no)
User noob = new User("boon","noob","noob@student.com","everywhere","every",new Date(0), null, Role.Student,"noob");
Token noobToken = new Token(noob, tokenService.generateNewToken(), new Date());
userRepository.save(noob);
tokenService.saveToken(noobToken);
with().body(herobrine).contentType(ContentType.JSON).header("Authorization", noobToken.getToken()).when().request("POST", "/user").then().statusCode(401);
}
@Test
public void userGetTest(){
User herobrine = new User("brine","hero","herobrine@student.com","in your WalLs","ShadowsLand",new Date(0), null,Role.Student,"test");
userRepository.save(herobrine);
Token t = new Token(herobrine, tokenService.generateNewToken(), new Date());
tokenRepository.save(t);
with().header("Authorization", t.getToken()).when().request("GET", "/user").then().assertThat().statusCode(200).body("firstName",equalTo("hero"));
}
@Test
public void userPatchTest(){
User herobrine = new User("brine","hero","herobrine@admin.com","in your WalLs","ShadowsLand",new Date(0), null,Role.Admin,"test");
userRepository.save(herobrine);
Token t = new Token(herobrine, tokenService.generateNewToken(), new Date());
tokenRepository.save(t);
Map<String, Object> data = new HashMap<String, Object>();
data.put("firstName", "test");
//Teste que le patch s'execute bien
with().body(data).contentType(ContentType.JSON).header("Authorization", t.getToken()).pathParam("id", herobrine.getRegNo()).when().request("PATCH", "/user/{id}").then().statusCode(200);
//Teste que la donnée a bien été altérée
with().header("Authorization", t.getToken()).when().request("GET", "/user").then().body("firstName",equalTo("test"));
}
@Test
public void UserDeleteTest(){
User god = new User("god","god","admin@admin.com","everywhere","every",new Date(0), null, Role.Admin,"goddoesntneedpassword");
Token godToken = new Token(god, tokenService.generateNewToken(), new Date());
userRepository.save(god);
tokenService.saveToken(godToken);
User herobrine = new User("brine","hero","herobrine@admin.com","in your WalLs","ShadowsLand",new Date(0), null,Role.Student,"test");
userRepository.save(herobrine);
with().header("Authorization", godToken.getToken()).pathParam("id", herobrine.getRegNo()).when().request("DELETE", "/user/{id}").then().statusCode(200);
Assert.assertEquals(userRepository.existsById(herobrine.getRegNo()), false);
}
}

View File

@ -0,0 +1,41 @@
package ovh.herisson.Clyde.Repositories;
import org.junit.Assert;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.TestPropertySource;
import ovh.herisson.Clyde.Tables.Role;
import ovh.herisson.Clyde.Tables.User;
import java.util.GregorianCalendar;
@DataJpaTest
@TestPropertySource(properties = {
"spring.test.database.replace=none",
"spring.datasource.url=jdbc:tc:postgresql:16-alpine:///db"
})
public class UserRepoTest {
@Autowired
UserRepository userRepo;
@BeforeEach
public void setup(){
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);
}
@AfterEach
public void clean(){
userRepo.deleteAll();
}
@Test
public void usertest(){
Assert.assertEquals("brine", userRepo.findById(1).getLastName());
Assert.assertTrue(new GregorianCalendar(2005, 4, 3).getTime().equals(userRepo.findById(1).getBirthDate()));
}
}

View File

@ -0,0 +1,80 @@
package ovh.herisson.Clyde.Services;
import org.junit.Assert;
import org.junit.Before;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.TestPropertySource;
import org.springframework.web.multipart.MultipartFile;
import org.testcontainers.shaded.com.google.common.net.MediaType;
import ovh.herisson.Clyde.Repositories.FileRepository;
import ovh.herisson.Clyde.Tables.FileType;
import ovh.herisson.Clyde.Tables.StorageFile;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
@DataJpaTest
@TestPropertySource(properties = {
"spring.test.database.replace=none",
"spring.datasource.url=jdbc:tc:postgresql:16-alpine:///db"
})
public class StorageServiceTest {
@Autowired
FileRepository fileRepo;
StorageService ss;
@BeforeEach
public void setup(){
if (ss == null){
ss = new StorageService(fileRepo);
}
}
@AfterEach
public void aftereach(){
fileRepo.deleteAll();
}
@Test
//Check si le fichier est bien sauvegardé dans la DB et si le fichier est bien sauvegardé au bon endroit
public void saveFile(){
//Test si le directory a bien été crée a l'init du fileService
Path rootloc = Paths.get("cdn/");
Assert.assertTrue(Files.exists(rootloc));
}
@Test
public void deleteFile() throws IOException {
File file = new File("cdn/test.txt");
file.createNewFile();
//On vérifie que le fichier a bien été crée
Assert.assertTrue(file.exists());
//StorageFile représentant le fichier
StorageFile sf = new StorageFile("testfile",file.getPath(), FileType.ProfilePicture);
fileRepo.save(sf);
//Check that the storagefile is properly saved
StorageFile resp = fileRepo.getStorageFileByName("testfile");
Assert.assertEquals(sf, resp);
ss.delete(sf);
//On vérifie que le fichier a bien été delete et que le StorageFile a été delete de la DB
Assert.assertFalse(file.exists());
resp = fileRepo.getStorageFileByName("testfile");
Assert.assertEquals(null, resp);
}
}

View File

@ -0,0 +1,93 @@
package ovh.herisson.Clyde.Services;
import org.junit.Assert;
import org.junit.Before;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.TestPropertySource;
import ovh.herisson.Clyde.Repositories.TokenRepository;
import ovh.herisson.Clyde.Repositories.UserRepository;
import ovh.herisson.Clyde.Tables.Role;
import ovh.herisson.Clyde.Tables.Token;
import ovh.herisson.Clyde.Tables.User;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import static org.junit.jupiter.api.Assertions.*;
@DataJpaTest
@TestPropertySource(properties = {
"spring.test.database.replace=none",
"spring.datasource.url=jdbc:tc:postgresql:16-alpine:///db"
})
class TokenServiceTest {
@Autowired
TokenRepository tokenRepository;
@Autowired
UserRepository userRepository;
@AfterEach
public void aftereach(){
tokenRepository.deleteAll();
userRepository.deleteAll();
}
@Test
void saveToken() {
User herobrine = userRepository.findById(1);
User herobrinenul = new User("brine","heronul","pasadmin@student.com","in your WalLs","ShadowsLand", new GregorianCalendar(2005, 4, 3).getTime(), null, Role.Admin,"admin");
TokenService tokenService = new TokenService(tokenRepository);
Token testToken = new Token(herobrine, tokenService.generateNewToken(), new Date());
tokenService.saveToken(testToken);
Iterable<Token> t = tokenService.getAllTokens();
Token tok = t.iterator().next();
Assert.assertEquals(herobrine, tok.getUser());
Assert.assertNotEquals(herobrinenul, tok.getUser());
}
@Test
void saveTokenLimit(){
TokenService tokenService = new TokenService(tokenRepository);
//On va stocker les token qu'on va sauvegarder au préalable dans une liste pour tester que les tokens remplacés sont bien ceux avec la date d'expi la plus jeune
//A la fin il ne devrait donc rester que les 5 derniers tokens de tokenList
ArrayList<Token> tokenList = new ArrayList<>();
GregorianCalendar gc = new GregorianCalendar();
User malveillant = new User("Cargo", "John", "CargoJ@mail.com", "secret", "secret", null, null, null, "secret");
userRepository.save(malveillant);
for (int i = 0; i < 20; i++){
gc.add(Calendar.DAY_OF_WEEK, 1);
Token t = new Token(malveillant, tokenService.generateNewToken(), gc.getTime());
tokenList.add(t);
tokenService.saveToken(t);
}
//Testons les tokens
ArrayList <Token> resp = tokenRepository.getByUserOrderByExpirationDate(malveillant);
Assert.assertTrue(resp.size() == 5);
for (int i = 1; i <= resp.size(); i++){
Assert.assertEquals(tokenList.get(tokenList.size()-i), resp.get(resp.size()-i));
}
}
}

View File

@ -0,0 +1,3 @@
spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect

View File

@ -19,9 +19,3 @@ npm run dev
```sh
npm run build
```
### Run Unit Tests with [Vitest](https://vitest.dev/)
```sh
npm run test:unit
```

View File

@ -18,8 +18,3 @@ var dev = tasks.register<NpmTask>("dev") {
tasks.register<NpmTask>("run") {
dependsOn(dev)
}
tasks.register<NpmTask>("test") {
dependsOn(tasks.npmInstall)
args.set(listOf("run", "test:unit"))
}

View File

@ -1,10 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<html>
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
<title> Clyde 🪦</title>
</head>
<body>
<div id="app"></div>

File diff suppressed because it is too large Load Diff

View File

@ -6,18 +6,16 @@
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"test:unit": "vitest"
"preview": "vite preview"
},
"dependencies": {
"vite-plugin-top-level-await": "^1.4.1",
"vue": "^3.4.15",
"vue3-toastify": "^0.2.1"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.3",
"@vue/test-utils": "^2.4.4",
"jsdom": "^24.0.0",
"vite": "^5.0.11",
"vitest": "^1.2.2"
"vite": "^5.0.11"
}
}

BIN
frontend/public/Clyde.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 318 B

View File

@ -0,0 +1,54 @@
login.guest.signin=Sign in
login.guest.register=Register
login.guest.alregister=Already Registered
login.guest.welcome=WELCOME TO THE UNIVERSITY
login.guest.email=E-MAIL
login.guest.firstname=FIRSTNAME
login.guest.surname=SURNAME
login.guest.country=COUNTRY
login.guest.address=ADDRESS
login.guest.password=PASSWORD
login.guest.nextpage=Next Page
login.guest.lastpage=Last Page
login.guest.submit=Submit
login.guest.birthday=BIRTHDAY
login.guest.confirm=CONFIRM
login.cPassword=Confirm Password
login.password=Password
app.home=Home
app.login=Login
app.notifications=Notifications
app.settings=Settings
app.messages=Messages
app.forum=Forum
app.schedules=Schedules
app.inscription.requests=Inscription Requests
app.manage.courses=Manage Courses
app.language=Language
app.manage.profile=Manage profile
app.studentList=Students List
app.users=Users
request.moreInfos=More Infos
request.accept=Accept
request.refuse=Refuse
courses.createCourse=Create course
courses.deleteCourse=Delete course
courses.modify=Modify
courses.toDelete=Course to Delete
courses.confirm=Confirm
courses.back=Back
profile.modify.data=Modify personnal data
profile.reRegister=Re-register
profile.unRegister=Unregister
profile.course.list=Courses list
profile.address=Address
profile.picture=Profile picture
profile.change.curriculum=Change curriculum
name=Name
Teacher=Teacher
Student=Student
Secretary=Secretary
Curriculum=curriculum
Credits=Credits
InscriptionService=I.S.
faculty=Faculty

View File

@ -0,0 +1,54 @@
login.guest.signin=SE CONNECTER
login.guest.register=S'enregistrer
login.guest.alregister=Déjà Enregistré
login.guest.welcome=BIENVENUE A L'UNIVERSITE
login.guest.email=E-MAIL
login.guest.firstname=PRENOM
login.guest.surname=NOM
login.guest.country=PAYS
login.guest.address=ADRESSE
login.guest.password=MOT DE PASSE
login.guest.nextpage=Prochaine Page
login.guest.lastpage=Derniere Page
login.guest.submit=Envoyer
login.guest.birthday=DATE DE NAISSANCE
login.guest.confirm=CONFIRMER
login.cPassword=Confirmer mot de passe
login.password=Mot de passe
app.home=Home
app.login=Se connecter
app.notifications=Notifications
app.settings=Options
app.messages=Messages
app.forum=Forum
app.schedules=Horaires
app.inscription.requests=Demandes d'Inscription
app.manage.courses=Gérer les cours
app.language=Langue
app.manage.profile=Gérer le profil
app.studentList=Liste des étudiants
app.users=Utilisateurs
request.moreInfos=Plus d'Infos
request.accept=Accepter
request.refuse=Refuser
courses.createCourse=Créer un cours
courses.deleteCourse=Supprimer un cours
courses.modify=Modifier
courses.toDelete=Cours à supprimer
courses.confirm=Confirmer
courses.back=Retour
profile.modify.data=Modifier données personnelles
profile.reRegister=Réinsciption
profile.unRegister=Désinscription
profile.course.list=Liste des cours
profile.address=Adresse
profile.picture=Photo de profil
profile.change.curriculum=Changer cursus
name=Nom
Teacher=Enseignant
Student=Etudiant
Secretary=Secrétaire
Curriculum=Cursus
Credits=Credits
InscriptionService=S.I.
faculty=Faculté

View File

@ -1,67 +1,168 @@
<script setup>
import 'https://kit.fontawesome.com/fb3bbd0a95.js'
import { toast } from 'vue3-toastify';
import { ref } from 'vue'
import { toast } from 'vue3-toastify';
import { ref } from 'vue'
import i18n, { setLang } from './i18n.js'
import { isLogged } from '@/rest/Users.js'
const test = ref();
import { appList, currentView } from '@/rest/apps.js'
var prevURL;
var currentURL = window.location.hash;
window.onhashchange = function() {
prevURL = currentURL;
currentURL = window.location.hash;
}
const Logged = ref(isLogged());
window.addEventListener('hashchange', () => {
if((location.hash === "#/home" && prevURL === "#/login") || (location.hash === "#/home" && prevURL === "#/profil")){
window.location.reload();
}
});
const home=ref(i18n("app.home"))
const notifications=ref(i18n("app.notifications"))
const settings=ref(i18n("app.settings"))
const login=ref(i18n("app.login"))
const active=ref(false)
const apps = ref([])
appList().then(e => apps.value = e)
async function draw(e) {
test.value = (await fetch("http://localhost:8080/ping"));
test.value = await test.value.json();
toast(test.value['txt']);
}
</script>
<template>
<ul style="padding-top:60px"class="vertical">
<li style="margin-top: 25px;" ><a href="#Messages"><item class="fa-solid fa-comment" style="font-size: 40px;" ></item>
<div class="text">Messages</div> </a></li>
<li ><a href="#Notifications"><item class="fa-solid fa-bell" style="font-size: 40px;" ></item>
<div class="text">Notifications</div></a></li>
<li ><a href="#Schedule"><item class="fa-solid fa-calendar-days" style="font-size: 40px;" ></item>
<div class="text">Schedules</div></a></li>
<li ><a href="#Forum"><item class="fa-solid fa-envelope" style="font-size: 40px;" ></item>
<div class="text">Forum</div></a></li>
</ul>
<div class="container">
<ul class="horizontal" style="box-shadow: 0px 3px 3px rgb(0, 0, 0);">
<li title="Home">
<a href="#home">
<img @click="draw" src="./assets/Clyde.png" style="width: 40px; height: auto; margin-top:4px">
</a>
</li>
<li title="Home">
<a href="#home">
<item class=" fa-solid fa-house" style="margin-top: 7px; margin-bottom: 3px;"></item>
</a>
</li>
<li style="float: right;" title="Account">
<a href="#Account">
<item class="fa-solid fa-user" style="margin-top: 7px; margin-bottom: 3px;"></item>
<div class="topBar">
<ul class="horizontal">
<li title=home>
<a class="icon" href="#home">
<img class="clyde" src="/Clyde.png" style="width: 40px; height: auto; margin-top:4px">
</a></li>
<li style="float: right;" title="Notifications">
<a href="#Notifications">
<item class="fa-solid fa-bell" style="margin-top: 7px; margin-bottom: 3px;"></item>
<li title=home>
<a class="icon" href="#home">
<div class=" fa-solid fa-house" style="margin-top: 7px; margin-bottom: 3px;"></div>
</a></li>
<li style="float: right;" title="Options">
<a href="#Options">
<item class="fa-solid fa-gear" style="margin-top: 7px; margin-bottom: 3px;"></item>
<li style="float: right;" title=login>
<a class="icon" href="#/login">
<div class="fa-solid fa-user" :style="Logged ? 'color: orange' : 'haha'" style="margin-top: 7px; margin-bottom: 3px; "></div>
</a></li>
<li style="float: right;" title=notifications>
<a class="icon" href="#Notifications">
<div class="fa-solid fa-bell" style="margin-top: 7px; margin-bottom: 3px;"></div>
</a></li>
<li @click="active=!active" class="option"style="float: right;" title=settings>
<a class="icon" >
<div class="fa-solid fa-gear" style="margin-top: 7px; margin-bottom: 3px;"></div>
<div v-if="active" class="dropdown">
<div class="dropdown-content">{{i18n("app.language")}}</div>
<ul style="list-style-type:none;">
<li style=" margin-bottom:10px;margin-right:20px;float:left; font-size:10px; color:black;">
<button @:click="setLang('en');" href="#home">EN</button>
</li>
<li style="float:left;font-size:10px; color:black;"><button @:click="setLang('fr');" href="#home">FR</button></li>
</ul>
<div style='align-items:center;'>
<a style="cursor:pointer;font-size:20px;" href="#/profil" class="dropdown-content">
{{i18n("app.manage.profile")}}
</a>
</div>
</div>
</a></li>
</ul>
</div>
<div class="leftBar">
<ul class="vertical">
<li v-for="app in apps">
<a :href="app.path">
<div class="fa-solid" :class="app.icon" style="font-size: 40px;"></div>
<div class="text">{{app.text}}</div>
</a>
</li>
</ul>
</div>
<div class="page">
<Suspense>
<component :is="currentView" />
</Suspense>
</div>
</div>
</template>
<style scoped>
.container{
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-areas:
"topBar topBar"
"leftBar page";
row-gap:0px;
column-gap:0px;
}
.page {
grid-area:page;
place-self:center;
}
.topBar{
grid-area:topBar;
}
.leftBar{
grid-area:leftBar;
}
.option {
position: relative;
display: block;
}
.dropdown {
margin-top:55px;
width:160px;
display: inline-block;
height:110px;
font-size: 13px;
position: absolute;
z-index: 1;
background-color:white;
}
.dropdown-content {
min-width: 160px;
text-align: center;
margin-bottom: 10px;
right:0;
color:rgb(50,50,50);
text-decoration: none;
font-size:24px
}
.dropdown-content div{
display:block;
}
ul.vertical{
list-style-type: none;
margin: 0;
padding: 0;
margin-top: 61px;
top:0;
left:0;
padding: 25px 0 0;
width: 70px ;
background-color: rgb(53, 53, 53);
border-right:5px;
border-color:black;
height: 100%;
position: fixed;
overflow:auto;
overflow:;
transition-duration: .3s;
}
@ -76,7 +177,6 @@
background-color: rgb(112, 112, 112);
border-radius:6px;
color: white;
transform: translate(0px ,1px);
}
@ -91,15 +191,17 @@
}
ul.horizontal {
z-index: 101;
box-shadow: 0px 3px 3px rgb(0, 0, 0);
display: block ;
list-style-type:none;
margin:0;
padding: 0;
top: 0;
left:0;
position: fixed;
height:61px;
width: 100%;
overflow: hidden;
background-color: rgb(24, 24, 24);
}
@ -110,7 +212,7 @@
}
ul.horizontal li a:hover:not(.active){
ul.horizontal li a.icon:hover:not(.active){
background-color: black;
border-radius:6px;
color:white;
@ -121,13 +223,13 @@
ul.vertical:hover {
z-index: 100;
width: 250px;
border-radius: 40px;
border-top-right-radius: 40px;
box-shadow: 3px 0px 3px rgb(0, 0, 0);
transition-duration: .3s;
}
.text {
position: absolute;
right: 0%;
width: 0%;
opacity: 0;
@ -139,8 +241,15 @@
ul.vertical:hover .text {
opacity: 1;
width: 70%;
width: 60%;
transition-duration: .3s;
padding-left: 5px;
padding-left: 15px;
}
.clyde:hover{
content: url("./assets/angry_clyde.png")
}
</style>
<!-- vim:set noet sts=0 sw=4 ts=2: -->

View File

@ -0,0 +1,113 @@
<script setup>
import i18n from "@/i18n.js"
import {ref} from 'vue'
import {validateRegister, getAllRegisters } from '@/rest/ServiceInscription.js'
const requests = ref(await getAllRegisters());
console.log(requests);
async function upPage(id,review){
await validateRegister(id,review);
requests.value = await getAllRegisters();
}
</script>
<template>
<div v-for="item of requests">
<div class="bodu" v-if="item.state === 'Pending'">
<div class="container">
<div class="id"><a>{{item.id}}</a></div>
<div class="surname"><a>{{item.lastName}}</a></div>
<div class="firstname"><a>{{item.firstName}}</a></div>
<div class="infos"><button style="background-color:rgb(105,05,105);" >{{i18n("request.moreInfos")}}</button></div>
<div class="accept"><button @click="upPage(item.id,'Accepted')" style="background-color:rgb(0,105,50);">{{i18n("request.accept")}}</button></div>
<div class="refuse"><button @click="upPage(item.id,'Refused')" style="background-color:rgb(105,0,0);">{{i18n("request.refuse")}}</button></div>
</div>
</div>
</div>
</template>
<style scoped>
.container{
color:white;
height:100px;
font-size:20px;
display:grid;
grid-template-columns:[firstCol-start]100px[firstCol-end secondCol-start]150px[secondCol-end thirdCol-start]200px[thirdCol-end fourthCol-start]150px[fourthCol-end]150px[fifthCol-end]150px[sixthCol-end]150px[endCol];
grid-template-areas:
"id type surname firstname infos accept refuse";
column-gap:10px;
}
.infos {
grid-area:infos;
align-self:center;
}
.accept{
grid-area:accept;
align-self:center;
}
.refuse{
grid-area:refuse;
align-self:center;
}
.titles {
grid-area:titles;
background-color:rgb(215,215,215);
}
.id{
grid-area:id;
margin-left:40px;
align-self:center;
}
.type{
grid-area:type;
align-self:center;
}
.surname{
grid-area:surname;
align-self:center;
white-space: nowrap;
overflow: hidden;
text-overflow:ellipsis;
}
.firstname{
grid-area:firstname;
align-self:center;
white-space: nowrap;
overflow: hidden;
text-overflow:ellipsis;
}
button{
font-size:15px;
height:50px;
width:100px;
border:none;
border-radius:20px;
}
.bodu {
width:100%;
margin-bottom:10px;
border:2px solid black;
border-radius:9px;
background-color:rgb(50,50,50);
}
</style>

242
frontend/src/Apps/Login.vue Normal file
View File

@ -0,0 +1,242 @@
<script setup>
import {reactive, ref } from 'vue'
import i18n from '@/i18n.js'
import { login , register , disconnect, isLogged} from '@/rest/Users.js'
import { getAllCurriculums } from '@/rest/curriculum.js'
import { uploadProfilePicture } from '@/rest/uploads.js'
import {toast} from 'vue3-toastify'
import 'vue3-toastify/dist/index.css';
const loginPage= ref(true)
const page = ref(0)
const outputs = reactive({
surname:null,
firstname:null,
password:null,
birthday:null,
email:null,
address:null,
country:null,
curriculum:null,
})
const submitValue= ref(i18n("login.guest.submit"))
const passwordConfirm=ref("")
const imageSaved = ref(false)
const ppData = ref(false)
const curricula= await getAllCurriculums();
function goBackHome(){
setTimeout(() => {
window.location.href="#/home";
}, "500");
}
function verifyInputs(pass){
if(pass==passwordConfirm.value){
page.value++;
return toast('Password and Confirm Password are correct.', {
type: "success",});
}
else{
return toast('Password and Confirm Password are different',{type: "error",});
}
}
if (isLogged()){
disconnect();
window.location.reload();}
</script>
<template style="background-color:rgba(255,255,255,0.05); border-radius:50px" >
<div class='loginBox'>
<div v-if="loginPage">
<form @submit.prevent="login(outputs.email,outputs.password);goBackHome();"class="form">
<h1 style="color:rgb(239,60,168); font-family: sans-serif;">
{{i18n("login.guest.signin")}}
</h1>
<div class="inputBox">
<p>ID / {{i18n("login.guest.email")}}</p>
<input type="text" v-model="outputs.email">
</div>
<div class="inputBox">
<p>{{i18n("login.guest.password")}}</p>
<input type="password" v-model="outputs.password">
</div>
<div class="register">
<a @click="loginPage=!loginPage">{{i18n("login.guest.register")}}</a>
</div>
<div class="inputBox">
<input type="submit" v-model="submitValue">
</div>
</form>
</div>
<div v-else>
<form class="form">
<h1 style="color:rgb(239,60,168); font-family: sans-serif; text-align:center;">
{{i18n("login.guest.welcome")}}
</h1>
<div v-if="page === 0">
<div class="inputBox">
<p>{{i18n("login.guest.surname")}}</p>
<input type="text" v-model="outputs.surname">
</div>
<div class="inputBox">
<p>{{i18n("login.guest.firstname")}}</p>
<input type="text" v-model="outputs.firstname">
</div>
<div class="inputBox">
<p>{{i18n("login.guest.birthday")}}</p>
<input type="date" v-model="outputs.birthday">
</div>
<div class="inputBox">
<p>{{i18n("login.guest.password")}}</p>
<input type="password" v-model="outputs.password">
</div>
<div class="inputBox">
<p>{{i18n("login.guest.confirm")}} {{i18n("login.guest.password")}}</p>
<input type="password" v-model="passwordConfirm">
</div>
<div class="switchpage">
<button @click="verifyInputs(outputs.password);">{{i18n("login.guest.nextpage")}}</button>
</div>
<div @click="(loginPage=!loginPage) && (page=0)" class="register">
<a>{{i18n("login.guest.alregister")}}</a>
</div>
</div>
<div v-else>
<div class="inputBox">
<p>{{i18n("login.guest.email")}}</p>
<input type="mail" v-model="outputs.email">
</div>
<div class="inputBox">
<p>{{i18n("login.guest.address")}}</p>
<input type="text" v-model="outputs.address">
</div>
<div class="inputBox">
<p>{{i18n("login.guest.country")}}</p>
<input type="text" v-model="outputs.country">
</div>
<form novalidate enctype="multipart/form-data" class="inputBox">
<p>{{i18n("profile.picture").toUpperCase()}}</p>
<input type="file" :disabled="imageSaved" @change="ppData = uploadProfilePicture($event.target.files); imageSaved = true;" accept="image/*">
</form>
<div class="inputBox">
<p>{{i18n("Curriculum").toUpperCase()}}</p>
<select v-model="outputs.curriculum">
<option v-for="item in curricula">{{item.curriculumId}}</option>
</select>
</div>
<div style="align-self:center;" class="inputBox">
<button style="margin-top:25px;" @click="register(outputs.firstname, outputs.surname, outputs.birthday, outputs.password, outputs.email, outputs.address, outputs.country, outputs.curriculum, ppData);">
{{i18n("login.guest.submit")}}
</button>
</div>
<div class="switchpage">
<button @click="page--">{{i18n("login.guest.lastpage")}}</button>
</div>
<div @click="(loginPage=!loginPage) && (page=0)" class="register">
<a>{{i18n("login.guest.alregister")}}</a>
</div>
</div>
</form>
</div>
</div>
</template>
<style scoped>
.loginBox {
background-color: rgb(24,24,24);
width: 100%;
height:100%;
justify-content: center;
padding: 10%;
border-radius: 5%;
box-shadow:0 5px 25px #000000;
}
.form {
position:relative;
width:100%;
display: flex;
flex-direction: column;
align-items:center;
gap: 3%;
}
.inputBox input,button,select {
width:100%;
border: none;
margin-right: 12.5%;
padding-left: 2.5%;
padding-top:2.5%;
padding-bottom:2.5%;
outline:none;
border-radius: 10px;
font-size:1.35em;
}
.inputBox p{
position:relative;
z-index: 100;
font-family:sans-serif ;
color:rgb(239,60,168);
transition:0.5;
}
.register{
color:rgb(239,60,168);
width: 100%;
display:flex;
cursor: pointer;
}
.switchpage{
width:100px;
background:rgb(255, 0 255);
border: none;
padding-right:0;
padding-top:10px;
padding-bottom:10px;
outline:none;
border-radius: 4px;
font-size:0.8em;
align-self:right;
}
input[type=submit],button,select{
margin-bottom:20px;
background-color: rgb(239,60,168);
cursor: pointer;
padding:10px;
font-size:1.35em;
border:none;
border-radius:20px;
}
button:active ,.switchpage:active{
opacity:0.8;
}
</style>

View File

@ -0,0 +1,275 @@
<script setup>
import i18n from "@/i18n.js"
import {reactive , ref} from 'vue'
import { getCourses,deleteCourse,alterCourse,createCourse } from "@/rest/courses.js"
import {getUser, getSelf, getTeachers } from "@/rest/Users.js"
const self = await getSelf();
const curriculum = ref(await getCourses(self.role));
const profList = await getTeachers();
const createMod = ref(false)
const deleteMod = ref(false)
const editElementID = ref("")
function editItem(id){
editElementID = id;
}
//Juste pour montrer le Create Mode
const pattern = {
"title":null,
"credits":null,
"owner":null,
}
let toModify = Object.assign({},pattern);
let toAdd = Object.assign({}, pattern);
async function addToCourse(){
let isnull= false;
for(const [key, value] of Object.entries(toAdd)){
console.log(toAdd.owner);
if(value === null){
isnull=true;
}
}
if (!isnull){
await createCourse(toAdd.title,toAdd.credits,toAdd.owner);
toAdd= Object.assign({},pattern);
curriculum.value = await getCourses(self.role);
}}
function setModify(item){
for(const el in profList){
if(profList[el].regNo === item.owner.regNo){
toModify.owner= profList[el];
}
}
toModify.credits= item.credits;
toModify.title= item.title;
}
async function patchCourse(course){
for (let element in toModify){
console.log(toModify,1)
console.log(toModify[element],2)
if (element =="owner" && (toModify[element].regNo != course.owner.regNo)){
await alterCourse(course.courseId,{owner:toModify[element].regNo});
}
else if(element == "title" && (toModify[element] != course.title)){
await alterCourse(course.courseId,{title:toModify[element]});
}
else if(element == "credits" && (parseInt(toModify[element]) != course.credits)){
await alterCourse(course.courseId,{credits:parseInt(toModify[element])});
}
}
toModify= Object.assign({},pattern);
curriculum.value = await getCourses(self.role);
}
//Juste pour montrer le Delete Mode
let toRemove = null;
async function removeCourse(course) {
await deleteCourse(course.courseId)
curriculum.value = await getCourses(self.role);
toRemove = null;
}
</script>
<template>
<div class="body">
<div v-if="!deleteMod && !createMod && (self.role !== 'Teacher')" class="listTitle buttonGrid">
<button class="create" @click="editElementID= '';createMod = true;">
{{i18n("courses.createCourse")}}
</button>
<button class="delete" @click="deleteMod=true" >
{{i18n("courses.deleteCourse")}}
</button>
</div>
<div v-if="createMod">
<form class="listElement">
<div style="margin-bottom:20px;">
{{i18n("name")}} :
<input v-model="toAdd.title">
</div>
<div style="margin-bottom:20px;">
{{i18n("Teacher")}} :
<select style="max-width:200px;" class="teacher" v-model="toAdd.owner">
<option v-for="item in profList" :value="item">{{item.lastName}}</option>
</select>
</div>
<div style="margin-bottom:20px;">
{{i18n("Credits")}} :
<input v-model="toAdd.credits">
</div>
<button class="create" @click="createMod=!createMod; addToCourse();"> {{i18n("courses.confirm")}} </button>
<button style="float:right;" @click="createMod=!createMod">{{i18n("courses.back")}}</button>
</form>
</div>
<div v-if="deleteMod">
<form class="listElement">
<div style="margin-bottom:20px;">
{{i18n("courses.toDelete")}} :
<select style="max-width:200px;" class="teacher" v-model="toRemove">
<option v-for="item in curriculum" :value='item'>{{item.title}}</option>
</select>
</div>
<button class="delete" @click="deleteMod=!deleteMod; removeCourse(toRemove);"> {{i18n("courses.deleteCourse")}} </button>
<button style="float:right;" @click="deleteMod=!deleteMod"> {{i18n("courses.back")}}</button>
</form>
</div>
<div v-if="!createMod && !deleteMod" v-for="item in curriculum" :key="item.title">
<div v-if="editElementID !== item.title" style ="padding:15px 15px 15px 15px;">
<button @click="editElementID = item.title; setModify(item); ">
{{i18n("courses.modify")}}
</button>
</div>
<div v-else>
<button @click="editElementID= '';patchCourse(item)"> {{i18n("courses.confirm")}} </button>
<button @click="editElementID= '';"> {{i18n("courses.back")}} </button>
</div>
<div class="listElement" >
<div class="containerElement" v-if="editElementID !== item.title" >
<div class="name"> {{item.title}} </div>
<div class="teacher">{{item.owner.lastName}}</div>
<div class="credits">{{i18n("Credits")}}:{{item.credits}}</div>
</div>
<div class="containerElement"v-else>
<input style="max-width:200px;" class="name" v-model="toModify.title">
<select v-if="self.role === 'Secretary'" style="max-width:200px;" class="teacher" v-model="toModify.owner">
<option v-for="(item,index) in profList" :value='item'>{{item.lastName}}</option>
</select>
<div v-else class="teacher">{{item.owner.lastName}}</div>
<input v-if="self.role==='Secretary'"style="max-width:100px;"class="credits" v-model="toModify.credits">
<div v-else class="credits">{{i18n("Credits")}}:{{item.credits}}</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.body {
width:100%;
margin-bottom:10px;
}
.containerElement{
justify-content:center;
display:grid;
grid-template-columns:350px 350px 200px;
grid-template-areas:
"name teacher credits";
column-gap:10px;
}
.name {
grid-area:name;
align-self:center;
}
.teacher{
grid-area:teacher;
align-self:center;
}
.credits{
grid-area:credits;
align-self:center;
}
.listElement{
border:2px solid black;
font-size:25px;
color:white;
padding:20px;
background-color:rgb(50,50,50);
border-radius:20px;
margin-bottom:10px;
}
.modify{
font-size:25px;
padding:10px 10px 10px 10px;
background-color: rgb(239,60,168);
cursor: pointer;
border:none;
border-radius:15px;
}
input, select{
padding:10px 10px 10px 10px;
font-size:25px;
cursor: pointer;
border:none;
border-radius:15px;
}
button{
font-size:15px;
height:50px;
width:100px;
border:none;
border-radius:20px;
}
.buttonGrid{
display:grid;
grid-template-columns: auto auto;
column-gap:50px;
grid-template-areas:
"create delete";
}
.create{
grid-area:create;
background-color:rgb(0,200,0);
}
.delete{
grid-area:delete;
background-color:rgb(200,0,0);
}
.listTitle{
display: flex;
justify-content: center;
align-items: center;
width:400px;
margin-left:auto;
margin-right:auto;
border:2px solid black;
font-size:25px;
color:white;
padding:20px;
background-color:rgb(50,50,50);
border-radius:20px;margin-bottom:10px;
button:hover{
opacity:0.8;
}
}
</style>

View File

@ -0,0 +1,321 @@
<script setup>
import {reactive, ref } from 'vue'
import {getSelf,alterSelf,disconnect,deleteUser} from '../rest/Users.js'
import {getSelfCurriculum, getAllCurriculums} from '../rest/curriculum.js'
import {getCourses} from "../rest/courses.js"
import i18n from "@/i18n.js"
import { uploadProfilePicture } from '@/rest/uploads.js'
const user = ref(await getSelf());
const UserCurriculum = ref("");
const curricula = ref (await getAllCurriculums());
if(user.value.role === "Student"){
UserCurriculum.value = await getSelfCurriculum();
}
if(user.role === "Teacher"){
UserCurriculum.value = await getCourses("Teacher");
}
const modif = ref(false);
const curric = ref(false);
const reg = ref(false);
const pattern = {
profilPictureUrl:null,
email:null,
address:null,
password:null,
};
const patternInfos ={
email: null,
password: null,
passwordConfirm:null,
id:null,
}
let toModify= Object.assign({}, pattern);
let personnalInfos = Object.assign({}, patternInfos);
function resetInputs(inputs,list){
inputs=Object.assign({},list);
}
async function ChangeInfos(){
for (let element in toModify){
if (element =="email" && (toModify[element] !== null)){
await alterSelf(user.value.regNo,{email : toModify[element]});
}
if (element =="profilPictureUrl" && (toModify[element] !== null)){
await alterSelf(user.value.regNo,{ profilPictureUrl : toModify[element]});
}
else if(element == "address" && (toModify[element] !== null)){
await alterSelf(user.value.regNo,{address : toModify[element]});
}
else if(element == "password" && (toModify[element] !== null)){
await alterSelf(user.value.regNo,{password : toModify[element]});
}
}
toModify= Object.assign({},pattern);
user.value = await getSelf()
}
function setModify(item){
toModify.address = item.address;
toModify.profilPictureUrl = item.profilPictureUrl;
toModify.email= item.email;
toModify.password= item.password;
}
async function unRegister(){
deleteUser(user.value.regNo);
disconnect()
setTimeout(() => {
window.location.href="#/home";
}, "500");
}
function getPP(){
if(user.value.profilePictureUrl === null){
return "/Clyde.png"
}
return user.profilePictureUrl
}
</script>
<template>
<div class="body">
<div class="container">
<div class="profilPic">
<img class="subContainter" :src=getPP()>
</div>
<div class="globalInfos">
<div v-if="modif==false && curric==false && reg==false " class="infosContainer" >
<div>
{{user.firstName}} {{user.lastName}}
</div>
<div>
E-mail: {{user.email}}
</div>
<div v-if="user.role==='Student'">
{{user.option}} {{i18n(user.role)}}
</div>
<div v-else>
Role: {{i18n((user.role))}}
</div>
<div>
<button @click="modif=!modif; setModify(user)"> {{i18n("profile.modify.data")}} </button>
</div>
<div v-if="(user.role==='Student')">
<button @click="reg=!reg">{{i18n("profile.reRegister")}}</button>
<button @click="unRegister()" style="float:right;background-color:rgb(150,0,0);">{{i18n("profile.unRegister")}}</button>
</div>
<div v-if="(user.role==='Student')">
<button @click="curric=!curric">{{i18n("profile.change.curriculum")}}</button>
</div>
</div>
<div v-else-if="modif" class="infosContainer">
<div>
{{i18n("profile.picture")}}:
<input type="file" @change="user.profilPicture = uploadProfilePicture($event.target.files);" accept="image/*">
</div>
<div>
E-mail:
<input type="mail" v-model="toModify.email" />
</div>
<div>
{{i18n("profile.address")}}:
<input type="text" v-model="toModify.id">
</div>
<div>
{{i18n("login.password")}}:
<input type="password" v-model="toModify.password">
</div>
<div>
{{i18n("login.cPassword")}}:
<input type="password" v-model="toModify.passwordConfirm">
</div>
<div>
<button @click=" modif=!modif; ChangeInfos();">{{i18n("courses.confirm")}}</button>
<button @click="modif=!modif; resetInputs(toModify,pattern);" style="float:right;">{{i18n("courses.back")}}</button>
</div>
</div>
<div v-else-if="curric" class="infosContainer">
<div style="height:40px;">
{{i18n("Curriculum")}}:
<select v-model="curriculum" >
<option v-for="item in curricula" style="font-size:20px;" :value="item">{{item.option}}</option>
</select>
</div>
<div>
<button @click=" curric=!curric;">{{i18n("courses.confirm")}}</button>
<button @click="curric=!curric; resetInputs(personnalInfos,patternInfos);" style="float:right;">{{i18n("courses.back")}}</button>
</div>
</div>
<div v-else-if="reg" class="infosContainer">
<div>
E-mail:
<input type="mail" v-model="toModify.email" />
</div>
<div>
ID :
<input type="text" v-model="toModify.id">
</div>
<div>
{{i18n("login.password")}}:
<input type="password" v-model="toModify.password">
</div>
<div>
{{i18n("login.cPassword")}}:
<input type="password" id="confirm">
</div>
<div>
<button @click=" reg=!reg;">{{i18n("courses.confirm")}}</button>
<button @click=" reg=!reg; resetInputs(personnalInfos,patternInfos);" style="float:right;">{{i18n("courses.back")}}</button>
</div>
</div>
</div>
<div v-if="modif==false && curric==false && reg==false "class="moreInfos">
<div v-if="(user.role ==='Student')">
<div class="listTitle">
{{i18n("profile.course.list")}}
</div>
<div class="listElement" v-for="item in UserCurriculum.courses">
<div class=" containerElement">
<div class="name"> {{item.title}} </div>
<div class="teacher">{{item.owner.lastName}}</div>
<div class="credits">Credits:{{item.credits}}</div>
</div>
</div>
</div>
<div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.container{
display:grid;
grid-template-columns:200px 900px;
grid-template-rows:200px auto;
column-gap:30px;
row-gap:45px;
grid-template-areas:
"profilPic globalInfos"
"minfos minfos";
}
.profilPic{
grid-area:profilPic;
}
.globalInfos {
grid-area:globalInfos;
align-self :center;
}
.subContainter{
width:100%;
background-color:rgb(50,50,50);
border-radius:20px;
border:4px solid black;
}
.moreInfos {
grid-area:minfos;
}
.body {
width:100%;
margin-bottom:10px;
}
.containerElement{
justify-content:center;
display:grid;
grid-template-columns:350px 350px 200px;
grid-template-areas:
"name teacher credits";
column-gap:10px;
}
.name {
grid-area:name;
align-self:center;
}
.teacher{
grid-area:teacher;
align-self:center;
}
.credits{
grid-area:credits;
align-self:center;
}
.listTitle{
display: flex;
justify-content: center;
align-items: center;
width:200px;
margin-left:auto;
margin-right:auto;
border:2px solid black;
font-size:25px;
color:white;
padding:20px;
background-color:rgb(50,50,50);
border-radius:20px;margin-bottom:10px;
}
.listElement{
border:2px solid black;
font-size:25px;
color:white;
padding:20px;
background-color:rgb(50,50,50);
border-radius:20px;
margin-bottom:10px;
}
.infosContainer {
padding-bottom:50px;
border:2px solid black;
font-size:25px;
color:white;
padding:20px;
background-color:rgb(50,50,50);
border-radius:20px;
}
button{
border:none;
background-color:rgb(239, 60, 168);
border-radius:10px;
height:35px;
margin-top:10px;
}
button:hover{
opacity:0.8;
}
</style>

View File

@ -0,0 +1,100 @@
<script setup>
import i18n from "@/i18n.js"
import { reactive } from 'vue'
import { getStudents } from '../rest/Users.js'
const users = await getStudents();
</script>
<template>
<div v-for="item in users">
<div class="bodu">
<div class="container">
<div class="status"><a style="margin-left:30px">{{item.status}}</a></div>
<div class="option"><a>{{item.role}}</a></div>
<div class="surname"><a>{{item.lastName}}</a></div>
<div class="firstname"><a>{{item.firstName}}</a></div>
<div class="infos"><button style="background-color:rgb(105,05,105);" >{{i18n("request.moreInfos")}} </button></div>
</div>
</div>
</div>
</template>
<style scoped>
.container{
color:white;
height:100px;
font-size:30px;
display:grid;
grid-template-columns:250px 250px 250px 250px 150px;
grid-template-areas:
"status option surname firstname infos";
column-gap:10px;
}
.infos {
grid-area:infos;
align-self:center;
}
.option{
grid-area:option;
align-self:center;
}
.refuse{
grid-area:refuse;
align-self:center;
}
.titles {
grid-area:titles;
background-color:rgb(215,215,215);
}
.id{
grid-area:id;
margin-left:40px;
align-self:center;
}
.status{
grid-area:status;
align-self:center;
}
.surname{
grid-area:surname;
align-self:center;
white-space: nowrap;
overflow: hidden;
text-overflow:ellipsis;
}
.firstname{
grid-area:firstname;
align-self:center;
white-space: nowrap;
overflow: hidden;
text-overflow:ellipsis;
}
button{
font-size:15px;
height:50px;
width:100px;
border:none;
border-radius:20px;
}
.bodu {
width:100%;
margin-bottom:10px;
border:2px solid black;
border-radius:9px;
background-color:rgb(50,50,50);
}
</style>

View File

@ -0,0 +1,86 @@
<script setup>
import i18n from "@/i18n.js"
import { reactive } from 'vue'
import { getAllUsers } from '../rest/Users.js'
const users = await getAllUsers();
</script>
<template>
<div v-for="item in users">
<div class="bodu">
<div class="container">
<div class="role"><a style="margin-left:30px">{{i18n(item.role)}}</a></div>
<div class="surname"><a>{{item.lastName}}</a></div>
<div class="firstname"><a>{{item.firstName}}</a></div>
<div class="infos"><button style="background-color:rgb(105,05,105);" >{{i18n("request.moreInfos")}} </button></div>
</div>
</div>
</div>
</template>
<style scoped>
.container{
justify-content:center;
align-items:center;
color:white;
height:100px;
font-size:30px;
display:grid;
grid-template-columns:250px 250px 250px 150px;
grid-template-areas:
"role surname firstname infos";
column-gap:10px;
}
.infos {
grid-area:infos;
align-items:center;
}
.role {
grid-area:role;
align-self:center;
}
.surname{
grid-area:surname;
align-self:center;
white-space: nowrap;
overflow: hidden;
text-overflow:ellipsis;
}
.firstname{
grid-area:firstname;
align-self:center;
white-space: nowrap;
overflow: hidden;
text-overflow:ellipsis;
}
button{
font-size:15px;
height:50px;
width:100px;
border:none;
border-radius:20px;
}
.bodu {
width:100%;
margin-bottom:10px;
border:2px solid black;
border-radius:9px;
background-color:rgb(50,50,50);
}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,86 +0,0 @@
/* color palette from <https://github.com/vuejs/theme> */
:root {
--vt-c-white: #ffffff;
--vt-c-white-soft: #f8f8f8;
--vt-c-white-mute: #f2f2f2;
--vt-c-black: #181818;
--vt-c-black-soft: #222222;
--vt-c-black-mute: #282828;
--vt-c-indigo: #2c3e50;
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
--vt-c-text-light-1: var(--vt-c-indigo);
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
--vt-c-text-dark-1: var(--vt-c-white);
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
}
/* semantic color variables for this project */
:root {
--color-background: var(--vt-c-white);
--color-background-soft: var(--vt-c-white-soft);
--color-background-mute: var(--vt-c-white-mute);
--color-border: var(--vt-c-divider-light-2);
--color-border-hover: var(--vt-c-divider-light-1);
--color-heading: var(--vt-c-text-light-1);
--color-text: var(--vt-c-text-light-1);
--section-gap: 160px;
}
@media (prefers-color-scheme: dark) {
:root {
--color-background: var(--vt-c-black);
--color-background-soft: var(--vt-c-black-soft);
--color-background-mute: var(--vt-c-black-mute);
--color-border: var(--vt-c-divider-dark-2);
--color-border-hover: var(--vt-c-divider-dark-1);
--color-heading: var(--vt-c-text-dark-1);
--color-text: var(--vt-c-text-dark-2);
}
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
font-weight: normal;
}
body {
min-height: 100vh;
color: var(--color-text);
background: var(--color-background);
transition:
color 0.5s,
background-color 0.5s;
line-height: 1.6;
font-family:
Inter,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Oxygen,
Ubuntu,
Cantarell,
'Fira Sans',
'Droid Sans',
'Helvetica Neue',
sans-serif;
font-size: 15px;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

View File

@ -2,4 +2,3 @@ body {
background-color: rgb(53, 25, 60);
margin:0;
}

View File

@ -1,44 +0,0 @@
<script setup>
defineProps({
msg: {
type: String,
required: true
}
})
</script>
<template>
<div class="greetings">
<h1 class="green">{{ msg }}</h1>
<h3>
Youve successfully created a project with
<a href="https://vitejs.dev/" target="_blank" rel="noopener">Vite</a> +
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>.
</h3>
</div>
</template>
<style scoped>
h1 {
font-weight: 500;
font-size: 2.6rem;
position: relative;
top: -10px;
}
h3 {
font-size: 1.2rem;
}
.greetings h1,
.greetings h3 {
text-align: center;
}
@media (min-width: 1024px) {
.greetings h1,
.greetings h3 {
text-align: left;
}
}
</style>

View File

@ -1,88 +0,0 @@
<script setup>
import WelcomeItem from './WelcomeItem.vue'
import DocumentationIcon from './icons/IconDocumentation.vue'
import ToolingIcon from './icons/IconTooling.vue'
import EcosystemIcon from './icons/IconEcosystem.vue'
import CommunityIcon from './icons/IconCommunity.vue'
import SupportIcon from './icons/IconSupport.vue'
</script>
<template>
<WelcomeItem>
<template #icon>
<DocumentationIcon />
</template>
<template #heading>Documentation</template>
Vues
<a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
provides you with all information you need to get started.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<ToolingIcon />
</template>
<template #heading>Tooling</template>
This project is served and bundled with
<a href="https://vitejs.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
recommended IDE setup is
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a> +
<a href="https://github.com/johnsoncodehk/volar" target="_blank" rel="noopener">Volar</a>. If
you need to test your components and web pages, check out
<a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a> and
<a href="https://on.cypress.io/component" target="_blank" rel="noopener"
>Cypress Component Testing</a
>.
<br />
More instructions are available in <code>README.md</code>.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<EcosystemIcon />
</template>
<template #heading>Ecosystem</template>
Get official tools and libraries for your project:
<a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
<a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
<a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
<a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
you need more resources, we suggest paying
<a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
a visit.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<CommunityIcon />
</template>
<template #heading>Community</template>
Got stuck? Ask your question on
<a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>, our official
Discord server, or
<a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
>StackOverflow</a
>. You should also subscribe to
<a href="https://news.vuejs.org" target="_blank" rel="noopener">our mailing list</a> and follow
the official
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
twitter account for latest news in the Vue world.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<SupportIcon />
</template>
<template #heading>Support Vue</template>
As an independent project, Vue relies on community backing for its sustainability. You can help
us by
<a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
</WelcomeItem>
</template>

View File

@ -1,87 +0,0 @@
<template>
<div class="item">
<i>
<slot name="icon"></slot>
</i>
<div class="details">
<h3>
<slot name="heading"></slot>
</h3>
<slot></slot>
</div>
</div>
</template>
<style scoped>
.item {
margin-top: 2rem;
display: flex;
position: relative;
}
.details {
flex: 1;
margin-left: 1rem;
}
i {
display: flex;
place-items: center;
place-content: center;
width: 32px;
height: 32px;
color: var(--color-text);
}
h3 {
font-size: 1.2rem;
font-weight: 500;
margin-bottom: 0.4rem;
color: var(--color-heading);
}
@media (min-width: 1024px) {
.item {
margin-top: 0;
padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
}
i {
top: calc(50% - 25px);
left: -26px;
position: absolute;
border: 1px solid var(--color-border);
background: var(--color-background);
border-radius: 8px;
width: 50px;
height: 50px;
}
.item:before {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
bottom: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:after {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
top: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:first-of-type:before {
display: none;
}
.item:last-of-type:after {
display: none;
}
}
</style>

Some files were not shown because too many files have changed in this diff Show More