131 Commits

Author SHA1 Message Date
f3c5401b07 added annoying bundle.yaml to gitignore
All checks were successful
Format / formatting (push) Successful in 5s
Build / build (push) Successful in 43s
CI / build (push) Successful in 11s
2025-05-10 22:51:59 +02:00
f2448a029f added two endpoints necessary for routing in project request phase
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 41s
CI / build (push) Successful in 11s
2025-05-10 20:39:45 +02:00
d4533ea725 added an endpoint to see if useraccuont is pending or not
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 42s
CI / build (push) Successful in 11s
2025-05-09 21:23:35 +02:00
255af7ee7f feat: final test in sharedApi passing, it took a while to find where the bug is getAppointments by project
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 41s
CI / build (push) Successful in 11s
2025-05-07 20:57:03 +02:00
3b308cfa6d fix: my bad 403 error codes are never thrown by src code, now is up to date
All checks were successful
Format / formatting (push) Successful in 5s
Build / build (push) Successful in 39s
CI / build (push) Successful in 10s
2025-05-07 11:44:09 +02:00
d31bf259dd Merge branch 'main' into backend-test
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 40s
CI / build (push) Successful in 11s
Format / formatting (pull_request) Successful in 6s
2025-05-07 11:06:30 +02:00
43b40c9432 feat: just added 403 response
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 40s
CI / build (push) Successful in 10s
Format / formatting (pull_request) Successful in 5s
2025-05-07 11:04:24 +02:00
e84f69c21a fix: unused imports
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 41s
CI / build (push) Successful in 11s
2025-05-07 11:02:08 +02:00
c76e83f2bf feat: changed endpoints
Some checks failed
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 41s
CI / build (push) Failing after 8s
2025-05-07 11:00:15 +02:00
1f0f9196c4 feat: fixed 403 errors
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 40s
CI / build (push) Successful in 11s
2025-05-07 10:45:38 +02:00
40e577ef07 Merge pull request 'backend-test' (#10) from backend-test into main
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 41s
CI / build (push) Successful in 11s
Reviewed-on: #10
Reviewed-by: adnane <adnane.alami@bordeaux-inp.fr>
Reviewed-by: anas <anas.maillal@bordeaux-inp.fr>
Reviewed-by: omar <omar.el_alaoui_el_ismaili@bordeaux-inp.fr>
2025-05-07 10:43:30 +02:00
13845394e3 feat: added doc for endpoint make-admin
All checks were successful
Format / formatting (push) Successful in 25s
Build / build (push) Successful in 44s
CI / build (push) Successful in 13s
Format / formatting (pull_request) Successful in 6s
2025-05-04 20:15:03 +02:00
f4589c6306 fix: bug on CORS discussed before
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 46s
CI / build (push) Successful in 13s
Format / formatting (pull_request) Successful in 6s
2025-05-01 21:03:23 +02:00
6004bce4e8 Merge branch 'main' into backend-test
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 42s
CI / build (push) Successful in 11s
2025-05-01 20:53:18 +02:00
0730275e75 feat: added create-account
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 44s
CI / build (push) Successful in 11s
2025-05-01 20:51:10 +02:00
5183a088e7 fix: forgot to remove a pram in an endpoint in docs
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 45s
CI / build (push) Successful in 13s
2025-04-29 21:41:25 +02:00
b503cae235 fix: styling
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 1m33s
CI / build (push) Successful in 11s
2025-04-29 21:25:03 +02:00
fcf4e1c01d feat: added an endpoint for fething the project an entrepreneur is associated with
Some checks failed
Format / formatting (push) Failing after 6s
Build / build (push) Successful in 1m28s
CI / build (push) Successful in 11s
2025-04-29 21:22:13 +02:00
3f18304028 formatting works time in and time out, empty commit to fix
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 42s
CI / build (push) Successful in 11s
2025-04-29 19:31:28 +02:00
bbb4debcd8 fix: changed the data structure used in getAllSectionCells for processing the latest version of sectioneCells as it gave some exception (it doesn't like being iterated and modified at the same time)
Some checks failed
Format / formatting (push) Failing after 6s
Build / build (push) Successful in 41s
CI / build (push) Successful in 11s
2025-04-29 19:18:12 +02:00
6f7fc70c4c didn't use the correct function for seting ids, test fixed
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 41s
CI / build (push) Successful in 16s
2025-04-29 18:50:25 +02:00
3d57ecb01a fix: fixed some sectionCell fetching logic (previously wasn't grouping by idReference), found out that idRefrence in sectionCell is always being incremented at inserion still looking for a fix
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 41s
CI / build (push) Successful in 11s
2025-04-29 13:59:05 +02:00
3673aa379c formatting
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 40s
CI / build (push) Successful in 11s
2025-04-23 12:21:56 +02:00
b672b2e9f9 just changed test location in file, hope these commits don't diverge
Some checks failed
Format / formatting (push) Failing after 6s
Build / build (push) Successful in 42s
CI / build (push) Successful in 11s
2025-04-23 12:11:57 +02:00
193876e51c I forgot to push the package-lock.json probably gonna need it since half the stuff used for swagger-ui is old unfortunately 2025-04-23 12:11:57 +02:00
b8c7c6f587 feat: spotted some responses on post requests I forgot to remove 2025-04-23 12:11:57 +02:00
bee47473d5 feat: finsihed tests for EntrepreneurApiService
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 40s
CI / build (push) Successful in 13s
2025-04-23 11:54:18 +02:00
e7739af80b feat: more tests
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 41s
CI / build (push) Successful in 11s
2025-04-23 11:52:08 +02:00
32557f8f87 forgot to format
Some checks failed
Format / formatting (push) Successful in 6s
Build / build (push) Failing after 39s
CI / build (push) Successful in 11s
2025-04-23 11:50:48 +02:00
8ee06b93a6 fix: added null check in sharedService and updated test
Some checks failed
Format / formatting (push) Failing after 5s
Build / build (push) Failing after 39s
CI / build (push) Successful in 11s
2025-04-23 11:47:41 +02:00
6861d07dfc tests ?
Some checks failed
Format / formatting (push) Successful in 6s
Build / build (push) Failing after 39s
CI / build (push) Successful in 14s
2025-04-23 10:48:40 +02:00
8403bc0592 fixing formatting: sure is fun
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 40s
CI / build (push) Successful in 10s
2025-04-22 09:51:31 +02:00
5edcf9ffc8 fix: fixed formatting to be compatible with workflow
Some checks failed
Format / formatting (push) Failing after 6s
Build / build (push) Successful in 41s
CI / build (push) Successful in 11s
2025-04-22 09:46:07 +02:00
5615b0fb11 fix: update doc to encompose all response codes hopefully
Some checks failed
Format / formatting (push) Failing after 6s
Build / build (push) Successful in 41s
CI / build (push) Successful in 10s
2025-04-22 00:21:08 +02:00
8a13993d8a fix: made endpoints match documentation naming conventions 'just the mapping' and noted endpoints not yet implemented in documentation/openapi/notes.md
Some checks failed
Format / formatting (push) Failing after 6s
Build / build (push) Successful in 40s
CI / build (push) Successful in 11s
2025-04-21 23:55:14 +02:00
561f6d16b3 tests: implemented some tests, overall percentage of coverage is 40%, still trying to find a way arround class comparaison
Some checks failed
Format / formatting (push) Failing after 6s
Build / build (push) Successful in 41s
CI / build (push) Successful in 11s
2025-04-21 23:17:32 +02:00
832539f43b feat: added doc for upcoming endpoints to finish up entrepreneur join, response codes remaining to update
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 39s
CI / build (push) Successful in 10s
2025-04-21 10:54:50 +02:00
dfea20b9c4 fix: aadded changes, doc is ssomewhat coherent still need to change some endpoint names in controller and some minor changes
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 38s
CI / build (push) Successful in 10s
2025-04-16 12:31:00 +02:00
f96872fb6b fix: not red anymore
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 38s
CI / build (push) Successful in 11s
2025-04-16 11:55:54 +02:00
0140672812 why is cache enabled again ??
Some checks failed
Format / formatting (push) Successful in 5s
Build / build (push) Failing after 38s
CI / build (push) Successful in 11s
2025-04-16 11:29:25 +02:00
7df2c768c8 fix : tests
Some checks failed
CI / build (push) Waiting to run
Format / formatting (push) Successful in 5s
Build / build (push) Has been cancelled
2025-04-16 11:26:25 +02:00
6029457735 fix: more tests working, still need fixes
Some checks failed
Format / formatting (push) Failing after 4s
Build / build (push) Failing after 5m8s
CI / build (push) Successful in 10s
2025-04-16 10:36:59 +02:00
55112c8508 test: added initial test file mainly definitions and descritions of tests haven't finshed
Some checks failed
Format / formatting (push) Failing after 6s
Build / build (push) Failing after 5m6s
CI / build (push) Successful in 11s
2025-04-16 10:15:13 +02:00
676f1204cb feat: updated doc to reflect details of server, still not done editing it
Some checks failed
CI / build (push) Waiting to run
Format / formatting (push) Successful in 7s
Build / build (push) Has been cancelled
2025-04-16 10:12:16 +02:00
66be0baca6 feat: created a better account creation flow
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 5m20s
CI / build (push) Successful in 11s
2025-04-09 17:39:43 +02:00
7e1271cfe2 Merge pull request 'fix: reverted previous commit, cache juste does not work' (#8) from fix_cache into main
All checks were successful
Format / formatting (push) Successful in 5s
Build / build (push) Successful in 44s
CI / build (push) Successful in 11s
Reviewed-on: #8
2025-04-06 20:56:39 +02:00
801ecb3817 Merge branch 'main' into fix_cache
All checks were successful
Format / formatting (push) Successful in 5s
Build / build (push) Successful in 46s
CI / build (push) Successful in 11s
Format / formatting (pull_request) Successful in 6s
2025-04-06 20:56:22 +02:00
cc89d4c79f fix: reverted previous commit, cache juste does not work
Some checks are pending
Format / formatting (push) Waiting to run
Build / build (push) Waiting to run
CI / build (push) Waiting to run
Format / formatting (pull_request) Successful in 6s
2025-04-06 20:55:35 +02:00
adf9a93e2e Merge pull request 'feat: enabled graddle cache. Subsequent actions should be fasters' (#7) from fix_cache into main
Some checks failed
CI / build (push) Waiting to run
Format / formatting (push) Successful in 5s
Build / build (push) Has been cancelled
Reviewed-on: #7
2025-04-06 20:41:13 +02:00
37d8bcc719 feat: enabled graddle cache. Subsequent actions should be fasters
Some checks failed
Format / formatting (push) Successful in 5s
Build / build (push) Has been cancelled
CI / build (push) Successful in 12s
Format / formatting (pull_request) Successful in 6s
2025-04-06 20:39:45 +02:00
385c5cd8d0 fix: added back the cache since the action ran once on the main branch
All checks were successful
Format / formatting (push) Successful in 5s
Build / build (push) Successful in 5m16s
CI / build (push) Successful in 12s
2025-04-06 20:32:45 +02:00
b672dd200c fix: name coherence + test logic
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 43s
CI / build (push) Successful in 13s
2025-04-06 20:30:29 +02:00
9e1f568ea4 fix: comparaison between two projects instead of their IDs
Some checks failed
Format / formatting (push) Successful in 6s
Build / build (push) Failing after 38s
CI / build (push) Successful in 14s
2025-04-06 20:14:43 +02:00
aaa6e46d0c fix (kinda) : refactored update of data, still trying to fix bug
Some checks failed
Format / formatting (push) Successful in 6s
Build / build (push) Failing after 39s
CI / build (push) Successful in 11s
from EntrepreneurApiServiceTests (code is a bit messy with prints and comments dw)
2025-04-06 19:22:18 +02:00
9b9cfbdb2e merged openapi with backend-test
Some checks failed
Format / formatting (push) Successful in 6s
Build / build (push) Failing after 37s
CI / build (push) Successful in 13s
2025-04-02 11:17:28 +02:00
5b6b647697 feat: started test for EntrepreneurServiceApi
Some checks failed
Format / formatting (push) Successful in 5s
Build / build (push) Failing after 37s
CI / build (push) Successful in 11s
2025-04-02 10:25:50 +02:00
81ce4fdb4c fix: commented docker back lines in order to push after trying to fix the error in tests
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 39s
CI / build (push) Successful in 11s
2025-03-30 19:35:14 +02:00
ebd76a30ee feat: updated date format next is descriptions and setting up http request tests 2025-03-27 17:34:41 +01:00
ead11215ba Merge pull request 'backend-api' (#6) from backend-api into main
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 38s
CI / build (push) Successful in 10s
Reviewed-on: #6
Reviewed-by: Theo <tlelez@enseirb-matmeca.fr>
Reviewed-by: adnane <adnane.alami@bordeaux-inp.fr>
Reviewed-by: mohamed_maoulainine <mohamed_maoulainine.maoulainine@bordeaux-inp.fr>
2025-03-26 19:04:08 +01:00
6ff6ce5052 fix: just fixed duplicate test files due to bad merge
All checks were successful
Format / formatting (push) Successful in 9s
Build / build (push) Successful in 43s
CI / build (push) Successful in 11s
2025-03-26 10:04:46 +01:00
60ec920cff fix: split openapi src files and made bash file to run
Some checks failed
Format / formatting (push) Successful in 5s
Build / build (push) Failing after 32s
CI / build (push) Successful in 11s
2025-03-23 17:12:31 +01:00
900a4c5bdc merged backend-api onto openapi to avoid working with worktree
Some checks failed
Format / formatting (push) Successful in 7s
Build / build (push) Failing after 30s
CI / build (push) Successful in 11s
2025-03-23 15:41:44 +01:00
d0b615c59d fix: the endpoints reflect the db models and changes since the last version of the doc, notes.md indicate some changes that are needed to happen in the controller and questions to be discussed
All checks were successful
CI / build (push) Successful in 11s
2025-03-21 09:42:57 +01:00
eccf116f49 feat: added swagger-ui to read docs and test api, fix: minor changes to yaml file, more to come
All checks were successful
CI / build (push) Successful in 13s
2025-03-20 19:11:32 +01:00
8491c9b3cf added minor change 2025-03-19 22:02:28 +01:00
137bc84c21 Merge branch 'backend-api' of ssh://gitea.piair.dev:2222/piair/MyINPulse into backend-api
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 38s
CI / build (push) Successful in 10s
Format / formatting (pull_request) Successful in 5s
2025-03-19 12:06:00 +01:00
3c61fdca93 feat: finished implementing apiService functions 2025-03-19 12:05:56 +01:00
5ee3755548 feat: added new tests and fixed few issues
All checks were successful
Format / formatting (push) Successful in 7s
Build / build (push) Successful in 38s
CI / build (push) Successful in 12s
2025-03-19 12:05:01 +01:00
52511dd4c4 fix: Makefile now run everything needed to build the app 2025-03-19 10:42:46 +01:00
84b70f8f38 fix: sometimes, project administrators may be null. Fixing nullPointerException
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 37s
CI / build (push) Successful in 11s
2025-03-17 09:18:21 +01:00
834d68949c fix: tabulation error
Some checks failed
Format / formatting (push) Successful in 6s
Build / build (push) Failing after 39s
CI / build (push) Successful in 11s
2025-03-17 09:08:33 +01:00
fea8687664 feat: now running tests
All checks were successful
Format / formatting (push) Successful in 6s
CI / build (push) Successful in 10s
2025-03-17 09:05:24 +01:00
c94d3654ce fix: updating foreign keys when adding new entity to the db
All checks were successful
Format / formatting (push) Successful in 7s
Build / build (push) Successful in 31s
CI / build (push) Successful in 11s
2025-03-15 15:23:18 +01:00
d5c89bf8f4 fix: spelling
All checks were successful
Format / formatting (push) Successful in 5s
Build / build (push) Successful in 27s
CI / build (push) Successful in 11s
2025-03-12 12:25:26 +01:00
78c72bdd72 fix: linter
Some checks failed
Format / formatting (push) Failing after 5s
Build / build (push) Successful in 27s
CI / build (push) Successful in 10s
2025-03-12 12:23:27 +01:00
307c7e700b merge
Some checks failed
Format / formatting (push) Failing after 5s
Build / build (push) Successful in 27s
CI / build (push) Successful in 10s
2025-03-12 12:19:35 +01:00
8d486dce89 feat: continued implementing adminApiService 2025-03-12 12:16:01 +01:00
653f923693 fix: bugfix
All checks were successful
Format / formatting (push) Successful in 5s
Build / build (push) Successful in 27s
CI / build (push) Successful in 11s
2025-03-12 12:08:49 +01:00
64da3c9ab0 feat: tests on AdminApiService 2025-03-12 12:07:48 +01:00
419ceec1bc feat: switched from String to ProjectDecisionValues
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 28s
CI / build (push) Successful in 11s
2025-03-12 10:25:19 +01:00
e011a5534e feat: switched from String to ProjectDecisionValues
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 30s
CI / build (push) Successful in 15s
2025-03-12 10:21:08 +01:00
ef964c4d35 fix: removed id + renamed mainEmail to primaryEmail everywhere
All checks were successful
Format / formatting (push) Successful in 8s
Build / build (push) Successful in 28s
CI / build (push) Successful in 11s
2025-03-11 13:02:17 +01:00
5608b12f84 fix: removed id + renamed mainEmail to primaryEmail everywhere 2025-03-11 13:01:53 +01:00
467babab79 fix: removed id + renamed mainEmail to primaryEmail everywhere 2025-03-11 13:01:28 +01:00
a2e2395cc2 feat: added new tests and coverage report 2025-03-11 13:00:38 +01:00
e3393c8834 test
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 28s
CI / build (push) Successful in 10s
2025-03-09 21:20:20 +01:00
5f8fe4a374 feat: precommit hook for google java format 2025-03-09 21:19:00 +01:00
c5e7736a16 fix: wtf does idea do ?? Why d methods move ? fixed linter again...
All checks were successful
Format / formatting (push) Successful in 5s
Build / build (push) Successful in 27s
CI / build (push) Successful in 10s
2025-03-09 21:10:25 +01:00
04589392cb fix: removed debug logging
Some checks failed
Format / formatting (push) Failing after 6s
Build / build (push) Successful in 29s
CI / build (push) Successful in 11s
2025-03-09 21:07:29 +01:00
1106cf8478 feat: added tests. 2025-03-09 21:06:31 +01:00
215d80ad70 fix: removed contradictive @NotNull preventing to add data to database. 2025-03-09 21:04:52 +01:00
dded62c25a fix: take latest implementation of logging module + imported inmemory database for testing 2025-03-09 20:22:20 +01:00
3de7ebe2b1 fix: remoed debug logging 2025-03-09 20:21:32 +01:00
8153496a0f feat: implemented database for testing purposes
All checks were successful
Format / formatting (push) Successful in 7s
Build / build (push) Successful in 28s
CI / build (push) Successful in 11s
2025-03-04 18:42:14 +01:00
861e7495a7 fix: re-enabled cache to drastically reduce action time. This should be fixed later
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 27s
CI / build (push) Successful in 10s
2025-03-01 01:00:52 +01:00
d78e43f7e0 fix: improved the workflow
Some checks failed
Format / formatting (push) Successful in 5s
Build / build (push) Has been cancelled
CI / build (push) Successful in 11s
2025-03-01 00:58:50 +01:00
3ca97cf378 fix: improved the workflow
All checks were successful
Format / formatting (push) Successful in 6s
Build / build (push) Successful in 28s
CI / build (push) Successful in 12s
2025-03-01 00:57:34 +01:00
e6a8d98d63 fix: improved the workflow
Some checks failed
Format / formatting (push) Successful in 6s
Build / build (push) Failing after 34s
CI / build (push) Successful in 11s
2025-02-28 12:20:48 +01:00
8894fea6d4 fix: improved the workflow
Some checks failed
Format / formatting (push) Successful in 6s
Build / build (push) Failing after 18s
CI / build (push) Successful in 10s
2025-02-28 12:20:05 +01:00
236bb0d167 fix: improved the workflow
Some checks failed
Format / formatting (push) Successful in 5s
Build / build (push) Failing after 6s
CI / build (push) Successful in 11s
2025-02-28 12:18:36 +01:00
d4dcc95d9b fix: removed cache to speed up things
Some checks failed
Format / formatting (push) Successful in 5s
Build / build (push) Failing after 14s
CI / build (push) Successful in 11s
2025-02-28 12:16:43 +01:00
dc843299eb fix: action create the gradlew wrapper
Some checks failed
Format / formatting (push) Successful in 5s
Build / build (push) Failing after 4m49s
CI / build (push) Successful in 11s
2025-02-28 12:10:13 +01:00
f3eaf8fe34 fix: action create the gradlew wrapper
Some checks failed
Format / formatting (push) Successful in 6s
Build / build (push) Failing after 4m46s
CI / build (push) Successful in 11s
2025-02-28 12:04:11 +01:00
628c61fb8b feat: pipeline should now test if the project builds
Some checks failed
Format / formatting (push) Successful in 5s
Build / build (push) Failing after 5m49s
CI / build (push) Successful in 10s
2025-02-28 11:55:43 +01:00
4880f3829c I don't get it, how does it keeps failing with the formatter installed... time to create pre-commit hook I guess
All checks were successful
Format / formatting (push) Successful in 6s
CI / build (push) Successful in 10s
2025-02-28 11:47:45 +01:00
80b2d087e4 feat: implemented date filtration and a utils service to prevent code ducplication
Some checks failed
Format / formatting (push) Failing after 7s
CI / build (push) Successful in 11s
2025-02-28 11:45:55 +01:00
b5c03798fc fix: formatter now follow the same logic as idea, see https://github.com/google/google-java-format/issues/566
All checks were successful
Format / formatting (push) Successful in 5s
CI / build (push) Successful in 10s
2025-02-26 18:55:45 +01:00
1d970ce5f5 feat: continued to implement SharedApiService (if linter fails i don't understand)
Some checks failed
Format / formatting (push) Failing after 6s
CI / build (push) Successful in 11s
2025-02-26 18:33:09 +01:00
f9de5ed6bf feat: finished creating services from controllers, continued implementing entrepreneurServiceApi with some validation
Some checks failed
Format / formatting (push) Failing after 6s
CI / build (push) Successful in 11s
2025-02-26 17:35:52 +01:00
e75a5c9d2c fix: linter ??? pls idea be better
All checks were successful
Format / formatting (push) Successful in 5s
CI / build (push) Successful in 12s
2025-02-26 15:57:03 +01:00
5c3b2b138d feat: renamex title to sectionId and added a new shared API call
Some checks failed
Format / formatting (push) Failing after 5s
CI / build (push) Successful in 11s
2025-02-26 15:55:33 +01:00
8d4dc7916d feat: added most of shared API calls
Some checks failed
Format / formatting (push) Failing after 5s
CI / build (push) Successful in 10s
2025-02-26 15:31:02 +01:00
1a6db7c953 feat: added color in logs
All checks were successful
Format / formatting (push) Successful in 6s
CI / build (push) Successful in 11s
2025-02-26 15:29:55 +01:00
3890aed158 Merge branch 'backend-api' of ssh://gitea.piair.dev:2222/piair/MyINPulse into backend-api
All checks were successful
Format / formatting (push) Successful in 5s
CI / build (push) Successful in 11s
2025-02-26 14:51:52 +01:00
dd5ca2cbd7 feat: entrepreneur api and api service 2025-02-26 14:51:02 +01:00
024deeba41 fix: linter - how did this append ?
All checks were successful
Format / formatting (push) Successful in 6s
CI / build (push) Successful in 10s
2025-02-26 14:30:58 +01:00
1cebebf1a5 feat: implemented most of the backend api for administrator
Some checks failed
Format / formatting (push) Failing after 6s
CI / build (push) Successful in 11s
2025-02-26 14:29:38 +01:00
d8bc7cc9b6 feat: added log4j. It's way better than System.stderr. 2025-02-26 14:28:31 +01:00
067eeb9494 docs: added examples and changed some weird character
All checks were successful
CI / build (push) Successful in 11s
2025-02-26 11:31:45 +01:00
e66fa33577 feat: added a new database service
All checks were successful
Format / formatting (push) Successful in 7s
CI / build (push) Successful in 13s
2025-02-26 10:32:44 +01:00
b355463dd9 docs: added needed modications and reorganized yaml file
All checks were successful
CI / build (push) Successful in 11s
2025-02-25 22:34:33 +01:00
27e70ee109 fix: naming issues with database and better data
All checks were successful
Format / formatting (push) Successful in 7s
CI / build (push) Successful in 11s
2025-02-24 17:19:18 +01:00
153501c8d4 Fix: merge
All checks were successful
Format / formatting (push) Successful in 7s
CI / build (push) Successful in 11s
2025-02-19 18:52:43 +01:00
40afde89b7 Fix: renamed all the tables, with repo and controller associated to them (might have missed some), and fix some key dependency issues 2025-02-19 18:41:37 +01:00
4698aa549f feat: frontend call now include the token and send the email from the token to backen servie
All checks were successful
Format / formatting (push) Successful in 6s
CI / build (push) Successful in 11s
2025-02-19 12:09:37 +01:00
79e949bdd4 feat: configured gradle file to generate code for api interface from swagger specification
All checks were successful
CI / build (push) Successful in 11s
2025-02-19 01:36:52 +01:00
04a73073c1 feat: switch to a service layer architecture
All checks were successful
Format / formatting (push) Successful in 6s
CI / build (push) Successful in 11s
2025-02-18 22:15:14 +01:00
11ab5e1dc4 feat: merged Keycloak / postgres
All checks were successful
Format / formatting (push) Successful in 7s
CI / build (push) Successful in 11s
2025-02-18 17:20:08 +01:00
3cb12dab4f feat: created signature of all api functions
All checks were successful
Format / formatting (push) Successful in 8s
CI / build (push) Successful in 11s
2025-02-18 10:50:21 +01:00
0a9d83655f feat: query to database from and unaut endpoint
All checks were successful
Format / formatting (push) Successful in 9s
CI / build (push) Successful in 12s
2025-02-13 21:57:41 +01:00
ef8c8e896d feat: added openapi documentation to the project
All checks were successful
CI / build (push) Successful in 11s
2025-02-12 20:59:13 +01:00
97 changed files with 11380 additions and 1345 deletions

View File

@ -15,4 +15,4 @@ jobs:
- uses: axel-op/googlejavaformat-action@v3
with:
args: "--set-exit-if-changed --skip-sorting-imports --aosp -n"
args: "--set-exit-if-changed --skip-sorting-imports --skip-reflowing-long-strings --aosp -n"

View File

@ -0,0 +1,32 @@
name: Build
on:
push:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Load .env file
uses: xom9ikk/dotenv@v2.3.0
with:
path: ./config/
mode: dev
load-mode: strict
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 21
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
cache-disabled: true # Once the code has been pushed once in main, this should be reenabled.
- name: init gradle
working-directory: ./MyINPulse-back/
run: ./gradlew build # todo: run test, currently fail because no database is present

6
.gitignore vendored
View File

@ -1,5 +1,9 @@
.env
.idea
keycloak/CAS/target
keycloak/.installed
docker-compose.yaml
postgres/data
node_modules
.vscode
postgres/data
bundled.yaml

View File

@ -2,6 +2,7 @@ help:
@echo "make [clean dev-front prod dev-back dev]"
clean:
pkill -9 node
@cp config/frontdev.env front/MyINPulse-front/.env
@cp config/frontdev.env .env
@cp config/frontdev.env MyINPulse-back/.env
@ -19,8 +20,14 @@ front/MyINPulse-front/.installed:
vite: ./front/MyINPulse-front/.installed
keycloak: ./keycloak/.installed
dev-front: clean vite
keycloak/.installed:
@echo "running one time install"
@cd keycloak/CAS && sudo sh build.sh
@touch ./keycloak/.installed
dev-front: clean vite keycloak
@cp config/frontdev.env front/MyINPulse-front/.env
@cp config/frontdev.env .env
@cp config/frontdev.env MyINPulse-back/.env
@ -28,7 +35,7 @@ dev-front: clean vite
@docker compose up -d --build
@cd ./front/MyINPulse-front/ && npm run dev
prod: clean
prod: clean keycloak
@cp config/prod.env front/MyINPulse-front/.env
@cp config/prod.env .env
@cp config/prod.env .env
@ -37,7 +44,7 @@ prod: clean
dev-back:
dev-back: keycloak
@cp config/backdev.env front/MyINPulse-front/.env
@cp config/backdev.env .env
@cp config/backdev.env MyINPulse-back/.env
@ -46,7 +53,7 @@ dev-back:
@echo "cd MyINPulse-back" && echo 'export $$(cat .env | xargs)'
@echo "./gradlew bootRun --args='--server.port=8081'"
dev: clean vite
dev: clean vite keycloak
@cp config/dev.env front/MyINPulse-front/.env
@cp config/dev.env .env
@cp config/dev.env MyINPulse-back/.env
@ -55,3 +62,13 @@ dev: clean vite
@echo "cd MyINPulse-back" && echo 'export $$(cat .env | xargs)'
@echo "./gradlew bootRun --args='--server.port=8081'"
@cd ./front/MyINPulse-front/ && npm run dev &
test-back: clean keycloak
@cp config/dev.env front/MyINPulse-front/.env
@cp config/dev.env .env
@cp config/dev.env MyINPulse-back/.env
@cp config/dev.docker-compose.yaml docker-compose.yaml
@docker compose up -d --build
@echo "cd MyINPulse-back" && echo 'export $$(cat .env | xargs)'
@cd ./MyINPulse-back/ && ./gradlew test && ./gradlew jacocoTestReport
@firefox ./MyINPulse-back/build/jacocoHtml/index.html

View File

@ -1,33 +1,59 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.4.2'
id 'io.spring.dependency-management' version '1.1.7'
id 'java'
id 'org.springframework.boot' version '3.4.2'
id 'io.spring.dependency-management' version '1.1.7'
id 'jacoco'
}
group = 'enseirb'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
repositories {
mavenCentral()
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
implementation 'org.postgresql:postgresql'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.+'
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.+'
implementation 'org.postgresql:postgresql'
implementation group: 'com.itextpdf', name: 'itextpdf', version: '5.5.13.3'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'com.h2database:h2'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
useJUnitPlatform()
}
test {
finalizedBy jacocoTestReport // report is always generated after tests run
}
jacocoTestReport {
dependsOn test // tests are required to run before generating the report
reports {
xml.required = false
csv.required = false
html.outputLocation = layout.buildDirectory.dir('jacocoHtml')
}
}
jacoco {
toolVersion = "0.8.12"
reportsDirectory = layout.buildDirectory.dir('customJacocoReportDir')
}

View File

@ -1,40 +0,0 @@
package enseirb.myinpulse.api;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
import javax.management.relation.RoleNotFoundException;
@SpringBootApplication
@RestController
public class GetUserInfo {
// TODO: understand how to get data
@GetMapping("/getUserInfo")
public Object user(Principal principal) {
System.out.println("GetUserInfo + " + principal);
System.out.println(SecurityContextHolder.getContext().getAuthentication());
return SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
@CrossOrigin(methods = {RequestMethod.GET, RequestMethod.OPTIONS})
@GetMapping("/unauth/random")
public boolean rand(@RequestHeader("Authorization") String token) throws RoleNotFoundException {
System.err.println(token);
return Math.random() > 0.5;
}
@GetMapping("/admin/random")
public boolean rand2() {
return Math.random() > 0.5;
}
@GetMapping("/entrepreneur/random")
public boolean rand3() {
return Math.random() > 0.5;
}
}

View File

@ -2,7 +2,7 @@
* Source: https://github.com/ChristianHuff-DEV/secure-spring-rest-api-using-keycloak/blob/main/src/main/java/io/betweendata/RestApi/security/oauth2/KeycloakJwtRolesConverter.java
* edited by Pierre Tellier
*/
package enseirb.myinpulse.security;
package enseirb.myinpulse.config;
import static java.util.stream.Collectors.toSet;

View File

@ -2,8 +2,6 @@ package enseirb.myinpulse.config;
import static org.springframework.security.authorization.AuthorityAuthorizationManager.hasRole;
import enseirb.myinpulse.security.KeycloakJwtRolesConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -33,7 +31,7 @@ public class WebSecurityCustomConfiguration {
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of(frontendUrl));
configuration.setAllowedMethods(Arrays.asList("GET", "OPTIONS"));
configuration.setAllowedMethods(Arrays.asList("GET", "OPTIONS", "POST", "PUT", "DELETE"));
configuration.setAllowedHeaders(
Arrays.asList("authorization", "content-type", "x-auth-token"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
@ -62,10 +60,14 @@ public class WebSecurityCustomConfiguration {
.access(hasRole("REALM_MyINPulse-entrepreneur"))
.requestMatchers("/admin/**")
.access(hasRole("REALM_MyINPulse-admin"))
.requestMatchers("/shared/**")
.hasAnyRole(
"REALM_MyINPulse-admin",
"REALM_MyINPulse-entrepreneur")
.requestMatchers("/unauth/**")
.permitAll()
.authenticated()
.anyRequest()
.authenticated())
.denyAll())
.oauth2ResourceServer(
oauth2 ->
oauth2.jwt(

View File

@ -0,0 +1,129 @@
package enseirb.myinpulse.controller;
import enseirb.myinpulse.model.*;
import enseirb.myinpulse.service.AdminApiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.web.bind.annotation.*;
@SpringBootApplication
@RestController
public class AdminApi {
private final AdminApiService adminApiService;
@Autowired
AdminApi(AdminApiService adminApiService) {
this.adminApiService = adminApiService;
}
/**
* TODO: description
*
* @return a list of all project managed by the current admin user
*/
@GetMapping("/admin/projects")
public Iterable<Project> getProjects(@AuthenticationPrincipal Jwt principal) {
return adminApiService.getProjectsOfAdmin(principal.getClaimAsString("email"));
}
/**
* TODO: Why in admin instead of shared ? + desc
*
* @return a list of upcoming appointments for the current user
*/
@GetMapping("/admin/appointments/upcoming")
public Iterable<Appointment> getUpcomingAppointments(@AuthenticationPrincipal Jwt principal) {
return adminApiService.getUpcomingAppointments(principal.getClaimAsString("email"));
}
/**
* TODO: description
*
* @return a list of current unvalidated projects, waiting to be accepted
*/
@GetMapping("/admin/projects/pending")
public Iterable<Project> getPendingProjects() {
return adminApiService.getPendingProjects();
}
/**
* Endpoint used to make a decision about a project.
*
* <p>The decision must contain the administrator
*
* @return the status code of the request
*/
@PostMapping("/admin/projects/pending/decision")
public void validateProject(@RequestBody ProjectDecision decision) {
adminApiService.validateProject(decision);
}
/**
* Endpoint used to manually add a project by an admin
*
* @return the status code of the request
*/
@PostMapping("/admin/project")
public void addNewProject(@RequestBody Project project) {
adminApiService.addNewProject(project);
}
/**
* TODO: shouldn't it be an PUT request ? / What is the rerun type
*
* <p>Endpoint used to add a new report to an appointment
*
* @return the status code of the request
*/
@PostMapping("/admin/appointments/report/{appointmentId}")
public void createAppointmentReport(
@PathVariable long appointmentId,
@RequestBody Report report,
@AuthenticationPrincipal Jwt principal) {
adminApiService.createAppointmentReport(
appointmentId, report, principal.getClaimAsString("email"));
}
/**
* TODO: Shouldn't a project be kept in history ? 2 different endpoints ?
*
* <p>Endpoint used to completely remove a project.
*
* @return the status code of the request
*/
@DeleteMapping("/admin/projects/{projectId}")
public void deleteProject(@PathVariable long projectId) {
adminApiService.deleteProject(projectId);
}
@PostMapping("/admin/make-admin/{userId}")
public void setAdmin(@PathVariable long userId, @AuthenticationPrincipal Jwt principal) {
this.adminApiService.setAdmin(userId, principal.getTokenValue());
}
@PostMapping("/admin/accounts/validate/{userId}")
public void validateEntrepreneurAcc(
@PathVariable long userId, @AuthenticationPrincipal Jwt principal) {
this.adminApiService.validateEntrepreneurAccount(userId, principal.getTokenValue());
}
@GetMapping("/admin/pending-accounts")
public Iterable<User> validateEntrepreneurAcc() {
return this.adminApiService.getPendingUsers();
}
@PostMapping("/admin/create-account")
public void createAccount(@AuthenticationPrincipal Jwt principal) {
String userSurname = principal.getClaimAsString("userSurname");
String username = principal.getClaimAsString("preferred_username");
String primaryMail = principal.getClaimAsString("email");
String secondaryMail = principal.getClaimAsString("secondaryMail");
String phoneNumber = principal.getClaimAsString("phoneNumber");
this.adminApiService.createAccount(
userSurname, username, primaryMail, secondaryMail, phoneNumber);
}
}

View File

@ -0,0 +1,116 @@
package enseirb.myinpulse.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import enseirb.myinpulse.model.Project;
import enseirb.myinpulse.model.SectionCell;
import enseirb.myinpulse.service.EntrepreneurApiService;
@SpringBootApplication
@RestController
public class EntrepreneurApi {
private final EntrepreneurApiService entrepreneurApiService;
@Autowired
EntrepreneurApi(EntrepreneurApiService entrepreneurApiService) {
this.entrepreneurApiService = entrepreneurApiService;
}
/**
* TODO: check return type
*
* <p>Endpoint used to update a LC section.
*
* @return status code
*/
@PutMapping("/entrepreneur/sectionCells/{sectionCellId}")
public void editSectionCell(
@PathVariable Long sectionCellId,
@RequestBody String content,
@AuthenticationPrincipal Jwt principal) {
entrepreneurApiService.editSectionCell(
sectionCellId, content, principal.getClaimAsString("email"));
}
/**
* Endpoint used to update a LC section.
*
* @return status code
*/
@GetMapping("/entrepreneur/projects")
public Iterable<Project> getEntrepreneurProjectId(
@PathVariable Long sectionCellId,
@RequestBody String content,
@AuthenticationPrincipal Jwt principal) {
return entrepreneurApiService.getProjectIdViaClaim(principal.getClaimAsString("email"));
}
/**
* TODO: checkReturn Type
*
* <p>Endpoint used to delete a LC section
*
* @return status code
*/
@DeleteMapping("/entrepreneur/sectionCells/{sectionCellId}")
public void removeSectionCell(
@PathVariable Long sectionCellId, @AuthenticationPrincipal Jwt principal) {
entrepreneurApiService.removeSectionCell(
sectionCellId, principal.getClaimAsString("email"));
}
/**
* TODO: check return type
*
* <p>Endpoint used to create a new LC section
*
* @return status code
*/
@PostMapping("/entrepreneur/sectionCells")
public void addLCSection(
@RequestBody SectionCell sectionCell, @AuthenticationPrincipal Jwt principal) {
entrepreneurApiService.addSectionCell(sectionCell, principal.getClaimAsString("email"));
}
/**
* TODO: check return type
*
* <p>Endpoint used to request the creation of a new project
*
* @return status code
*/
@PostMapping("/entrepreneur/projects/request")
public void requestNewProject(
@RequestBody Project project, @AuthenticationPrincipal Jwt principal) {
entrepreneurApiService.requestNewProject(project, principal.getClaimAsString("email"));
}
/*
* <p>Endpoint to check if project is has already been validated by an admin
*/
@GetMapping("/entrepreneur/projects/project-is-active")
public Boolean checkIfProjectValidated(@AuthenticationPrincipal Jwt principal) {
return entrepreneurApiService.checkIfEntrepreneurProjectActive(
principal.getClaimAsString("email"));
}
/*
* <p>Endpoint to check if a user requested a project (used when project is pending)
*/
@GetMapping("/entrepreneur/projects/has-pending-request")
public Boolean checkIfHasRequested(@AuthenticationPrincipal Jwt principal) {
return entrepreneurApiService.entrepreneurHasPendingRequestedProject(
principal.getClaimAsString("email"));
}
}

View File

@ -0,0 +1,105 @@
package enseirb.myinpulse.controller;
import com.itextpdf.text.DocumentException;
import enseirb.myinpulse.model.*;
import enseirb.myinpulse.service.SharedApiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.net.URISyntaxException;
@SpringBootApplication
@RestController
public class SharedApi {
private final SharedApiService sharedApiService;
@Autowired
SharedApi(SharedApiService sharedApiService) {
this.sharedApiService = sharedApiService;
}
/**
* Endpoint used to get the data inside the lean canvas
*
* @return a list of lean canvas sections
*/
@GetMapping("/shared/projects/sectionCells/{projectId}/{sectionId}/{date}")
public Iterable<SectionCell> getLCSection(
@PathVariable("projectId") Long projectId,
@PathVariable("sectionId") Long sectionId,
@PathVariable("date") String date,
@AuthenticationPrincipal Jwt principal) {
return sharedApiService.getSectionCells(
projectId, sectionId, date, principal.getClaimAsString("email"));
}
/**
* Endpoint used to get entrepreneurs details
*
* @return a list of all entrepreneurs in a project
*/
@GetMapping("/shared/projects/entrepreneurs/{projectId}")
public Iterable<Entrepreneur> getEntrepreneursByProjectId(
@PathVariable int projectId, @AuthenticationPrincipal Jwt principal) {
return sharedApiService.getEntrepreneursByProjectId(
projectId, principal.getClaimAsString("email"));
}
/**
* Endpoint used to get the administrator of a project.
*
* @return the admin of a project
*/
@GetMapping("/shared/projects/admin/{projectId}")
public Administrator getAdminByProjectId(
@PathVariable int projectId, @AuthenticationPrincipal Jwt principal) {
return sharedApiService.getAdminByProjectId(projectId, principal.getClaimAsString("email"));
}
/**
* Endpoint used to get all appointments of a single project.
*
* @return a list of all appointments.
*/
@GetMapping("/shared/projects/appointments/{projectId}")
public Iterable<Appointment> getAppointmentsByProjectId(
@PathVariable int projectId, @AuthenticationPrincipal Jwt principal) {
return sharedApiService.getAppointmentsByProjectId(
projectId, principal.getClaimAsString("email"));
}
/**
* Endpoint used to generate a PDF report
*
* @return a PDF file? TODO: how does that works ?
*/
@GetMapping("/shared/appointments/report/{appointmentId}")
public void getPDFReport(
@PathVariable int appointmentId, @AuthenticationPrincipal Jwt principal) {
try {
sharedApiService.getPDFReport(appointmentId, principal.getClaimAsString("email"));
} catch (DocumentException e) {
System.out.println(e + "Document exception");
} catch (URISyntaxException e) {
System.out.println(e + "Error with URI");
} catch (IOException e) {
System.out.println(e + "Failed to access file");
}
}
/**
* @return TODO
*/
@PostMapping("/shared/appointments/request")
public void createAppointmentRequest(
@RequestBody Appointment appointment, @AuthenticationPrincipal Jwt principal) {
sharedApiService.createAppointmentRequest(appointment, principal.getClaimAsString("email"));
}
}

View File

@ -0,0 +1,61 @@
package enseirb.myinpulse.controller;
import enseirb.myinpulse.model.Entrepreneur;
import enseirb.myinpulse.service.EntrepreneurApiService;
import enseirb.myinpulse.service.UtilsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.web.bind.annotation.*;
@SpringBootApplication
@RestController
public class UnauthApi {
private final EntrepreneurApiService entrepreneurApiService;
private final UtilsService utilsService;
@Autowired
UnauthApi(EntrepreneurApiService entrepreneurApiService, UtilsService utilsService) {
this.entrepreneurApiService = entrepreneurApiService;
this.utilsService = utilsService;
}
@PostMapping("/unauth/finalize")
public void createAccount(@AuthenticationPrincipal Jwt principal) {
boolean sneeStatus;
if (principal.getClaimAsString("sneeStatus") != null) {
sneeStatus = principal.getClaimAsString("sneeStatus").equals("true");
} else {
sneeStatus = false;
}
String userSurname = principal.getClaimAsString("userSurname");
String username = principal.getClaimAsString("preferred_username");
String primaryMail = principal.getClaimAsString("email");
String secondaryMail = principal.getClaimAsString("secondaryMail");
String phoneNumber = principal.getClaimAsString("phoneNumber");
String school = principal.getClaimAsString("school");
String course = principal.getClaimAsString("course");
Entrepreneur e =
new Entrepreneur(
userSurname,
username,
primaryMail,
secondaryMail,
phoneNumber,
school,
course,
sneeStatus,
true);
entrepreneurApiService.createAccount(e);
}
@GetMapping("/unauth/check-if-not-pending")
public Boolean checkAccountStatus(@AuthenticationPrincipal Jwt principal) {
// Throws 404 if user not found
return utilsService.checkEntrepreneurNotPending(principal.getClaimAsString("email"));
}
}

View File

@ -1,4 +1,4 @@
package enseirb.myinpulse.exceptions;
package enseirb.myinpulse.exception;
public class RoleNotFoudException extends RuntimeException {
public RoleNotFoudException(String message) {

View File

@ -1,4 +1,4 @@
package enseirb.myinpulse.exceptions;
package enseirb.myinpulse.exception;
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {

View File

@ -0,0 +1,66 @@
package enseirb.myinpulse.model;
import jakarta.persistence.*;
import jakarta.persistence.PrimaryKeyJoinColumn;
import jakarta.persistence.Table;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "administrator")
@PrimaryKeyJoinColumn(name = "idAdministrator", referencedColumnName = "idUser")
public class Administrator extends User {
@OneToMany(mappedBy = "projectAdministrator", fetch = FetchType.LAZY, orphanRemoval = true)
private final List<Project> listProject = new ArrayList<>();
/*@OneToMany(mappedBy = "administratorSectionCell", fetch = FetchType.LAZY, orphanRemoval = true)
private List<SectionCell> listSectionCell = new ArrayList<>();*/
// should now be useless
@OneToMany(mappedBy = "administratorAnnotation", fetch = FetchType.LAZY, orphanRemoval = true)
private final List<Annotation> listAnnotation = new ArrayList<>();
/*@OneToMany(mappedBy = "administratorAppointment", fetch = FetchType.LAZY, orphanRemoval = true)
private final List<Appointment> listAppointment = new ArrayList<>();*/
// should now be useless
@OneToOne(mappedBy = "administratorAppointment", fetch = FetchType.LAZY, orphanRemoval = true)
private MakeAppointment makeAppointment;
public Administrator() {}
public Administrator(
String userSurname,
String username,
String primaryMail,
String secondaryMail,
String phoneNumber) {
super(userSurname, username, primaryMail, secondaryMail, phoneNumber, false);
}
public List<Project> getListProject() {
return listProject;
}
public void updateListProject(Project project) {
listProject.add(project);
}
public List<Annotation> getListAnnotation() {
return listAnnotation;
}
public void updateListAnnotation(Annotation annotation) {
listAnnotation.add(annotation);
}
public MakeAppointment getMakeAppointment() {
return makeAppointment;
}
public void setMakeAppointment(MakeAppointment makeAppointment) {
this.makeAppointment = makeAppointment;
}
}

View File

@ -0,0 +1,61 @@
package enseirb.myinpulse.model;
import jakarta.persistence.*;
@Entity
@Table(name = "annotation")
public class Annotation {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idAnnotation;
private String comment;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idSectionCell")
private SectionCell sectionCellAnnotation;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idAdministrator")
private Administrator administratorAnnotation;
public Annotation() {}
public Annotation(Long idAnnotation, String commentary) {
this.idAnnotation = idAnnotation;
this.comment = comment;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Long getIdAnnotation() {
return idAnnotation;
}
public void setIdAnnotation(Long idAnnotation) {
this.idAnnotation = idAnnotation;
}
public SectionCell getSectionCellAnnotation() {
return sectionCellAnnotation;
}
public void setSectionCellAnnotation(SectionCell sectionCellAnnotation) {
this.sectionCellAnnotation = sectionCellAnnotation;
}
public Administrator getAdministratorAnnotation() {
return administratorAnnotation;
}
public void setAdministratorAnnotation(Administrator administratorAnnotation) {
this.administratorAnnotation = administratorAnnotation;
}
}

View File

@ -0,0 +1,126 @@
package enseirb.myinpulse.model;
import jakarta.persistence.*;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "appointment")
public class Appointment {
/*@OneToMany(mappedBy = "appointmentEntrepreneurs", fetch = FetchType.LAZY, orphanRemoval = true)
private final List<Entrepreneur> listEntrepreneur =
new ArrayList<>(); */
// should now be useless
@ManyToMany(
fetch = FetchType.LAZY,
cascade = {CascadeType.ALL})
@JoinTable(
name = "concern",
joinColumns = @JoinColumn(name = "idAppointment"),
inverseJoinColumns = @JoinColumn(name = "idSectionCell"))
List<SectionCell> listSectionCell = new ArrayList<>();
@OneToOne(mappedBy = "appointmentReport", fetch = FetchType.LAZY, orphanRemoval = true)
private Report report;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idAppointment;
private LocalDate appointmentDate;
private LocalTime appointmentTime;
private LocalTime appointmentDuration;
@Column(length = 255)
private String appointmentPlace;
private String appointmentSubject;
public Appointment() {}
public Appointment(
Long idAppointment,
LocalDate appointmentDate,
LocalTime appointmentTime,
LocalTime appointmentDuration,
String appointmentPlace,
String appointmentSubject) {
this.idAppointment = idAppointment;
this.appointmentDate = appointmentDate;
this.appointmentTime = appointmentTime;
this.appointmentDuration = appointmentDuration;
this.appointmentPlace = appointmentPlace;
this.appointmentSubject = appointmentSubject;
}
public Long getIdAppointment() {
return idAppointment;
}
public void setIdAppointment(Long idAppointment) {
this.idAppointment = idAppointment;
}
public LocalDate getAppointmentDate() {
return appointmentDate;
}
public void setAppointmentDate(LocalDate appointmentDate) {
this.appointmentDate = appointmentDate;
}
public LocalTime getAppointmentTime() {
return appointmentTime;
}
public void setAppointmentTime(LocalTime appointmentTime) {
this.appointmentTime = appointmentTime;
}
public LocalTime getAppointmentDuration() {
return appointmentDuration;
}
public void setAppointmentDuration(LocalTime appointmentDuration) {
this.appointmentDuration = appointmentDuration;
}
public String getAppointmentPlace() {
return appointmentPlace;
}
public void setAppointmentPlace(String appointmentPlace) {
this.appointmentPlace = appointmentPlace;
}
public String getAppointmentSubject() {
return appointmentSubject;
}
public void setAppointmentSubject(String appointmentSubject) {
this.appointmentSubject = appointmentSubject;
}
public List<SectionCell> getAppointmentListSectionCell() {
return listSectionCell;
}
public void updateListSectionCell(SectionCell sectionCell) {
listSectionCell.add(sectionCell);
}
public Report getAppointmentReport() {
return report;
}
public void setAppointmentReport(Report report) {
this.report = report;
}
}

View File

@ -0,0 +1,139 @@
package enseirb.myinpulse.model;
import jakarta.persistence.*;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
@Entity
@Table(name = "entrepreneur")
@PrimaryKeyJoinColumn(name = "idEntrepreneur", referencedColumnName = "idUser")
public class Entrepreneur extends User {
@Column(length = 255)
private String school;
@Column(length = 255)
private String course;
private boolean sneeStatus;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idProjectParticipation", referencedColumnName = "idProject")
private Project projectParticipation;
// @Column(insertable=false, updatable=false)
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idProjectProposed", referencedColumnName = "idProject")
private Project projectProposed;
/*@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idAppointment")
private Appointment appointmentEntrepreneur;*/
// should now be useless
@OneToOne(mappedBy = "entrepreneurAppointment", fetch = FetchType.LAZY, orphanRemoval = true)
private MakeAppointment makeAppointment;
public Entrepreneur() {}
public Entrepreneur(
String userSurname,
String username,
String primaryMail,
String secondaryMail,
String phoneNumber,
String school,
String course,
boolean sneeStatus,
boolean pending) {
super(userSurname, username, primaryMail, secondaryMail, phoneNumber, pending);
this.school = school;
this.course = course;
this.sneeStatus = sneeStatus;
}
public Entrepreneur(
String userSurname,
String username,
String primaryMail,
String secondaryMail,
String phoneNumber,
String school,
String course,
boolean sneeStatus) {
super(userSurname, username, primaryMail, secondaryMail, phoneNumber, true);
this.school = school;
this.course = course;
this.sneeStatus = sneeStatus;
}
public Entrepreneur(
String userSurname,
String userName,
String primaryMail,
String secondaryMail,
String phoneNumber,
String school,
String course,
boolean sneeStatus,
Project projectParticipation,
Project projectProposed,
MakeAppointment makeAppointment,
boolean pending) {
super(userSurname, userName, primaryMail, secondaryMail, phoneNumber, pending);
this.school = school;
this.course = course;
this.sneeStatus = sneeStatus;
this.projectParticipation = projectParticipation;
this.projectProposed = projectProposed;
this.makeAppointment = makeAppointment;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
public String getCourse() {
return course;
}
public void setCourse(String course) {
this.course = course;
}
public boolean isSneeStatus() {
return sneeStatus;
}
public void setSneeStatus(boolean statusSnee) {
this.sneeStatus = sneeStatus;
}
public Project getProjectParticipation() {
return projectParticipation;
}
public void setProjectParticipation(Project projectParticipation) {
this.projectParticipation = projectParticipation;
}
public Project getProjectProposed() {
return projectProposed;
}
public void setProjectProposed(Project projectProposed) {
this.projectProposed = projectProposed;
}
public MakeAppointment getMakeAppointment() {
return makeAppointment;
}
public void setMakeAppointment(MakeAppointment makeAppointment) {
this.makeAppointment = makeAppointment;
}
}

View File

@ -0,0 +1,26 @@
package enseirb.myinpulse.model;
import jakarta.persistence.*;
@Entity
@Table(name = "make_appointment")
public class MakeAppointment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idMakeAppointment;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idAdministrator")
private Administrator administratorAppointment;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idEntrepreneur")
private Entrepreneur entrepreneurAppointment;
public MakeAppointment() {}
public MakeAppointment(Long idMakeAppointment) {
this.idMakeAppointment = idMakeAppointment;
}
}

View File

@ -0,0 +1,149 @@
package enseirb.myinpulse.model;
import jakarta.persistence.*;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "project")
public class Project {
@OneToMany(mappedBy = "projectParticipation", fetch = FetchType.LAZY, orphanRemoval = true)
private final List<Entrepreneur> listEntrepreneurParticipation = new ArrayList<>();
@OneToMany(mappedBy = "projectSectionCell", fetch = FetchType.LAZY, orphanRemoval = true)
private final List<SectionCell> listSectionCell = new ArrayList<>();
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idProject;
@Column(length = 255)
private String projectName;
private byte[] logo;
private LocalDate creationDate;
@Column private ProjectDecisionValue projectStatus;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idAdministrator")
private Administrator projectAdministrator;
@OneToOne(mappedBy = "projectProposed", fetch = FetchType.LAZY, orphanRemoval = true)
private Entrepreneur entrepreneurProposed;
public Project() {}
public Project(
String projectName,
byte[] logo,
LocalDate creationDate,
ProjectDecisionValue projectStatus,
Administrator projectAdministrator) {
this.projectName = projectName;
this.logo = logo;
this.creationDate = creationDate;
// this.projectStatus = (long) projectStatus.ordinal();
this.projectStatus = projectStatus;
this.projectAdministrator = projectAdministrator;
}
public Project(
String projectName,
byte[] logo,
LocalDate creationDate,
ProjectDecisionValue projectStatus,
Administrator projectAdministrator,
Entrepreneur entrepreneurProposed) {
this.projectName = projectName;
this.logo = logo;
this.creationDate = creationDate;
this.projectStatus = projectStatus;
this.projectAdministrator = projectAdministrator;
this.entrepreneurProposed = entrepreneurProposed;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
Project project = (Project) o;
return this.idProject == project.idProject;
}
public Long getIdProject() {
return idProject;
}
public void setIdProject(Long idProject) {
this.idProject = idProject;
}
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public byte[] getLogo() {
return logo;
}
public void setLogo(byte[] logo) {
this.logo = logo;
}
public LocalDate getCreationDate() {
return creationDate;
}
public void setCreationDate(LocalDate creationDate) {
this.creationDate = creationDate;
}
public ProjectDecisionValue getProjectStatus() {
return projectStatus;
}
public void setProjectStatus(ProjectDecisionValue projectStatus) {
this.projectStatus = projectStatus;
}
public List<Entrepreneur> getListEntrepreneurParticipation() {
return listEntrepreneurParticipation;
}
public void updateListEntrepreneurParticipation(Entrepreneur projectParticipant) {
listEntrepreneurParticipation.add(projectParticipant);
}
public List<SectionCell> getListSectionCell() {
return listSectionCell;
}
public void updateListSectionCell(SectionCell projectSectionCell) {
listSectionCell.add(projectSectionCell);
}
public Administrator getProjectAdministrator() {
return projectAdministrator;
}
public void setProjectAdministrator(Administrator projectAdministrator) {
this.projectAdministrator = projectAdministrator;
}
public Entrepreneur getEntrepreneurProposed() {
return entrepreneurProposed;
}
public void setEntrepreneurProposed(Entrepreneur entrepreneurProposed) {
this.entrepreneurProposed = entrepreneurProposed;
}
}

View File

@ -0,0 +1,25 @@
package enseirb.myinpulse.model;
public class ProjectDecision {
public long projectId;
public long adminId;
public long isAccepted;
public ProjectDecision(long projectId, long adminId, long isAccepted) {
this.projectId = projectId;
this.adminId = adminId;
this.isAccepted = isAccepted;
}
@Override
public String toString() {
return "ProjectDecision{"
+ "projectId="
+ projectId
+ ", adminId="
+ adminId
+ ", isAccepted="
+ isAccepted
+ '}';
}
}

View File

@ -0,0 +1,9 @@
package enseirb.myinpulse.model;
public enum ProjectDecisionValue {
PENDING,
ACTIVE,
ENDED,
ABORTED,
REJECTED,
}

View File

@ -0,0 +1,48 @@
package enseirb.myinpulse.model;
import jakarta.persistence.*;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "report")
public class Report {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idReport;
private String reportContent;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idAppointment")
private Appointment appointmentReport;
public Report() {}
public Report(Long idReport, String reportContent) {
this.idReport = idReport;
this.reportContent = reportContent;
}
public Long getIdReport() {
return idReport;
}
public String getReportContent() {
return reportContent;
}
public void setReportContent(String reportContent) {
this.reportContent = reportContent;
}
public Appointment getAppointmentReport() {
return appointmentReport;
}
public void setAppointmentReport(Appointment appointmentReport) {
this.appointmentReport = appointmentReport;
}
}

View File

@ -1,4 +1,4 @@
package enseirb.myinpulse.utils.keycloak.datatypes;
package enseirb.myinpulse.model;
public class RoleRepresentation {
public String id;

View File

@ -0,0 +1,125 @@
package enseirb.myinpulse.model;
import jakarta.persistence.*;
import org.hibernate.annotations.Generated;
import org.hibernate.generator.EventType;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "section_cell")
public class SectionCell {
@ManyToMany(mappedBy = "listSectionCell")
private final List<Appointment> listAppointment = new ArrayList<>();
@OneToMany(mappedBy = "sectionCellAnnotation", fetch = FetchType.LAZY, orphanRemoval = true)
private final List<Annotation> listAnnotation = new ArrayList<>();
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idSectionCell;
@Column(columnDefinition = "serial")
@Generated(event = EventType.INSERT)
private Long idReference;
@Column() private long sectionId;
private String contentSectionCell;
/*@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idAdministrator")
private Administrator administratorSectionCell;*/
// should now be useless
private LocalDateTime modificationDate;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idProject")
private Project projectSectionCell;
public SectionCell() {}
public SectionCell(
Long idSectionCell,
Long sectionId,
String contentSectionCell,
LocalDateTime modificationDate,
Project projectSectionCell) {
this.idSectionCell = idSectionCell;
this.sectionId = sectionId;
this.contentSectionCell = contentSectionCell;
this.modificationDate = modificationDate;
this.projectSectionCell = projectSectionCell;
}
public Long getIdSectionCell() {
return idSectionCell;
}
public void setIdSectionCell(Long idSectionCell) {
this.idSectionCell = idSectionCell;
}
public Long getIdReference() {
return idReference;
}
public void setIdReference(Long idReference) {
this.idReference = idReference;
}
public Long getSectionId() {
return sectionId;
}
public void setSectionId(Long sectionId) {
this.sectionId = sectionId;
}
public String getContentSectionCell() {
return contentSectionCell;
}
public void setContentSectionCell(String contentSectionCell) {
this.contentSectionCell = contentSectionCell;
}
public LocalDateTime getModificationDate() {
return modificationDate;
}
public void setModificationDate(LocalDateTime modificationDate) {
this.modificationDate = modificationDate;
}
public Project getProjectSectionCell() {
return projectSectionCell;
}
public List<Appointment> getAppointmentSectionCell() {
return listAppointment;
}
public void updateAppointmentSectionCell(Appointment appointment) {
listAppointment.add(appointment);
}
public List<Annotation> getListAnnotation() {
return listAnnotation;
}
public void updateListAnnotation(Annotation annotation) {
listAnnotation.add(annotation);
}
public void setSectionId(long sectionId) {
this.sectionId = sectionId;
}
public void setProjectSectionCell(Project projectSectionCell) {
this.projectSectionCell = projectSectionCell;
}
}

View File

@ -0,0 +1,103 @@
package enseirb.myinpulse.model;
import jakarta.persistence.*;
@Entity
@Table(name = "user_inpulse")
@Inheritance(strategy = InheritanceType.JOINED)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idUser;
@Column(length = 255)
private String userSurname;
@Column(length = 255)
private String userName;
@Column(length = 255)
private String primaryMail;
@Column(length = 255)
private String secondaryMail;
@Column(length = 20)
private String phoneNumber;
@Column private boolean pending;
public User() {}
public User(
String userSurname,
String userName,
String primaryMail,
String secondaryMail,
String phoneNumber,
boolean pending) {
this.userSurname = userSurname;
this.userName = userName;
this.primaryMail = primaryMail;
this.secondaryMail = secondaryMail;
this.phoneNumber = phoneNumber;
this.pending = pending;
}
public Long getIdUser() {
return idUser;
}
public void setIdUser(Long idUser) {
this.idUser = idUser;
}
public String getUserSurname() {
return userSurname;
}
public void setUserSurname(String userSurname) {
userSurname = userSurname;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
userName = userName;
}
public String getPrimaryMail() {
return primaryMail;
}
public void setPrimaryMail(String primaryMail) {
this.primaryMail = primaryMail;
}
public String getSecondaryMail() {
return secondaryMail;
}
public void setSecondaryMail(String secondaryMail) {
this.secondaryMail = secondaryMail;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
phoneNumber = phoneNumber;
}
public boolean isPending() {
return pending;
}
public void setPending(boolean pending) {
this.pending = pending;
}
}

View File

@ -1,4 +1,4 @@
package enseirb.myinpulse.utils.keycloak.datatypes;
package enseirb.myinpulse.model;
public class UserRepresentation {
public String id;

View File

@ -1,38 +0,0 @@
package enseirb.myinpulse.postgres_db.controller;
import enseirb.myinpulse.postgres_db.model.Administrateurs;
import enseirb.myinpulse.postgres_db.repository.AdministrateursRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import java.util.Optional;
@RestController
public class AdministrateursController {
@Autowired AdministrateursRepository administrateursRepository;
@GetMapping("/Administrateurs")
@ResponseBody
public Iterable<Administrateurs> allAdministrateurs() {
return this.administrateursRepository.findAll();
}
@GetMapping("/Administrateurs/{id}")
public Administrateurs getAdministrateursById(@PathVariable Long id) {
Optional<Administrateurs> administrateur = this.administrateursRepository.findById(id);
if (administrateur.isEmpty()) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Cet administrateur n'existe pas");
}
return administrateur.get();
}
@PostMapping("/Administrateurs")
public Administrateurs addAdministrateurs(@RequestBody Administrateurs administrateurs) {
return this.administrateursRepository.save(administrateurs);
}
}

View File

@ -1,49 +0,0 @@
package enseirb.myinpulse.postgres_db.controller;
import enseirb.myinpulse.postgres_db.model.ComptesRendus;
import enseirb.myinpulse.postgres_db.repository.ComptesRendusRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import java.util.Optional;
@RestController
public class ComptesRendusController {
@Autowired ComptesRendusRepository comptesRendusRepository;
@GetMapping("/ComptesRendus")
@ResponseBody
public Iterable<ComptesRendus> allComptesRendus() {
return this.comptesRendusRepository.findAll();
}
@GetMapping("/ComptesRendus/{id}")
public ComptesRendus getComptesRendusById(@PathVariable Long id) {
Optional<ComptesRendus> compteRendu = this.comptesRendusRepository.findById(id);
if (compteRendu.isEmpty()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce compte rendu n'existe pas");
}
return compteRendu.get();
}
@PostMapping("/ComptesRendus")
public ComptesRendus addComptesRendus(@RequestBody ComptesRendus comptesRendus) {
return this.comptesRendusRepository.save(comptesRendus);
}
@PostMapping("/ComptesRendus/{id}")
public ComptesRendus updateProjets(@PathVariable Long id, String contenu_compte_rendu) {
Optional<ComptesRendus> compteRendu = this.comptesRendusRepository.findById(id);
if (compteRendu.isEmpty()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce compte rendu n'existe pas");
}
if (contenu_compte_rendu != null) {
compteRendu.get().setContenu_compte_rendu(contenu_compte_rendu);
}
return this.comptesRendusRepository.save(compteRendu.get());
}
}

View File

@ -1,58 +0,0 @@
package enseirb.myinpulse.postgres_db.controller;
import enseirb.myinpulse.postgres_db.model.Entrepreneurs;
import enseirb.myinpulse.postgres_db.repository.EntrepreneursRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import java.util.Optional;
@RestController
public class EntrepreneursController {
@Autowired EntrepreneursRepository entrepreneursRepository;
@GetMapping("/Entrepreneurs")
@ResponseBody
public Iterable<Entrepreneurs> allEntrepreneurs() {
return this.entrepreneursRepository.findAll();
}
@GetMapping("/Entrepreneurs/{id}")
public Entrepreneurs getEntrepreneursById(@PathVariable Long id) {
Optional<Entrepreneurs> entrepreneur = entrepreneursRepository.findById(id);
if (entrepreneur.isEmpty()) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Cet entrepreneur n'existe pas");
}
return entrepreneur.get();
}
@PostMapping("/Entrepreneurs")
public Entrepreneurs addEntrepreneurs(@RequestBody Entrepreneurs entrepreneurs) {
return this.entrepreneursRepository.save(entrepreneurs);
}
@PostMapping("/Entrepreneurs/{id}")
public Entrepreneurs updateEntrepreneurs(
@PathVariable Long id, String ecole, String filiere, Boolean status_snee) {
Optional<Entrepreneurs> entrepreneur = entrepreneursRepository.findById(id);
if (entrepreneur.isEmpty()) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Cet entrepreneur n'existe pas");
}
if (ecole != null) {
entrepreneur.get().setEcole(ecole);
}
if (filiere != null) {
entrepreneur.get().setFiliere(filiere);
}
if (status_snee != null) {
entrepreneur.get().setStatus_snee(status_snee);
}
return this.entrepreneursRepository.save(entrepreneur.get());
}
}

View File

@ -1,64 +0,0 @@
package enseirb.myinpulse.postgres_db.controller;
import enseirb.myinpulse.postgres_db.model.Projets;
import enseirb.myinpulse.postgres_db.repository.ProjetsRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import java.time.LocalDate;
import java.util.Optional;
@RestController
public class ProjetsController {
@Autowired ProjetsRepository projetsRepository;
@GetMapping("/Projets")
@ResponseBody
public Iterable<Projets> allProjets() {
return this.projetsRepository.findAll();
}
@GetMapping("/Projets/{id}")
public Projets getProjetsById(@PathVariable Long id) {
Optional<Projets> projet = this.projetsRepository.findById(id);
if (projet.isEmpty()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce projet n'existe pas");
}
return projet.get();
}
@PostMapping("/Projets")
public Projets addProjets(@RequestBody Projets projet) {
return this.projetsRepository.save(projet);
}
@PostMapping("/Projets/{id}")
public Projets updateProjets(
@PathVariable Long id,
String nom_projet,
byte[] logo,
LocalDate date_creation,
String status_projet) {
Optional<Projets> projet = this.projetsRepository.findById(id);
if (projet.isEmpty()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce projet n'existe pas");
}
if (nom_projet != null) {
projet.get().setNom_projet(nom_projet);
}
if (logo != null) {
projet.get().setLogo(logo);
}
if (date_creation != null) {
projet.get().setDate_creation(date_creation);
}
if (status_projet != null) {
projet.get().setStatus_projet(status_projet);
}
return this.projetsRepository.save(projet.get());
}
}

View File

@ -1,67 +0,0 @@
package enseirb.myinpulse.postgres_db.controller;
import enseirb.myinpulse.postgres_db.model.RendezVous;
import enseirb.myinpulse.postgres_db.repository.RendezVousRepository;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
@RestController
public class RendezVousController {
@Autowired RendezVousRepository rendezVousRepository;
@GetMapping("/RendezVous")
@ResponseBody
public Iterable<RendezVous> allRendezVous() {
return this.rendezVousRepository.findAll();
}
@GetMapping("/RendezVous/{id}")
public RendezVous getRendezVousById(@PathVariable Long id) {
Optional<RendezVous> rendezVous = this.rendezVousRepository.findById(id);
if (rendezVous.isEmpty()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce rendez vous n'existe pas");
}
return rendezVous.get();
}
@PostMapping("/RendezVous")
public RendezVous addRendezVous(@RequestBody RendezVous rendezVous) {
return this.rendezVousRepository.save(rendezVous);
}
@PostMapping("/RendezVous/{id}")
public RendezVous updateRendezVous(
@PathVariable Long id,
LocalDate date_rdv,
LocalTime heure_rdv,
LocalTime duree_rdv,
String lieu_rdv,
String sujet_rdv) {
Optional<RendezVous> rendezVous = this.rendezVousRepository.findById(id);
if (rendezVous.isEmpty()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce rendez vous n'existe pas");
}
if (date_rdv != null) {
rendezVous.get().setDate_rdv(date_rdv);
}
if (heure_rdv != null) {
rendezVous.get().setHeure_rdv(heure_rdv);
}
if (duree_rdv != null) {
rendezVous.get().setDuree_rdv(duree_rdv);
}
if (lieu_rdv != null) {
rendezVous.get().setLieu_rdv(lieu_rdv);
}
if (sujet_rdv != null) {
rendezVous.get().setSujet_rdv(sujet_rdv);
}
return this.rendezVousRepository.save(rendezVous.get());
}
}

View File

@ -1,60 +0,0 @@
package enseirb.myinpulse.postgres_db.controller;
import enseirb.myinpulse.postgres_db.model.Sections;
import enseirb.myinpulse.postgres_db.repository.SectionsRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import java.time.LocalDateTime;
import java.util.Optional;
@RestController
public class SectionsController {
@Autowired SectionsRepository sectionsRepository;
@GetMapping("/Sections")
@ResponseBody
public Iterable<Sections> allSections() {
return this.sectionsRepository.findAll();
}
@GetMapping("/Sections/{id}")
public Sections getSectionsById(@PathVariable Long id) {
Optional<Sections> section = this.sectionsRepository.findById(id);
if (section.isEmpty()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Cette section n'extise pas");
}
return section.get();
}
@PostMapping("/Sections")
public Sections addSections(@RequestBody Sections sections) {
return this.sectionsRepository.save(sections);
}
@PostMapping("/Sections/{id}")
public Sections updateSections(
@PathVariable Long id,
String titre,
String contenu_section,
LocalDateTime date_modification) {
Optional<Sections> section = this.sectionsRepository.findById(id);
if (section.isEmpty()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Cette section n'extise pas");
}
if (titre != null) {
section.get().setTitre(titre);
}
if (contenu_section != null) {
section.get().setContenu_section(contenu_section);
}
if (date_modification != null) {
section.get().setDate_modification(date_modification);
}
return this.sectionsRepository.save(section.get());
}
}

View File

@ -1,67 +0,0 @@
package enseirb.myinpulse.postgres_db.controller;
import enseirb.myinpulse.postgres_db.model.Utilisateurs;
import enseirb.myinpulse.postgres_db.repository.UtilisateursRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import java.util.Optional;
@RestController
public class UtilisateursController {
@Autowired UtilisateursRepository utilisateursRepository;
@GetMapping("/Utilisateurs")
@ResponseBody
public Iterable<Utilisateurs> allUtilisateurs() {
return this.utilisateursRepository.findAll();
}
@GetMapping("/Utilisateurs/{id}")
public Utilisateurs getUtilisateursById(@PathVariable Long id) {
Optional<Utilisateurs> utilisateur = utilisateursRepository.findById(id);
if (utilisateur.isEmpty()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Cet utilisateur n'existe pas");
}
return utilisateur.get();
}
@PostMapping("/Utilisateurs")
public Utilisateurs addUtilisateurs(@RequestBody Utilisateurs utilisateurs) {
return this.utilisateursRepository.save(utilisateurs);
}
@PostMapping("/Utilisateurs/{id}")
public Utilisateurs updateUtilisateurs(
@PathVariable Long id,
String nom_utilisateur,
String prenom_utilisateur,
String mail_principal,
String mail_secondaire,
String numero_telephone) {
Optional<Utilisateurs> utilisateur = utilisateursRepository.findById(id);
if (utilisateur.isEmpty()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Cet utilisateur n'existe pas");
}
if (nom_utilisateur != null) {
utilisateur.get().setNom_utilisateur(nom_utilisateur);
}
if (prenom_utilisateur != null) {
utilisateur.get().setPrenom_utilisateur(prenom_utilisateur);
}
if (mail_principal != null) {
utilisateur.get().setMail_principal(mail_principal);
}
if (mail_secondaire != null) {
utilisateur.get().setMail_secondaire(mail_secondaire);
}
if (numero_telephone != null) {
utilisateur.get().setNumero_telephone(numero_telephone);
}
return this.utilisateursRepository.save(utilisateur.get());
}
}

View File

@ -1,43 +0,0 @@
package enseirb.myinpulse.postgres_db.model;
import jakarta.persistence.*;
import jakarta.persistence.PrimaryKeyJoinColumn;
import jakarta.persistence.Table;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "administrateurs")
@PrimaryKeyJoinColumn(name = "id_administrateur", referencedColumnName = "id_utilisateur")
public class Administrateurs extends Utilisateurs {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "id_projet")
private Projets projetsAdministrateurs;
@OneToMany(mappedBy = "administrateursSections", fetch = FetchType.LAZY, orphanRemoval = true)
private List<Sections> ListSections = new ArrayList<>();
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "id_rdv")
private RendezVous rendezVousAdministrateurs;
public Administrateurs() {}
public Administrateurs(
String nom_utilisateur,
Long id_utilisateur,
String prenom_utilisateur,
String mail_principal,
String mail_secondaire,
String numero_telephone) {
super(
nom_utilisateur,
id_utilisateur,
prenom_utilisateur,
mail_principal,
mail_secondaire,
numero_telephone);
}
}

View File

@ -1,46 +0,0 @@
package enseirb.myinpulse.postgres_db.model;
import jakarta.persistence.*;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
@Entity
@Table(name = "comptes_rendus")
public class ComptesRendus {
@Id
@NotNull
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id_compte_rendu;
private String contenu_compte_rendu;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "id_rdv")
private RendezVous rendezVousComptesRendus;
public ComptesRendus() {}
public ComptesRendus(Long id_compte_rendu, String contenu_compte_rendu) {
this.id_compte_rendu = id_compte_rendu;
this.contenu_compte_rendu = contenu_compte_rendu;
}
public Long getId_compte_rendu() {
return id_compte_rendu;
}
public void setId_compte_rendu(Long id_compte_rendu) {
this.id_compte_rendu = id_compte_rendu;
}
public String getContenu_compte_rendu() {
return contenu_compte_rendu;
}
public void setContenu_compte_rendu(String contenu_compte_rendu) {
this.contenu_compte_rendu = contenu_compte_rendu;
}
}

View File

@ -1,80 +0,0 @@
package enseirb.myinpulse.postgres_db.model;
import jakarta.persistence.*;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
@Entity
@Table(name = "entrepreneurs")
@PrimaryKeyJoinColumn(name = "id_entrepreneur", referencedColumnName = "id_utilisateur")
public class Entrepreneurs extends Utilisateurs {
@Column(length = 255)
private String ecole;
@Column(length = 255)
private String filiere;
private boolean status_snee;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "id_projet_participation", referencedColumnName = "id_projet")
private Projets projetsParticipation;
// @Column(insertable=false, updatable=false)
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "id_projet_propose", referencedColumnName = "id_projet")
private Projets projetsPropose;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "id_rdv")
private RendezVous rendezVousEntrepreneurs;
public Entrepreneurs() {}
public Entrepreneurs(
String nom_utilisateur,
Long id_utilisateur,
String prenom_utilisateur,
String mail_principal,
String mail_secondaire,
String numero_telephone,
String ecole,
boolean status_snee,
String filiere) {
super(
nom_utilisateur,
id_utilisateur,
prenom_utilisateur,
mail_principal,
mail_secondaire,
numero_telephone);
this.ecole = ecole;
this.status_snee = status_snee;
this.filiere = filiere;
}
public String getEcole() {
return ecole;
}
public void setEcole(String ecole) {
this.ecole = ecole;
}
public String getFiliere() {
return filiere;
}
public void setFiliere(String filiere) {
this.filiere = filiere;
}
public boolean isStatus_snee() {
return status_snee;
}
public void setStatus_snee(boolean status_snee) {
this.status_snee = status_snee;
}
}

View File

@ -1,98 +0,0 @@
package enseirb.myinpulse.postgres_db.model;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "projets")
public class Projets {
@Id
@NotNull
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id_projet;
@Column(length = 255)
private String nom_projet;
private byte[] logo;
private LocalDate date_creation;
@Column(length = 255)
private String status_projet;
@OneToMany(mappedBy = "projetsAdministrateurs", fetch = FetchType.LAZY, orphanRemoval = true)
private List<Administrateurs> listAdministrateurs = new ArrayList<>();
@OneToMany(mappedBy = "projetsParticipation", fetch = FetchType.LAZY, orphanRemoval = true)
private List<Entrepreneurs> ListEntrepreneursParticipation = new ArrayList<>();
@OneToOne(mappedBy = "projetsPropose", fetch = FetchType.LAZY, orphanRemoval = true)
private Entrepreneurs entrepreneursPropose;
@OneToMany(mappedBy = "projetsSections", fetch = FetchType.LAZY, orphanRemoval = true)
private List<Sections> ListSections = new ArrayList<>();
// Hibernate expects entities to have a no-arg constructor,
// though it does not necessarily have to be public.
public Projets() {}
public Projets(
Long id_projet,
String nom_projet,
byte[] logo,
LocalDate date_creation,
String status_projet) {
this.id_projet = id_projet;
this.nom_projet = nom_projet;
this.logo = logo;
this.date_creation = date_creation;
this.status_projet = status_projet;
}
public Long getId_projet() {
return id_projet;
}
public void setId_projet(Long id_projet) {
this.id_projet = id_projet;
}
public String getNom_projet() {
return nom_projet;
}
public void setNom_projet(String nom_projet) {
this.nom_projet = nom_projet;
}
public byte[] getLogo() {
return logo;
}
public void setLogo(byte[] logo) {
this.logo = logo;
}
public LocalDate getDate_creation() {
return date_creation;
}
public void setDate_creation(LocalDate date_creation) {
this.date_creation = date_creation;
}
public String getStatus_projet() {
return status_projet;
}
public void setStatus_projet(String status_projet) {
this.status_projet = status_projet;
}
}

View File

@ -1,111 +0,0 @@
package enseirb.myinpulse.postgres_db.model;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "rendez_vous")
public class RendezVous {
@OneToMany(mappedBy = "rendezVousEntrepreneurs", fetch = FetchType.LAZY, orphanRemoval = true)
private final List<Entrepreneurs> ListEntrepreneurs = new ArrayList<>();
@OneToMany(mappedBy = "rendezVousAdministrateurs", fetch = FetchType.LAZY, orphanRemoval = true)
private final List<Administrateurs> ListAdministrateurs = new ArrayList<>();
@OneToMany(mappedBy = "rendezVousComptesRendus", fetch = FetchType.LAZY, orphanRemoval = true)
private final List<ComptesRendus> ListComptesRendus = new ArrayList<>();
@ManyToMany(
fetch = FetchType.LAZY,
cascade = {CascadeType.ALL})
@JoinTable(
name = "concerner",
joinColumns = @JoinColumn(name = "id_rdv"),
inverseJoinColumns = @JoinColumn(name = "id_section"))
List<Sections> ListSections = new ArrayList<>();
@Id
@NotNull
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id_rdv;
private LocalDate date_rdv;
private LocalTime heure_rdv;
private LocalTime duree_rdv;
@Column(length = 255)
private String lieu_rdv;
private String sujet_rdv;
public RendezVous() {}
public RendezVous(
Long id_rdv,
LocalDate date_rdv,
LocalTime heure_rdv,
LocalTime duree_rdv,
String lieu_rdv,
String sujet_rdv) {
this.id_rdv = id_rdv;
this.date_rdv = date_rdv;
this.heure_rdv = heure_rdv;
this.duree_rdv = duree_rdv;
this.lieu_rdv = lieu_rdv;
this.sujet_rdv = sujet_rdv;
}
public Long getId_rdv() {
return id_rdv;
}
public void setId_rdv(Long id_rdv) {
this.id_rdv = id_rdv;
}
public LocalDate getDate_rdv() {
return date_rdv;
}
public void setDate_rdv(LocalDate date_rdv) {
this.date_rdv = date_rdv;
}
public LocalTime getHeure_rdv() {
return heure_rdv;
}
public void setHeure_rdv(LocalTime heure_rdv) {
this.heure_rdv = heure_rdv;
}
public LocalTime getDuree_rdv() {
return duree_rdv;
}
public void setDuree_rdv(LocalTime duree_rdv) {
this.duree_rdv = duree_rdv;
}
public String getLieu_rdv() {
return lieu_rdv;
}
public void setLieu_rdv(String lieu_rdv) {
this.lieu_rdv = lieu_rdv;
}
public String getSujet_rdv() {
return sujet_rdv;
}
public void setSujet_rdv(String sujet_rdv) {
this.sujet_rdv = sujet_rdv;
}
}

View File

@ -1,81 +0,0 @@
package enseirb.myinpulse.postgres_db.model;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "sections")
public class Sections {
@Id
@NotNull
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id_section;
@Column(length = 255)
private String titre;
private String contenu_section;
private LocalDateTime date_modification;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "id_projet")
private Projets projetsSections;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "id_admnistrateur")
private Administrateurs administrateursSections;
@ManyToMany(mappedBy = "ListSections")
private List<RendezVous> rendezVous = new ArrayList<>();
public Sections() {}
public Sections(
Long id_section,
String titre,
String contenu_section,
LocalDateTime date_modification) {
this.id_section = id_section;
this.titre = titre;
this.contenu_section = contenu_section;
this.date_modification = date_modification;
}
public String getTitre() {
return titre;
}
public void setTitre(String titre) {
this.titre = titre;
}
public Long getId_section() {
return id_section;
}
public void setId_section(Long id_section) {
this.id_section = id_section;
}
public String getContenu_section() {
return contenu_section;
}
public void setContenu_section(String contenu_section) {
this.contenu_section = contenu_section;
}
public LocalDateTime getDate_modification() {
return date_modification;
}
public void setDate_modification(LocalDateTime date_modification) {
this.date_modification = date_modification;
}
}

View File

@ -1,95 +0,0 @@
package enseirb.myinpulse.postgres_db.model;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
@Entity
@Table(name = "utilisateurs")
@Inheritance(strategy = InheritanceType.JOINED)
public class Utilisateurs {
@Id
@NotNull
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id_utilisateur;
@Column(length = 255)
private String nom_utilisateur;
@Column(length = 255)
private String prenom_utilisateur;
@Column(length = 255)
private String mail_principal;
@Column(length = 255)
private String mail_secondaire;
@Column(length = 20)
private String numero_telephone;
public Utilisateurs() {}
public Utilisateurs(
String nom_utilisateur,
Long id_utilisateur,
String prenom_utilisateur,
String mail_principal,
String mail_secondaire,
String numero_telephone) {
this.nom_utilisateur = nom_utilisateur;
this.id_utilisateur = id_utilisateur;
this.prenom_utilisateur = prenom_utilisateur;
this.mail_principal = mail_principal;
this.mail_secondaire = mail_secondaire;
this.numero_telephone = numero_telephone;
}
public Long getId_utilisateur() {
return id_utilisateur;
}
public void setId_utilisateur(Long id_utilisateur) {
this.id_utilisateur = id_utilisateur;
}
public String getNom_utilisateur() {
return nom_utilisateur;
}
public void setNom_utilisateur(String nom_utilisateur) {
this.nom_utilisateur = nom_utilisateur;
}
public String getPrenom_utilisateur() {
return prenom_utilisateur;
}
public void setPrenom_utilisateur(String prenom_utilisateur) {
this.prenom_utilisateur = prenom_utilisateur;
}
public String getMail_principal() {
return mail_principal;
}
public void setMail_principal(String mail_principal) {
this.mail_principal = mail_principal;
}
public String getMail_secondaire() {
return mail_secondaire;
}
public void setMail_secondaire(String mail_secondaire) {
this.mail_secondaire = mail_secondaire;
}
public String getNumero_telephone() {
return numero_telephone;
}
public void setNumero_telephone(String numero_telephone) {
this.numero_telephone = numero_telephone;
}
}

View File

@ -1,14 +0,0 @@
package enseirb.myinpulse.postgres_db.repository;
import enseirb.myinpulse.postgres_db.model.Administrateurs;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
@RepositoryRestResource
public interface AdministrateursRepository extends JpaRepository<Administrateurs, Long> {
/* @Query("SELECT a from Administrateurs a")
Administrateurs findAllAdministrateurs(); */
}

View File

@ -1,9 +0,0 @@
package enseirb.myinpulse.postgres_db.repository;
import enseirb.myinpulse.postgres_db.model.ComptesRendus;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
@RepositoryRestResource
public interface ComptesRendusRepository extends JpaRepository<ComptesRendus, Long> {}

View File

@ -1,14 +0,0 @@
package enseirb.myinpulse.postgres_db.repository;
import enseirb.myinpulse.postgres_db.model.Entrepreneurs;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
@RepositoryRestResource
public interface EntrepreneursRepository extends JpaRepository<Entrepreneurs, Long> {
/* @Query("SELECT e from Entrepreneurs e")
Entrepreneurs findAllEntrepreneurs(); */
}

View File

@ -1,9 +0,0 @@
package enseirb.myinpulse.postgres_db.repository;
import enseirb.myinpulse.postgres_db.model.Projets;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
@RepositoryRestResource
public interface ProjetsRepository extends JpaRepository<Projets, Long> {}

View File

@ -1,9 +0,0 @@
package enseirb.myinpulse.postgres_db.repository;
import enseirb.myinpulse.postgres_db.model.RendezVous;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
@RepositoryRestResource
public interface RendezVousRepository extends JpaRepository<RendezVous, Long> {}

View File

@ -1,9 +0,0 @@
package enseirb.myinpulse.postgres_db.repository;
import enseirb.myinpulse.postgres_db.model.Sections;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
@RepositoryRestResource
public interface SectionsRepository extends JpaRepository<Sections, Long> {}

View File

@ -1,14 +0,0 @@
package enseirb.myinpulse.postgres_db.repository;
import enseirb.myinpulse.postgres_db.model.Utilisateurs;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
@RepositoryRestResource
public interface UtilisateursRepository extends JpaRepository<Utilisateurs, Long> {
/* @Query("SELECT u from Utilisateurs u")
Utilisateurs findAllUtilisateurs(); */
}

View File

@ -0,0 +1,17 @@
package enseirb.myinpulse.repository;
import enseirb.myinpulse.model.Administrator;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import java.util.Optional;
@RepositoryRestResource
public interface AdministratorRepository extends JpaRepository<Administrator, Long> {
/* @Query("SELECT a from Administrators a")
Administrator findAllAdministrator(); */
Optional<Administrator> findByPrimaryMail(String PrimaryMail);
}

View File

@ -0,0 +1,9 @@
package enseirb.myinpulse.repository;
import enseirb.myinpulse.model.Annotation;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
@RepositoryRestResource
public interface AnnotationRepository extends JpaRepository<Annotation, Long> {}

View File

@ -0,0 +1,9 @@
package enseirb.myinpulse.repository;
import enseirb.myinpulse.model.Appointment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
@RepositoryRestResource
public interface AppointmentRepository extends JpaRepository<Appointment, Long> {}

View File

@ -0,0 +1,17 @@
package enseirb.myinpulse.repository;
import enseirb.myinpulse.model.Entrepreneur;
import enseirb.myinpulse.model.Project;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
@RepositoryRestResource
public interface EntrepreneurRepository extends JpaRepository<Entrepreneur, Long> {
Iterable<Entrepreneur> getEntrepreneurByProjectParticipation(Project project);
/* @Query("SELECT e from Entrepreneur e")
Entrepreneur findAllEntrepreneurl(); */
}

View File

@ -0,0 +1,9 @@
package enseirb.myinpulse.repository;
import enseirb.myinpulse.model.MakeAppointment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
@RepositoryRestResource
public interface MakeAppointmentRepository extends JpaRepository<MakeAppointment, Long> {}

View File

@ -0,0 +1,19 @@
package enseirb.myinpulse.repository;
import enseirb.myinpulse.model.Administrator;
import enseirb.myinpulse.model.Project;
import enseirb.myinpulse.model.ProjectDecisionValue;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import java.util.Optional;
@RepositoryRestResource
public interface ProjectRepository extends JpaRepository<Project, Long> {
Iterable<Project> findByProjectAdministrator(Administrator administrator);
Iterable<Project> findByProjectStatus(ProjectDecisionValue status);
Optional<Project> findByProjectName(String projectName);
}

View File

@ -0,0 +1,9 @@
package enseirb.myinpulse.repository;
import enseirb.myinpulse.model.Report;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
@RepositoryRestResource
public interface ReportRepository extends JpaRepository<Report, Long> {}

View File

@ -0,0 +1,20 @@
package enseirb.myinpulse.repository;
import enseirb.myinpulse.model.Project;
import enseirb.myinpulse.model.SectionCell;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import java.time.LocalDateTime;
@RepositoryRestResource
public interface SectionCellRepository extends JpaRepository<SectionCell, Long> {
Iterable<SectionCell> findByProjectSectionCellAndSectionId(Project project, long sectionId);
Iterable<SectionCell> findByProjectSectionCellAndSectionIdAndModificationDateBefore(
Project project, long sectionId, LocalDateTime date);
Iterable<SectionCell> findByProjectSectionCell(Project project);
}

View File

@ -0,0 +1,18 @@
package enseirb.myinpulse.repository;
import enseirb.myinpulse.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import java.util.Optional;
@RepositoryRestResource
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByPrimaryMail(String primaryMail);
Iterable<User> findAllByPendingEquals(boolean pending);
/* @Query("SELECT u from User u")
User findAllUser(); */
}

View File

@ -0,0 +1,220 @@
package enseirb.myinpulse.service;
import static enseirb.myinpulse.model.ProjectDecisionValue.ACTIVE;
import static enseirb.myinpulse.model.ProjectDecisionValue.REJECTED;
import enseirb.myinpulse.model.*;
import enseirb.myinpulse.service.database.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.util.ArrayList;
import java.util.List;
@Service
public class AdminApiService {
protected static final Logger logger = LogManager.getLogger();
private final ProjectService projectService;
private final UserService userService;
private final AdministratorService administratorService;
private final EntrepreneurService entrepreneurService;
private final UtilsService utilsService;
private final AppointmentService appointmentService;
private final ReportService reportService;
private final SectionCellService sectionCellService;
@Autowired
AdminApiService(
ProjectService projectService,
UserService userService,
AdministratorService administratorService,
UtilsService utilsService,
EntrepreneurService entrepreneurService,
AppointmentService appointmentService,
ReportService reportService,
SectionCellService sectionCellService) {
this.projectService = projectService;
this.userService = userService;
this.administratorService = administratorService;
this.utilsService = utilsService;
this.appointmentService = appointmentService;
this.reportService = reportService;
this.sectionCellService = sectionCellService;
this.entrepreneurService = entrepreneurService;
}
// TODO: check if tests are sufficient - peer verification required
public Iterable<Project> getProjectsOfAdmin(String mail) {
return projectService.getProjectsByAdminId(
administratorService.getAdministratorById(
this.userService.getUserByEmail(mail).getIdUser()));
}
public Iterable<Appointment> getUpcomingAppointments(String mail) {
logger.info("User {} check their upcoming appointments", mail);
User user = this.userService.getUserByEmail(mail);
List<Appointment> appointments = new ArrayList<>();
if (user instanceof Administrator) {
List<Project> projects = new ArrayList<>(((Administrator) user).getListProject());
projects.forEach(
project -> {
project.getListSectionCell()
.forEach(
sectionCell -> {
appointments.addAll(
this.sectionCellService
.getAppointmentsBySectionCellId(
sectionCell
.getIdSectionCell()));
});
});
}
if (user instanceof Entrepreneur) {
Project project = ((Entrepreneur) user).getProjectParticipation();
if (project == null) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND,
"The user has no project, thus no appointments. No users should have no project");
}
project.getListSectionCell()
.forEach(
sectionCell -> {
appointments.addAll(
this.sectionCellService.getAppointmentsBySectionCellId(
sectionCell.getIdSectionCell()));
});
}
return appointments;
}
// TODO: check if tests are sufficient - peer verification required
public Iterable<Project> getPendingProjects() {
return this.projectService.getPendingProjects();
}
// TODO: check if tests are sufficient - peer verification required
public void validateProject(ProjectDecision decision) {
projectService.updateProject(
decision.projectId,
null,
null,
(decision.isAccepted == 1) ? ACTIVE : REJECTED,
null,
null,
this.administratorService.getAdministratorById(decision.adminId));
}
// TODO: check if tests are sufficient - peer verification required
public Project addNewProject(Project project) {
project.setIdProject(null);
// We remove the ID from the request to be sure that it will be auto generated
try {
this.projectService.getProjectByName(project.getProjectName(), true);
throw new ResponseStatusException(HttpStatus.CONFLICT, "Project already exists");
} catch (ResponseStatusException e) {
if (e.getStatusCode() == HttpStatus.CONFLICT) {
throw new ResponseStatusException(HttpStatus.CONFLICT, "Project already exists");
}
}
Project newProject = projectService.addNewProject(project);
if (project.getProjectAdministrator() != null) {
newProject.getProjectAdministrator().updateListProject(newProject);
}
if (newProject.getEntrepreneurProposed() != null) {
Entrepreneur proposed = newProject.getEntrepreneurProposed();
proposed.setProjectProposed(newProject);
proposed.setProjectParticipation(newProject);
}
newProject
.getListEntrepreneurParticipation()
.forEach(
participation -> {
participation.setProjectParticipation(newProject);
});
newProject
.getListSectionCell()
.forEach(
sectionCell -> {
sectionCell.setProjectSectionCell(newProject);
});
return newProject;
}
public void createAppointmentReport(long appointmentId, Report report, String mail) {
long projectId =
this.appointmentService
.getAppointmentById(appointmentId)
.getAppointmentListSectionCell()
.getFirst()
.getProjectSectionCell()
.getIdProject();
if (!utilsService.isAllowedToCheckProject(mail, projectId)) {
logger.warn(
"User {} tried to add an report for appointment {} but is not allowed to.",
mail,
projectId);
throw new ResponseStatusException(
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
}
logger.info("User {} added a report for appointment {}", mail, projectId);
Report addedReport = this.reportService.addNewReport(report);
addedReport.setAppointmentReport(this.appointmentService.getAppointmentById(appointmentId));
this.appointmentService.getAppointmentById(appointmentId).setAppointmentReport(addedReport);
}
// TODO: test
public void deleteProject(long projectId) {
this.projectService.deleteProjectById(projectId);
}
public void setAdmin(long userId, String token) {
Entrepreneur e = this.entrepreneurService.getEntrepreneurById(userId);
Administrator a =
new Administrator(
e.getUserSurname(),
e.getUserName(),
e.getPrimaryMail(),
e.getSecondaryMail(),
e.getPhoneNumber());
this.entrepreneurService.deleteEntrepreneur(e);
this.administratorService.addAdministrator(a);
try {
KeycloakApi.setRoleToUser(a.getUserName(), "MyINPulse-admin", token);
} catch (Exception err) {
logger.error(err);
}
}
public void validateEntrepreneurAccount(long userId, String token) {
Entrepreneur e = this.entrepreneurService.getEntrepreneurById(userId);
try {
KeycloakApi.setRoleToUser(e.getUserName(), "MyINPulse-entrepreneur", token);
} catch (Exception err) {
logger.error(err);
}
this.entrepreneurService.validateEntrepreneurById(userId);
}
public Iterable<User> getPendingUsers() {
return this.userService.getPendingAccounts();
}
public void createAccount(
String username,
String userSurname,
String primaryMail,
String secondaryMail,
String phoneNumber) {
Administrator a =
new Administrator(username, userSurname, primaryMail, secondaryMail, phoneNumber);
this.administratorService.addAdministrator(a);
}
}

View File

@ -0,0 +1,284 @@
package enseirb.myinpulse.service;
import static enseirb.myinpulse.model.ProjectDecisionValue.PENDING;
import static enseirb.myinpulse.model.ProjectDecisionValue.ACTIVE;
import enseirb.myinpulse.model.Entrepreneur;
import enseirb.myinpulse.model.Project;
import enseirb.myinpulse.model.SectionCell;
import enseirb.myinpulse.model.User;
import enseirb.myinpulse.service.database.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Service
public class EntrepreneurApiService {
protected static final Logger logger = LogManager.getLogger();
private final SectionCellService sectionCellService;
private final ProjectService projectService;
private final UtilsService utilsService;
private final UserService userService;
private final EntrepreneurService entrepreneurService;
private final AdministratorService administratorService;
private final AppointmentService appointmentService;
private final AnnotationService annotationService;
@Autowired
EntrepreneurApiService(
SectionCellService sectionCellService,
ProjectService projectService,
UtilsService utilsService,
UserService userService,
EntrepreneurService entrepreneurService,
AdministratorService administratorService,
AppointmentService appointmentService,
AnnotationService annotationService) {
this.sectionCellService = sectionCellService;
this.projectService = projectService;
this.utilsService = utilsService;
this.userService = userService;
this.entrepreneurService = entrepreneurService;
this.administratorService = administratorService;
this.appointmentService = appointmentService;
this.annotationService = annotationService;
}
public void editSectionCell(Long sectionCellId, String content, String mail) {
if (sectionCellId == null) {
logger.warn("Trying to edit unknown section cell");
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Cette cellule de section n'existe pas");
}
SectionCell sectionCell = sectionCellService.getSectionCellById(sectionCellId);
if (!utilsService.isAllowedToCheckProject(
mail, this.sectionCellService.getProjectId(sectionCellId))) {
logger.warn(
"User {} tried to edit section cells {} of the project {} but is not allowed to.",
mail,
sectionCellId,
this.sectionCellService.getProjectId(sectionCellId));
throw new ResponseStatusException(
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
}
logger.info(
"User {} edited section cell {} of the project with id {}",
mail,
sectionCellId,
this.sectionCellService.getProjectId(sectionCellId));
SectionCell newSectionCell =
new SectionCell(
null,
sectionCell.getSectionId(),
content,
LocalDateTime.now(),
sectionCell.getProjectSectionCell());
newSectionCell.setIdReference(sectionCell.getIdReference());
this.addSectionCell(newSectionCell, mail);
sectionCell
.getAppointmentSectionCell()
.forEach(
appointment -> {
this.appointmentService.updateAppointmentListSectionCell(
appointment.getIdAppointment(), newSectionCell);
});
sectionCell
.getListAnnotation()
.forEach(
annotation -> {
this.annotationService.updateAnnotationSectionCell(
annotation.getIdAnnotation(), newSectionCell);
});
}
public void removeSectionCell(Long sectionCellId, String mail) {
if (sectionCellId == null) {
logger.warn("Trying to remove unknown section cell");
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Cette cellule de section n'existe pas");
}
SectionCell editSectionCell = sectionCellService.getSectionCellById(sectionCellId);
if (!utilsService.isAllowedToCheckProject(
mail, this.sectionCellService.getProjectId(sectionCellId))) {
logger.warn(
"User {} tried to remove section cells {} of the project {} but is not allowed to.",
mail,
sectionCellId,
this.sectionCellService.getProjectId(sectionCellId));
throw new ResponseStatusException(
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
}
logger.info(
"User {} removed section cell {} of the project with id {}",
mail,
sectionCellId,
this.sectionCellService.getProjectId(sectionCellId));
SectionCell removedSectionCell =
new SectionCell(
null,
-1L,
"",
LocalDateTime.now(),
this.projectService.getProjectById(
editSectionCell.getProjectSectionCell().getIdProject()));
sectionCellService.addNewSectionCell(removedSectionCell);
this.sectionCellService.updateSectionCellReferenceId(
removedSectionCell.getIdSectionCell(), editSectionCell.getIdReference());
projectService.updateProjectListSectionCell(
sectionCellService.getProjectId(sectionCellId), removedSectionCell);
// sectionCellService.removeSectionCellById(sectionCellId);
}
public void addSectionCell(SectionCell sectionCell, String mail) {
if (sectionCell == null) {
logger.warn("Trying to create an empty section cell");
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST, "La cellule de section fournie est vide");
}
if (sectionCell.getSectionId() == -1) {
logger.warn("Trying to create an illegal section cell");
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST, "La cellule de section fournie n'est pas valide");
}
if (!utilsService.isAllowedToCheckProject(
mail, sectionCell.getProjectSectionCell().getIdProject())) {
logger.warn(
"User {} tried to add a section cell to the project {} but is not allowed to.",
mail,
sectionCell.getProjectSectionCell().getIdProject());
throw new ResponseStatusException(
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
}
logger.info(
"User {} added a new section cell {} to the project {}",
mail,
sectionCell.getIdSectionCell(),
sectionCell.getProjectSectionCell().getIdProject());
SectionCell newSectionCell =
sectionCellService.addNewSectionCell(
sectionCell); // if here, logger fails cause id is null (not added yet)
newSectionCell.getProjectSectionCell().updateListSectionCell(newSectionCell);
newSectionCell
.getAppointmentSectionCell()
.forEach(
appointment -> {
this.appointmentService.updateAppointmentListSectionCell(
appointment.getIdAppointment(), newSectionCell);
});
newSectionCell
.getListAnnotation()
.forEach(
annotation -> {
this.annotationService.updateAnnotationSectionCell(
annotation.getIdAnnotation(), newSectionCell);
});
}
public void requestNewProject(Project project, String mail) {
if (project == null) {
logger.warn("Trying to request the creation of a null project");
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Le projet fourni est vide");
}
logger.info("User {} created a new project named {}", mail, project.getProjectName());
project.setEntrepreneurProposed((Entrepreneur) this.userService.getUserByEmail(mail));
projectService.addNewProject(project);
this.projectService.updateProjectStatus(project.getIdProject(), PENDING);
if (project.getProjectAdministrator() != null) {
this.administratorService.updateAdministratorListProject(
project.getProjectAdministrator().getIdUser(), project);
}
this.entrepreneurService.updateEntrepreneurProjectProposed(
this.userService.getUserByEmail(mail).getIdUser(), project);
this.entrepreneurService.updateEntrepreneurProjectParticipation(
this.userService.getUserByEmail(mail).getIdUser(), project);
project.getListEntrepreneurParticipation()
.forEach(
entrepreneur ->
this.entrepreneurService.updateEntrepreneurProjectParticipation(
entrepreneur.getIdUser(), project));
project.getListSectionCell()
.forEach(
sectionCell ->
this.sectionCellService.updateSectionCellProject(
sectionCell.getIdSectionCell(), project));
}
public void createAccount(Entrepreneur e) {
try {
userService.getUserByEmail(e.getPrimaryMail());
logger.error("The user {} already exists in the system", e.getPrimaryMail());
} catch (ResponseStatusException err) {
this.entrepreneurService.addEntrepreneur(e);
return;
}
throw new ResponseStatusException(HttpStatus.CONFLICT, "User already exists in the system");
}
public Iterable<Project> getProjectIdViaClaim(String email) {
Long UserId = this.userService.getUserByEmail(email).getIdUser();
Entrepreneur entrepreneur = this.entrepreneurService.getEntrepreneurById(UserId);
List<Project> Project_List = new ArrayList<>();
Project_List.add(entrepreneur.getProjectParticipation());
return Project_List;
}
public Iterable<Entrepreneur> getAllEntrepreneurs() {
return entrepreneurService.getAllEntrepreneurs();
}
/**
* Checks if an entrepreneur with the given email has a project that is ACTIVE.
*
* @param email The email of the entrepreneur.
* @return true if the entrepreneur has an active project, false otherwise.
*/
public Boolean checkIfEntrepreneurProjectActive(String email) {
User user = this.userService.getUserByEmail(email);
if (user == null) {
return false;
}
Long userId = user.getIdUser();
Entrepreneur entrepreneur = this.entrepreneurService.getEntrepreneurById(userId);
if (entrepreneur == null) {
return false;
}
Project proposedProject = entrepreneur.getProjectProposed();
return proposedProject != null && proposedProject.getProjectStatus() == ACTIVE;
}
/**
* Checks if an entrepreneur with the given email has proposed a project.
*
* @param email The email of the entrepreneur.
* @return true if the entrepreneur has a proposed project, false otherwise.
*/
public Boolean entrepreneurHasPendingRequestedProject(String email) {
User user = this.userService.getUserByEmail(email);
if (user == null) {
return false;
}
Long userId = user.getIdUser();
Entrepreneur entrepreneur = this.entrepreneurService.getEntrepreneurById(userId);
if (entrepreneur == null) {
return false;
}
Project proposedProject = entrepreneur.getProjectProposed();
if (entrepreneur.getProjectProposed() == null) {
return false;
}
return proposedProject.getProjectStatus() == PENDING;
}
}

View File

@ -1,17 +1,22 @@
package enseirb.myinpulse.utils.keycloak;
package enseirb.myinpulse.service;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import enseirb.myinpulse.exceptions.UserNotFoundException;
import enseirb.myinpulse.utils.keycloak.datatypes.RoleRepresentation;
import enseirb.myinpulse.utils.keycloak.datatypes.UserRepresentation;
import enseirb.myinpulse.exception.UserNotFoundException;
import enseirb.myinpulse.model.RoleRepresentation;
import enseirb.myinpulse.model.UserRepresentation;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.client.RestClient;
import java.util.List;
import javax.management.relation.RoleNotFoundException;
public class KeycloakApi {
protected static final Logger logger = LogManager.getLogger();
static final String keycloakUrl;
static final String realmName;
@ -29,44 +34,48 @@ public class KeycloakApi {
realmName = System.getenv("VITE_KEYCLOAK_REALM");
}
static String toBearer(String b) {
return "Bearer " + b;
}
/**
* Uses Keycloak API to retrieve a role representation of a role by its name
*
* @param roleName name of the role
* @param bearer authorization header used by the client to authenticate to keycloak
* @param token authorization header used by the client to authenticate to keycloak
*/
public static RoleRepresentation getRoleRepresentationByName(String roleName, String bearer)
public static RoleRepresentation getRoleRepresentationByName(String roleName, String token)
throws RoleNotFoundException {
RoleRepresentation[] response =
RoleRepresentation response =
RestClient.builder()
.baseUrl(keycloakUrl)
.defaultHeader("Authorization", bearer)
.defaultHeader("Authorization", toBearer(token))
.build()
.get()
.uri("/admin/realms/{realmName}/roles/{roleName}", realmName, roleName)
.retrieve()
.body(RoleRepresentation[].class);
if (response == null || response.length == 0) {
throw new RoleNotFoundException("Role not found");
}
return response[0];
.body(RoleRepresentation.class);
/*
{"id":"7a845f2e-c832-4465-8cd8-894d72bc13f1","name":"MyINPulse-entrepreneur","description":"Role for entrepreneur","composite":false,"clientRole":false,"containerId":"0d6f691b-e328-471a-b89e-c30bd7e5b6b0","attributes":{}}
*/
// TODO: check what happens when role does not exist
return response;
}
/**
* Use keycloak API to to retreive a userID via his name or email.
*
* @param username username or mail of the user
* @param bearer bearer of the user, allowing access to database
* @param token bearer of the user, allowing access to database
* @return the userid, as a String
* @throws UserNotFoundException
*/
public static String getUserIdByName(String username, String bearer)
public static String getUserIdByName(String username, String token)
throws UserNotFoundException {
UserRepresentation[] response =
RestClient.builder()
.baseUrl(keycloakUrl)
.defaultHeader("Authorization", bearer)
.defaultHeader("Authorization", toBearer(token))
.build()
.get()
.uri(
@ -91,27 +100,26 @@ public class KeycloakApi {
*
* @param username
* @param roleName
* @param bearer
* @param token
* @throws RoleNotFoundException
* @throws UserNotFoundException
*/
public static void setRoleToUser(String username, String roleName, String bearer)
public static void setRoleToUser(String username, String roleName, String token)
throws RoleNotFoundException, UserNotFoundException {
RoleRepresentation roleRepresentation = getRoleRepresentationByName(roleName, bearer);
String userId = getUserIdByName(username, bearer);
RoleRepresentation roleRepresentation = getRoleRepresentationByName(roleName, token);
String userId = getUserIdByName(username, token);
List<RoleRepresentation> rolesToAdd = List.of(roleRepresentation);
logger.debug("Adding role {} to user {}", roleRepresentation.id, userId);
RestClient.builder()
.baseUrl(keycloakUrl)
.defaultHeader("Authorization", bearer)
.defaultHeader("Authorization", toBearer(token))
.build()
.post()
.uri(
"/admin/realms/${realmName}/users/${userId}/role-mappings/realm",
realmName,
userId)
.body(roleRepresentation)
.uri("/admin/realms/" + realmName + "/users/" + userId + "/role-mappings/realm")
.body(rolesToAdd)
.contentType(APPLICATION_JSON)
.retrieve();
.retrieve()
.toBodilessEntity();
}
/**

View File

@ -0,0 +1,324 @@
package enseirb.myinpulse.service;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.PdfWriter;
import enseirb.myinpulse.controller.AdminApi;
import enseirb.myinpulse.controller.EntrepreneurApi;
import enseirb.myinpulse.model.*;
import enseirb.myinpulse.service.database.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Service
public class SharedApiService {
private final AdminApi adminApi;
private final EntrepreneurApi entrepreneurApi;
protected static final Logger logger = LogManager.getLogger();
private final ProjectService projectService;
private final EntrepreneurService entrepreneurService;
private final SectionCellService sectionCellService;
private final AppointmentService appointmentService;
private final UtilsService utilsService;
@Autowired
SharedApiService(
ProjectService projectService,
EntrepreneurService entrepreneurService,
SectionCellService sectionCellService,
AppointmentService appointmentService,
UtilsService utilsService,
EntrepreneurApi entrepreneurApi,
AdminApi adminApi) {
this.projectService = projectService;
this.entrepreneurService = entrepreneurService;
this.sectionCellService = sectionCellService;
this.appointmentService = appointmentService;
this.utilsService = utilsService;
this.entrepreneurApi = entrepreneurApi;
this.adminApi = adminApi;
}
// TODO filter this with date
public Iterable<SectionCell> getSectionCells(
long projectId, long sectionId, String date, String mail) {
if (!utilsService.isAllowedToCheckProject(mail, projectId)) {
logger.warn(
"User {} tried to check section cells of the project {} but is not allowed to.",
mail,
projectId);
throw new ResponseStatusException(
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(date, formatter);
Project project = this.projectService.getProjectById(projectId);
return this.sectionCellService.getLatestSectionCellsByIdReferenceBeforeDate(
project, sectionId, dateTime);
}
// Retrieve all up to date (for every sectionId) sectionCells of a project
public Iterable<SectionCell> getAllSectionCells(long projectId, String mail) {
if (!utilsService.isAllowedToCheckProject(mail, projectId)) {
logger.warn(
"User {} tried to check section cells of the project {} but is not allowed to.",
mail,
projectId);
throw new ResponseStatusException(
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
}
Project project = this.projectService.getProjectById(projectId);
Map<Long, SectionCell> latestSectionCellsMap =
new HashMap<>(); // List for the intermediate result
// Iterate through all SectionCells associated with the project
// This loop iterates over project.getListSectionCell() but does NOT modify it which causes
// ConcurrentModificationException.
// Modifications are done only on the latestSectionCellsMap (which is safe).
project.getListSectionCell() // <-- Iterating over the original list (read-only)
.forEach(
projectCell -> {
Long idReference = projectCell.getIdReference();
// Check if we have already seen a SectionCell with this idReference in
// our map
if (latestSectionCellsMap.containsKey(idReference)) {
SectionCell existingCell = latestSectionCellsMap.get(idReference);
// Compare modification dates. If the current cell is newer, replace
// the one in the map.
if (projectCell
.getModificationDate()
.isAfter(existingCell.getModificationDate())) {
latestSectionCellsMap.put(idReference, projectCell);
}
} else {
// If this is the first time we encounter this idReference, add the
// cell to the map.
latestSectionCellsMap.put(idReference, projectCell);
}
});
return new ArrayList<>(latestSectionCellsMap.values());
}
// TODO: test
public Iterable<Entrepreneur> getEntrepreneursByProjectId(long projectId, String mail) {
if (!utilsService.isAllowedToCheckProject(mail, projectId)) {
logger.warn(
"User {} tried to check the member of the project {} but is not allowed to.",
mail,
projectId);
throw new ResponseStatusException(
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
}
Project project = this.projectService.getProjectById(projectId);
return this.entrepreneurService.GetEntrepreneurByProject(project);
}
// TODO: test
public Administrator getAdminByProjectId(long projectId, String mail) {
if (!utilsService.isAllowedToCheckProject(mail, projectId)) {
logger.warn(
"User {} tried to check the admin of the project {} but is not allowed to.",
mail,
projectId);
throw new ResponseStatusException(
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
}
Project project = this.projectService.getProjectById(projectId);
return project.getProjectAdministrator();
}
public Iterable<Appointment> getAppointmentsByProjectId(long projectId, String mail) {
if (!utilsService.isAllowedToCheckProject(mail, projectId)) {
logger.warn(
"User {} tried to check the appointments related to the project {} but is not allowed to.",
mail,
projectId);
throw new ResponseStatusException(
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
}
logger.info(
"User {} tried to check the appointments related to the project {}",
mail,
projectId);
Project project = projectService.getProjectById(projectId);
Iterable<SectionCell> sectionCellsIterable =
this.sectionCellService.getSectionCellsByProject(project);
// Use a Set to collect unique appointments
Set<Appointment> uniqueAppointments = new HashSet<>();
sectionCellsIterable.forEach(
sectionCell -> {
List<Appointment> sectionAppointments =
this.sectionCellService.getAppointmentsBySectionCellId(
sectionCell.getIdSectionCell());
// Add all appointments from this section cell to the Set
uniqueAppointments.addAll(sectionAppointments);
});
// Convert the Set back to a List for the return value
return new ArrayList<>(uniqueAppointments);
}
public void getPDFReport(long appointmentId, String mail)
throws DocumentException, URISyntaxException, IOException {
long projectId =
this.appointmentService
.getAppointmentById(appointmentId)
.getAppointmentListSectionCell()
.getFirst()
.getProjectSectionCell()
.getIdProject();
if (!utilsService.isAllowedToCheckProject(mail, projectId)) {
logger.warn(
"User {} tried to generate the PDF report {} related to the appointment {} but is not allowed to.",
mail,
this.appointmentService
.getAppointmentById(appointmentId)
.getAppointmentReport()
.getIdReport(),
appointmentId);
throw new ResponseStatusException(
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
}
logger.info(
"User {} generated the PDF report related to appointment {}", mail, appointmentId);
String reportContent =
this.appointmentService
.getAppointmentById(appointmentId)
.getAppointmentReport()
.getReportContent();
// PDF generation
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("Report" + appointmentId + ".pdf"));
document.open();
Paragraph title =
new Paragraph(
new Phrase(
"Compte Rendu - Réunion du "
+ this.appointmentService
.getAppointmentById(appointmentId)
.getAppointmentDate()
.toString(),
FontFactory.getFont(
FontFactory.HELVETICA,
20,
Font.BOLDITALIC,
BaseColor.BLACK)));
title.setAlignment(Element.ALIGN_CENTER);
document.add(title);
Font subsection =
FontFactory.getFont(FontFactory.HELVETICA, 14, Font.UNDERLINE, BaseColor.DARK_GRAY);
Font body = FontFactory.getFont(FontFactory.COURIER, 12, BaseColor.BLACK);
String[] split = reportContent.split(" ");
String tmp = "";
int counter = 1;
for (String s : split) {
if (s.equals("//")) {
Chunk chunk = new Chunk(tmp, body);
document.add(chunk);
document.add(new Paragraph("\n"));
tmp = "";
Paragraph paragraph = new Paragraph("Point n°" + counter + " : ", subsection);
document.add(paragraph);
document.add(new Paragraph("\n"));
counter++;
} else {
tmp = tmp.concat(s + " ");
}
}
Chunk chunk = new Chunk(tmp, body);
document.add(chunk);
document.add(new Paragraph("\n"));
document.close();
// Replace uri with website address
Files.copy(
new URI(
"http://localhost:8080/shared/projects/appointments/report/"
+ appointmentId)
.toURL()
.openStream(),
Paths.get("Report" + appointmentId + ".pdf"),
StandardCopyOption.REPLACE_EXISTING);
// delete file, we don't want to stock all reports on the server
File file = new File("Report" + appointmentId + ".pdf");
if (!file.delete()) {
logger.warn("Failed to delete report {}", file.getAbsolutePath());
}
}
public void createAppointmentRequest(Appointment appointment, String mail) {
long projectId =
appointment
.getAppointmentListSectionCell()
.getFirst()
.getProjectSectionCell()
.getIdProject();
if (!utilsService.isAllowedToCheckProject(mail, projectId)) {
logger.warn(
"User {} tried to create for the project {} but is not allowed to.",
mail,
projectId);
throw new ResponseStatusException(
HttpStatus.UNAUTHORIZED, "You're not allowed to check this project");
}
logger.info("User {} tried to create an appointment for project {}", mail, projectId);
Appointment newAppointment = this.appointmentService.addNewAppointment(appointment);
newAppointment
.getAppointmentListSectionCell()
.forEach(
sectionCell -> {
sectionCell.updateAppointmentSectionCell(newAppointment);
});
/*
* On initial insertion, the resport value is null unless that report does already exist in the db somewhere
* If a non null value is passed and it does not exist in db it will throw an exception
*/
if (newAppointment.getAppointmentReport() != null) {
newAppointment.getAppointmentReport().setAppointmentReport(newAppointment);
}
}
}

View File

@ -0,0 +1,81 @@
package enseirb.myinpulse.service;
import enseirb.myinpulse.model.Administrator;
import enseirb.myinpulse.model.Entrepreneur;
import enseirb.myinpulse.model.Project;
import enseirb.myinpulse.model.User;
import enseirb.myinpulse.service.database.AdministratorService;
import enseirb.myinpulse.service.database.EntrepreneurService;
import enseirb.myinpulse.service.database.ProjectService;
import enseirb.myinpulse.service.database.UserService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.util.Objects;
@Service
public class UtilsService {
protected static final Logger logger = LogManager.getLogger();
private final UserService userService;
private final ProjectService projectService;
private final EntrepreneurService entrepreneurService;
private final AdministratorService administratorService;
@Autowired
UtilsService(
ProjectService projectService,
UserService userService,
EntrepreneurService entrepreneurService,
AdministratorService administratorService) {
this.userService = userService;
this.projectService = projectService;
this.entrepreneurService = entrepreneurService;
this.administratorService = administratorService;
}
// TODO: test?
public Boolean isAllowedToCheckProject(String mail, long projectId) {
if (isAnAdmin(mail)) {
return true;
}
User user = this.userService.getUserByEmail(mail);
Entrepreneur entrepreneur = this.entrepreneurService.getEntrepreneurById(user.getIdUser());
if (entrepreneur == null) {
logger.debug("testing access with an unknown Entrepreneur");
return false;
}
if (entrepreneur.getProjectParticipation() == null) {
logger.debug("testing access with an user with no project participation");
return false;
}
Project project = this.projectService.getProjectById(projectId);
// We compare the ID instead of the project themselves
return Objects.equals(
entrepreneur.getProjectParticipation().getIdProject(), project.getIdProject());
}
// TODO: test
public Boolean isAnAdmin(String mail) {
try {
long userId = this.userService.getUserByEmail(mail).getIdUser();
Administrator a = this.administratorService.getAdministratorById(userId);
return true;
} catch (ResponseStatusException e) {
logger.info(e);
return false;
}
}
public Boolean checkEntrepreneurNotPending(String email) {
// Throws 404 if user not found
User user = userService.getUserByEmail(email);
return !user.isPending();
}
}

View File

@ -0,0 +1,106 @@
package enseirb.myinpulse.service.database;
import enseirb.myinpulse.model.Administrator;
import enseirb.myinpulse.model.Annotation;
import enseirb.myinpulse.model.MakeAppointment;
import enseirb.myinpulse.model.Project;
import enseirb.myinpulse.repository.AdministratorRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.util.Optional;
@Service
public class AdministratorService {
protected static final Logger logger = LogManager.getLogger();
private final AdministratorRepository administratorRepository;
@Autowired
AdministratorService(AdministratorRepository administratorRepository) {
this.administratorRepository = administratorRepository;
}
public Iterable<Administrator> allAdministrators() {
return this.administratorRepository.findAll();
}
public Administrator getAdministratorById(long id) {
Optional<Administrator> administrator = this.administratorRepository.findById(id);
if (administrator.isEmpty()) {
logger.error("No administrator found with id {}", id);
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Cet administrateur n'existe pas");
}
return administrator.get();
}
public Administrator getAdministratorByPrimaryMain(String primaryMail) {
Optional<Administrator> administrator =
this.administratorRepository.findByPrimaryMail(primaryMail);
if (administrator.isEmpty()) {
logger.error("No administrator found with the mail {}", primaryMail);
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Cet administrateur n'existe pas");
}
return administrator.get();
}
public Administrator addAdministrator(Administrator administrator) {
return this.administratorRepository.save(administrator);
}
public void updateAdministratorListProject(long idAdministrator, Project project) {
Administrator administrator = getAdministratorById(idAdministrator);
administrator.updateListProject(project);
this.administratorRepository.save(administrator);
}
public void updateAdministratorListAnnotation(long idAdministrator, Annotation annotation) {
Administrator administrator = getAdministratorById(idAdministrator);
administrator.updateListAnnotation(annotation);
this.administratorRepository.save(administrator);
}
public void updateAdministratorMakeAppointment(
long idAdministrator, MakeAppointment makeAppointment) {
Administrator administrator = getAdministratorById(idAdministrator);
administrator.setMakeAppointment(makeAppointment);
this.administratorRepository.save(administrator);
}
public Administrator updateAdministrator(
Long idAdministrator,
Project project,
Annotation annotation,
MakeAppointment makeAppointment) {
Optional<Administrator> administrator = administratorRepository.findById(idAdministrator);
if (administrator.isEmpty()) {
logger.error(
"updateAdministrator : No administrator found with id {}", idAdministrator);
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Cet administrateur n'existe pas");
}
if (project != null) {
administrator.get().updateListProject(project);
}
if (annotation != null) {
administrator.get().updateListAnnotation(annotation);
}
if (makeAppointment != null) {
administrator.get().setMakeAppointment(makeAppointment);
}
return this.administratorRepository.save(administrator.get());
}
/*
public Administrator getAdministratorByProject(Project project) {
r
}
*/
}

View File

@ -0,0 +1,81 @@
package enseirb.myinpulse.service.database;
import enseirb.myinpulse.model.Administrator;
import enseirb.myinpulse.model.Annotation;
import enseirb.myinpulse.model.SectionCell;
import enseirb.myinpulse.repository.AnnotationRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.util.Optional;
@Service
public class AnnotationService {
protected static final Logger logger = LogManager.getLogger();
private final AnnotationRepository annotationRepository;
@Autowired
AnnotationService(AnnotationRepository annotationRepository) {
this.annotationRepository = annotationRepository;
}
public Iterable<Annotation> getAllAnnotations() {
return annotationRepository.findAll();
}
public Annotation getAnnotationById(Long id) {
Optional<Annotation> annotation = annotationRepository.findById(id);
if (annotation.isEmpty()) {
logger.error("getAnnotationById : No annotation found with id {}", id);
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Cette annotation n'existe pas");
}
return annotation.get();
}
public Annotation addNewAnnotation(Annotation annotation) {
return this.annotationRepository.save(annotation);
}
public void deleteAnnotationById(Long id) {
this.annotationRepository.deleteById(id);
}
public void updateAnnotationComment(long idAnnotation, String comment) {
Annotation annotation = getAnnotationById(idAnnotation);
annotation.setComment(comment);
this.annotationRepository.save(annotation);
}
public Annotation updateAnnotation(Long id, String comment) {
Optional<Annotation> annotation = annotationRepository.findById(id);
if (annotation.isEmpty()) {
logger.error("updateAnnotation : No annotation found with id {}", id);
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Cette annotation n'existe pas");
}
if (comment != null) {
annotation.get().setComment(comment);
}
return this.annotationRepository.save(annotation.get());
}
public void updateAnnotationSectionCell(long idAnnotation, SectionCell sectionCell) {
Annotation annotation = getAnnotationById(idAnnotation);
annotation.setSectionCellAnnotation(sectionCell);
this.annotationRepository.save(annotation);
}
public void updateAnnotationAdministrator(long idAnnotation, Administrator administrator) {
Annotation annotation = getAnnotationById(idAnnotation);
annotation.setAdministratorAnnotation(administrator);
this.annotationRepository.save(annotation);
}
}

View File

@ -0,0 +1,120 @@
package enseirb.myinpulse.service.database;
import enseirb.myinpulse.model.Appointment;
import enseirb.myinpulse.model.SectionCell;
import enseirb.myinpulse.repository.AppointmentRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.Optional;
@Service
public class AppointmentService {
private static final Logger logger = LogManager.getLogger(AppointmentService.class);
private AppointmentRepository appointmentRepository;
@Autowired
AppointmentService(AppointmentRepository appointmentRepository) {
this.appointmentRepository = appointmentRepository;
}
public Iterable<Appointment> getallAppointments() {
return this.appointmentRepository.findAll();
}
public Appointment getAppointmentById(Long id) {
Optional<Appointment> appointment = this.appointmentRepository.findById(id);
if (appointment.isEmpty()) {
logger.error("getAppointmentById : No appointment found with id {}", id);
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce rendez vous n'existe pas");
}
return appointment.get();
}
public Appointment addNewAppointment(Appointment appointment) {
return this.appointmentRepository.save(appointment);
}
public void deleteAppointmentById(Long id) {
this.appointmentRepository.deleteById(id);
}
public void updateAppointmentDate(long idAppointment, LocalDate date) {
Appointment appointment = getAppointmentById(idAppointment);
appointment.setAppointmentDate(date);
this.appointmentRepository.save(appointment);
}
public void updateAppointmentTime(long idAppointment, LocalTime time) {
Appointment appointment = getAppointmentById(idAppointment);
appointment.setAppointmentTime(time);
this.appointmentRepository.save(appointment);
}
public void updateAppointmentDuration(long idAppointment, LocalTime duration) {
Appointment appointment = getAppointmentById(idAppointment);
appointment.setAppointmentDuration(duration);
this.appointmentRepository.save(appointment);
}
public void updateAppointmentPlace(long idAppointment, String place) {
Appointment appointment = getAppointmentById(idAppointment);
appointment.setAppointmentPlace(place);
this.appointmentRepository.save(appointment);
}
public void updateAppointmentSubject(long idAppointment, String subject) {
Appointment appointment = getAppointmentById(idAppointment);
appointment.setAppointmentSubject(subject);
this.appointmentRepository.save(appointment);
}
public void updateAppointmentListSectionCell(long idAppointment, SectionCell sectionCell) {
Appointment appointment = getAppointmentById(idAppointment);
appointment.updateListSectionCell(sectionCell);
this.appointmentRepository.save(appointment);
}
public Appointment updateAppointment(
Long id,
LocalDate appointmentDate,
LocalTime appointmentTime,
LocalTime appointmentDuration,
String appointmentPlace,
String appointmentSubject,
SectionCell sectionCell) {
Optional<Appointment> appointment = this.appointmentRepository.findById(id);
if (appointment.isEmpty()) {
logger.error("updateAppointment : No appointment found with id {}", id);
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce rendez vous n'existe pas");
}
if (appointmentDate != null) {
appointment.get().setAppointmentDate(appointmentDate);
}
if (appointmentTime != null) {
appointment.get().setAppointmentTime(appointmentTime);
}
if (appointmentDuration != null) {
appointment.get().setAppointmentDuration(appointmentDuration);
}
if (appointmentPlace != null) {
appointment.get().setAppointmentPlace(appointmentPlace);
}
if (appointmentSubject != null) {
appointment.get().setAppointmentSubject(appointmentSubject);
}
if (sectionCell != null) {
appointment.get().updateListSectionCell(sectionCell);
}
return this.appointmentRepository.save(appointment.get());
}
}

View File

@ -0,0 +1,135 @@
package enseirb.myinpulse.service.database;
import enseirb.myinpulse.model.Entrepreneur;
import enseirb.myinpulse.model.MakeAppointment;
import enseirb.myinpulse.model.Project;
import enseirb.myinpulse.repository.EntrepreneurRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.util.Optional;
@Service
public class EntrepreneurService {
protected static final Logger logger = LogManager.getLogger();
private final EntrepreneurRepository entrepreneurRepository;
EntrepreneurService(EntrepreneurRepository entrepreneurRepository) {
this.entrepreneurRepository = entrepreneurRepository;
}
public Iterable<Entrepreneur> getAllEntrepreneurs() {
return this.entrepreneurRepository.findAll();
}
public Entrepreneur getEntrepreneurById(Long id) {
Optional<Entrepreneur> entrepreneur = entrepreneurRepository.findById(id);
if (entrepreneur.isEmpty()) {
logger.error("getEntrepreneurById : No entrepreneur found with id {}", id);
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Cet entrepreneur n'existe pas");
}
return entrepreneur.get();
}
public Entrepreneur addEntrepreneur(Entrepreneur entrepreneur) {
return this.entrepreneurRepository.save(entrepreneur);
}
public void updateEntrepreneurSchool(long idEntrepreneur, String school) {
Entrepreneur entrepreneur = getEntrepreneurById(idEntrepreneur);
entrepreneur.setSchool(school);
this.entrepreneurRepository.save(entrepreneur);
}
public void updateEntrepreneurCourse(long idEntrepreneur, String course) {
Entrepreneur entrepreneur = getEntrepreneurById(idEntrepreneur);
entrepreneur.setCourse(course);
this.entrepreneurRepository.save(entrepreneur);
}
public void updateEntrepreneurSneeStatus(long idEntrepreneur, boolean status) {
Entrepreneur entrepreneur = getEntrepreneurById(idEntrepreneur);
entrepreneur.setSneeStatus(status);
this.entrepreneurRepository.save(entrepreneur);
}
public void updateEntrepreneurProjectParticipation(
long idEntrepreneur, Project projectParticipation) {
Entrepreneur entrepreneur = getEntrepreneurById(idEntrepreneur);
entrepreneur.setProjectParticipation(projectParticipation);
this.entrepreneurRepository.save(entrepreneur);
}
public void updateEntrepreneurProjectProposed(long idEntrepreneur, Project projectProposed) {
Entrepreneur entrepreneur = getEntrepreneurById(idEntrepreneur);
entrepreneur.setProjectParticipation(projectProposed);
this.entrepreneurRepository.save(entrepreneur);
}
public void updateEntrepreneurMakeAppointment(
long idEntrepreneur, MakeAppointment makeAppointment) {
Entrepreneur entrepreneur = getEntrepreneurById(idEntrepreneur);
entrepreneur.setMakeAppointment(makeAppointment);
this.entrepreneurRepository.save(entrepreneur);
}
public Entrepreneur updateEntrepreneur(
Long id,
String school,
String course,
Boolean sneeStatus,
Project projectParticipation,
Project projectProposed,
MakeAppointment makeAppointment) {
Optional<Entrepreneur> entrepreneur = entrepreneurRepository.findById(id);
if (entrepreneur.isEmpty()) {
logger.error("updateEntrepreneur : No entrepreneur found with id {}", id);
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Cet entrepreneur n'existe pas");
}
if (school != null) {
entrepreneur.get().setSchool(school);
}
if (course != null) {
entrepreneur.get().setCourse(course);
}
if (sneeStatus != null) {
entrepreneur.get().setSneeStatus(sneeStatus);
}
if (projectParticipation != null) {
entrepreneur.get().setProjectParticipation(projectParticipation);
}
if (projectProposed != null) {
entrepreneur.get().setProjectParticipation(projectProposed);
}
if (makeAppointment != null) {
entrepreneur.get().setMakeAppointment(makeAppointment);
}
return this.entrepreneurRepository.save(entrepreneur.get());
}
public Iterable<Entrepreneur> GetEntrepreneurByProject(Project project) {
return this.entrepreneurRepository.getEntrepreneurByProjectParticipation(project);
}
public void deleteEntrepreneur(Entrepreneur e) {
this.entrepreneurRepository.delete(e);
}
public void validateEntrepreneurById(Long id) {
System.out.println("\nVALIDATING\n");
Optional<Entrepreneur> e = this.entrepreneurRepository.findById(id);
if (e.isEmpty()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Entrepreneur n'existe pas");
}
e.get().setPending(false);
this.entrepreneurRepository.save(e.get());
}
}

View File

@ -0,0 +1,159 @@
package enseirb.myinpulse.service.database;
import static enseirb.myinpulse.model.ProjectDecisionValue.PENDING;
import enseirb.myinpulse.model.*;
import enseirb.myinpulse.repository.ProjectRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.util.List;
import java.util.Optional;
@Service
public class ProjectService {
protected static final Logger logger = LogManager.getLogger();
private final ProjectRepository projectRepository;
@Autowired
ProjectService(ProjectRepository projectRepository) {
this.projectRepository = projectRepository;
}
public Iterable<Project> getAllProjects() {
return this.projectRepository.findAll();
}
public Project getProjectById(Long id) {
Optional<Project> project = this.projectRepository.findById(id);
if (project.isEmpty()) {
logger.error("No project found with id {}", id);
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce projet n'existe pas");
}
return project.get();
}
public Iterable<Project> getProjectsByAdminId(Administrator administrator) {
return this.projectRepository.findByProjectAdministrator(administrator);
}
// TODO: validation
public Project addNewProject(Project project) {
return this.projectRepository.save(project);
}
public void updateProjectName(long idProject, String name) {
Project project = getProjectById(idProject);
project.setProjectName(name);
this.projectRepository.save(project);
}
public void updateProjectLogo(long idProject, byte[] logo) {
Project project = getProjectById(idProject);
project.setLogo(logo);
this.projectRepository.save(project);
}
public void updateProjectStatus(long idProject, ProjectDecisionValue status) {
Project project = getProjectById(idProject);
project.setProjectStatus(status);
this.projectRepository.save(project);
}
public void updateProjectEntrepreneurParticipation(
long idProject, Entrepreneur entrepreneurParticipation) {
Project project = getProjectById(idProject);
project.updateListEntrepreneurParticipation(entrepreneurParticipation);
this.projectRepository.save(project);
}
public void updateProjectListSectionCell(long idProject, SectionCell sectionCell) {
Project project = getProjectById(idProject);
project.updateListSectionCell(sectionCell);
this.projectRepository.save(project);
}
public void updateProjectAdministrator(long idProject, Administrator administrator) {
Project project = getProjectById(idProject);
project.setProjectAdministrator(administrator);
this.projectRepository.save(project);
}
public Project updateProject(
Long id,
String projectName,
byte[] logo,
ProjectDecisionValue projectStatus,
Entrepreneur entrepreneurParticipation,
SectionCell sectionCell,
Administrator administrator) {
Optional<Project> project = this.projectRepository.findById(id);
if (project.isEmpty()) {
logger.error("Project with id {} not found.", id);
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce projet n'existe pas");
}
if (projectName != null) {
project.get().setProjectName(projectName);
}
if (logo != null) {
project.get().setLogo(logo);
}
if (projectStatus != null) {
// TODO: check if this is really useful
/*
if (!validateStatus(projectStatus)) {
logger.error("updateProjectStatus: Invalid status {}", projectStatus);
throw new ResponseStatusException(
HttpStatus.NOT_ACCEPTABLE, "Ce status n'est pas accepté");
}
*/
project.get().setProjectStatus(projectStatus);
}
if (entrepreneurParticipation != null) {
project.get().updateListEntrepreneurParticipation(entrepreneurParticipation);
}
if (sectionCell != null) {
project.get().updateListSectionCell(sectionCell);
}
if (administrator != null) {
project.get().setProjectAdministrator(administrator);
}
return this.projectRepository.save(project.get());
}
public Boolean validateStatus(String status) {
return List.of("PENDING", "ACTIVE", "ENDED").contains(status);
}
public Iterable<Project> getPendingProjects() {
return this.projectRepository.findByProjectStatus(PENDING);
}
public void deleteProjectById(Long id) {
this.projectRepository.deleteById(id);
}
public Project getProjectByName(String name, boolean noerror) {
Optional<Project> project = this.projectRepository.findByProjectName(name);
if (project.isEmpty()) {
if (noerror) logger.error("No project found with name {}", name);
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce projet n'existe pas");
}
return project.get();
}
public Project getProjectByName(String name) {
return getProjectByName(name, false);
}
}

View File

@ -0,0 +1,76 @@
package enseirb.myinpulse.service.database;
import enseirb.myinpulse.model.Appointment;
import enseirb.myinpulse.model.Report;
import enseirb.myinpulse.repository.ReportRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.util.Optional;
@Service
public class ReportService {
protected static final Logger logger = LogManager.getLogger();
private final ReportRepository reportRepository;
@Autowired
ReportService(ReportRepository reportRepository) {
this.reportRepository = reportRepository;
}
public Iterable<Report> getAllReports() {
return this.reportRepository.findAll();
}
public Report getReportById(Long id) {
Optional<Report> report = this.reportRepository.findById(id);
if (report.isEmpty()) {
logger.error("getReportById : No report found with id {}", id);
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce compte rendu n'existe pas");
}
return report.get();
}
// TODO: do some validation
public Report addNewReport(Report report) {
return this.reportRepository.save(report);
}
public void deleteReportById(Long id) {
this.reportRepository.deleteById(id);
}
public void updateReportContent(long idReport, String content) {
Report report = getReportById(idReport);
report.setReportContent(content);
this.reportRepository.save(report);
}
public void updateReportAppointment(long idReport, Appointment appointment) {
Report report = getReportById(idReport);
report.setAppointmentReport(appointment);
this.reportRepository.save(report);
}
public Report updateReport(Long id, String reportContent, Appointment appointment) {
Optional<Report> report = this.reportRepository.findById(id);
if (report.isEmpty()) {
logger.error("updateReport : No report found with id {}", id);
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce compte rendu n'existe pas");
}
if (reportContent != null) {
report.get().setReportContent(reportContent);
}
if (appointment != null) {
report.get().setAppointmentReport(appointment);
}
return this.reportRepository.save(report.get());
}
}

View File

@ -0,0 +1,183 @@
package enseirb.myinpulse.service.database;
import enseirb.myinpulse.model.Annotation;
import enseirb.myinpulse.model.Appointment;
import enseirb.myinpulse.model.Project;
import enseirb.myinpulse.model.SectionCell;
import enseirb.myinpulse.repository.SectionCellRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Service
public class SectionCellService {
protected static final Logger logger = LogManager.getLogger();
private final SectionCellRepository sectionCellRepository;
@Autowired
SectionCellService(SectionCellRepository sectionCellRepository) {
this.sectionCellRepository = sectionCellRepository;
}
public Iterable<SectionCell> getAllSectionCells() {
return this.sectionCellRepository.findAll();
}
public SectionCell getSectionCellById(Long id) {
Optional<SectionCell> sectionCell = this.sectionCellRepository.findById(id);
if (sectionCell.isEmpty()) {
logger.error("getSectionCellById : No sectionCell found with id {}", id);
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Cette cellule de section n'existe pas");
}
return sectionCell.get();
}
public SectionCell addNewSectionCell(SectionCell sectionCell) {
return this.sectionCellRepository.save(sectionCell);
}
public void removeSectionCellById(Long id) {
this.sectionCellRepository.deleteById(id);
}
public void updateSectionCellReferenceId(Long idSectionCell, Long referenceId) {
SectionCell sectionCell = this.getSectionCellById(idSectionCell);
sectionCell.setIdReference(referenceId);
this.sectionCellRepository.save(sectionCell);
}
public void updateSectionCellContent(long idSectionCell, String content) {
SectionCell sectionCell = getSectionCellById(idSectionCell);
sectionCell.setContentSectionCell(content);
this.sectionCellRepository.save(sectionCell);
}
public void updateSectionCellListAppointment(long idSectionCell, Appointment appointment) {
SectionCell sectionCell = getSectionCellById(idSectionCell);
sectionCell.updateAppointmentSectionCell(appointment);
this.sectionCellRepository.save(sectionCell);
}
public void updateSectionCellListAnnotation(long idSectionCell, Annotation annotation) {
SectionCell sectionCell = getSectionCellById(idSectionCell);
sectionCell.updateListAnnotation(annotation);
this.sectionCellRepository.save(sectionCell);
}
public void updateSectionCellProject(long idSectionCell, Project project) {
SectionCell sectionCell = getSectionCellById(idSectionCell);
sectionCell.setProjectSectionCell(project);
this.sectionCellRepository.save(sectionCell);
}
public SectionCell updateSectionCell(
Long id,
String contentSectionCell,
Appointment appointment,
Annotation annotation,
Project project) {
Optional<SectionCell> sectionCell = this.sectionCellRepository.findById(id);
if (sectionCell.isEmpty()) {
logger.error("updateSectionCell : No sectionCell found with id {}", id);
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Cette cellule de section n'existe pas");
}
if (contentSectionCell != null) {
sectionCell.get().setContentSectionCell(contentSectionCell);
sectionCell.get().setModificationDate(LocalDateTime.now());
}
if (appointment != null) {
sectionCell.get().updateAppointmentSectionCell(appointment);
sectionCell.get().setModificationDate(LocalDateTime.now());
}
if (annotation != null) {
sectionCell.get().updateListAnnotation(annotation);
sectionCell.get().setModificationDate(LocalDateTime.now());
}
if (project != null) {
sectionCell.get().setProjectSectionCell(project);
sectionCell.get().setModificationDate(LocalDateTime.now());
}
return this.sectionCellRepository.save(sectionCell.get());
}
public Iterable<SectionCell> getSectionCellsByProject(Project project, Long sectionId) {
return this.sectionCellRepository.findByProjectSectionCellAndSectionId(project, sectionId);
}
public Iterable<SectionCell> getSectionCellsByProject(Project project) {
logger.info("Fetching SectionCells for Project ID: {}", project.getIdProject());
Iterable<SectionCell> sectionCells =
this.sectionCellRepository.findByProjectSectionCell(project);
List<SectionCell> sectionCellList = new ArrayList<>();
sectionCells.forEach(
cell -> {
sectionCellList.add(cell);
});
return sectionCellList;
}
public Long getProjectId(Long sectionCellId) {
SectionCell sectionCell = getSectionCellById(sectionCellId);
Project sectionProject = sectionCell.getProjectSectionCell();
return sectionProject.getIdProject();
}
public List<Appointment> getAppointmentsBySectionCellId(Long sectionCellId) {
SectionCell sectionCell = getSectionCellById(sectionCellId);
return sectionCell.getAppointmentSectionCell();
}
public Iterable<SectionCell> getSectionCellsByProjectAndSectionIdBeforeDate(
Project project, long sectionId, LocalDateTime date) {
return sectionCellRepository.findByProjectSectionCellAndSectionIdAndModificationDateBefore(
project, sectionId, date);
}
public Iterable<SectionCell> getLatestSectionCellsByIdReferenceBeforeDate(
Project project, long sectionId, LocalDateTime date) {
// 1. Fetch ALL relevant SectionCells modified before the date
Iterable<SectionCell> allMatchingCells =
sectionCellRepository.findByProjectSectionCellAndSectionIdAndModificationDateBefore(
project, sectionId, date);
// 2. Find the latest for each idReference
Map<Long, SectionCell> latestCellsByIdReference = new HashMap<>();
for (SectionCell cell : allMatchingCells) {
Long idReference = cell.getIdReference();
// Check if we've seen this idReference before
if (latestCellsByIdReference.containsKey(idReference)) {
// If yes, compare modification dates
SectionCell existingLatest = latestCellsByIdReference.get(idReference);
// If the current cell is more recent, update the map
if (cell.getModificationDate().isAfter(existingLatest.getModificationDate())) {
latestCellsByIdReference.put(idReference, cell);
}
} else {
// If this is the first time we see this idReference, add it to the map
latestCellsByIdReference.put(idReference, cell);
}
}
// 3. Return the collection of the latest cells (the values from the map)
return latestCellsByIdReference.values();
}
}

View File

@ -0,0 +1,124 @@
package enseirb.myinpulse.service.database;
import enseirb.myinpulse.model.User;
import enseirb.myinpulse.repository.UserRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.server.ResponseStatusException;
import java.util.Optional;
@Service
public class UserService {
protected static final Logger logger = LogManager.getLogger();
private final UserRepository userRepository;
@Autowired
UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public Iterable<User> getAllUsers() {
return this.userRepository.findAll();
}
public User getUserById(long id) {
Optional<User> user = this.userRepository.findById(id);
if (user.isEmpty()) {
logger.error("getUserById : No user found with id {}", id);
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Cet utilisateur n'existe pas");
}
return user.get();
}
// TODO
public User getUserByEmail(String email) {
Optional<User> opt_user = this.userRepository.findByPrimaryMail(email);
if (opt_user.isEmpty()) {
logger.error("getUserByEmail : No user found with email {}", email);
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Cet utilisateur n'existe pas");
}
return opt_user.get();
}
public Iterable<User> allUsers() {
return this.userRepository.findAll();
}
public User addUser(@RequestBody User user) {
return this.userRepository.save(user);
}
public void updateUserSurname(long idUser, String surname) {
User user = getUserById(idUser);
user.setUserSurname(surname);
this.userRepository.save(user);
}
public void updateUserName(long idUser, String name) {
User user = getUserById(idUser);
user.setUserName(name);
this.userRepository.save(user);
}
public void updateUserPrimaryMail(long idUser, String primaryMail) {
User user = getUserById(idUser);
user.setPrimaryMail(primaryMail);
this.userRepository.save(user);
}
public void updateUserSecondaryMail(long idUser, String secondaryMail) {
User user = getUserById(idUser);
user.setSecondaryMail(secondaryMail);
this.userRepository.save(user);
}
public void updateUserPhoneNumber(long idUser, String phoneNumber) {
User user = getUserById(idUser);
user.setPhoneNumber(phoneNumber);
this.userRepository.save(user);
}
public User updateUser(
@PathVariable Long id,
String userSurname,
String userName,
String primaryMail,
String secondaryMail,
String phoneNumber) {
Optional<User> user = userRepository.findById(id);
if (user.isEmpty()) {
logger.error("updateUser : No user found with id {}", id);
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Cet utilisateur n'existe pas");
}
if (userName != null) {
user.get().setUserName(userName);
}
if (userSurname != null) {
user.get().setUserSurname(userSurname);
}
if (primaryMail != null) {
user.get().setPrimaryMail(primaryMail);
}
if (secondaryMail != null) {
user.get().setSecondaryMail(secondaryMail);
}
if (phoneNumber != null) {
user.get().setPhoneNumber(phoneNumber);
}
return this.userRepository.save(user.get());
}
public Iterable<User> getPendingAccounts() {
return this.userRepository.findAllByPendingEquals(true);
}
}

View File

@ -1,8 +1,8 @@
spring.application.name=myinpulse
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://localhost:7080/realms/test/protocol/openid-connect/certs
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:7080/realms/test
logging.level.org.springframework.security=DEBUG
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://localhost:7080/realms/${VITE_KEYCLOAK_REALM}/protocol/openid-connect/certs
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:7080/realms/${VITE_KEYCLOAK_REALM}
spring.datasource.url=jdbc:postgresql://${DATABASE_URL}/${BACKEND_DB}
spring.datasource.username=${BACKEND_USER}
spring.datasource.password=${BACKEND_PASSWORD}
spring.jpa.hibernate.ddl-auto=update
logging.pattern.console=%d{yyyy-MMM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n

View File

@ -1,57 +1,88 @@
TRUNCATE projets, utilisateurs, entrepreneurs, sections, rendez_vous, comptes_rendus CASCADE;
TRUNCATE project, user_inpulse, entrepreneur, administrator, section_cell, appointment, report, annotation CASCADE;
INSERT INTO projets (nom_projet, logo, date_creation, status_projet)
SELECT setval('annotation_id_annotation_seq', 1, false);
SELECT setval('appointment_id_appointment_seq', 1, false);
SELECT setval('make_appointment_id_make_appointment_seq', 1, false);
SELECT setval('project_id_project_seq', 1, false);
SELECT setval('report_id_report_seq', 1, false);
SELECT setval('section_cell_id_section_cell_seq', 1, false);
SELECT setval('user_inpulse_id_user_seq', 1, false);
INSERT INTO user_inpulse (user_surname, user_name, primary_mail, secondary_mail, phone_number)
VALUES ('Dupont', 'Dupond', 'super@mail.fr', 'super2@mail.fr', '06 45 72 45 98'),
('Martin', 'Matin', 'genial@mail.fr', 'genial2@mail.fr', '06 52 14 58 73'),
('Charvet', 'Lautre', 'mieux@tmail.fr', 'mieux2@tmail.fr', '07 49 82 16 35'),
('Leguez', 'Theo', 'bof@mesmails.fr', 'bof2@mesmails.fr', '+33 6 78 14 25 29'),
('Kia', 'Bi', 'special@mail.fr', 'special2@mail.fr', '07 65 31 38 95'),
('Ducaillou', 'Pierre', 'maildefou@xyz.fr', 'maildefou2@xyz.fr', '06 54 78 12 62'),
('Janine', 'Dave', 'janine@labri.fr', 'janine2@labri.fr', '06 87 12 45 95');
INSERT INTO administrator (id_administrator)
VALUES (7);
INSERT INTO project (project_name, logo, creation_date, project_status, id_administrator)
VALUES ('Eau du robinet', decode('013d7d16d7ad4fefb61bd95b765c8ceb', 'hex'), TO_DATE('01-OCT-2023', 'DD-MON-YYYY'),
'En cours'),
('Air oxygéné', decode('150647a0984e8f228cd14b54', 'hex'), TO_DATE('04-APR-2024', 'DD-MON-YYYY'), 'En cours'),
'En cours', 7),
('Air oxygéné', decode('150647a0984e8f228cd14b54', 'hex'), TO_DATE('04-APR-2024', 'DD-MON-YYYY'), 'En cours', 7),
('Débat concours', decode('022024abd5486e245c145dda65116f', 'hex'), TO_DATE('22-NOV-2023', 'DD-MON-YYYY'),
'Suspendu'),
'Suspendu', 7),
('HDeirbMI', decode('ab548d6c1d595a2975e6476f544d14c55a', 'hex'), TO_DATE('07-DEC-2024', 'DD-MON-YYYY'),
'Lancement');
INSERT INTO utilisateurs (nom_utilisateur, prenom_utilisateur, mail_principal, mail_secondaire, numero_telephone) VALUES
('Dupont', 'Dupond', 'super@mail.fr', 'super2@mail.fr', '06 45 72 45 98'),
('Martin', 'Matin', 'genial@mail.fr', 'genial2@mail.fr', '06 52 14 58 73'),
('Charvet', 'Lautre', 'mieux@tmail.fr', 'mieux2@tmail.fr', '07 49 82 16 35'),
('Leguez', 'Theo', 'bof@mesmails.fr', 'bof2@mesmails.fr', '+33 6 78 14 25 29'),
('Kia', 'Bi', 'special@mail.fr', 'special2@mail.fr', '07 65 31 38 95'),
('Ducaillou', 'Pierre', 'maildefou@xyz.fr', 'maildefou2@xyz.fr', '06 54 78 12 62');
'Lancement', 7);
INSERT INTO entrepreneurs (ecole, filiere, status_snee, id_entrepreneur) VALUES
('ENSEIRB-MATMECA', 'INFO', TRUE, 1),
('ENSC', 'Cognitique', TRUE, 2),
('ENSEIRB-MATMECA', 'MATMECA', FALSE, 3),
('SupOptique', 'Classique', TRUE, 4),
('ENSEGID', 'Géoscience', FALSE, 5),
('ENSMAC', 'Matériaux composites - Mécanique', FALSE, 6);
INSERT INTO entrepreneur (school, course, snee_status, id_entrepreneur, id_project_participation, id_project_proposed)
VALUES ('ENSEIRB-MATMECA', 'INFO', TRUE, 1, 4, 4),
('ENSC', 'Cognitique', TRUE, 2, 2, null),
('ENSEIRB-MATMECA', 'MATMECA', FALSE, 3, 3, 3),
('SupOptique', 'Classique', TRUE, 4, 1, 1),
('ENSEGID', 'Géoscience', FALSE, 5, 1, null),
('ENSMAC', 'Matériaux composites - Mécanique', FALSE, 6, 2, 2);
INSERT INTO sections (titre, contenu_section, date_modification) VALUES
('Problème', 'les problèmes...', TO_TIMESTAMP('15-JAN-2025 09:30:20', 'DD-MON-YYYY, HH24:MI:SS')),
('Segment de client', 'Le segment AB passant le client n°8 est de longueur 32mm.
Le segment BC a quant à lui un longueur de 28mm. Quelle la longueur du segment AC ?', TO_TIMESTAMP('12-OCT-2022 17:47:38', 'DD-MON-YYYY, HH24:MI:SS')),
('Proposition de valeur unique', '''Son prix est de 2594€'' ''Ah oui c''est unique en effet', TO_TIMESTAMP('25-MAY-2024 11:12:04', 'DD-MON-YYYY, HH24:MI:SS')),
('Solution', 'Un problème ? Une solution', TO_TIMESTAMP('08-FEB-2024 10:17:53', 'DD-MON-YYYY, HH24:MI:SS')),
('Canaux', 'Ici nous avons la Seine, là-bas le Rhin, oh et plus loin le canal de Suez', TO_TIMESTAMP('19-JUL-2023 19:22:45', 'DD-MON-YYYY, HH24:MI:SS')),
('Sources de revenus', 'Y''en n''a pas on est pas payé. Enfin y''a du café quoi', TO_TIMESTAMP('12-JAN-2025 11:40:26', 'DD-MON-YYYY, HH24:MI:SS')),
('Structure des coûts', '''Ah oui là ça va faire au moins 1000€ par mois'', Eirbware', TO_TIMESTAMP('06-FEB-2025 13:04:06', 'DD-MON-YYYY, HH24:MI:SS')),
('Indicateurs clés', 'On apprend les clés comme des badges, ça se fait', TO_TIMESTAMP('05-FEB-2025 12:42:38', 'DD-MON-YYYY, HH24:MI:SS')),
('Avantages concurrentiel', 'On est meilleur', TO_TIMESTAMP('23-APR-2024 16:24:02', 'DD-MON-YYYY, HH24:MI:SS'));
INSERT INTO rendez_vous (date_rdv, heure_rdv, duree_rdv, lieu_rdv, sujet_rdv) VALUES
(TO_DATE('24-DEC-2023', 'DD-MON-YYYY'), '00:00:00', '00:37:53', 'À la maison', 'Ouvrir les cadeaux'),
(TO_DATE('15-AUG-2024', 'DD-MON-YYYY'), '22:35:00', '00:12:36', 'Sur les quais ou dans un champ probablement', 'BOUM BOUM les feux d''artifices (on fête quoi déjà ?)'),
(TO_DATE('28-FEB-2023', 'DD-MON-YYYY'), '14:20:00', '00:20:00', 'Salle TD 15', 'Ah mince c''est pas une année bissextile !'),
(TO_DATE('23-JAN-2024', 'DD-MON-YYYY'), '12:56:27', '11:03:33', 'Là où le vent nous porte', 'Journée la plus importante de l''année'),
(TO_DATE('25-AUG-2025', 'DD-MON-YYYY'), '00:09:00', '01:00:00', 'Euh c''est par où l''amphi 56 ?', 'Rentrée scolaire (il fait trop froid c''est quoi ça on est en août)');
INSERT INTO section_cell (title, content_section_cell, modification_date, id_project)
VALUES ('Problème', 'les problèmes...', TO_TIMESTAMP('15-JAN-2025 09:30:20', 'DD-MON-YYYY, HH24:MI:SS'), 2),
('Segment de client', 'Le segment AB passant le client n°8 est de longueur 32mm.
Le segment BC a quant à lui un longueur de 28mm. Quelle la longueur du segment AC ?',
TO_TIMESTAMP('12-OCT-2022 17:47:38', 'DD-MON-YYYY, HH24:MI:SS'), 3),
('Proposition de valeur unique', '''Son prix est de 2594€'' ''Ah oui c''est unique en effet',
TO_TIMESTAMP('25-MAY-2024 11:12:04', 'DD-MON-YYYY, HH24:MI:SS'), 2),
('Solution', 'Un problème ? Une solution', TO_TIMESTAMP('08-FEB-2024 10:17:53', 'DD-MON-YYYY, HH24:MI:SS'), 1),
('Canaux', 'Ici nous avons la Seine, là-bas le Rhin, oh et plus loin le canal de Suez',
TO_TIMESTAMP('19-JUL-2023 19:22:45', 'DD-MON-YYYY, HH24:MI:SS'), 4),
('Sources de revenus', 'Y''en n''a pas on est pas payé. Enfin y''a du café quoi',
TO_TIMESTAMP('12-JAN-2025 11:40:26', 'DD-MON-YYYY, HH24:MI:SS'), 1),
('Structure des coûts', '''Ah oui là ça va faire au moins 1000€ par mois'', Eirbware',
TO_TIMESTAMP('06-FEB-2025 13:04:06', 'DD-MON-YYYY, HH24:MI:SS'), 3),
('Indicateurs clés', 'On apprend les clés comme des badges, ça se fait',
TO_TIMESTAMP('05-FEB-2025 12:42:38', 'DD-MON-YYYY, HH24:MI:SS'), 4),
('Avantages concurrentiel', 'On est meilleur', TO_TIMESTAMP('23-APR-2024 16:24:02', 'DD-MON-YYYY, HH24:MI:SS'),
2);
INSERT INTO comptes_rendus (contenu_compte_rendu) VALUES
('Ah oui ça c''est super, ah ouais j''aime bien, bien vu de penser à ça'),
('Bonne réunion'),
('Ouais, j''ai rien compris mais niquel on fait comme vous avez dit'),
('Non non ça va pas du tout ce que tu me proposes, faut tout refaire'),
('Réponse de la DSI : non'),
('Trop dommage qu''Apple ait sorti leur logiciel avant nous, on avait la même idée et tout on aurait tellement pu leur faire de la concurrence');
INSERT INTO appointment (appointment_date, appointment_time, appointment_duration, appointment_place,
appointment_subject)
VALUES (TO_DATE('24-DEC-2023', 'DD-MON-YYYY'), '00:00:00', '00:37:53', 'À la maison', 'Ouvrir les cadeaux'),
(TO_DATE('15-AUG-2024', 'DD-MON-YYYY'), '22:35:00', '00:12:36', 'Sur les quais ou dans un champ probablement',
'BOUM BOUM les feux d''artifices (on fête quoi déjà ?)'),
(TO_DATE('28-FEB-2023', 'DD-MON-YYYY'), '14:20:00', '00:20:00', 'Salle TD 15',
'Ah mince c''est pas une année bissextile !'),
(TO_DATE('23-JAN-2024', 'DD-MON-YYYY'), '12:56:27', '11:03:33', 'Là où le vent nous porte',
'Journée la plus importante de l''année'),
(TO_DATE('25-AUG-2025', 'DD-MON-YYYY'), '00:09:00', '01:00:00', 'Euh c''est par où l''amphi 56 ?',
'Rentrée scolaire (il fait trop froid c''est quoi ça on est en août)');
INSERT INTO report (report_content, id_appointment)
VALUES ('Ah oui ça c''est super, ah ouais j''aime bien, bien vu de penser à ça', 1),
('Bonne réunion', 3),
('Ouais, j''ai rien compris mais niquel on fait comme vous avez dit', 3),
('Non non ça va pas du tout ce que tu me proposes, faut tout refaire', 4),
('Réponse de la DSI : non', 2),
('Trop dommage qu''Apple ait sorti leur logiciel avant nous, on avait la même idée et tout on aurait tellement pu leur faire de la concurrence',
5);
INSERT INTO annotation (comment, id_administrator, id_section_cell)
VALUES ('faut changer ça hein', 7, 5),
('??? sérieusement, vous pensez que c''est une bonne idée ?', 7, 7),
('ok donc ça c''est votre business plan, bah glhf la team', 7, 2);

View File

@ -1 +1,2 @@
DROP TABLE IF EXISTS administrateurs, projets, utilisateurs, entrepreneurs, sections, rendez_vous, comptes_rendus, concerner CASCADE;
DROP TABLE IF EXISTS administrateurs, projets, utilisateurs, entrepreneurs, sections, rendez_vous, comptes_rendus, concerner CASCADE;
DROP TABLE IF EXISTS administrator, project, user_inpulse, entrepreneur, section_cell, appointment, make_appointment, report, annotation, concern CASCADE;

View File

@ -1,134 +0,0 @@
DROP TABLE IF EXISTS projets CASCADE;
DROP TABLE IF EXISTS utilisateurs CASCADE;
DROP TABLE IF EXISTS entrepreneurs CASCADE;
DROP TABLE IF EXISTS administrateurs CASCADE;
DROP TABLE IF EXISTS sections CASCADE;
DROP TABLE IF EXISTS rendez_vous CASCADE;
DROP TABLE IF EXISTS comptes_rendus CASCADE;
DROP TABLE IF EXISTS concerner CASCADE;
DROP TABLE IF EXISTS formes CASCADE;
CREATE TABLE projets
(
id_projet SERIAL NOT NULL,
nom_projet VARCHAR(255),
logo BYTEA,
date_creation DATE,
status_projet VARCHAR(255),
CONSTRAINT pk_projet PRIMARY KEY (id_projet)
);
CREATE TABLE utilisateurs
(
id_utilisateur SERIAL NOT NULL,
nom_utilisateur VARCHAR(255) ,
prenom_utilisateur VARCHAR(255) ,
mail_principal VARCHAR(255) ,
mail_secondaire VARCHAR(255) ,
numero_telephone VARCHAR(20) ,
CONSTRAINT pk_utilisateur PRIMARY KEY (id_utilisateur) );
CREATE TABLE entrepreneurs
(
id_entrepreneur SERIAL REFERENCES utilisateurs (id_utilisateur),
ecole VARCHAR(255),
filiere VARCHAR(255),
status_snee BOOLEAN,
CONSTRAINT pk_entrepreneur PRIMARY KEY (id_entrepreneur)
);
CREATE TABLE administrateurs
(
id_administrateur SERIAL REFERENCES utilisateurs (id_utilisateur),
CONSTRAINT pk_administrateur PRIMARY KEY (id_administrateur)
);
CREATE TABLE sections
(
id_section SERIAL NOT NULL,
titre VARCHAR(255),
contenu_section TEXT,
date_modification TIMESTAMP,
CONSTRAINT pk_section PRIMARY KEY (id_section)
);
CREATE TABLE rendez_vous
(
id_rdv SERIAL NOT NULL,
date_rdv DATE,
heure_rdv TIME,
duree_rdv TIME,
lieu_rdv VARCHAR(255),
sujet_rdv TEXT,
CONSTRAINT pk_rdv PRIMARY KEY (id_rdv)
);
CREATE TABLE comptes_rendus
(
id_compte_rendu SERIAL NOT NULL,
contenu_compte_rendu TEXT,
CONSTRAINT pk_compte_rendu PRIMARY KEY (id_compte_rendu)
);
CREATE TABLE concerner
(
id_section SERIAL REFERENCES sections (id_section),
id_rdv SERIAL REFERENCES sections (id_rdv),
CONSTRAINT pk_concerner PRIMARY KEY (id_section, id_rdv)
);
ALTER TABLE projets
ADD CONSTRAINT fk1_projet FOREIGN KEY (id_administrateur)
REFERENCES administrateurs (id_administrateur)
ON DELETE CASCADE;
ALTER TABLE projets
ADD CONSTRAINT fk2_projet FOREIGN KEY (id_entrepreneur_participation)
REFERENCES entrepreneurs (id_entrepreneur)
ON DELETE CASCADE;
ALTER TABLE entrepreneurs
ADD CONSTRAINT fk1_entrepreneur FOREIGN KEY (id_projet_propose)
REFERENCES projets (id_projet)
ON DELETE CASCADE;
ALTER TABLE sections
ADD CONSTRAINT fk1_section FOREIGN KEY (id_projet)
REFERENCES projets (id_projet)
ON DELETE CASCADE;
ALTER TABLE sections
ADD CONSTRAINT fk2_section FOREIGN KEY (id_administrateur)
REFERENCES administrateurs (id_administrateur)
ON DELETE CASCADE;
ALTER TABLE rendez-vous
ADD CONSTRAINT fk1_rdv FOREIGN KEY (id_entrepreneur)
REFERENCES entrepreneurs (id_entrepreneur)
ON
DELETE
CASCADE;
ALTER TABLE rendez-vous
ADD CONSTRAINT fk2_rdv FOREIGN KEY (id_administrateur)
REFERENCES administrateurs (id_administrateur)
ON
DELETE
CASCADE;
ALTER TABLE comptes-rendus
ADD CONSTRAINT fk1_compte_rendu FOREIGN KEY (id_rdv)
REFERENCES rendez_vous (id_rdv)
ON
DELETE
CASCADE;

View File

@ -0,0 +1,331 @@
package enseirb.myinpulse;
import static enseirb.myinpulse.model.ProjectDecisionValue.*;
import static org.junit.jupiter.api.Assertions.*;
import enseirb.myinpulse.model.*;
import enseirb.myinpulse.service.AdminApiService;
import enseirb.myinpulse.service.UtilsService;
import enseirb.myinpulse.service.database.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
@SpringBootTest
@Transactional
public class AdminApiServiceTest {
private static long administratorid;
private static Administrator administrator;
private static Entrepreneur entrepreneur;
private static Appointment appt;
private static Project p;
@Autowired private AdminApiService adminApiService;
@Autowired private ProjectService projectService;
@Autowired private EntrepreneurService entrepreneurService;
@Autowired private SectionCellService sectionCellService;
@Autowired private AppointmentService appointmentService;
@Autowired private UtilsService utilsService;
@BeforeAll
static void setup(
@Autowired AdministratorService administratorService,
@Autowired ProjectService projectService,
@Autowired EntrepreneurService entrepreneurService,
@Autowired AppointmentService appoitmentService,
@Autowired SectionCellService sectionCellService) {
administratorService.addAdministrator(
new Administrator(
"admin",
"admin",
"testAdminEmpty@example.com",
"testAdmin@example.com",
""));
administrator =
administratorService.addAdministrator(
new Administrator(
"admin2",
"admin2",
"testAdminFull@example.com",
"testAdmin@example.com",
""));
administratorid = administrator.getIdUser();
entrepreneur =
new Entrepreneur(
"JeSuisUnEntrepreneurDeCompet",
"EtUé",
"Entrepreneur@inpulse.com",
"mail2",
"phone",
"Ensimag nan jdeconne ENSEIRB (-matmeca mais on s'en fout)",
"info ofc",
false);
entrepreneurService.addEntrepreneur(entrepreneur);
Entrepreneur entrepreneur2 =
new Entrepreneur(
"GDProjets", "", "Entrepreneur2@inpulse.com", "", "", "", "info ofc", true);
entrepreneurService.addEntrepreneur(entrepreneur2);
p =
projectService.addNewProject(
new Project(
"sampleProjectAdminApiService",
null,
LocalDate.now(),
ACTIVE,
administratorService.getAdministratorByPrimaryMain(
"testAdminFull@example.com")));
entrepreneurService.updateEntrepreneurProjectParticipation(entrepreneur2.getIdUser(), p);
appt =
new Appointment(
null,
LocalDate.now(),
LocalTime.now(),
LocalTime.now(),
"Salle TD 03",
"Discussion importante");
}
private <T> List<T> IterableToList(Iterable<T> iterable) {
List<T> l = new ArrayList<>();
iterable.forEach(l::add);
return l;
}
@Test
void getProjectOfAdminIsEmpty() {
Iterable<Project> projects =
adminApiService.getProjectsOfAdmin("testAdminEmpty@example.com");
assertEquals(0, IterableToList(projects).size());
}
@Test
void getProjectOfInexistantAdminFails() {
String nonExistentAdminEmail = "testInexistantAdmin@example.com";
assertThrows(
ResponseStatusException.class,
() -> {
adminApiService.getProjectsOfAdmin(nonExistentAdminEmail);
});
}
@Test
void getProjectOfAdminNotEmpty() {
Iterable<Project> projects =
adminApiService.getProjectsOfAdmin("testAdminFull@example.com");
List<Project> l = IterableToList(projects);
assertEquals(1, l.size());
Project p = l.getFirst();
assertEquals("sampleProjectAdminApiService", p.getProjectName());
}
@Test
void getPendingProjectsEmpty() {
assertEquals(0, IterableToList(this.adminApiService.getPendingProjects()).size());
}
@Test
void getPendingProjectsNotEmpty() {
this.projectService.addNewProject(
new Project(
"PendingProjectAdminApiService1", null, LocalDate.now(), PENDING, null));
this.projectService.addNewProject(
new Project(
"PendingProjectAdminApiService2", null, LocalDate.now(), PENDING, null));
Iterable<Project> pendingProjects = this.adminApiService.getPendingProjects();
List<Project> pendingProjectsList = IterableToList(pendingProjects);
assertEquals(2, pendingProjectsList.size());
assertTrue(
List.of("PendingProjectAdminApiService1", "PendingProjectAdminApiService2")
.contains(pendingProjectsList.getFirst().getProjectName()));
assertTrue(
List.of("PendingProjectAdminApiService1", "PendingProjectAdminApiService2")
.contains(pendingProjectsList.getLast().getProjectName()));
}
@Test
void validateInexistantProject() {
ProjectDecision d = new ProjectDecision(-1, 0, 1);
assertThrows(ResponseStatusException.class, () -> this.adminApiService.validateProject(d));
}
@Test
void validateExistantProject() {
Project p =
new Project("PendingProjectAdminApiService2", null, LocalDate.now(), PENDING, null);
this.projectService.addNewProject(p);
assertEquals(PENDING, p.getProjectStatus());
ProjectDecision d = new ProjectDecision(p.getIdProject(), administratorid, 1);
this.adminApiService.validateProject(d);
assertEquals(ACTIVE, p.getProjectStatus());
// Check if the project was really updated in the database
assertEquals(0, IterableToList(this.adminApiService.getPendingProjects()).size());
}
@Test
void refuseExistantProject() {
Project p =
new Project("PendingProjectAdminApiService2", null, LocalDate.now(), PENDING, null);
this.projectService.addNewProject(p);
assertEquals(PENDING, p.getProjectStatus());
ProjectDecision d = new ProjectDecision(p.getIdProject(), administratorid, 0);
this.adminApiService.validateProject(d);
assertEquals(REJECTED, p.getProjectStatus());
// Check if the project was really updated in the database
assertEquals(0, IterableToList(this.adminApiService.getPendingProjects()).size());
}
@Test
void addProject() {
assertEquals(0, IterableToList(this.adminApiService.getPendingProjects()).size());
Project p1 =
new Project("PendingProjectAdminApiService2", null, LocalDate.now(), PENDING, null);
this.adminApiService.addNewProject(p1);
assertEquals(1, IterableToList(this.adminApiService.getPendingProjects()).size());
}
@Test
void addProjectToAdmin() {
assertEquals(0, administrator.getListProject().size());
Project p1 = new Project("addProjectToAdmin", null, LocalDate.now(), ACTIVE, administrator);
this.adminApiService.addNewProject(p1);
assertEquals(1, administrator.getListProject().size());
}
@Test
void addProjectToUser() {
assertNull(entrepreneur.getProjectParticipation());
Project p1 =
new Project("addProjectToAdmin", null, LocalDate.now(), ACTIVE, null, entrepreneur);
this.adminApiService.addNewProject(p1);
assertEquals(p1, entrepreneur.getProjectParticipation());
}
@Test
void addProjectWithManyUsers() {
Entrepreneur e1 = new Entrepreneur();
Entrepreneur e2 = new Entrepreneur();
Entrepreneur e3 = new Entrepreneur();
assertNull(e1.getProjectParticipation());
assertNull(e2.getProjectParticipation());
assertNull(e3.getProjectParticipation());
Project p1 = new Project("addProjectToAdmin", null, LocalDate.now(), ACTIVE, null, null);
p1.updateListEntrepreneurParticipation(e1);
p1.updateListEntrepreneurParticipation(e2);
p1.updateListEntrepreneurParticipation(e3);
this.adminApiService.addNewProject(p1);
assertEquals(p1, e1.getProjectParticipation());
assertEquals(p1, e2.getProjectParticipation());
assertEquals(p1, e3.getProjectParticipation());
}
@Test
void addDuplicateProject() {
Project p1 =
new Project("PendingProjectAdminApiService2", null, LocalDate.now(), PENDING, null);
Project p2 =
new Project("PendingProjectAdminApiService2", null, LocalDate.now(), PENDING, null);
this.adminApiService.addNewProject(p1);
assertThrows(ResponseStatusException.class, () -> this.adminApiService.addNewProject(p2));
}
// We could do a delete active project, but it's not really useful.
@Test
void deletePendingProject() {
int oldsize = IterableToList(this.adminApiService.getPendingProjects()).size();
Project p1 =
new Project("PendingProjectAdminApiService2", null, LocalDate.now(), PENDING, null);
Project p2 = this.adminApiService.addNewProject(p1);
assertEquals(oldsize + 1, IterableToList(this.adminApiService.getPendingProjects()).size());
this.adminApiService.deleteProject(p2.getIdProject());
assertEquals(oldsize, IterableToList(this.adminApiService.getPendingProjects()).size());
for (int i = 0; i < oldsize; i++) {
assertNotEquals(
p1.getIdProject(),
IterableToList(this.adminApiService.getPendingProjects())
.get(i)
.getIdProject());
}
}
@Test
void getUpcommingAppointmentUnkwnownUser() {
assertThrows(
ResponseStatusException.class,
() -> {
Iterable<Appointment> a =
this.adminApiService.getUpcomingAppointments(
"entrepreneur-inexistent@mail.fr");
});
}
@Test
void getUpcommingAppointmentNoProject() {
assertThrows(
ResponseStatusException.class,
() -> {
Iterable<Appointment> a =
this.adminApiService.getUpcomingAppointments(
"Entrepreneur@inpulse.com");
});
}
@Test
void getUpcommingAppointmentEmpty() {
Iterable<Appointment> a =
this.adminApiService.getUpcomingAppointments("Entrepreneur2@inpulse.com");
assertEquals(0, IterableToList(a).size());
}
@Test
void validateEntrepreneurAccount() {
assertTrue(entrepreneurService.getEntrepreneurById(entrepreneur.getIdUser()).isPending());
assertEquals(2, IterableToList(adminApiService.getPendingUsers()).size());
adminApiService.validateEntrepreneurAccount(entrepreneur.getIdUser(), "");
assertFalse(entrepreneurService.getEntrepreneurById(entrepreneur.getIdUser()).isPending());
assertEquals(1, IterableToList(adminApiService.getPendingUsers()).size());
}
@Test
void testCreateApptRepport() {
System.err.println(appt.getIdAppointment());
SectionCell s =
sectionCellService.addNewSectionCell(
new SectionCell(null, 1L, "jaja", LocalDateTime.now(), p));
appointmentService.addNewAppointment(appt);
appointmentService.updateAppointmentListSectionCell(appt.getIdAppointment(), s);
projectService.updateProjectListSectionCell(p.getIdProject(), s);
this.adminApiService.createAppointmentReport(
appt.getIdAppointment(),
new Report(null, "je rapporte de fou"),
"testAdminFull@example.com");
}
@Test
void testSetAdmin() {
assertFalse(utilsService.isAnAdmin(entrepreneur.getPrimaryMail()));
adminApiService.setAdmin(entrepreneur.getIdUser(), "");
assertTrue(utilsService.isAnAdmin(entrepreneur.getPrimaryMail()));
}
}

View File

@ -0,0 +1,324 @@
package enseirb.myinpulse;
import static enseirb.myinpulse.model.ProjectDecisionValue.*;
import static org.junit.jupiter.api.Assertions.*;
import enseirb.myinpulse.model.*;
import enseirb.myinpulse.service.EntrepreneurApiService;
import enseirb.myinpulse.service.database.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
@SpringBootTest
@Transactional
public class EntrepreneurApiServiceTest {
private static Entrepreneur entrepreneur;
private static Project project;
private static Iterable<SectionCell> sectionCells2;
private static Iterable<SectionCell> sectionCells3;
@Autowired private EntrepreneurApiService entrepreneurApiService;
@Autowired private EntrepreneurService entrepreneurService;
@Autowired private ProjectService projectService;
@Autowired private SectionCellService sectionCellService;
@Autowired private AnnotationService annotationService;
@Autowired private AppointmentService appointmentService;
@BeforeAll
static void setup(
@Autowired EntrepreneurService entrepreneurService,
@Autowired ProjectService projectService,
@Autowired SectionCellService sectionCellService) {
entrepreneur =
entrepreneurService.addEntrepreneur(
new Entrepreneur(
"entre",
"preneur",
"entrepreneur@mail.fr",
"entrepreneur2@mail.fr",
"01 45 71 25 48",
"ENSEIRB",
"Info",
false));
entrepreneurService.addEntrepreneur(
new Entrepreneur(
"entre2",
"preneur2",
"testentrepreneur@mail.fr",
"testentrepreneur2@mail.fr",
"",
"ENSEGID",
"",
true));
project =
projectService.addNewProject(
new Project("Project", null, LocalDate.now(), ACTIVE, null, entrepreneur));
entrepreneurService.updateEntrepreneurProjectProposed(entrepreneur.getIdUser(), project);
entrepreneurService.updateEntrepreneurProjectParticipation(
entrepreneur.getIdUser(), project);
SectionCell s1 =
sectionCellService.addNewSectionCell(
new SectionCell(
null,
2L,
"contenu très intéressant",
LocalDateTime.now(),
project));
SectionCell s2 =
sectionCellService.addNewSectionCell(
new SectionCell(
null,
3L,
"contenu très intéressant2",
LocalDateTime.now(),
project));
sectionCells2 = sectionCellService.getSectionCellsByProject(project, 2L);
sectionCells3 = sectionCellService.getSectionCellsByProject(project, 3L);
}
private <T> List<T> IterableToList(Iterable<T> iterable) {
List<T> l = new ArrayList<>();
iterable.forEach(l::add);
return l;
}
@Test
void editValidSectionCell() {
System.out.println("editValidSectionCell : ");
SectionCell modified = IterableToList(sectionCells2).getLast();
this.sectionCellService.updateSectionCellListAnnotation(
modified.getIdSectionCell(),
annotationService.addNewAnnotation(new Annotation(null, "oui j'annote encore")));
this.sectionCellService.updateSectionCellListAppointment(
modified.getIdSectionCell(),
appointmentService.addNewAppointment(
new Appointment(
null,
LocalDate.now(),
LocalTime.now(),
LocalTime.of(2, 5),
"TD14",
"clément s'est plaint")));
entrepreneurApiService.editSectionCell(
modified.getIdSectionCell(), "modified content", "entrepreneur@mail.fr");
// We get the data from the database again.
SectionCell s =
IterableToList(sectionCellService.getSectionCellsByProject(project, 2L)).getLast();
assertEquals("modified content", s.getContentSectionCell());
assertEquals(
2, IterableToList(sectionCellService.getSectionCellsByProject(project, 2L)).size());
}
@Test
void editInvalidSectionCell() {
System.out.println("editInvalidSectionCell : ");
assertThrows(
ResponseStatusException.class,
() ->
entrepreneurApiService.editSectionCell(
-1L, "should not be modified", "entrepreneur@mail.fr"));
SectionCell s =
IterableToList(sectionCellService.getSectionCellsByProject(project, 2L)).getLast();
assertEquals("contenu très intéressant", s.getContentSectionCell());
assertEquals(
1, IterableToList(sectionCellService.getSectionCellsByProject(project, 2L)).size());
}
@Test
void editSectionCellInvalidAccess() {
System.out.println("editSectionCellInvalidAccess : ");
assertThrows(
ResponseStatusException.class,
() ->
entrepreneurApiService.editSectionCell(
IterableToList(sectionCells3).getFirst().getIdSectionCell(),
"should not be modified",
"testentrepreneur@mail.fr"));
SectionCell s =
IterableToList(sectionCellService.getSectionCellsByProject(project, 2L)).getFirst();
assertEquals("contenu très intéressant", s.getContentSectionCell());
}
@Test
void editNullSectionCell() {
System.out.println("editNullSectionCell : ");
assertThrows(
ResponseStatusException.class,
() ->
entrepreneurApiService.editSectionCell(
null, "modified content", "entrepreneur@mail.fr"));
}
@Test
void removeValidSectionCell() {
System.out.println("removeValidSectionCell : ");
SectionCell tmpCell =
sectionCellService.addNewSectionCell(
new SectionCell(
null, 2L, "contenu temporaire", LocalDateTime.now(), project));
assertEquals(
2, IterableToList(sectionCellService.getSectionCellsByProject(project, 2L)).size());
assertDoesNotThrow(
() ->
entrepreneurApiService.removeSectionCell(
tmpCell.getIdSectionCell(), "entrepreneur@mail.fr"));
assertEquals(
tmpCell.getIdReference(),
IterableToList(sectionCellService.getSectionCellsByProject(project, -1L))
.getLast()
.getIdReference());
}
@Test
void removeInvalidSectionCell() {
System.out.println("removeInvalidSectionCell : ");
assertThrows(
ResponseStatusException.class,
() -> entrepreneurApiService.removeSectionCell(-1L, "entrepreneur@mail.fr"));
SectionCell s =
IterableToList(sectionCellService.getSectionCellsByProject(project, 2L)).getFirst();
assertEquals("contenu très intéressant", s.getContentSectionCell());
}
@Test
void removeNullSectionCell() {
System.out.println("removeNullSectionCell : ");
assertThrows(
ResponseStatusException.class,
() -> entrepreneurApiService.removeSectionCell(null, "entrepreneur@mail.fr"));
}
@Test
void addValidSectionCell() {
System.out.println("addValidSectionCell : ");
SectionCell added =
sectionCellService.addNewSectionCell(
new SectionCell(null, 2L, "contenu ajouté", LocalDateTime.now(), project));
added.updateListAnnotation(
annotationService.addNewAnnotation(new Annotation(null, "oui j'annote")));
added.updateAppointmentSectionCell(
appointmentService.addNewAppointment(
new Appointment(
null,
LocalDate.now(),
LocalTime.now(),
LocalTime.of(2, 5),
"TD15",
"clément qui se plaint")));
entrepreneurApiService.addSectionCell(added, "entrepreneur@mail.fr");
SectionCell s =
IterableToList(sectionCellService.getSectionCellsByProject(project, 2L)).getLast();
assertEquals("contenu ajouté", s.getContentSectionCell());
assertEquals(
2, IterableToList(sectionCellService.getSectionCellsByProject(project, 2L)).size());
}
@Test
void addSectionCellInvalidAccess() {
System.out.println("addSectionCellInvalidAccess : ");
SectionCell added =
new SectionCell(null, 2L, "contenu ajouté", LocalDateTime.now(), project);
assertThrows(
ResponseStatusException.class,
() -> entrepreneurApiService.addSectionCell(added, "fauxentrepreneur@mail.fr"));
SectionCell s =
IterableToList(sectionCellService.getSectionCellsByProject(project, 2L)).getLast();
assertEquals(
1, IterableToList(sectionCellService.getSectionCellsByProject(project, 2L)).size());
assertEquals("contenu très intéressant", s.getContentSectionCell());
}
@Test
void addInvalidSectionCell() {
System.out.println("addInvalidSectionCell : ");
SectionCell added =
sectionCellService.addNewSectionCell(
new SectionCell(null, -1L, "contenu ajouté", LocalDateTime.now(), project));
assertThrows(
ResponseStatusException.class,
() -> entrepreneurApiService.addSectionCell(added, "entrepreneur@mail.fr"));
}
@Test
void addNullSectionCell() {
System.out.println("addNullSectionCell : ");
assertThrows(
ResponseStatusException.class,
() -> entrepreneurApiService.addSectionCell(null, "entrepreneur@mail.fr"));
}
@Test
void requestValidProject() {
System.out.println("requestValidProject : ");
int nb_project = IterableToList(this.projectService.getAllProjects()).size();
Project validProject =
new Project("validProject", null, LocalDate.now(), ACTIVE, null, entrepreneur);
validProject.updateListEntrepreneurParticipation(
IterableToList(entrepreneurService.getAllEntrepreneurs()).getLast());
validProject.updateListSectionCell((IterableToList(sectionCells2).getFirst()));
entrepreneurApiService.requestNewProject(validProject, "entrepreneur@mail.fr");
assertEquals(PENDING, validProject.getProjectStatus());
assertEquals((nb_project + 1), IterableToList(this.projectService.getAllProjects()).size());
assertEquals(
IterableToList(entrepreneurService.getAllEntrepreneurs()).getLast(),
validProject.getListEntrepreneurParticipation().getLast());
assertEquals(
IterableToList(sectionCells2).getFirst().getIdSectionCell(),
validProject.getListSectionCell().getFirst().getIdSectionCell());
}
@Test
void requestNullProject() {
System.out.println("requestNullProject : ");
assertThrows(
ResponseStatusException.class,
() -> entrepreneurApiService.requestNewProject(null, "entrepreneur@mail.fr"));
}
@Test
void createNewValidAccount() {
System.out.println("createNewValidAccount : ");
int nb_entrepreneur = IterableToList(this.entrepreneurService.getAllEntrepreneurs()).size();
Entrepreneur newEntrepreneur =
new Entrepreneur(
"New",
"Test",
"mailtest@test.fr",
"mailtest2@test.fr",
"0888888888",
"ENSEIRB",
"ELEC",
false,
true);
assertDoesNotThrow(() -> entrepreneurApiService.createAccount(newEntrepreneur));
assertEquals(
(nb_entrepreneur + 1),
IterableToList(this.entrepreneurService.getAllEntrepreneurs()).size());
}
@Test
void createExistingAccount() {
System.out.println("createExistingAccount : ");
int nb_entrepreneur = IterableToList(this.entrepreneurService.getAllEntrepreneurs()).size();
assertThrows(
ResponseStatusException.class,
() -> entrepreneurApiService.createAccount(entrepreneur));
assertEquals(
nb_entrepreneur,
IterableToList(this.entrepreneurService.getAllEntrepreneurs()).size());
}
}

View File

@ -1,5 +1,6 @@
package enseirb.myinpulse;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@ -7,5 +8,6 @@ import org.springframework.boot.test.context.SpringBootTest;
class MyinpulseApplicationTests {
@Test
@DisplayName("contextLoad => Test if the context can load, i.e. the application can start")
void contextLoads() {}
}

View File

@ -0,0 +1,922 @@
package enseirb.myinpulse;
import static enseirb.myinpulse.model.ProjectDecisionValue.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.when;
import enseirb.myinpulse.model.*;
import enseirb.myinpulse.service.SharedApiService;
import enseirb.myinpulse.service.database.*;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import enseirb.myinpulse.service.UtilsService;
import org.junit.jupiter.api.BeforeAll; // Use BeforeAll for static setup
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; // Keep this import
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
// Helper to easily convert Iterable to List
class TestUtils {
static <T> List<T> toList(Iterable<T> iterable) {
List<T> list = new ArrayList<>();
if (iterable != null) {
iterable.forEach(list::add);
}
return list;
}
}
@SpringBootTest
@Transactional // Each @Test method runs in a transaction that is rolled back
public class SharedApiServiceTest {
@Autowired private SharedApiService sharedApiService;
// Autowire actual services to use in setup and test verification
@Autowired private ProjectService projectService;
@Autowired private AdministratorService administratorService;
@Autowired private EntrepreneurService entrepreneurService;
@Autowired private SectionCellService sectionCellService;
@Autowired private AppointmentService appointmentService;
// Mock UtilsService to control authorization logic
@MockitoBean private UtilsService mockUtilsService;
// Static variables for data created once before all tests
private static Project staticAuthorizedProject;
private static String staticAuthorizedMail;
private static Administrator staticAuthorizedAdmin;
private static Project staticUnauthorizedProject;
private static String staticUnauthorizedMail;
// --- Static Setup (Runs once before all tests) ---
// Use @BeforeAll static method with injected services
@BeforeAll
static void setupOnce(
@Autowired AdministratorService administratorService,
@Autowired ProjectService projectService,
@Autowired EntrepreneurService entrepreneurService) {
// Create and Save core test data here using injected services
staticAuthorizedAdmin =
administratorService.addAdministrator(getTestAdmin("static_authorized_admin"));
staticAuthorizedMail = staticAuthorizedAdmin.getPrimaryMail();
staticUnauthorizedProject =
projectService.addNewProject(
getTestProject(
"static_unauthorized_project",
administratorService.addAdministrator(
getTestAdmin("static_unauthorized_admin"))));
staticUnauthorizedMail =
administratorService
.addAdministrator(getTestAdmin("static_unauthorized_user"))
.getPrimaryMail(); // User who is NOT admin of the unauthorized project
staticAuthorizedProject =
projectService.addNewProject(
getTestProject("static_authorized_project", staticAuthorizedAdmin));
// Link a static entrepreneur to the authorized project if needed for some tests
// Entrepreneur staticLinkedEntrepreneur =
// entrepreneurService.addEntrepreneur(getTestEntrepreneur("static_linked_entrepreneur"));
// staticAuthorizedProject.updateListEntrepreneurParticipation(staticLinkedEntrepreneur);
// projectService.addNewProject(staticAuthorizedProject); // Re-save the project after
// updating lists
}
// --- Per-Test Setup (Runs before each test method) ---
@BeforeEach
void setupForEach() {
// Reset mock expectations before each test
MockitoAnnotations.openMocks(
this); // Needed for mocks if not using @ExtendWith(MockitoExtension.class)
// --- Configure the mock UtilsService based on the actual authorization rules ---
// Rule: Any admin can check any project.
// Assuming staticAuthorizedMail is an admin:
when(mockUtilsService.isAllowedToCheckProject(eq(staticAuthorizedMail), anyLong()))
.thenReturn(true); // Admin allowed for ANY project ID
// Rule: An entrepreneur can only check their own stuff.
// Assuming staticUnauthorizedMail is an entrepreneur NOT linked to staticAuthorizedProject
// or staticUnauthorizedProject:
when(mockUtilsService.isAllowedToCheckProject(eq(staticUnauthorizedMail), anyLong()))
.thenReturn(false); // Unauthorized entrepreneur NOT allowed for ANY project ID by
// default
}
// --- Helper Methods (Can remain non-static or static as needed) ---
private static Administrator getTestAdmin(String name) {
return new Administrator(
name + "_surname",
name,
name + "@example.com",
"secondary_" + name + "@example.com",
"0123456789");
}
private static Entrepreneur getTestEntrepreneur(String name) {
return new Entrepreneur(
name + "_surname",
name,
name + "@example.com",
"secondary_" + name + "@example.com",
"0123456789",
"Test School",
"Test Course",
false);
}
private static Project getTestProject(String name, Administrator admin) {
Project project = new Project(name, null, LocalDate.now(), ACTIVE, admin);
return project;
}
private static SectionCell getTestSectionCell(
Project project, Long sectionId, String content, LocalDateTime date) {
SectionCell sectionCell = new SectionCell();
sectionCell.setProjectSectionCell(project);
sectionCell.setSectionId(sectionId);
sectionCell.setContentSectionCell(content);
sectionCell.setModificationDate(date);
return sectionCell;
}
private static SectionCell getTestSectionCell(
Project project, Long sectionId, String content, LocalDateTime date, Long refrenceId) {
SectionCell sectionCell = new SectionCell();
sectionCell.setProjectSectionCell(project);
sectionCell.setSectionId(sectionId);
sectionCell.setContentSectionCell(content);
sectionCell.setModificationDate(date);
sectionCell.setIdReference(refrenceId);
return sectionCell;
}
private static Appointment getTestAppointment(
LocalDate date,
LocalTime time,
LocalTime duration,
String place,
String subject,
List<SectionCell> sectionCells,
Report report) {
Appointment appointment = new Appointment();
appointment.setAppointmentDate(date);
appointment.setAppointmentTime(time);
appointment.setAppointmentDuration(duration);
appointment.setAppointmentPlace(place);
appointment.setAppointmentSubject(subject);
if (sectionCells != null) {
sectionCells.forEach(appointment::updateListSectionCell);
}
if (report != null) {
appointment.setAppointmentReport(report);
report.setAppointmentReport(appointment);
}
return appointment;
}
private static Report getTestReport(String content) {
Report report = new Report();
report.setReportContent(content);
return report;
}
/*
* _____ _ ____ _ _ ____ _ _
* |_ _|__ ___| |_/ ___| ___ ___| |_(_) ___ _ __ / ___|___| | |
* | |/ _ \/ __| __\___ \ / _ \/ __| __| |/ _ \| '_ \| | / _ \ | |
* | | __/\__ \ |_ ___) | __/ (__| |_| | (_) | | | | |__| __/ | |
* |_|\___||___/\__|____/ \___|\___|\__|_|\___/|_| |_|\____\___|_|_|
*/
/*
* Tests retrieving section cells for a specific project and section ID before a given date
* when the user is authorized but no matching cells exist.
* Verifies that an empty list is returned.
*/
@Test
void testGetSectionCells_Authorized_NotFound() {
// Arrange: No specific section cells needed for this test, rely on clean @BeforeEach state
Long targetSectionId = 1L;
LocalDateTime dateFilter = LocalDateTime.now().plusDays(1);
// Act
Iterable<SectionCell> result =
sharedApiService.getSectionCells(
staticAuthorizedProject.getIdProject(),
targetSectionId,
dateFilter.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")),
staticAuthorizedMail);
List<SectionCell> resultList = TestUtils.toList(result);
// Assert
assertTrue(resultList.isEmpty());
}
/*
* Tests retrieving section cells when the user is not authorized for the project.
* Verifies that an Unauthorized ResponseStatusException is thrown.
*/
@Test
void testGetSectionCells_Unauthorized() {
// Arrange: mockUtilsService configured in BeforeEach
// Act & Assert
ResponseStatusException exception =
assertThrows(
ResponseStatusException.class,
() -> {
sharedApiService.getSectionCells(
staticAuthorizedProject
.getIdProject(), // Project static user is not
// authorized for
1L,
LocalDateTime.now()
.format(
DateTimeFormatter.ofPattern(
"yyyy-MM-dd HH:mm")),
staticUnauthorizedMail); // Static unauthorized user mail
});
assertEquals(HttpStatus.UNAUTHORIZED, exception.getStatusCode());
}
/*
* Tests retrieving all section cells for a project when the user is authorized
* but the project has no section cells.
* Verifies that an empty list is returned.
*/
@Test
void testGetAllSectionCells_Authorized_NoCells() {
// Arrange: staticAuthorizedProject has no section cells initially in BeforeAll
// Act
Iterable<SectionCell> result =
sharedApiService.getAllSectionCells(
staticAuthorizedProject.getIdProject(), staticAuthorizedMail);
List<SectionCell> resultList = TestUtils.toList(result);
// Assert
assertTrue(resultList.isEmpty());
}
/*
* Tests retrieving all section cells when the user is not authorized for the project.
* Verifies that an Unauthorized ResponseStatusException is thrown.
*/
@Test
void testGetAllSectionCells_Unauthorized() {
// Arrange: mockUtilsService configured in BeforeEach
// Act & Assert
ResponseStatusException exception =
assertThrows(
ResponseStatusException.class,
() -> {
sharedApiService.getAllSectionCells(
staticAuthorizedProject.getIdProject(), staticUnauthorizedMail);
});
assertEquals(HttpStatus.UNAUTHORIZED, exception.getStatusCode());
}
/*
* Tests retrieving section cells for a specific project and section ID before a given date
* when the user is authorized and matching cells exist.
* Verifies that only the correct cells are returned.
*/
@Test
// Commenting out failing test
void testGetSectionCells_Authorized_Found() {
Long targetSectionId = 1L;
// Set a date filter slightly in the future so our "latest before" cell is included
LocalDateTime dateFilter = LocalDateTime.now().plusMinutes(5);
// Creating versions of the SAME SectionCell (share the same idReference)
// the first version. This will get a GENERATED idReference.
SectionCell firstVersion =
getTestSectionCell(
staticAuthorizedProject,
targetSectionId,
"Content V1 (Oldest)",
LocalDateTime.now().minusDays(3) // Oldest date
);
sectionCellService.addNewSectionCell(firstVersion);
Long sharedIdReference = firstVersion.getIdReference();
assertNotNull(
sharedIdReference,
"idReference should be generated after saving the first version");
System.out.println("Generated sharedIdReference: " + sharedIdReference);
// Create subsequent versions and MANUALLY set the SAME idReference.
// These represent updates to the cell identified by sharedIdReference.
SectionCell middleVersion =
getTestSectionCell(
staticAuthorizedProject,
targetSectionId,
"Content V2 (Middle)",
LocalDateTime.now().minusDays(2), // Middle date, before filter
sharedIdReference);
middleVersion = sectionCellService.addNewSectionCell(middleVersion);
sectionCellService.updateSectionCellReferenceId(
middleVersion.getIdSectionCell(), sharedIdReference);
SectionCell latestBeforeFilter =
getTestSectionCell(
staticAuthorizedProject,
targetSectionId,
"Content V3 (Latest Before Filter)",
LocalDateTime.now().minusDays(1), // Latest date before filter
sharedIdReference);
latestBeforeFilter = sectionCellService.addNewSectionCell(latestBeforeFilter);
sectionCellService.updateSectionCellReferenceId(
latestBeforeFilter.getIdSectionCell(), sharedIdReference);
SectionCell futureVersion =
getTestSectionCell(
staticAuthorizedProject,
targetSectionId,
"Content V4 (Future - Should Be Excluded)",
LocalDateTime.now().plusDays(1), // Date is AFTER the filter
sharedIdReference);
futureVersion = sectionCellService.addNewSectionCell(futureVersion);
sectionCellService.updateSectionCellReferenceId(
futureVersion.getIdSectionCell(), sharedIdReference);
// --- Create other SectionCells that should NOT be included (different sectionId or
// project) ---
// Cell in a different section ID
sectionCellService.addNewSectionCell(
getTestSectionCell(
staticAuthorizedProject,
99L, // Different sectionId
"Content in Different Section",
LocalDateTime.now()));
// Act
Iterable<SectionCell> result =
sharedApiService.getSectionCells(
staticAuthorizedProject.getIdProject(), // Use static project ID
targetSectionId,
dateFilter.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")),
staticAuthorizedMail); // Use static authorized mail
List<SectionCell> resultList = TestUtils.toList(result);
assertEquals(1, resultList.size());
// Verify that the returned cell is the 'latestBeforeFilter' cell
// Comparing by idSectionCell is a good way to verify the exact entity
assertEquals(
latestBeforeFilter.getIdSectionCell(),
resultList.get(0).getIdSectionCell(),
"The returned SectionCell should be the one with the latest modification date before the filter.");
// Also assert the idReference and content
assertEquals(
sharedIdReference,
resultList.get(0).getIdReference(),
"The returned cell should have the shared idReference.");
assertEquals(
"Content V3 (Latest Before Filter)",
resultList.get(0).getContentSectionCell(),
"The returned cell should have the correct content.");
}
/*
* Tests retrieving the most recent section cell for each unique idReference
* within a project when the user is authorized and cells exist.
* Verifies that only the latest version of each referenced cell is returned.
*/
// Tests getAllSectionCells
@Test
// Commenting out failing test - Removed this comment as we are fixing it
void testGetAllSectionCells_Authorized_FoundLatest() {
// Arrange: Create specific SectionCells for this test
// Define the idReference values we will use for grouping
Long refIdGroup1 = 101L;
Long refIdGroup2 = 102L;
Long refIdOtherProject = 103L;
// --- Create and Add Cells for Group 1 (refIdGroup1) ---
// Create the older cell for group 1
SectionCell tempOldCell1 =
getTestSectionCell(
staticAuthorizedProject, // Project
1L, // Section ID (assuming this groups by section within refId)
"Ref1 Old", // Name
LocalDateTime.now().minusDays(3), // Date (older)
null); // Pass null or let getTestSectionCell handle it, we'll set
// idReference later
final SectionCell oldCell1 =
sectionCellService.addNewSectionCell(tempOldCell1); // Add to DB
// Create the newer cell for group 1
SectionCell tempNewerCell1 =
getTestSectionCell(
staticAuthorizedProject, // Project
1L, // Section ID
"Ref1 Newer", // Name
LocalDateTime.now().minusDays(2), // Date (newer than oldCell1)
null); // Pass null
final SectionCell newerCell1 =
sectionCellService.addNewSectionCell(tempNewerCell1); // Add to DB
// Now, update the idReference for both cells in Group 1 to the desired value
sectionCellService.updateSectionCellReferenceId(oldCell1.getIdSectionCell(), refIdGroup1);
sectionCellService.updateSectionCellReferenceId(newerCell1.getIdSectionCell(), refIdGroup1);
// --- Create and Add Cells for Group 2 (refIdGroup2) ---
// Create the older cell for group 2
SectionCell tempOldCell2 =
getTestSectionCell(
staticAuthorizedProject, // Project
2L, // Section ID (different section)
"Ref2 Old", // Name
LocalDateTime.now().minusDays(1), // Date (older than newerCell2)
null); // Pass null
final SectionCell oldCell2 =
sectionCellService.addNewSectionCell(tempOldCell2); // Add to DB
// Create the newer cell for group 2
SectionCell tempNewerCell2 =
getTestSectionCell(
staticAuthorizedProject, // Project
2L, // Section ID
"Ref2 Newer", // Name
LocalDateTime.now(), // Date (latest)
null); // Pass null
final SectionCell newerCell2 =
sectionCellService.addNewSectionCell(tempNewerCell2); // Add to DB
// Now, update the idReference for both cells in Group 2 to the desired value
sectionCellService.updateSectionCellReferenceId(oldCell2.getIdSectionCell(), refIdGroup2);
sectionCellService.updateSectionCellReferenceId(newerCell2.getIdSectionCell(), refIdGroup2);
// --- Create and Add Cell for Other Project (refIdOtherProject) ---
Project otherProject =
projectService.addNewProject(
getTestProject(
"other_project_for_cell_test",
administratorService.addAdministrator(
getTestAdmin("other_admin_cell_test"))));
SectionCell tempOtherProjectCell =
getTestSectionCell(
otherProject, // DIFFERENT Project
1L, // Section ID
"Other Project Cell", // Name
LocalDateTime.now(), // Date
null); // Pass null
final SectionCell otherProjectCell =
sectionCellService.addNewSectionCell(tempOtherProjectCell); // Add to DB
// Now, update the idReference for the Other Project cell
sectionCellService.updateSectionCellReferenceId(
otherProjectCell.getIdSectionCell(), refIdOtherProject);
// Act
// Ensure the service call uses the correct project ID and mail
Iterable<SectionCell> result =
sharedApiService.getAllSectionCells(
staticAuthorizedProject.getIdProject(), // Use static project ID
staticAuthorizedMail); // Use static authorized mail
List<SectionCell> resultList = TestUtils.toList(result);
// Assert
// We expect 2 cells from the staticAuthorizedProject:
// - The latest one from refIdGroup1 (newerCell1)
// - The latest one from refIdGroup2 (newerCell2)
assertEquals(2, resultList.size());
// Assert that the result list contains the LATEST cell from each group within the correct
// project
assertTrue(
resultList.stream()
.anyMatch(
cell ->
cell.getIdSectionCell()
.equals(newerCell1.getIdSectionCell())),
"Should contain the latest cell for Group 1"); // Add assertion message
assertTrue(
resultList.stream()
.anyMatch(
cell ->
cell.getIdSectionCell()
.equals(newerCell2.getIdSectionCell())),
"Should contain the latest cell for Group 2"); // Add assertion message
// Assert that the result list does NOT contain the OLDER cells from the correct project
assertFalse(
resultList.stream()
.anyMatch(
cell ->
cell.getIdSectionCell()
.equals(oldCell1.getIdSectionCell())),
"Should not contain the older cell for Group 1"); // Add assertion message
assertFalse(
resultList.stream()
.anyMatch(
cell ->
cell.getIdSectionCell()
.equals(oldCell2.getIdSectionCell())),
"Should not contain the older cell for Group 2"); // Add assertion message
// Assert that the result list does NOT contain the cell from the other project
assertFalse(
resultList.stream()
.anyMatch(
cell ->
cell.getIdSectionCell()
.equals(otherProjectCell.getIdSectionCell())),
"Should not contain cells from other projects"); // Add assertion message
}
/*
* _____ _ ____ _ ____ _ _ ____
* |_ _|__ ___| |_ / ___| ___| |_| _ \ _ __ ___ (_) ___ ___| |_| __ ) _ _
* | |/ _ \/ __| __| | _ / _ \ __| |_) | '__/ _ \| |/ _ \/ __| __| _ \| | | |
* | | __/\__ \ |_| |_| | __/ |_| __/| | | (_) | | __/ (__| |_| |_) | |_| |
* _|_|\___||___/\__|\____|\___|\__|_| |_| \___// |\___|\___|\__|____/ \__, |
* |_ _| _ \ |__/ |___/
* | || | | |
* | || |_| |
* |___|____/
*/
/*
* Tests retrieving entrepreneurs linked to a project when the user is authorized
* but no entrepreneurs are linked.
* Verifies that an empty list is returned.
*/
@Test
void testGetEntrepreneursByProjectId_Authorized_NotFound() {
// Arrange: staticAuthorizedProject has no entrepreneurs linked initially in BeforeAll
// Act
Iterable<Entrepreneur> result =
sharedApiService.getEntrepreneursByProjectId(
staticAuthorizedProject.getIdProject(), staticAuthorizedMail);
List<Entrepreneur> resultList = TestUtils.toList(result);
// Assert
assertTrue(resultList.isEmpty());
}
/*
* Tests retrieving entrepreneurs linked to a project when the user is not authorized.
* Verifies that an Unauthorized ResponseStatusException is thrown.
*/
@Test
void testGetEntrepreneursByProjectId_Unauthorized() {
// Arrange: mockUtilsService configured in BeforeEach
// Act & Assert
ResponseStatusException exception =
assertThrows(
ResponseStatusException.class,
() -> {
sharedApiService.getEntrepreneursByProjectId(
staticAuthorizedProject.getIdProject(), staticUnauthorizedMail);
});
assertEquals(HttpStatus.UNAUTHORIZED, exception.getStatusCode());
}
/*
* _____ _ ____ _ _ _ _ ____
* |_ _|__ ___| |_ / ___| ___| |_ / \ __| |_ __ ___ (_)_ __ | __ ) _ _
* | |/ _ \/ __| __| | _ / _ \ __| / _ \ / _` | '_ ` _ \| | '_ \| _ \| | | |
* | | __/\__ \ |_| |_| | __/ |_ / ___ \ (_| | | | | | | | | | | |_) | |_| |
* _|_|\___||___/\__|\____|\___|\__/_/ \_\__,_|_| |_| |_|_|_| |_|____/ \__, |
* |_ _| _ \ |___/
* | || | | |
* | || |_| |
* |___|____/
*
*/
/*
* Tests retrieving appointments linked to a project's section cells when the user is authorized
* but no such appointments exist.
* Verifies that an empty list is returned.
*/
@Test
void testGetAppointmentsByProjectId_Authorized_NotFound() {
// Arrange: staticAuthorizedProject has no linked section cells or appointments initially
// Act
Iterable<Appointment> result =
sharedApiService.getAppointmentsByProjectId(
staticAuthorizedProject.getIdProject(), staticAuthorizedMail);
List<Appointment> resultList = TestUtils.toList(result);
// Assert
assertTrue(resultList.isEmpty());
}
/*
* Tests retrieving the administrator linked to a project when the user is authorized
* and an administrator is linked.
* Verifies that the correct administrator is returned.
*/
// Tests getAdminByProjectId
@Test
void testGetAdminByProjectId_Authorized_Found() {
// Arrange: staticAuthorizedProject is created with staticAuthorizedAdmin in BeforeAll
// Act
Administrator result =
sharedApiService.getAdminByProjectId(
staticAuthorizedProject.getIdProject(), staticAuthorizedMail);
// Assert
assertNotNull(result);
assertEquals(staticAuthorizedAdmin.getIdUser(), result.getIdUser());
}
/*
* Tests retrieving the administrator linked to a project when the user is not authorized.
* Verifies that an Unauthorized ResponseStatusException is thrown.
*/
@Test
void testGetAdminByProjectId_Unauthorized() {
// Arrange: mockUtilsService configured in BeforeEach
// Act & Assert
ResponseStatusException exception =
assertThrows(
ResponseStatusException.class,
() -> {
sharedApiService.getAdminByProjectId(
staticAuthorizedProject.getIdProject(), staticUnauthorizedMail);
});
assertEquals(HttpStatus.UNAUTHORIZED, exception.getStatusCode());
}
/*
* _____ _
* |_ _|__ ___| |_
* | |/ _ \/ __| __|
* | | __/\__ \ |_
* |_|\___||___/\__| _ _ _
* / \ _ __ _ __ ___ (_)_ __ | |_ ___ _ __ ___ ___ _ __ | |_ ___
* / _ \ | '_ \| '_ \ / _ \| | '_ \| __/ _ \ '_ ` _ \ / _ \ '_ \| __/ __|
* / ___ \| |_) | |_) | (_) | | | | | || __/ | | | | | __/ | | | |_\__ \
* /_/ \_\ .__/| .__/ \___/|_|_| |_|\__\___|_| |_| |_|\___|_| |_|\__|___/
* |_| |_|
*/
/*
* Tests retrieving appointments linked to a project's section cells when the user is not authorized.
* Verifies that an Unauthorized ResponseStatusException is thrown.
*/
@Test
void testGetAppointmentsByProjectId_Unauthorized() {
// Arrange: mockUtilsService configured in BeforeEach
// Act & Assert
ResponseStatusException exception =
assertThrows(
ResponseStatusException.class,
() -> {
sharedApiService.getAppointmentsByProjectId(
staticAuthorizedProject.getIdProject(), staticUnauthorizedMail);
});
assertEquals(HttpStatus.UNAUTHORIZED, exception.getStatusCode());
}
@PersistenceContext // Inject EntityManager
private EntityManager entityManager;
// Assume these static variables are defined elsewhere in your test class
// private static Project staticAuthorizedProject;
// private static String staticAuthorizedMail;
// private static Administrator staticAuthorizedAdmin;
// Assume getTestSectionCell, getTestProject, getTestAdmin, getTestAppointment, TestUtils.toList
// are defined elsewhere
@Test
void testGetAppointmentsByProjectId_Authorized_Found() {
// Arrange: Create specific SectionCells and Appointments for this test
SectionCell cell1 =
sectionCellService.addNewSectionCell(
getTestSectionCell(
staticAuthorizedProject, 1L, "Cell 1 Test", LocalDateTime.now()));
SectionCell cell2 =
sectionCellService.addNewSectionCell(
getTestSectionCell(
staticAuthorizedProject, 2L, "Cell 2 Test", LocalDateTime.now()));
Project otherProject =
projectService.addNewProject(
getTestProject(
"other_project_app_test",
administratorService.addAdministrator(
getTestAdmin("other_admin_app_test"))));
SectionCell otherProjectCell =
sectionCellService.addNewSectionCell(
getTestSectionCell(
otherProject,
1L,
"Other Project Cell App Test",
LocalDateTime.now()));
// Create Appointments with SectionCells lists (Owning side)
Appointment app1 =
getTestAppointment(
LocalDate.now().plusDays(10),
LocalTime.NOON,
LocalTime.of(0, 30),
"Place 1 App Test",
"Subject 1 App Test",
List.of(cell1), // This links Appointment to SectionCell
null);
Appointment savedApp1 = appointmentService.addNewAppointment(app1);
Appointment app2 =
getTestAppointment(
LocalDate.now().plusDays(11),
LocalTime.NOON.plusHours(1),
LocalTime.of(1, 0),
"Place 2 App Test",
"Subject 2 App Test",
List.of(cell1, cell2), // This links Appointment to SectionCells
null);
Appointment savedApp2 = appointmentService.addNewAppointment(app2);
Appointment otherApp =
getTestAppointment(
LocalDate.now().plusDays(12),
LocalTime.MIDNIGHT,
LocalTime.of(0, 15),
"Other Place App Test",
"Other Subject App Test",
List.of(otherProjectCell), // This links Appointment to SectionCell
null);
Appointment savedOtherApp =
appointmentService.addNewAppointment(otherApp); // Capture saved entity
// --- IMPORTANT DEBUGGING STEPS ---
// Flush pending changes to the database (including join table inserts)
entityManager.flush();
// Clear the persistence context cache to ensure entities are loaded fresh from the database
entityManager.clear();
// --- END IMPORTANT DEBUGGING STEPS ---
// --- Add Debug Logging Here ---
// Re-fetch cells to see their state after saving Appointments and flushing/clearing cache
// These fetches should load from the database due to entityManager.clear()
SectionCell fetchedCell1_postPersist =
sectionCellService.getSectionCellById(cell1.getIdSectionCell());
SectionCell fetchedCell2_postPersist =
sectionCellService.getSectionCellById(cell2.getIdSectionCell());
SectionCell fetchedOtherCell_postPersist =
sectionCellService.getSectionCellById(otherProjectCell.getIdSectionCell());
// Access the lazy collections to see if they are populated from the DB
// This access should trigger lazy loading if the data is in the DB
List<Appointment> cell1Apps_postPersist =
fetchedCell1_postPersist.getAppointmentSectionCell();
List<Appointment> cell2Apps_postPersist =
fetchedCell2_postPersist.getAppointmentSectionCell();
List<Appointment> otherCellApps_postPersist =
fetchedOtherCell_postPersist.getAppointmentSectionCell();
// Ensure logging is enabled in SharedApiService and SectionCellService methods called below
Iterable<Appointment> result =
sharedApiService.getAppointmentsByProjectId(
staticAuthorizedProject.getIdProject(), // Use static project ID
staticAuthorizedMail); // Use static authorized mail
List<Appointment> resultList = TestUtils.toList(result);
// Assert
assertEquals(2, resultList.size());
assertTrue(
resultList.stream()
.anyMatch(a -> a.getIdAppointment().equals(savedApp1.getIdAppointment())));
assertTrue(
resultList.stream()
.anyMatch(a -> a.getIdAppointment().equals(savedApp2.getIdAppointment())));
assertFalse(
resultList.stream()
.anyMatch(
a ->
a.getIdAppointment()
.equals(savedOtherApp.getIdAppointment())));
}
/*
* Tests creating a new appointment request when the user is authorized
* for the project linked to the appointment's section cell.
* Verifies that the appointment and its relationships are saved correctly in the database.
*/
// Tests createAppointmentRequest
@Test
// Commenting out failing test
void testCreateAppointmentRequest_Authorized_Success() {
// Arrange: Create transient appointment linked to a cell in the static authorized project
LocalDate date = LocalDate.parse("2026-01-01");
LocalTime time = LocalTime.parse("10:00:00");
LocalTime duration = LocalTime.parse("00:30:00");
String place = "Meeting Room Integrated";
String subject = "Discuss Project Integrated";
SectionCell linkedCell =
sectionCellService.addNewSectionCell(
getTestSectionCell(
staticAuthorizedProject,
0L,
"Related Section Content Integrated",
LocalDateTime.now()));
Report newReport = null; // getTestReport(reportContent); // Uses no-arg constructor
Appointment newAppointment =
getTestAppointment(
date, time, duration, place, subject, List.of(linkedCell), newReport);
// mockUtilsService is configured in BeforeEach to allow staticAuthorizedMail for
// staticAuthorizedProject
// Act
// Allow the service method to call the actual appointmentService.addNewAppointment
assertDoesNotThrow(
() ->
sharedApiService.createAppointmentRequest(
newAppointment, staticAuthorizedMail));
// Assert: Retrieve the appointment from the DB and verify it and its relationships were
// saved
// We find it by looking for appointments linked to the authorized project's cells
Iterable<SectionCell> projectCells =
sectionCellService.getSectionCellsByProject(
staticAuthorizedProject, linkedCell.getSectionId()); // Fetch relevant cells
List<Appointment> projectAppointmentsList = new ArrayList<>();
projectCells.forEach(
cell ->
projectAppointmentsList.addAll(
sectionCellService.getAppointmentsBySectionCellId(
cell.getIdSectionCell()))); // Get appointments for
// those cells
Optional<Appointment> createdAppointmentOpt =
projectAppointmentsList.stream()
.filter(
a ->
a.getAppointmentDate().equals(date)
&& a.getAppointmentTime().equals(time)
&& a.getAppointmentPlace().equals(place)
&& a.getAppointmentSubject().equals(subject))
.findFirst();
assertTrue(createdAppointmentOpt.isPresent());
Appointment createdAppointment = createdAppointmentOpt.get();
// FIX: Corrected bidirectional link check
assertEquals(1, createdAppointment.getAppointmentListSectionCell().size());
assertTrue(
createdAppointment.getAppointmentListSectionCell().stream()
.anyMatch(
sc -> sc.getIdSectionCell().equals(linkedCell.getIdSectionCell())));
List<Appointment> appointmentsLinkedToCell =
TestUtils.toList(
sectionCellService.getAppointmentsBySectionCellId(
linkedCell.getIdSectionCell()));
assertTrue(
appointmentsLinkedToCell.stream()
.anyMatch(
a ->
a.getIdAppointment()
.equals(createdAppointment.getIdAppointment())));
}
}

View File

@ -0,0 +1,10 @@
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
spring.sql.init.mode=never
spring.application.name=myinpulse-test
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://localhost:7080/realms/test/protocol/openid-connect/certs
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:7080/realms/test
spring.jpa.hibernate.ddl-auto=update
logging.pattern.console=%d{yyyy-MMM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n

22
config/.env.dev Normal file
View File

@ -0,0 +1,22 @@
POSTGRES_DB=postgres_db
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres_db_user_password
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=admin
KEYCLOAK_HOSTNAME=localhost
KEYCLOAK_DB=keycloak_db
KEYCLOAK_USER=keycloak_db_user
KEYCLOAK_PASSWORD=keycloak_db_user_password
BACKEND_DB=backend_db
BACKEND_USER=backend_db_user
BACKEND_PASSWORD=backend_db_user_password
DATABASE_URL=localhost:5433
VITE_KEYCLOAK_URL=http://localhost:7080
VITE_KEYCLOAK_CLIENT_ID=myinpulse-dev
VITE_KEYCLOAK_REALM=test
VITE_APP_URL=http://localhost:5173
VITE_BACKEND_URL=http://localhost:8081/

View File

@ -16,7 +16,7 @@ BACKEND_PASSWORD=backend_db_user_password
DATABASE_URL=localhost:5433
VITE_KEYCLOAK_URL=http://localhost:7080
VITE_KEYCLOAK_CLIENT_ID=myinpulse-dev
VITE_KEYCLOAK_REALM=test
VITE_KEYCLOAK_CLIENT_ID=MyINPulse-vite
VITE_KEYCLOAK_REALM=MyINPulse
VITE_APP_URL=http://localhost:5173
VITE_BACKEND_URL=http://localhost:8081/

12
documentation/Doc.txt Normal file
View File

@ -0,0 +1,12 @@
Format des comptes rendus de réunion :
Texte organisé par bullet point, chaque bullet point est séparé par "//" pour pouvoir être correctement généré.
Exemple :
Le texte "// blablabla // oui bonjour"
donne le résultat
Point n°1 :
blablabla
Point n°2 :
oui bonjour

View File

@ -0,0 +1,13 @@
## API Endpoints notes
### EntrepreneurApi and SharedApi
#### Endpoint Name Changes
- `/entrepreneur/lcsection/modify/{sectionId}``/entrepreneur/sectionCell/modify/{sectionId}`
### Admin api
- `/admin/appointments/report/{appointmentId}` has no PUT and DELETE
- `/admin/request-join` and `/admin/request-join/decision/{joinRequestId}` have not yet been implemented
### Unauth api
- `/unauth/request-join/{projectId}` has not yet been implemented

View File

@ -0,0 +1,11 @@
#!/bin/bash
cd ./swagger-ui
if [ ! -d "./node_modules/" ]
then
npm install
npm install swagger-cli
fi
npm start

View File

@ -0,0 +1,387 @@
# Admin API Endpoints
paths:
/admin/projects:
get:
operationId: getAdminProjects
summary: Get projects associated with the admin
tags:
- Admin API
security:
- MyINPulse: [MyINPulse-admin]
description: Retrieves a list of projects managed by the requesting admin, including details for overview.
responses:
"200":
description: OK - List of projects returned successfully.
content:
application/json:
schema:
type: array
items:
$ref: "./main.yaml#/components/schemas/project"
"400":
description: Bad Request - Invalid project data provided (e.g., missing required fields).
"401":
description: Unauthorized - Authentication required or invalid token.
"403":
description: Bad Token - Invalid Keycloack configuration.
post:
operationId: addProjectManually
summary: Manually add a new project
description: Creates a new project with the provided details. (NOTE that this meant for manually inserting projects, for example importing already existing projects).
tags:
- Admin API
security:
- MyINPulse: [MyINPulse-admin]
requestBody:
required: true
description: Project details to create. `idProject` and `creationDate` will be ignored if sent and set by the server.
content:
application/json:
schema:
$ref: "./main.yaml#/components/schemas/project"
responses:
"200": # Use 200 Created for successful creation
description: Created - Project added successfully. Returns the created project.
content:
application/json:
schema:
$ref: "./main.yaml#/components/schemas/project"
"409":
description: Bad Request - Project already exists.
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.
/admin/projects/pending:
get:
operationId: getPendingProjects
summary: Get projects awaiting validation
tags:
- Admin API
security:
- MyINPulse: [MyINPulse-admin]
description: Retrieves a list of projects submitted by entrepreneurs that are pending admin approval.
responses:
"200":
description: OK - List of pending projects returned.
content:
application/json:
schema:
type: array
items:
$ref: "./main.yaml#/components/schemas/project" # Assuming pending projects use the same schema
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.
/admin/request-join:
get:
operationId: getPendingProjects
summary: Get entrepreneurs project join requests
tags:
- Admin API
security:
- MyINPulse: [MyINPulse-admin]
description: Retrieves a list of pending requests from entrepreneurs to join an existing project.
responses:
"200":
description: OK - List of pending project join requests.
content:
application/json:
schema:
type: array
items:
$ref: "./main.yaml#/components/schemas/joinRequest"
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.
/admin/request-join/decision/{joinRequestId}:
post:
summary: Approve or reject a pending project join request
tags:
- Admin API
security:
- MyINPulse: [MyINPulse-admin]
parameters:
- in: path
name: joinRequestId
required: true
schema:
type: integer
description: The ID of the pending join request to decide upon.
description: |-
Allows an admin to make a decision on an ebtrepreneur's request to join an existing project awaiting validation.
If approved (isAccepted=true), the entrepreneur is linked to the project with ID joinRequestId.
If rejected (isAccepted=false), the pending request data might be archived or deleted based on business logic.
responses:
"200":
description: OK - No Content, decision processed successfully..
content:
application/json:
$ref: "./main.yaml#/components/schemas/joinRequestDecision"
"400":
description: Bad Request - Invalid input (e.g., missing decision).
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.
/admin/projects/pending/decision:
post:
operationId: decidePendingProject
summary: Approve or reject a pending project
tags:
- Admin API
description: |-
Allows an admin to make a decision on a project awaiting validation.
If approved (isAccepted=true), the project status changes, and it's linked to the involved users.
If rejected (isAccepted=false), the pending project data might be archived or deleted based on business logic.
security:
- MyINPulse: [MyINPulse-admin]
requestBody:
required: true
description: Decision payload.
content:
application/json:
schema:
$ref: './main.yaml#/components/schemas/projectDecision'
responses:
"200": # Use 200 No Content for successful action with no body
description: No Content - Decision processed successfully.
"400":
description: Bad Request - Invalid input (e.g., missing decision).
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.
/admin/pending-accounts: # Path updated
get:
operationId: getPendingAccounts
summary: Get accounts awaiting validation
description: Retrieves a list of entrepreneur user accounts that are pending admin validation.
tags:
- Admin API
security:
- MyINPulse: [MyINPulse-admin]
responses:
"200":
description: OK - List of pending accounts returned.
content:
application/json:
schema:
type: array
items:
$ref: "./main.yaml#/components/schemas/user-entrepreneur"
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.
/admin/accounts/validate/{userId}:
post: # Changed to POST as it changes state
operationId: validateUserAccount
summary: Validate a pending user account
description: Marks the user account specified by userId as validated/active.
tags:
- Admin API
security:
- MyINPulse: [MyINPulse-admin]
parameters:
- in: path
name: userId
required: true
schema:
type: integer
description: The ID of the user account to validate.
example: 102
responses:
"200":
description: No Content - Account validated successfully.
"400":
description: Bad Request - Invalid user ID format.
"403":
description: Bad Token - Invalid Keycloack configuration.
"401":
description: Unauthorized.
/admin/appointments/upcoming:
get:
operationId: getUpcomingAppointments
summary: Get upcoming appointments for an admin
tags:
- Admin API
security:
- MyINPulse: [MyINPulse-admin]
description: Retrieves a list of appointments scheduled for an admin in the future.
responses:
"200":
description: OK - List of upcoming appointments.
content:
application/json:
schema:
type: array
items:
$ref: "./main.yaml#/components/schemas/appointment"
"403":
description: Bad Token - Invalid Keycloack configuration.
"404":
description: no appointments found.
"401":
description: Unauthorized.
/admin/appointments/report/{appointmentId}:
post:
operationId: createAppointmentReport
summary: Create a report for an appointment
description: Creates and links a new report (e.g., meeting minutes) to the specified appointment using the provided content.
tags:
- Admin API
security:
- MyINPulse: [MyINPulse-admin]
parameters:
- in: path
name: appointmentId
required: true
schema:
type: integer
description: ID of the appointment to add a report to.
example: 303
requestBody:
required: true
description: Report content. `idReport` will be ignored if sent.
content:
application/json:
schema:
$ref: "./main.yaml#/components/schemas/report"
responses:
"200":
description: Created - Report created and linked successfully. Returns the created report.
content:
application/json:
schema: { $ref: "./main.yaml#/components/schemas/report" }
"400":
description: Bad Request - Invalid input (e.g., missing content, invalid appointment ID format).
"403":
description: Bad Token - Invalid Keycloack configuration.
"401":
description: Unauthorized.
put: # Changed to PUT for update/replacement
operationId: updateAppointmentReport
summary: Update an existing appointment report
description: Updates the content of an existing report linked to the specified appointment. Replaces the entire report content.
tags:
- Admin API
security:
- MyINPulse: [MyINPulse-admin]
parameters:
- in: path
name: appointmentId
required: true
schema:
type: integer
description: ID of the appointment whose report needs updating.
example: 303
requestBody:
required: true
description: New report content. `idReport` in the body should match the existing report's ID or will be ignored.
content:
application/json:
schema:
$ref: "./main.yaml#/components/schemas/report"
responses:
"200":
description: OK - Report updated successfully. Returns the updated report.
content:
application/json:
schema: { $ref: "./main.yaml#/components/schemas/report" }
"400":
description: Bad Request - Invalid input (e.g., missing content).
"403":
description: Bad Token - Invalid Keycloack configuration.
"401":
description: Unauthorized.
/admin/projects/{projectId}:
delete:
operationId: removeProject
summary: Remove a project
description: Permanently removes the project specified by projectId and potentially related data (use with caution).
tags:
- Admin API
security:
- MyINPulse: [MyINPulse-admin]
parameters:
- in: path
name: projectId
required: true
schema:
type: integer
description: The ID of the project to remove.
example: 12
responses:
"200":
description: No Content - Project removed successfully.
"400":
description: Bad Request - Invalid project ID format.
"403":
description: Bad Token - Invalid Keycloack configuration.
"401":
description: Unauthorized.
/admin/make-admin/{userId}:
post:
operationId: grantAdminRights
summary: Grant admin rights to a user
tags:
- Admin API
security:
- MyINPulse: [MyINPulse-admin]
description: Elevates the specified user to also have administrator privileges. Assumes the user already exists.
parameters:
- in: path
name: userId
required: true
schema:
type: integer
description: The ID of the user to grant admin rights.
example: 103
responses:
"200": # Use 200 No Content
description: No Content - Admin rights granted successfully.
"400":
description: Bad Request - Invalid user ID format or user is already an admin.
"403":
description: Bad Token - Invalid Keycloack configuration.
"401":
description: Unauthorized.
/admin/create-account:
post:
summary: Creates Admin out Jwt Token
tags:
- Admin API
security:
- MyINPulse: [MyINPulse-admin]
description: Create an admin instance in the MyINPulse DB of the information provided from the authenticated user's keycloack token.
The information required in the token are `userSurname`, `username`, `primaryMail`, `secondaryMail`, `phoneNumber`.
responses:
"200":
description: No Content - Admin user created successfully.
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.

View File

@ -0,0 +1,197 @@
# Entrepreneur API Endpoints
paths:
/entrepreneur/projects/request:
post:
operationId: requestProjectCreation
summary: Request creation and validation of a new project
tags:
- Entrepreneurs API
description: |-
Submits a request for a new project. The project details are provided in the request body.
The requesting entrepreneur (identified by the token) will be associated to it.
The project is created with a 'pending' status, awaiting admin approval.
security:
- MyINPulse: [MyINPulse-entrepreneur]
requestBody:
required: true
description: Project details for the request. `status`, `creationDate` are required by the model when being sent but is ignored by the server;
primarily expects a valid `projectId`, `name`, `logo`.
content:
application/json:
schema:
$ref: "./main.yaml#/components/schemas/project"
responses:
"200":
description: Accepted - Project creation request received and is pending validation.
"400":
description: Bad Request - Invalid input (e.g., missing name).
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.
/entrepreneur/sectionCells: # Base path
post:
operationId: addSectionCell
summary: Add a cell to a Lean Canvas section
description: Adds a new cell (like a sticky note) with the provided content to a specific section of the entrepreneur's project's Lean Canvas. Assumes project context is known based on user's token.
`idSectionCell` and `modificationDate` are server-generated so they're values in the request are ignored by the server.
tags:
- Entrepreneurs API
security:
- MyINPulse: [MyINPulse-entrepreneur]
requestBody:
required: true
description: Section cell details. `idSectionCell` and `modificationDate` will be ignored if sent.
content:
application/json:
schema:
$ref: "./main.yaml#/components/schemas/sectionCell"
responses:
"200":
description: Created - Section cell added successfully. Returns the created cell.
"400":
description: Bad Request - Invalid input (e.g., missing content or sectionId).
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.
/entrepreneur/sectionCells/{sectionCellId}:
put:
operationId: modifySectionCell
summary: Modify data in a Lean Canvas section cell
description: Updates the content of an existing Lean Canvas section cell specified by `sectionCellId`. The server "updates" (it keeps a record of the previous version to keep a history of all the sectionCells and creates a new ones with the specified modifications) the `modificationDate`.
tags:
- Entrepreneurs API
security:
- MyINPulse: [MyINPulse-entrepreneur]
parameters:
- in: path
name: sectionCellId
required: true
schema:
type: integer
description: The ID of the section cell to modify.
example: 508
requestBody:
required: true
description: Updated section cell details. `sectionCellId` "the path parameter" is the only id that's consideredn the `sectionCellId` id in the request body is ignored. `modificationDate` should be updated by the server.
content:
application/json:
schema:
$ref: "./main.yaml#/components/schemas/sectionCell"
responses:
"200":
description: OK - Section cell updated successfully. Returns the updated cell.
"404":
description: Bad Request - Invalid input or ID mismatch.
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.
delete:
operationId: removeSectionCell
summary: Remove a Lean Canvas section cell
description: Deletes the Lean Canvas section cell specified by `sectionCellId`.
tags:
- Entrepreneurs API
security:
- MyINPulse: [MyINPulse-entrepreneur]
parameters:
- in: path
name: sectionCellId
required: true
schema:
type: integer
description: The ID of the section cell to remove.
example: 509
responses:
"200":
description: No Content - Section cell removed successfully.
"400":
description: Bad Request - Invalid ID format.
"404":
description: Bad Request - sectionCell not found.
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.
/entrepreneur/projects:
get:
summary: gets the projectId of the project associated with the entrepreneur
description: returns a list of projectIds of the projects associated with the entrepreneur
tags:
- Entrepreneurs API
security:
- MyINPulse: [MyINPulse-entrepreneur]
parameters:
responses:
"200":
description: OK - Section cell updated successfully. Returns the updated cell.
content:
application/json:
schema:
type: array
items:
$ref: "./main.yaml#/components/schemas/project"
"404":
description: Bad Request - Invalid input or ID mismatch.
"401":
description: Unauthorized or identity not found
"403":
description: Bad Token - Invalid Keycloack configuration.
/entrepreneur/projects/project-is-active:
get:
summary: checks if the project associated with an entrepreneur is active
description: returns a boolean if the project associated with an entrepreneur has an active status
(i.e has been validated by an admin). The user should be routed to LeanCanvas. any other response code
should be treated as false
tags:
- Entrepreneurs API
security:
- MyINPulse: [MyINPulse-entrepreneur]
parameters:
responses:
"200":
description: OK - got the value successfully any other response code should be treated as false.
content:
application/json:
schema:
type: boolean
"404":
description: Bad Request - Invalid input or ID mismatch.
"401":
description: Unauthorized or identity not found
"403":
description: Bad Token - Invalid Keycloack configuration.
/entrepreneur/projects/has-pending-request:
get:
summary: checks if the user has a pending projectRequest
description: returns a boolean if the project associated with an entrepreneur has a pending status
(i.e has not yet been validated by an admin). The user should be routed to a page telling him that he should
wait for admin validation. any other response code should be treated as false.
tags:
- Entrepreneurs API
security:
- MyINPulse: [MyINPulse-entrepreneur]
parameters:
responses:
"200":
description: OK - got the value successfully any other response code should be treated as false.
content:
application/json:
schema:
type: boolean
"404":
description: Bad Request - Invalid input or ID mismatch.
"401":
description: Unauthorized or identity not found
"403":
description: Bad Token - Invalid Keycloack configuration.

View File

@ -0,0 +1,159 @@
openapi: 3.0.3
info:
title: MyInpulse Backend API
description: This serves as an OpenAPI documentation for the MyInpulse backend service, covering operations for Entrepreneurs, Admins, and shared functionalities.
version: 0.2.1
tags:
- name: Entrepreneurs API
description: API endpoints primarily for Entrepreneur users.
- name: Admin API
description: API endpoints restricted to Admin users for management tasks.
- name: Shared API
description: API endpoints accessible by both Entrepreneurs and Admins.
- name: Unauth API
description: API endpoints related to user account management.
components:
schemas:
user:
$ref: "models.yaml#/user"
user-entrepreneur:
$ref: "models.yaml#/user-entrepreneur"
user-admin:
$ref: "models.yaml#/user-admin"
sectionCell:
$ref: "models.yaml#/sectionCell"
project:
$ref: "models.yaml#/project"
report:
$ref: "models.yaml#/report"
appointment:
$ref: "models.yaml#/appointment"
joinRequest:
$ref: "models.yaml#/joinRequest"
projectDecision:
$ref: "models.yaml#/projectDecision"
joinRequestDecision:
$ref: "models.yaml#/joinRequestDecision"
securitySchemes:
MyINPulse:
type: oauth2
description: OAuth2 authentication using Keycloak.
flows:
implicit:
authorizationUrl: '{keycloakBaseUrl}/realms/{keycloakRealm}/protocol/openid-connect/auth'
scopes:
MyINPulse-admin: Grants administrator access.
MyINPulse-entrepreneur: Grants standard entrepreneur user access.
servers:
- url: '{serverProtocol}://{serverHost}:{serverPort}'
description: API Server
variables:
serverProtocol:
enum: [http, https]
default: http
serverHost:
default: localhost
serverPort:
enum: ['8081']
default: '8081'
keycloakBaseUrl:
default: http://localhost:7080
description: Base URL for the Keycloak server.
keycloakRealm:
default: MyInpulseRealm
description: Keycloak realm name.
paths:
# _ _ _ _ _ _
# | | | |_ __ __ _ _ _| |_| |__ / \ _ __ (_)
# | | | | '_ \ / _` | | | | __| '_ \ / _ \ | '_ \| |
# | |_| | | | | (_| | |_| | |_| | | |/ ___ \| |_) | |
# \___/|_| |_|\__,_|\__,_|\__|_| |_/_/ \_\ .__/|_|
# |_|
/unauth/finalize:
$ref: "./unauthApi.yaml#/paths/~1unauth~1finalize"
/unauth/request-join/{projectId}:
$ref: "./unauthApi.yaml#/paths/~1unauth~1request-join~1{projectId}"
/unauth/request-admin-role:
$ref: "./unauthApi.yaml#/paths/~1unauth~1request-admin-role"
/unauth/check-if-not-pending:
$ref: "./unauthApi.yaml#/paths/~1unauth~1check-if-not-pending"
# _ ____ __ __ ___ _ _ _ ____ ___
# / \ | _ \| \/ |_ _| \ | | / \ | _ \_ _|
# / _ \ | | | | |\/| || || \| | / _ \ | |_) | |
# / ___ \| |_| | | | || || |\ | / ___ \| __/| |
# /_/ \_\____/|_| |_|___|_| \_| /_/ \_\_| |___|
#
/admin/pending-accounts:
$ref: "./adminApi.yaml#/paths/~1admin~1pending-accounts"
/admin/accounts/validate/{userId}:
$ref: "./adminApi.yaml#/paths/~1admin~1accounts~1validate~1{userId}"
/admin/request-join:
$ref: "./adminApi.yaml#/paths/~1admin~1request-join"
/admin/request-join/decision/{joinRequestId}:
$ref: "./adminApi.yaml#/paths/~1admin~1request-join~1decision~1{joinRequestId}"
/admin/projects:
$ref: "./adminApi.yaml#/paths/~1admin~1projects"
/admin/projects/pending:
$ref: "./adminApi.yaml#/paths/~1admin~1projects~1pending"
/admin/projects/pending/decision:
$ref: "./adminApi.yaml#/paths/~1admin~1projects~1pending~1decision"
/admin/appointments/report/{appointmentId}:
$ref: "./adminApi.yaml#/paths/~1admin~1appointments~1report~1{appointmentId}"
/admin/appointments/upcoming:
$ref: "./adminApi.yaml#/paths/~1admin~1appointments~1upcoming"
/admin/projects/{projectId}:
$ref: "./adminApi.yaml#/paths/~1admin~1projects~1{projectId}"
/admin/make-admin/{userId}:
$ref: "./adminApi.yaml#/paths/~1admin~1make-admin~1{userId}"
/admin/create-account:
$ref: "./adminApi.yaml#/paths/~1admin~1create-account"
# ____ _ _ _ ____ ___
# / ___|| |__ __ _ _ __ ___ __| | / \ | _ \_ _|
# \___ \| '_ \ / _` | '__/ _ \/ _` | / _ \ | |_) | |
# ___) | | | | (_| | | | __/ (_| | / ___ \| __/| |
# |____/|_| |_|\__,_|_| \___|\__,_| /_/ \_\_| |___|
#
/shared/projects/sectionCells/{projectId}/{sectionId}/{date}:
$ref: "./sharedApi.yaml#/paths/~1shared~1projects~1sectionCells~1{projectId}~1{sectionId}~1{date}"
/shared/projects/entrepreneurs/{projectId}:
$ref: "./sharedApi.yaml#/paths/~1shared~1projects~1entrepreneurs~1{projectId}"
/shared/projects/admin/{projectId}:
$ref: "./sharedApi.yaml#/paths/~1shared~1projects~1admin~1{projectId}"
/shared/projects/appointments/{projectId}:
$ref: "./sharedApi.yaml#/paths/~1shared~1projects~1appointments~1{projectId}"
/shared/appointments/report/{appointmentId}:
$ref: "./sharedApi.yaml#/paths/~1shared~1appointments~1report~1{appointmentId}"
/shared/appointments/request:
$ref: "./sharedApi.yaml#/paths/~1shared~1appointments~1request"
# _____ _ _ _____ ____ _____ ____ ____ _____ _ _ _____ _ _ ____
# | ____| \ | |_ _| _ \| ____| _ \| _ \| ____| \ | | ____| | | | _ \
# | _| | \| | | | | |_) | _| | |_) | |_) | _| | \| | _| | | | | |_) |
# | |___| |\ | | | | _ <| |___| __/| _ <| |___| |\ | |___| |_| | _ <
# |_____|_|_\_| |_| |_| \_\_____|_| |_| \_\_____|_| \_|_____|\___/|_| \_\
# / \ | _ \_ _|
# / _ \ | |_) | |
# / ___ \| __/| |
# /_/ \_\_| |___|
#
/entrepreneur/projects:
$ref: "./entrepreneurApi.yaml#/paths/~1entrepreneur~1projects"
/entrepreneur/projects/request:
$ref: "./entrepreneurApi.yaml#/paths/~1entrepreneur~1projects~1request"
/entrepreneur/sectionCells:
$ref: "./entrepreneurApi.yaml#/paths/~1entrepreneur~1sectionCells"
/entrepreneur/sectionCells/{sectionCellId}:
$ref: "./entrepreneurApi.yaml#/paths/~1entrepreneur~1sectionCells~1{sectionCellId}"
/entrepreneur/projects/project-is-active:
$ref: "./entrepreneurApi.yaml#/paths/~1entrepreneur~1projects~1project-is-active"
/entrepreneur/projects/has-pending-request:
$ref: "./entrepreneurApi.yaml#/paths/~1entrepreneur~1projects~1has-pending-request"

View File

@ -0,0 +1,210 @@
# models.yaml
user:
type: object
properties:
idUser:
type: integer
description: Unique identifier for the user.
#readOnly: true # Typically generated by the server
example: 101
userSurname:
type: string
description: User's surname (last name).
example: "Doe"
userName:
type: string
description: User's given name (first name).
example: "John"
primaryMail:
type: string
format: email
description: User's primary email address.
example: "john.doe@example.com"
secondaryMail:
type: string
format: email
description: User's secondary email address (optional).
example: "j.doe@personal.com"
phoneNumber:
type: string
description: User's phone number.
example: "+33612345678" # Example using international format
user-entrepreneur:
allOf:
- $ref: "#/user"
- type: object
properties:
school:
type: string
description: The school the entrepreneur attends/attended.
example: "ENSEIRB-MATMECA"
course:
type: string
description: The specific course or program of study.
example: "Electronics"
sneeStatus:
type: boolean
description: Indicates if the user has SNEE status (Statut National d'Étudiant-Entrepreneur).
example: true
example: # Added full object example
idUser: 101
userSurname: "Doe"
userName: "John"
primaryMail: "john.doe@example.com"
secondaryMail: "j.doe@personal.com"
phoneNumber: "+33612345678"
school: "ENSEIRB-MATMECA"
course: "Electronics"
sneeStatus: true
user-admin:
allOf:
- $ref: "#/user"
# No additional properties needed for this example
example: # Added full object example
idUser: 55
userSurname: "Admin"
userName: "Super"
primaryMail: "admin@myinpulse.com"
phoneNumber: "+33512345678"
sectionCell:
type: object
description: Represents a cell (like a sticky note) within a specific section of a project's Lean Canvas.
properties:
idSectionCell:
type: integer
description: Unique identifier for the section cell.
#readOnly: true # Generated by server
example: 508
sectionId:
type: integer
description: Identifier of the Lean Canvas section this cell belongs to (e.g., 1 for Problem, 2 for Solution).
example: 1
contentSectionCell:
type: string
description: The text content of the section cell.
example: "Users find it hard to track project progress."
modificationDate:
type: string
format: date # Using Java LocalDate -> YYYY-MM-DD
description: The date when this cell was last modified.
#readOnly: true # Typically updated by the server on modification
example: "yyyy-MM-dd HH:mm"
project:
type: object
description: Represents a project being managed or developed.
properties:
idProject:
type: integer
description: Unique identifier for the project.
#readOnly: true # Generated by server
example: 12
projectName:
type: string
description: The name of the project.
example: "MyInpulse Mobile App"
creationDate:
type: string
format: date # Using Java LocalDate -> YYYY-MM-DD
description: The date when the project was created in the system.
#readOnly: true # Set by server
example: "yyyy-MM-dd HH:mm"
logo:
type: string
format: byte
description: Base64 encoded string representing the project logo image.
example: "/*Base64 encoded string representing the project logo image*/"
status:
type: string
enum: [PENDING, ACTIVE, ENDED, ABORTED, REJECTED]
description: Corresponds to a status enum internal to the backend, it's value in in requests
incoming to the server should be ignored as the client shouldn't be specifying them.
example: "NaN"
joinRequest:
type: object
description: Represents a request from an entrepreneur to join an already existing project.
properties:
idProject:
type: integer
description: the ID of the project the entrepreneur wants to join.
example: 42
entrepreneur:
$ref: "#/user-entrepreneur"
report:
type: object
description: Represents a report associated with an appointment.
properties:
idReport:
type: integer
description: Unique identifier for the report.
#readOnly: true # Generated by server
example: 987
reportContent:
type: string
description: The textual content of the report. Could be plain text or Markdown (specify if known).
example: "Discussed roadmap milestones for Q3. Agreed on preliminary UI mockups."
appointment: # Corrected typo
type: object
description: Represents a scheduled meeting or appointment.
properties:
idAppointment: # Assuming there's an ID
type: integer
description: Unique identifier for the appointment.
#readOnly: true
example: 303
appointmentDate:
type: string
format: date # Using Java LocalDate -> YYYY-MM-DD
description: The date of the appointment.
example: "2025-05-10"
appointmentTime:
type: string
format: time # Using Java LocalTime -> HH:mm:ss
description: The time of the appointment (local time).
example: "14:30:00"
appointmentDuration:
type: string
description: Duration of the appointment in ISO 8601 duration format (e.g., PT1H30M for 1 hour 30 minutes).
example: "PT1H" # Example for 1 hour
appointmentPlace:
type: string
description: Location or meeting link for the appointment.
example: "Meeting Room 3 / https://meet.example.com/abc-def-ghi"
appointmentSubject:
type: string
description: The main topic or subject of the appointment.
example: "Q3 Roadmap Planning"
# Consider adding project ID or user IDs if relevant association exists
projectDecision:
type: object
description: Represents a decision from an admin to accept a pending project.
properties:
projectId:
type: integer
description: The ID of the project the entrepreneur wants to join.
example: 12
adminId:
type: integer
description: The ID of the project the admin who will supervise the project in case of admission.
example: 2
isAccepted:
type: boolean
description: The boolean value of the decision.
example: "true"
joinRequestDecision:
type: object
description: Represents a decision from an admin to accept a pending project join request.
properties:
isAccepted:
type: boolean
description: The boolean value of the decision.
example: "true"

View File

@ -0,0 +1,193 @@
# Shared API Endpoints
paths:
/shared/projects/sectionCells/{projectId}/{sectionId}/{date}:
get:
operationId: getSectionCellsByDate
summary: Get project section cells modified on a specific date
tags:
- Shared API
security:
- MyINPulse: [MyINPulse-entrepreneur, MyINPulse-admin]
description: Retrieves section cells belonging to a specific section of a project, filtered by the last modification date. Requires user to have access to the project.
parameters:
- in: path
name: projectId
required: true
schema: { type: integer }
description: ID of the project.
- in: path
name: sectionId
required: true
schema: { type: integer }
description: ID of the Lean Canvas section.
- in: path
name: date
required: true
schema: { type: string, format: date } # Expect YYYY-MM-DD
description: The modification date to filter by (YYYY-MM-DD HH:mm).
responses:
"200":
description: OK - List of section cells matching the criteria.
content:
application/json:
schema:
type: array
items:
$ref: "./main.yaml#/components/schemas/sectionCell"
"400":
description: Bad Request - Invalid parameter format.
"403":
description: Bad Token - Invalid Keycloack configuration.
"401":
description: Unauthorized.
/shared/projects/entrepreneurs/{projectId}:
get:
operationId: getProjectEntrepreneurs
summary: Get entrepreneurs associated with a project
tags:
- Shared API
security:
- MyINPulse: [MyINPulse-entrepreneur, MyINPulse-admin]
description: Retrieves a list of entrepreneur users associated with the specified project. Requires access to the project.
parameters:
- in: path
name: projectId
required: true
schema: { type: integer }
description: ID of the project.
responses:
"200":
description: OK - List of entrepreneurs.
content:
application/json:
schema:
type: array
items:
$ref: "./main.yaml#/components/schemas/user-entrepreneur"
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.
"404":
description: Not Found - Project not found.
/shared/projects/admin/{projectId}: # Path updated
get:
operationId: getProjectAdmin
summary: Get admin associated with a project
tags:
- Shared API
security:
- MyINPulse: [MyINPulse-entrepreneur, MyINPulse-admin]
description: Retrieves a list of admin users associated with the specified project. Requires access to the project.
parameters:
- in: path
name: projectId
required: true
schema: { type: integer }
description: ID of the project.
responses:
"200":
description: OK - admin.
content:
application/json:
schema:
$ref: "./main.yaml#/components/schemas/user-admin"
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.
"404":
description: Not Found - Project not found.
/shared/projects/appointments/{projectId}:
get:
operationId: getProjectAppointments
summary: Get appointments related to a project
tags:
- Shared API
security:
- MyINPulse: [MyINPulse-entrepreneur, MyINPulse-admin]
description: Retrieves a list of appointments associated with the specified project. Requires access to the project.
parameters:
- in: path
name: projectId
required: true
schema: { type: integer }
description: ID of the project.
responses:
"200":
description: OK - List of appointments.
content:
application/json:
schema:
type: array
items:
$ref: "./main.yaml#/components/schemas/appointment"
"403":
description: Bad Token - Invalid Keycloack configuration.
"401":
description: Unauthorized.
/shared/appointments/report/{appointmentId}: # Path updated
get:
operationId: getAppointmentReport # Shared endpoint implies read-only access might be possible
summary: Get the report for an appointment
tags:
- Shared API
security:
- MyINPulse: [MyINPulse-entrepreneur, MyINPulse-admin]
description: Retrieves the report associated with a specific appointment. Requires user to have access to the appointment/project.
parameters:
- in: path
name: appointmentId
required: true
schema: { type: integer }
description: ID of the appointment.
responses:
"200":
description: OK - Report PDF returned.
content:
application/pdf:
schema:
schema:
type: string
format: binary
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.
/shared/appointments/request:
post:
operationId: requestAppointment
summary: Request a new appointment
tags:
- Shared API
security:
- MyINPulse: [MyINPulse-entrepreneur, MyINPulse-admin]
description: Allows a user (entrepreneur or admin) to request a new appointment, potentially with another user or regarding a project. Details in the body. The request might need confirmation or create a pending appointment.
requestBody:
required: true
description: Details of the appointment request.
content:
application/json:
schema:
$ref: "./main.yaml#/components/schemas/appointment" # Assuming request uses same model structure
# Potentially add projectId or targetUserId here
responses:
"200": # Accepted seems appropriate for a request
description: Accepted - Appointment request submitted.
"400":
description: Bad Request - Invalid appointment details.
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.

View File

@ -0,0 +1,90 @@
# _ _ _ _ _ _
# | | | |_ __ __ _ _ _| |_| |__ / \ _ __ (_)
# | | | | '_ \ / _` | | | | __| '_ \ / _ \ | '_ \| |
# | |_| | | | | (_| | |_| | |_| | | |/ ___ \| |_) | |
# \___/|_| |_|\__,_|\__,_|\__|_| |_/_/ \_\ .__/|_|
# |_|
paths:
/unauth/finalize:
post:
summary: Finalize account setup using authentication token
description: |-
Completes the user account creation/setup process in the MyInpulse system.
This endpoint requires the user to be authenticated via Keycloak (e.g., after initial login).
User details (name, email, etc.) are extracted from the authenticated user's token (e.g., Keycloak JWT).
No request body is needed. The account is marked as pending admin validation upon successful finalization.
tags:
- Unauth API
responses:
"200":
description: Created - Account finalized and pending admin validation. Returns the user profile.
"400":
description: Bad Request - Problem processing the token or user data derived from it.
"401":
description: Unauthorized - Valid authentication token required.
"403":
description: Bad Token - Invalid Keycloack configuration.
/unauth/request-join/{projectId}:
post:
summary: Request to join an existing project
description: Submits a request for the authenticated user (keycloack authenticated) to join the project specified by projectId. Their role is then changed to entrepreneur in server and Keycloak. This requires approval from a project admin.
tags:
- Unauth API
parameters:
- in: path
name: projectId
required: true
schema:
type: integer
description: The ID of the project to request joining.
example: 15
responses: # Moved responses block to correct level
"200":
description: Accepted - Join request submitted and pending approval.
"400":
description: Bad Request - Invalid project ID format
"409":
description: Already member/request pending.
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.
/unauth/request-admin-role:
post:
summary: Request to become an admin
description: Submits a request for the authenticated user (keycloack authenticated) to become an admin. Their role is then changed to admin in server and Keycloak. This requires approval from a project admin.
tags:
- Unauth API
responses:
"200":
description: Accepted - Become admin request submitted and pending approval.
"400":
description: Bad Request - Invalid project ID format or already member/request pending.
"401":
description: Unauthorized.
"403":
description: Bad Token - Invalid Keycloack configuration.
/unauth/check-if-not-pending:
get:
summary: Returns a boolean of whether the user's account is not pending
description: Returns a boolean with value `true` if the user's account is not pending and `false` if it is.
tags:
- Unauth API
responses:
"200":
description: Accepted - Become admin request submitted and pending approval.
content:
application/json:
schema:
type: boolean
"400":
description: Bad Request - Invalid project ID format or already member/request pending.
"401":
description: Unauthorized.
"404":
description: Bad Request - User not found in database.
"403":
description: Bad Token - Invalid Keycloack configuration.

View File

@ -0,0 +1,14 @@
const express = require("express");
const swaggerUi = require("swagger-ui-express");
const yaml = require("js-yaml");
const fs = require("fs");
const app = express();
const swaggerDocument = yaml.load(fs.readFileSync("../src/bundled.yaml", "utf8"));
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument));
app.listen(3000, () => {
console.log("Swagger UI running at http://localhost:3000/api-docs");
});

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
{
"name": "swagger-ui",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"bundle": "swagger-cli bundle -o ../src/bundled.yaml -t yaml ../src/main.yaml",
"start": "npm run bundle; node main.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"express": "^4.21.2",
"js-yaml": "^4.1.0",
"package.json": "^2.0.1",
"swagger-cli": "^4.0.4",
"swagger-ui-express": "^5.0.1"
}
}

View File

@ -4,6 +4,7 @@ import { callApi } from "@/services/api.ts";
import { ref } from "vue";
const CustomRequest = ref("");
const USERID = ref("");
</script>
<template>
@ -34,30 +35,7 @@ const CustomRequest = ref("");
<td>Current refresh token</td>
<td>{{ store.user.refreshToken }}</td>
</tr>
<tr>
<td>Entrepreneur API call</td>
<td>
<button @click="callApi('random')">call</button>
</td>
<td>res</td>
<td></td>
</tr>
<tr>
<td>Admin API call</td>
<td>
<button @click="callApi('random2')">call</button>
</td>
<td>res</td>
<td></td>
</tr>
<tr>
<td>Unauth API call</td>
<td>
<button @click="callApi('random3')">call</button>
</td>
<td>res</td>
<td id="3"></td>
</tr>
<tr>
<td>
<input v-model="CustomRequest" placeholder="edit me" />
@ -66,6 +44,83 @@ const CustomRequest = ref("");
<button @click="callApi(CustomRequest)">call</button>
</td>
</tr>
<tr>
<td>Create an account</td>
<td>
<button @click="callApi('unauth/create_account')">
call
</button>
</td>
<td>res</td>
<td id="4"></td>
</tr>
<tr>
<td>Get Pending Accounts</td>
<td>
<button @click="callApi('/admin/pending-accounts')">
call
</button>
</td>
<td>res</td>
<td id="6"></td>
</tr>
<tr>
<td>admin/validate_user_account/{id}</td>
<td>
<button
@click="
callApi('admin/validate_user_account/' + USERID)
"
>
call
</button>
</td>
<td>
<input v-model="USERID" placeholder="user ID" />
</td>
<td id="5"></td>
</tr>
<tr>
<td>admin/setadmin/{uid}</td>
<td>
<button @click="callApi('admin/setadmin/' + USERID)">
call
</button>
</td>
<td>
<input v-model="USERID" placeholder="user ID" />
</td>
</tr>
<tr>
<td>Unauth API call</td>
<td>
<button @click="callApi('unauth/dev')">call</button>
</td>
<td>res</td>
<td id="8"></td>
</tr>
<tr>
<td>Unauth API call</td>
<td>
<button @click="callApi('unauth/dev')">call</button>
</td>
<td>res</td>
<td id="9"></td>
</tr>
<tr>
<td>Unauth API call</td>
<td>
<button @click="callApi('unauth/dev')">call</button>
</td>
<td>res</td>
<td id="10"></td>
</tr>
</tbody>
</table>
</template>

2
hooks/README.md Normal file
View File

@ -0,0 +1,2 @@
# Useful hooks in this project
To use, just add the content of the wanted hook in `.git/hook/pre-commit`. You may need to use `chmod +x pre-commit`

24
hooks/google-java-format Executable file
View File

@ -0,0 +1,24 @@
#!/bin/bash
# Path to the Google Java Formatter JAR
FORMATTER_JAR="$HOME/.local/share/java/google-java-format.jar"
# Download the Google Java Formatter JAR if it doesn't exist
if [ ! -f "$FORMATTER_JAR" ]; then
echo "Downloading Google Java Formatter..."
mkdir -p "$(dirname "$FORMATTER_JAR")"
curl -L -o "$FORMATTER_JAR" https://github.com/google/google-java-format/releases/download/v1.20.0/google-java-format-1.20.0-all-deps.jar
fi
# Format all staged Java files
STAGED_JAVA_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep "\.java$")
if [ -n "$STAGED_JAVA_FILES" ]; then
echo "Formatting Java files..."
java -jar "$FORMATTER_JAR" --skip-sorting-imports --skip-reflowing-long-strings --aosp --replace $STAGED_JAVA_FILES
# Re-stage the formatted files
git add $STAGED_JAVA_FILES
fi
exit 0

2638
keycloak/realm.json Normal file

File diff suppressed because it is too large Load Diff