24 Commits

Author SHA1 Message Date
Vu Tuan Minh
9c2241c0b1 Update README.md 2025-10-25 02:07:11 +02:00
Vu Tuan Minh
571d7f0402 Test keycloak worked with README.md 2025-10-25 01:56:58 +02:00
trochas
2404733cbe readme 2025-10-24 21:20:16 +02:00
trochas
7c71555add readem + correction 2025-10-23 22:21:36 +02:00
Vu Tuan Minh
3f0e3c801c Maybe add thymeleaf?
need to test and add config keycloak
2025-10-22 01:39:18 +02:00
trochas
f6250a2724 test et correction 2025-10-17 13:58:59 +02:00
trochas
ddd4188524 controller fini, non testé 2025-10-15 22:31:28 +02:00
trochas
8874f38696 controller fini, non testé 2025-10-15 22:31:16 +02:00
trochas
c5f6fa71b9 Nettoyage selon .gitignore 2025-10-12 18:35:20 +02:00
trochas
614c8e4dd9 Ajout du .gitignore 2025-10-12 18:31:21 +02:00
trochas
cfc6847096 Controller question fini et testé avec postman 2025-10-12 18:29:25 +02:00
trochas
dcd069c884 Controller question fini et testé avec postman 2025-10-12 18:26:51 +02:00
trochas
754551ef6c QuestionController, creat et update fonctionent 2025-10-11 16:59:02 +02:00
trochas
57d58f5b27 fix bug spring (h2 version + value var dans ReponseCourte) 2025-10-11 13:51:53 +02:00
trochas
09444a94ed Merge remote-tracking branch 'refs/remotes/origin/tp_spring' into tp_spring 2025-10-08 11:31:47 +02:00
trochas
20248b56e1 Controller reponse et session 2025-10-08 11:30:55 +02:00
tuanvu
44c3144eb0 update pom.xml 2025-10-08 11:06:47 +02:00
trochas
5a9481f92c controller Question fini 2025-10-08 10:52:43 +02:00
trochas
e913f8154d merge 2025-10-08 10:13:06 +02:00
trochas
e2b86cb8e0 TODO controller 2025-10-08 10:10:51 +02:00
tuanvu
a0f7399e83 push init4 2025-10-06 12:20:36 +02:00
tuanvu
fd66500f46 push init3 2025-10-06 11:18:26 +02:00
tuanvu
d677d9ddb5 push init2 2025-10-06 10:59:10 +02:00
tuanvu
e3743e6d16 push init 2025-10-06 10:52:07 +02:00
62 changed files with 2371 additions and 1911 deletions

738
Insomnia_test.yaml Normal file
View File

@@ -0,0 +1,738 @@
type: collection.insomnia.rest/5.0
name: TP4
meta:
id: wrk_edb44e38083f4e9f83998faf549c0d7a
created: 1754408137750
modified: 1761341975705
description: ""
collection:
- name: SESSION
meta:
id: fld_6a3d533b4c7a494986be94875f20da98
created: 1761344709621
modified: 1761344822984
sortKey: -1761344728121.25
description: ""
children:
- url: http://localhost:8082/session/getAll
name: Get all session from USER
meta:
id: req_1655a615b20d49f8bdf3fc81c5d6b761
created: 1761165598138
modified: 1761344718542
isPrivate: false
description: ""
sortKey: -1761344718509
method: GET
body:
mimeType: application/x-www-form-urlencoded
params:
- id: pair_54b0a24cfe5c4d81ae864d64640e35f2
name: client_id
value: myspringbootapp
description: ""
disabled: false
- id: pair_f6c73c60f3024e42bbacc223615d3be1
name: client_secret
value: Y7xpKQbFalUFTGUGD9XDBcvawvs3zsWZ
description: ""
disabled: false
- id: pair_3698939343424230a63d135857f0acb1
name: username
value: myuser2
description: ""
disabled: false
- id: pair_f8b4c07baea14742a4ebd8f005ff5e92
name: password
value: "1"
description: ""
disabled: false
- id: pair_e49d8dbb324d484bad8747b563ae1615
name: grant_type
value: password
description: ""
disabled: false
headers:
- name: Content-Type
value: application/x-www-form-urlencoded
id: pair_987cf70c521843c8a47e1c51976cce3b
type: text
multiline: false
- name: User-Agent
value: insomnia/11.6.1
id: pair_4c3461e4c95d45bd973dcb4bfd5e519a
- id: pair_b3814f137d494ce389fbe6075385cb71
name: Authorization
value: Bearer
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVaDlNMG8wMERKaEdTQzdTRjdmdDlFZWFDNmE4UVdKV0NPXzdENVBKeXFRIn0.eyJleHAiOjE3NjEzNDQ5NzgsImlhdCI6MTc2MTM0NDY3OCwianRpIjoib25ydHJvOjAyY2MxNDU5LWUwY2MtNzUzZi0yNWY3LTk1MWQ0Zjg0N2Q5ZSIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbXlzcHJpbmdib290YXBwcmVhbG0iLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiOTkyZTI3OTktN2ExOS00ZWY1LTk0ODItYWMzMjljNTNhNDc5IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibXlzcHJpbmdib290YXBwIiwic2lkIjoiNDQ4Y2NiMjUtYzZjNC05OTU1LTk2ZmItZDgxMmNjZDRlMjMyIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJVU0VSIiwiZGVmYXVsdC1yb2xlcy1teXNwcmluZ2Jvb3RhcHByZWFsbSJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoidWlvYXpkcSB6c29rZHFzamtkIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibXl1c2VyMiIsImdpdmVuX25hbWUiOiJ1aW9hemRxIiwiZmFtaWx5X25hbWUiOiJ6c29rZHFzamtkIiwiZW1haWwiOiJva0BjYWNhLmNvbSJ9.mhQIeD0e_kuS_zCZDGd6x2mq4VqeRBemFiCM-4NcSRwSvLqSl0AKla4pfpOg88dXyKjYbSJyszQ7-qMtO3NFgFT5Tlcf5pb-FR8p5XRk1XgKcKX-9-kirbhsuHzFRMbRSRr7RooPLvhqqarxZtAAPWtEzXveysVTIYLffhhJ7MdYLfQRVFhUGTyashuYH-H6_L8DpjGhie_bcf7VXfo4-UupJEmcUBzjmDXt4aunAl1-qEdLoJ0FgqQwB63DGxoVnRePBYCmiuUJM_KXQ8bi_epkwyeL6HDRL6GuudCIPWTNLYckU0wXWb5nLcQBAjE3s3DidyYKpndZbNjYXKOkaw
description: ""
disabled: false
settings:
renderRequestBody: true
encodeUrl: true
followRedirects: global
cookies:
send: true
store: true
rebuildPath: true
- url: http://localhost:8082/session/create
name: "CREATE session with ADMIN "
meta:
id: req_3a89035567d94274a0965addaf869500
created: 1761166627479
modified: 1761344721839
isPrivate: false
description: ""
sortKey: -1761344718609
method: POST
body:
mimeType: application/json
text: '{"theme": "Science Informatic"}'
headers:
- name: Content-Type
value: application/json
id: pair_2694b5ff2f964512842dc3fa44ccd3e1
- name: User-Agent
value: insomnia/11.6.1
id: pair_4c3461e4c95d45bd973dcb4bfd5e519a
- id: pair_b3814f137d494ce389fbe6075385cb71
name: Authorization
value: Bearer
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVaDlNMG8wMERKaEdTQzdTRjdmdDlFZWFDNmE4UVdKV0NPXzdENVBKeXFRIn0.eyJleHAiOjE3NjEzNDQ4MTYsImlhdCI6MTc2MTM0NDUxNiwianRpIjoib25ydHJvOmNjNTE3YmI2LTMzMzMtN2RiMy03NGI1LTlkYjNhOTQzZGNhMiIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbXlzcHJpbmdib290YXBwcmVhbG0iLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiMmY5YWRhYzQtODU4Ni00NTI4LWE4Y2QtM2I3M2I5NTc0ODBiIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibXlzcHJpbmdib290YXBwIiwic2lkIjoiZTFjZDE4YzAtOWQyNS04ZjFmLWM4MzMtYTdmMDcwZGMwOGQ2IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJBRE1JTiIsImRlZmF1bHQtcm9sZXMtbXlzcHJpbmdib290YXBwcmVhbG0iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6IlRpYm8gUm9jaGFzIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibXl1c2VyIiwiZ2l2ZW5fbmFtZSI6IlRpYm8iLCJmYW1pbHlfbmFtZSI6IlJvY2hhcyIsImVtYWlsIjoidGlib0BjYWNhLmNvbSJ9.PM3Bj5-c3QFWeVy6fhcrVZDE2CqzGZPYW3ZLg46whc1vCYbb7c_ASuu0pJKDXHIiRrH2_Yws1qtY5u5fSquZ1zHENppsB4ltRwpf2dTQjZ5-0a_ULbbXsONCJ_TUxAkUaTuy6XNYXAjRf8nH_SirfDRgTB47ynOXTKqGVNZYhgkQKbpxZ1UwVOciQpeuXQqbIXBhfo5Ejpyp8DiWkkXujDnJGJua2FQaNfSvDmas4BSB2V4_2rXAbT72t76INu3vJYetGO5wPgWppwl0PVK3dvOIK_iSMR0LHp8-MMlykPZpESxq1DGLfHAP7XYDS2u0yiddhGZY0fD4ziegDDVJpw
description: ""
disabled: false
settings:
renderRequestBody: true
encodeUrl: true
followRedirects: global
cookies:
send: true
store: true
rebuildPath: true
- url: http://localhost:8082/session/delete/5
name: "DELETE session with ADMIN "
meta:
id: req_28a034a37be54183b1423364b01ecb71
created: 1761344610268
modified: 1761348128370
isPrivate: false
description: ""
sortKey: -1761344718559
method: DELETE
body:
mimeType: application/json
text: ""
headers:
- name: Content-Type
value: application/json
id: pair_2694b5ff2f964512842dc3fa44ccd3e1
- name: User-Agent
value: insomnia/11.6.1
id: pair_4c3461e4c95d45bd973dcb4bfd5e519a
- id: pair_b3814f137d494ce389fbe6075385cb71
name: Authorization
value: Bearer
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVaDlNMG8wMERKaEdTQzdTRjdmdDlFZWFDNmE4UVdKV0NPXzdENVBKeXFRIn0.eyJleHAiOjE3NjEzNDQ4MTYsImlhdCI6MTc2MTM0NDUxNiwianRpIjoib25ydHJvOmNjNTE3YmI2LTMzMzMtN2RiMy03NGI1LTlkYjNhOTQzZGNhMiIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbXlzcHJpbmdib290YXBwcmVhbG0iLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiMmY5YWRhYzQtODU4Ni00NTI4LWE4Y2QtM2I3M2I5NTc0ODBiIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibXlzcHJpbmdib290YXBwIiwic2lkIjoiZTFjZDE4YzAtOWQyNS04ZjFmLWM4MzMtYTdmMDcwZGMwOGQ2IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJBRE1JTiIsImRlZmF1bHQtcm9sZXMtbXlzcHJpbmdib290YXBwcmVhbG0iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6IlRpYm8gUm9jaGFzIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibXl1c2VyIiwiZ2l2ZW5fbmFtZSI6IlRpYm8iLCJmYW1pbHlfbmFtZSI6IlJvY2hhcyIsImVtYWlsIjoidGlib0BjYWNhLmNvbSJ9.PM3Bj5-c3QFWeVy6fhcrVZDE2CqzGZPYW3ZLg46whc1vCYbb7c_ASuu0pJKDXHIiRrH2_Yws1qtY5u5fSquZ1zHENppsB4ltRwpf2dTQjZ5-0a_ULbbXsONCJ_TUxAkUaTuy6XNYXAjRf8nH_SirfDRgTB47ynOXTKqGVNZYhgkQKbpxZ1UwVOciQpeuXQqbIXBhfo5Ejpyp8DiWkkXujDnJGJua2FQaNfSvDmas4BSB2V4_2rXAbT72t76INu3vJYetGO5wPgWppwl0PVK3dvOIK_iSMR0LHp8-MMlykPZpESxq1DGLfHAP7XYDS2u0yiddhGZY0fD4ziegDDVJpw
description: ""
disabled: false
settings:
renderRequestBody: true
encodeUrl: true
followRedirects: global
cookies:
send: true
store: true
rebuildPath: true
- name: TOKEN
meta:
id: fld_edbd6e42d9804716ab375d1a9c4e34f8
created: 1761344734288
modified: 1761344734288
sortKey: -1761344734288
description: ""
children:
- url: http://localhost:8080/realms/myspringbootapprealm/protocol/openid-connect/token
name: POST token of myuser2 (USER)
meta:
id: req_6042b7d04430475090e584300c99eab9
created: 1759266818074
modified: 1761344742391
isPrivate: false
description: ""
sortKey: -1761344738832
method: POST
body:
mimeType: application/x-www-form-urlencoded
params:
- id: pair_54b0a24cfe5c4d81ae864d64640e35f2
name: client_id
value: myspringbootapp
description: ""
disabled: false
- id: pair_f6c73c60f3024e42bbacc223615d3be1
name: client_secret
value: Y7xpKQbFalUFTGUGD9XDBcvawvs3zsWZ
description: ""
disabled: false
- id: pair_3698939343424230a63d135857f0acb1
name: username
value: myuser2
description: ""
disabled: false
- id: pair_f8b4c07baea14742a4ebd8f005ff5e92
name: password
value: "1"
description: ""
disabled: false
- id: pair_e49d8dbb324d484bad8747b563ae1615
name: grant_type
value: password
description: ""
disabled: false
headers:
- name: Content-Type
value: application/x-www-form-urlencoded
id: pair_987cf70c521843c8a47e1c51976cce3b
type: text
multiline: false
- name: User-Agent
value: insomnia/11.6.1
id: pair_4c3461e4c95d45bd973dcb4bfd5e519a
settings:
renderRequestBody: true
encodeUrl: true
followRedirects: global
cookies:
send: true
store: true
rebuildPath: true
- url: http://localhost:8080/realms/myspringbootapprealm/protocol/openid-connect/token
name: POST token of myuser (ADMIN)
meta:
id: req_01c3633b3ca74f01addf57999b2e0c4c
created: 1761341868733
modified: 1761345268241
isPrivate: false
description: ""
sortKey: -1761344738732
method: POST
body:
mimeType: application/x-www-form-urlencoded
params:
- id: pair_54b0a24cfe5c4d81ae864d64640e35f2
name: client_id
value: myspringbootapp
description: ""
disabled: false
- id: pair_f6c73c60f3024e42bbacc223615d3be1
name: client_secret
value: Y7xpKQbFalUFTGUGD9XDBcvawvs3zsWZ
description: ""
disabled: false
- id: pair_3698939343424230a63d135857f0acb1
name: username
value: myuser
description: ""
disabled: false
- id: pair_f8b4c07baea14742a4ebd8f005ff5e92
name: password
value: "1"
description: ""
disabled: false
- id: pair_e49d8dbb324d484bad8747b563ae1615
name: grant_type
value: password
description: ""
disabled: false
headers:
- name: Content-Type
value: application/x-www-form-urlencoded
id: pair_987cf70c521843c8a47e1c51976cce3b
type: text
multiline: false
- name: User-Agent
value: insomnia/11.6.1
id: pair_4c3461e4c95d45bd973dcb4bfd5e519a
settings:
renderRequestBody: true
encodeUrl: true
followRedirects: global
cookies:
send: true
store: true
rebuildPath: true
- name: RESPONSE
meta:
id: fld_bc553a9a2b6f4c869522a93d27180c10
created: 1761344775233
modified: 1761348525580
sortKey: -1761344726579.5625
description: ""
children:
- url: http://localhost:8082/reponse/create/choix
name: "CREATE resp choix with ADMIN "
meta:
id: req_c8c745e6a7f54f53a3767e741ac7fee2
created: 1761344835170
modified: 1761345288184
isPrivate: false
description: ""
sortKey: -1761344838422
method: POST
body:
mimeType: application/json
text: '{"theme": "Science Informatic"}'
headers:
- name: Content-Type
value: application/json
id: pair_2694b5ff2f964512842dc3fa44ccd3e1
- name: User-Agent
value: insomnia/11.6.1
id: pair_4c3461e4c95d45bd973dcb4bfd5e519a
- id: pair_b3814f137d494ce389fbe6075385cb71
name: Authorization
value: Bearer
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVaDlNMG8wMERKaEdTQzdTRjdmdDlFZWFDNmE4UVdKV0NPXzdENVBKeXFRIn0.eyJleHAiOjE3NjEzNDU1ODEsImlhdCI6MTc2MTM0NTI4MSwianRpIjoib25ydHJvOjJmOWViYjE0LTExNGUtN2JmZS02NzllLTUzZDE5NmQzMTAxNiIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbXlzcHJpbmdib290YXBwcmVhbG0iLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiMmY5YWRhYzQtODU4Ni00NTI4LWE4Y2QtM2I3M2I5NTc0ODBiIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibXlzcHJpbmdib290YXBwIiwic2lkIjoiOTEzYzRlZTAtNWY3MS03NjMyLTkyOGItNDU0YzNmODJhYzcxIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJBRE1JTiIsImRlZmF1bHQtcm9sZXMtbXlzcHJpbmdib290YXBwcmVhbG0iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6IlRpYm8gUm9jaGFzIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibXl1c2VyIiwiZ2l2ZW5fbmFtZSI6IlRpYm8iLCJmYW1pbHlfbmFtZSI6IlJvY2hhcyIsImVtYWlsIjoidGlib0BjYWNhLmNvbSJ9.rRmFvq0OJmCf6p6pZqm2cPGOYhMc8_xhuApZw5yMHjhKIu-faEwd_-cd1yIE8SJ4VqKi979l5ZT4wLTiGRT6tDKyKkd6gszMXJ71YmphM0czEV-gpOLodA9UxQN_W1nDjE7l3f6Xe_LZgyHUzTIt3sJP8GTbFtzaOyeRsMa9VYcA0gxkeUoymbfFerpvpF3z2c2U_OjZkoT79GpRpzqzqGzZoyDVO8KglWh4tE0pSwy9zCKqs_DcTxxD_6OIUyWujwrriy9SRGd2lfYoQROEqfi1lU5Jwi7cdNwHfyjzm6m0xBsJkJGjkEOf747vxUKrMqwxmYWUSWZ7s1dhdEYBuA
description: ""
disabled: false
settings:
renderRequestBody: true
encodeUrl: true
followRedirects: global
cookies:
send: true
store: true
rebuildPath: true
- url: http://localhost:8082/reponse/create/courte
name: "CREATE resp courte with ADMIN "
meta:
id: req_8cfde146a3b74765acc4e5607adf9fb7
created: 1761344881275
modified: 1761344909081
isPrivate: false
description: ""
sortKey: -1761344788627
method: POST
body:
mimeType: application/json
text: '{"theme": "Science Informatic"}'
headers:
- name: Content-Type
value: application/json
id: pair_2694b5ff2f964512842dc3fa44ccd3e1
- name: User-Agent
value: insomnia/11.6.1
id: pair_4c3461e4c95d45bd973dcb4bfd5e519a
- id: pair_b3814f137d494ce389fbe6075385cb71
name: Authorization
value: Bearer
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVaDlNMG8wMERKaEdTQzdTRjdmdDlFZWFDNmE4UVdKV0NPXzdENVBKeXFRIn0.eyJleHAiOjE3NjEzNDUxOTksImlhdCI6MTc2MTM0NDg5OSwianRpIjoib25ydHJvOjhmODU1YmEyLWMxN2MtMDBhNy1lMTVhLTRhOTg3ZWE5OWRmMiIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbXlzcHJpbmdib290YXBwcmVhbG0iLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiMmY5YWRhYzQtODU4Ni00NTI4LWE4Y2QtM2I3M2I5NTc0ODBiIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibXlzcHJpbmdib290YXBwIiwic2lkIjoiMzE0MjQ2MDgtMzFmMi01ZmJhLTQ3M2EtNmFhZGNiMWRkNzJmIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJBRE1JTiIsImRlZmF1bHQtcm9sZXMtbXlzcHJpbmdib290YXBwcmVhbG0iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6IlRpYm8gUm9jaGFzIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibXl1c2VyIiwiZ2l2ZW5fbmFtZSI6IlRpYm8iLCJmYW1pbHlfbmFtZSI6IlJvY2hhcyIsImVtYWlsIjoidGlib0BjYWNhLmNvbSJ9.c0P5T6tk__nXWvdv0_YOW78GAZy0e6Q9o5dvjB8resS8_PcJne-d2RgH2gzES36I1X4E71Quj5WpXVGZSR_j7P25MIo4Xm-5kRlnMfsWFNWpTkjmos0CI5d2VP4vW0iDqvucLNhW3Z1aYgmC1KxLrrIPhUXob5_2xem4yWA6dJdfeUZzTv_a5yOIiDpDxpZhNUHAgfK_tWzivYdNLqLSd-dvgZD9PZeFcYoXcT3fWNhZW6Ix8FKvHuUjpczCGoc7k4flqdDcbU2_UK4liByeKntQ1JuD1a5gNM6Sp9ijrvQVouB8N8ejcRTQjlRy-mXlQUUbtYimOerBTvuJyGE-RQ
description: ""
disabled: false
settings:
renderRequestBody: true
encodeUrl: true
followRedirects: global
cookies:
send: true
store: true
rebuildPath: true
- url: http://localhost:8082/reponse/getAll
name: Get all resp courte from USER
meta:
id: req_4b38e162a28d4909bf45b7b9abc204a4
created: 1761344930516
modified: 1761345550386
isPrivate: false
description: ""
sortKey: -1761344788527
method: GET
body:
mimeType: application/x-www-form-urlencoded
params:
- id: pair_54b0a24cfe5c4d81ae864d64640e35f2
name: client_id
value: myspringbootapp
description: ""
disabled: false
- id: pair_f6c73c60f3024e42bbacc223615d3be1
name: client_secret
value: Y7xpKQbFalUFTGUGD9XDBcvawvs3zsWZ
description: ""
disabled: false
- id: pair_3698939343424230a63d135857f0acb1
name: username
value: myuser2
description: ""
disabled: false
- id: pair_f8b4c07baea14742a4ebd8f005ff5e92
name: password
value: "1"
description: ""
disabled: false
- id: pair_e49d8dbb324d484bad8747b563ae1615
name: grant_type
value: password
description: ""
disabled: false
headers:
- name: Content-Type
value: application/x-www-form-urlencoded
id: pair_987cf70c521843c8a47e1c51976cce3b
type: text
multiline: false
- name: User-Agent
value: insomnia/11.6.1
id: pair_4c3461e4c95d45bd973dcb4bfd5e519a
- id: pair_b3814f137d494ce389fbe6075385cb71
name: Authorization
value: Bearer
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVaDlNMG8wMERKaEdTQzdTRjdmdDlFZWFDNmE4UVdKV0NPXzdENVBKeXFRIn0.eyJleHAiOjE3NjEzNDU2MjAsImlhdCI6MTc2MTM0NTMyMCwianRpIjoib25ydHJvOjJhMGIxOGZiLWE4MjEtMWI3MS1iODQ1LWE5NGY0NWY1ZDA4MSIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbXlzcHJpbmdib290YXBwcmVhbG0iLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiOTkyZTI3OTktN2ExOS00ZWY1LTk0ODItYWMzMjljNTNhNDc5IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibXlzcHJpbmdib290YXBwIiwic2lkIjoiMzFhYmVlNzYtOWJkNy02NWMyLWY0MzMtOTJiZjliODZlMDA1IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJVU0VSIiwiZGVmYXVsdC1yb2xlcy1teXNwcmluZ2Jvb3RhcHByZWFsbSJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoidWlvYXpkcSB6c29rZHFzamtkIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibXl1c2VyMiIsImdpdmVuX25hbWUiOiJ1aW9hemRxIiwiZmFtaWx5X25hbWUiOiJ6c29rZHFzamtkIiwiZW1haWwiOiJva0BjYWNhLmNvbSJ9.GBNldYmb4q02AaOwnu1xoLxkF_9qvadLdw1ftjetOsaDNYSe_y_9XhqmStc1ocD11AJUVr0Ix9fqB6TACoNMBS6gegSI6xmmdjT2ABqGilcpMs3OY6edNB8qZ9LP_YFK_z6UWdBBgWmETSfr9zRGVOOfLDMFwadgxCtbeV1AxGLTmfdVLCDPOlZseN3SNKHeFbC_ApYgPR-_vO1Fjl8KE8CucWULoDzgyHBdU1zqlLttlpaOQHl6aHWS0mtb4ymvQWDp7UZd-aukVb41UT5oeVtPS9HC6w2jfd4UBxG1T2TdTfazoXXk1eGgAD7ir6QyoB2Pkv9aANiRMMrTlk0C_w
description: ""
disabled: false
settings:
renderRequestBody: true
encodeUrl: true
followRedirects: global
cookies:
send: true
store: true
rebuildPath: true
- url: http://localhost:8082/reponse/addReponse/2
name: PUT resp courte from ADMIN
meta:
id: req_2704faf70033478ab6ae1def154fa917
created: 1761345052972
modified: 1761345244528
isPrivate: false
description: ""
sortKey: -1761344763679.5
method: PUT
body:
mimeType: application/json
text: |-
{
"reponse": "La bonne réponse 2"
}
headers:
- name: Content-Type
value: application/json
- name: User-Agent
value: insomnia/11.6.1
id: pair_4c3461e4c95d45bd973dcb4bfd5e519a
- id: pair_b3814f137d494ce389fbe6075385cb71
name: Authorization
value: Bearer
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVaDlNMG8wMERKaEdTQzdTRjdmdDlFZWFDNmE4UVdKV0NPXzdENVBKeXFRIn0.eyJleHAiOjE3NjEzNDUyNDgsImlhdCI6MTc2MTM0NDk0OCwianRpIjoib25ydHJvOjFiMzcwMjU1LTg5MzgtM2U0Zi1lMTBiLTVlOGZmOTYwNzVlMCIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbXlzcHJpbmdib290YXBwcmVhbG0iLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiOTkyZTI3OTktN2ExOS00ZWY1LTk0ODItYWMzMjljNTNhNDc5IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibXlzcHJpbmdib290YXBwIiwic2lkIjoiYTVjYWNlMDUtYTIxZS1kMzk2LTdhYjEtMDRmOWEwNTg5YzQwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJVU0VSIiwiZGVmYXVsdC1yb2xlcy1teXNwcmluZ2Jvb3RhcHByZWFsbSJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoidWlvYXpkcSB6c29rZHFzamtkIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibXl1c2VyMiIsImdpdmVuX25hbWUiOiJ1aW9hemRxIiwiZmFtaWx5X25hbWUiOiJ6c29rZHFzamtkIiwiZW1haWwiOiJva0BjYWNhLmNvbSJ9.Hqsi5Pk5Hrh61cKDEmMbGpA2kv3YTW-WOh0Z4NhrZn2GeCphKI3ApgRV3Zbkrt_UbyUv3z9UW69eZLUFIS-LZRMNBiwSl7U86xlNA9s5A9aiCL7GU5NsyCy4zNlqNo2RHZP_2RLB-aPtmWr8eDjFEhN0M8WwZJIje-vvDUQAugAKe6x0g8L1IbajYxGSHqScIYE8UAV9sA-HcVOVY92uGUG3T8xZK4_v9EvUI3hfleHaQVBilhlh_cHhcOTngvBgO4C__npW9KJYKeQiPqXyrN5cmNeJWJ38UcfcoinSXsXAjdwPQDTikg9W8x9qf9-MyVIDRBHZBwqj65MkyRCEcQ
description: ""
disabled: false
settings:
renderRequestBody: true
encodeUrl: true
followRedirects: global
cookies:
send: true
store: true
rebuildPath: true
- url: http://localhost:8082/reponse/addChoix/13
name: PUT resp choix from ADMIN
meta:
id: req_4188b0f6c89f4cce9159f88c380a46cb
created: 1761345107220
modified: 1761345327676
isPrivate: false
description: ""
sortKey: -1761344751255.75
method: PUT
body:
mimeType: application/json
text: |-
{
"choix": "Option A"
}
headers:
- name: Content-Type
value: application/json
id: pair_911df3ed408a4f8399789d8f9cdac928
- name: User-Agent
value: insomnia/11.6.1
id: pair_4c3461e4c95d45bd973dcb4bfd5e519a
- id: pair_b3814f137d494ce389fbe6075385cb71
name: Authorization
value: Bearer
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVaDlNMG8wMERKaEdTQzdTRjdmdDlFZWFDNmE4UVdKV0NPXzdENVBKeXFRIn0.eyJleHAiOjE3NjEzNDU2MjAsImlhdCI6MTc2MTM0NTMyMCwianRpIjoib25ydHJvOjJhMGIxOGZiLWE4MjEtMWI3MS1iODQ1LWE5NGY0NWY1ZDA4MSIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbXlzcHJpbmdib290YXBwcmVhbG0iLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiOTkyZTI3OTktN2ExOS00ZWY1LTk0ODItYWMzMjljNTNhNDc5IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibXlzcHJpbmdib290YXBwIiwic2lkIjoiMzFhYmVlNzYtOWJkNy02NWMyLWY0MzMtOTJiZjliODZlMDA1IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJVU0VSIiwiZGVmYXVsdC1yb2xlcy1teXNwcmluZ2Jvb3RhcHByZWFsbSJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoidWlvYXpkcSB6c29rZHFzamtkIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibXl1c2VyMiIsImdpdmVuX25hbWUiOiJ1aW9hemRxIiwiZmFtaWx5X25hbWUiOiJ6c29rZHFzamtkIiwiZW1haWwiOiJva0BjYWNhLmNvbSJ9.GBNldYmb4q02AaOwnu1xoLxkF_9qvadLdw1ftjetOsaDNYSe_y_9XhqmStc1ocD11AJUVr0Ix9fqB6TACoNMBS6gegSI6xmmdjT2ABqGilcpMs3OY6edNB8qZ9LP_YFK_z6UWdBBgWmETSfr9zRGVOOfLDMFwadgxCtbeV1AxGLTmfdVLCDPOlZseN3SNKHeFbC_ApYgPR-_vO1Fjl8KE8CucWULoDzgyHBdU1zqlLttlpaOQHl6aHWS0mtb4ymvQWDp7UZd-aukVb41UT5oeVtPS9HC6w2jfd4UBxG1T2TdTfazoXXk1eGgAD7ir6QyoB2Pkv9aANiRMMrTlk0C_w
description: ""
disabled: false
settings:
renderRequestBody: true
encodeUrl: true
followRedirects: global
cookies:
send: true
store: true
rebuildPath: true
- url: http://localhost:8082/reponse/get/13
name: Get all resp choix from USER
meta:
id: req_dcface58294d4fd793f7ba39bbfb1bd8
created: 1761345559727
modified: 1761345567849
isPrivate: false
description: ""
sortKey: -1761344776103.25
method: GET
body:
mimeType: application/x-www-form-urlencoded
params:
- id: pair_54b0a24cfe5c4d81ae864d64640e35f2
name: client_id
value: myspringbootapp
description: ""
disabled: false
- id: pair_f6c73c60f3024e42bbacc223615d3be1
name: client_secret
value: Y7xpKQbFalUFTGUGD9XDBcvawvs3zsWZ
description: ""
disabled: false
- id: pair_3698939343424230a63d135857f0acb1
name: username
value: myuser2
description: ""
disabled: false
- id: pair_f8b4c07baea14742a4ebd8f005ff5e92
name: password
value: "1"
description: ""
disabled: false
- id: pair_e49d8dbb324d484bad8747b563ae1615
name: grant_type
value: password
description: ""
disabled: false
headers:
- name: Content-Type
value: application/x-www-form-urlencoded
id: pair_987cf70c521843c8a47e1c51976cce3b
type: text
multiline: false
- name: User-Agent
value: insomnia/11.6.1
id: pair_4c3461e4c95d45bd973dcb4bfd5e519a
- id: pair_b3814f137d494ce389fbe6075385cb71
name: Authorization
value: Bearer
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVaDlNMG8wMERKaEdTQzdTRjdmdDlFZWFDNmE4UVdKV0NPXzdENVBKeXFRIn0.eyJleHAiOjE3NjEzNDU2MjAsImlhdCI6MTc2MTM0NTMyMCwianRpIjoib25ydHJvOjJhMGIxOGZiLWE4MjEtMWI3MS1iODQ1LWE5NGY0NWY1ZDA4MSIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbXlzcHJpbmdib290YXBwcmVhbG0iLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiOTkyZTI3OTktN2ExOS00ZWY1LTk0ODItYWMzMjljNTNhNDc5IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibXlzcHJpbmdib290YXBwIiwic2lkIjoiMzFhYmVlNzYtOWJkNy02NWMyLWY0MzMtOTJiZjliODZlMDA1IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJVU0VSIiwiZGVmYXVsdC1yb2xlcy1teXNwcmluZ2Jvb3RhcHByZWFsbSJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoidWlvYXpkcSB6c29rZHFzamtkIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibXl1c2VyMiIsImdpdmVuX25hbWUiOiJ1aW9hemRxIiwiZmFtaWx5X25hbWUiOiJ6c29rZHFzamtkIiwiZW1haWwiOiJva0BjYWNhLmNvbSJ9.GBNldYmb4q02AaOwnu1xoLxkF_9qvadLdw1ftjetOsaDNYSe_y_9XhqmStc1ocD11AJUVr0Ix9fqB6TACoNMBS6gegSI6xmmdjT2ABqGilcpMs3OY6edNB8qZ9LP_YFK_z6UWdBBgWmETSfr9zRGVOOfLDMFwadgxCtbeV1AxGLTmfdVLCDPOlZseN3SNKHeFbC_ApYgPR-_vO1Fjl8KE8CucWULoDzgyHBdU1zqlLttlpaOQHl6aHWS0mtb4ymvQWDp7UZd-aukVb41UT5oeVtPS9HC6w2jfd4UBxG1T2TdTfazoXXk1eGgAD7ir6QyoB2Pkv9aANiRMMrTlk0C_w
description: ""
disabled: false
settings:
renderRequestBody: true
encodeUrl: true
followRedirects: global
cookies:
send: true
store: true
rebuildPath: true
- url: http://localhost:8082/reponse/delete/5
name: "DELETE resp with ADMIN "
meta:
id: req_e04466dab86345809e01cec179a7e210
created: 1761348162308
modified: 1761348196375
isPrivate: false
description: ""
sortKey: -1761344751155.75
method: DELETE
body:
mimeType: application/json
text: ""
headers:
- name: Content-Type
value: application/json
id: pair_2694b5ff2f964512842dc3fa44ccd3e1
- name: User-Agent
value: insomnia/11.6.1
id: pair_4c3461e4c95d45bd973dcb4bfd5e519a
- id: pair_b3814f137d494ce389fbe6075385cb71
name: Authorization
value: Bearer
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVaDlNMG8wMERKaEdTQzdTRjdmdDlFZWFDNmE4UVdKV0NPXzdENVBKeXFRIn0.eyJleHAiOjE3NjEzNDg0ODUsImlhdCI6MTc2MTM0ODE4NSwianRpIjoib25ydHJvOjg4YWY2ZGE0LWYwMzAtMjMyZi0wYzVmLTNjM2E4YzhlNzcwOCIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbXlzcHJpbmdib290YXBwcmVhbG0iLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiMmY5YWRhYzQtODU4Ni00NTI4LWE4Y2QtM2I3M2I5NTc0ODBiIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibXlzcHJpbmdib290YXBwIiwic2lkIjoiM2UyZmRhNzAtY2JiOC1jODZjLTc1YjYtMjQxMzY5YjU1Njg2IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJBRE1JTiIsImRlZmF1bHQtcm9sZXMtbXlzcHJpbmdib290YXBwcmVhbG0iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6IlRpYm8gUm9jaGFzIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibXl1c2VyIiwiZ2l2ZW5fbmFtZSI6IlRpYm8iLCJmYW1pbHlfbmFtZSI6IlJvY2hhcyIsImVtYWlsIjoidGlib0BjYWNhLmNvbSJ9.I4qJZegiHsGn1JLbZMUF6waDq387tCXpOVWuaf4B-emczDw53cfVLGAHefbPmqYSrENqRJwpI-BrWdFxgNO8ELLMfrEKw_dyYbtfM_GJLcxo4zlvaoldZ2RhIN4muJB52zeKPYuBg34KwrlDR49HYvqGkrhNz9Ve8Jl4sbig4T8U53vhveLu0qqpC58RoC-5oXboq8qxVllGbk9mBUDzzU6DpzhyZOp8ywvf-qHs2JJW5svG4en6O2uK4Hpu4Nm_Mr6_ReI5jOJ-XK8C4eCZFjtPOo16x5lA07k4UVRBxu7W1ccMOp_N56pkmwftaOt40EXezXgmEBxmwxCWwzyJhA
description: ""
disabled: false
settings:
renderRequestBody: true
encodeUrl: true
followRedirects: global
cookies:
send: true
store: true
rebuildPath: true
- url: http://localhost:8082/reponse/removeChoix/1
name: "DELETE resp choix with ADMIN "
meta:
id: req_16e00e9051c84902a69a7822a49b8bfc
created: 1761348252746
modified: 1761348405701
isPrivate: false
description: ""
sortKey: -1761344744993.875
method: PUT
body:
mimeType: application/json
text: |-
{
"choix": "OptionA"
}
headers:
- name: Content-Type
value: application/json
id: pair_2694b5ff2f964512842dc3fa44ccd3e1
- name: User-Agent
value: insomnia/11.6.1
id: pair_4c3461e4c95d45bd973dcb4bfd5e519a
- id: pair_b3814f137d494ce389fbe6075385cb71
name: Authorization
value: Bearer
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVaDlNMG8wMERKaEdTQzdTRjdmdDlFZWFDNmE4UVdKV0NPXzdENVBKeXFRIn0.eyJleHAiOjE3NjEzNDg1OTIsImlhdCI6MTc2MTM0ODI5MiwianRpIjoib25ydHJvOjQwYjU0YTViLWRkMmItZTNlYy0zNDA3LWU5ODAwNWE5YThjMSIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbXlzcHJpbmdib290YXBwcmVhbG0iLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiMmY5YWRhYzQtODU4Ni00NTI4LWE4Y2QtM2I3M2I5NTc0ODBiIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibXlzcHJpbmdib290YXBwIiwic2lkIjoiNjg0MjQ3YzUtZDAxYy0yY2Y3LTI0NTYtYWQ3MTgyNTExZWQ4IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJBRE1JTiIsImRlZmF1bHQtcm9sZXMtbXlzcHJpbmdib290YXBwcmVhbG0iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6IlRpYm8gUm9jaGFzIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibXl1c2VyIiwiZ2l2ZW5fbmFtZSI6IlRpYm8iLCJmYW1pbHlfbmFtZSI6IlJvY2hhcyIsImVtYWlsIjoidGlib0BjYWNhLmNvbSJ9.aUvRWi5eYa0AmrLeTVKVHRA_oc0qPsHwsXZIQMhxWea8CEv3ScXi_BNi_H5U-3D_wAdGjOXz8iWS4WS2TtYiCjOwNhCmwVfheN36X-ub_h3PpmCn-SH68V7f-761BMmXk4Uao91CyQ-kXdhDJqde3qcmBsLjwx3ccuzmF9cMwUpoUVkCnWxfJEIhR-MGvjxxtku_EZZxce3CLFsxXmNYi8oa-BjMYh5GG3GQg2MIuivDIF-gfZFxjYZRV4icwybDTZ0jQht6aVopnoapnVh7kkggvjafsfmy0EZ34dkV5VsQGOOo-L6d4WRo9JbkO1e2ZiphMjCtU_W_H0eqbLqRsw
description: ""
disabled: false
settings:
renderRequestBody: true
encodeUrl: true
followRedirects: global
cookies:
send: true
store: true
rebuildPath: true
- name: QUIZZ
meta:
id: fld_7cc2d773f5a942ac98e9614bafc67a43
created: 1761348455968
modified: 1761348514804
sortKey: -1761344725037.875
description: ""
children:
- url: http://localhost:8082/quizz/create/1
name: "CREATE quizz with ADMIN "
meta:
id: req_e954bc2df607411a889380466d7889f0
created: 1761348544027
modified: 1761348778718
isPrivate: false
description: ""
sortKey: -1761348548595
method: POST
body:
mimeType: application/json
text: "{}"
headers:
- name: Content-Type
value: application/json
id: pair_2694b5ff2f964512842dc3fa44ccd3e1
- name: User-Agent
value: insomnia/11.6.1
id: pair_4c3461e4c95d45bd973dcb4bfd5e519a
- id: pair_b3814f137d494ce389fbe6075385cb71
name: Authorization
value: Bearer
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVaDlNMG8wMERKaEdTQzdTRjdmdDlFZWFDNmE4UVdKV0NPXzdENVBKeXFRIn0.eyJleHAiOjE3NjEzNDg4NzksImlhdCI6MTc2MTM0ODU3OSwianRpIjoib25ydHJvOmJiYmQyM2QwLTY2ZTctMWY0NS1iNTFiLTBiZGFjNzQzZmZiMyIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbXlzcHJpbmdib290YXBwcmVhbG0iLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiMmY5YWRhYzQtODU4Ni00NTI4LWE4Y2QtM2I3M2I5NTc0ODBiIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibXlzcHJpbmdib290YXBwIiwic2lkIjoiN2FjZmE3YWItNTk4ZC01ZmVlLTU0MzktYzMyNDYyYzFkM2JjIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJBRE1JTiIsImRlZmF1bHQtcm9sZXMtbXlzcHJpbmdib290YXBwcmVhbG0iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6IlRpYm8gUm9jaGFzIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibXl1c2VyIiwiZ2l2ZW5fbmFtZSI6IlRpYm8iLCJmYW1pbHlfbmFtZSI6IlJvY2hhcyIsImVtYWlsIjoidGlib0BjYWNhLmNvbSJ9.TrxycBI76TRjSNjA7kwDNycyKjmNwhjfMnQ2xOi0hVvBqpQN-nIH6mvm3hv6FwoTCVZz9lwwS5kpn83Z4FoYZVY5oKGYsccNR77tg42Rahn1UXOuQuCs4v9W0oqClQa5PtI8loQXO9d5P3mc8uuUvO2vClnGRrky48DqGDSis30fXPY-c26TIZvIRyi_PWPSOK2i2k9w7fkWPodkkGxdaRm4Sc45hNXCA9FT8xRJhzfxJ21ynOovx2Z9y8lILqV5Q4NqjMOTlzyVwkj6vS3veXIJkHAAk8LPdHJKoPrrqQzXXsb3ZIgTl8DyF2cYcJ58vOOle91UoGuqWi1U-pJSnw
description: ""
disabled: false
settings:
renderRequestBody: true
encodeUrl: true
followRedirects: global
cookies:
send: true
store: true
rebuildPath: true
- url: http://localhost:8082/quizz/getAll
name: Get all quizz from USER
meta:
id: req_f1529608fc064c4f83df2717cefb01ef
created: 1761348670144
modified: 1761348786170
isPrivate: false
description: ""
sortKey: -1761348548495
method: GET
body:
mimeType: application/x-www-form-urlencoded
params:
- id: pair_54b0a24cfe5c4d81ae864d64640e35f2
name: client_id
value: myspringbootapp
description: ""
disabled: false
- id: pair_f6c73c60f3024e42bbacc223615d3be1
name: client_secret
value: Y7xpKQbFalUFTGUGD9XDBcvawvs3zsWZ
description: ""
disabled: false
- id: pair_3698939343424230a63d135857f0acb1
name: username
value: myuser2
description: ""
disabled: false
- id: pair_f8b4c07baea14742a4ebd8f005ff5e92
name: password
value: "1"
description: ""
disabled: false
- id: pair_e49d8dbb324d484bad8747b563ae1615
name: grant_type
value: password
description: ""
disabled: false
headers:
- name: Content-Type
value: application/x-www-form-urlencoded
id: pair_987cf70c521843c8a47e1c51976cce3b
type: text
multiline: false
- name: User-Agent
value: insomnia/11.6.1
id: pair_4c3461e4c95d45bd973dcb4bfd5e519a
- id: pair_b3814f137d494ce389fbe6075385cb71
name: Authorization
value: Bearer
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVaDlNMG8wMERKaEdTQzdTRjdmdDlFZWFDNmE4UVdKV0NPXzdENVBKeXFRIn0.eyJleHAiOjE3NjEzNDg4NzksImlhdCI6MTc2MTM0ODU3OSwianRpIjoib25ydHJvOmJiYmQyM2QwLTY2ZTctMWY0NS1iNTFiLTBiZGFjNzQzZmZiMyIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbXlzcHJpbmdib290YXBwcmVhbG0iLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiMmY5YWRhYzQtODU4Ni00NTI4LWE4Y2QtM2I3M2I5NTc0ODBiIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibXlzcHJpbmdib290YXBwIiwic2lkIjoiN2FjZmE3YWItNTk4ZC01ZmVlLTU0MzktYzMyNDYyYzFkM2JjIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJBRE1JTiIsImRlZmF1bHQtcm9sZXMtbXlzcHJpbmdib290YXBwcmVhbG0iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6IlRpYm8gUm9jaGFzIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibXl1c2VyIiwiZ2l2ZW5fbmFtZSI6IlRpYm8iLCJmYW1pbHlfbmFtZSI6IlJvY2hhcyIsImVtYWlsIjoidGlib0BjYWNhLmNvbSJ9.TrxycBI76TRjSNjA7kwDNycyKjmNwhjfMnQ2xOi0hVvBqpQN-nIH6mvm3hv6FwoTCVZz9lwwS5kpn83Z4FoYZVY5oKGYsccNR77tg42Rahn1UXOuQuCs4v9W0oqClQa5PtI8loQXO9d5P3mc8uuUvO2vClnGRrky48DqGDSis30fXPY-c26TIZvIRyi_PWPSOK2i2k9w7fkWPodkkGxdaRm4Sc45hNXCA9FT8xRJhzfxJ21ynOovx2Z9y8lILqV5Q4NqjMOTlzyVwkj6vS3veXIJkHAAk8LPdHJKoPrrqQzXXsb3ZIgTl8DyF2cYcJ58vOOle91UoGuqWi1U-pJSnw
description: ""
disabled: false
settings:
renderRequestBody: true
encodeUrl: true
followRedirects: global
cookies:
send: true
store: true
rebuildPath: true
- name: QUESTION
meta:
id: fld_c6cc9e699561490db8dce6d93e60a0cd
created: 1761348479799
modified: 1761348510649
sortKey: -1761344727350.4062
description: ""
cookieJar:
name: Default Jar
meta:
id: jar_068e06f12cad1a0f9f00592ae145d89f7e23f621
created: 1759266691097
modified: 1761348288035
cookies:
- key: JSESSIONID
value: 43CC5321D4DE83F58DA69D80E2AC45A1
domain: localhost
path: /
httpOnly: true
hostOnly: true
creation: 2025-10-22T19:54:48.589Z
lastAccessed: 2025-10-24T23:24:48.035Z
id: eeeea037-2a2e-4b1b-badb-22b5c98f4519
environments:
name: Base Environment
meta:
id: env_068e06f12cad1a0f9f00592ae145d89f7e23f621
created: 1754408137751
modified: 1759266691083
isPrivate: false

167
README.md
View File

@@ -1,117 +1,92 @@
# TP TAA # TP TAA
## TP2 Partie API REST
### Compte rendu ## TP3 - TP4
Dans ce TP REST, nous avons implémenté les éléments suivants:
- Mapper pour convertir les entités vers les DTO et inversement
- Lombok afin de simplifier le code et éviter le code boilerplate (getters, setters, constructeurs, etc.)
- API REST pour exposer les différentes ressources
- Swagger UI pour documenter et tester facilement toutes les méthodes de lAPI.
- DTO (Data Transfer Objects) afin déviter les problèmes de boucle infinie liés aux relations bidirectionnelles entre entités.
### Nous avons maintenant deux rôles :
#### Execution du projet - ADMIN : correspond à lenseignant
Recharger les dépendances Maven :
`mvn clean install`
Lancer la base de données (Linux) : `./run-hsqldb-server.sh` - USER : correspond à létudiant
Lancer le serveur par fichier `src/main/java/fr.istic.taa.jaxrs/RestServer.java` Pour Keycloak, il faudrait normalement créer les utilisateurs via OAuth2. Cependant, pour ce TP, nous avons utilisé directement la base de données (BDD) pour créer les utilisateurs.
Après le lancement du serveur, on a testé des appels API avec Insomnia et l'interface Swagger est accessible via: http://localhost:8080/api ### Remarques sur les entités
Seuls Utilisateur et Question sont fonctionnels, il reste quelques problèmes sur le reste.
Pour les classes Quizz, Question et Utilisateur, nous avons testé que tout fonctionne, mais elles sont liées à Utilisateur. Cela na pas beaucoup de sens avec les rôles USER de Keycloak et ce nest pas lobjectif principal du TP.
#### Diagramme de classe ### Tests avec Insomnia
```mermaid
classDiagram
Utilisateur "*" -- "*" Session
Session "*" -- "*" Quizz
Quizz "1" -- "1..*" Question
Utilisateur "1" -- "*" Quizz
Question "1" -- "1" Reponse
Reponse <|-- ReponseCourte
Reponse <|-- Choix
class Utilisateur { Pour simplifier et se concentrer sur les fonctionnalités principales, nous avons testé les classes Session et Reponse directement via Insomnia.
-id : int
-name : String
-session : List&lt;Session&gt;
-email : String
-password : String
-quizzs : String
}
class Session{
-id : int
-codePIN : int
-quizzs : List&lt;Quizz&gt;
-utilisateurs : List&lt;Utilisateur&gt;
-theme : String
}
class Quizz{
-session: Session
-id : int
-createur: Utilisateur
}
class Reponse{
-id : int
-question: Question
-reponses : ArrayList&lt;String&gt;
}
class Choix{
-choix : ArrayList&lt;String&gt;
}
class ReponseCourte{
}
class Question{
-id : int
-enonce : String
-reponse: Reponse
}
```
##### Utilisateur Resource ### Example de token admin et user dans OAuth2
| Methode | URL | Description | - Site web de décodage:
|---------|---------------------------------------------------|-------------------------------------------------------| https://www.jwt.io/
| GET | `/utilisateur` | Retourne toute la liste de l'utilisateur |
| POST | `/utilisateur/register` | S'incrire nouveaux utilisateur |
| GET | `/utilisateur/login` | Se connecter |
| GET | `/utilisateur/{id}` | Retourne l'utilisateur par id |
| GET | `/utilisateur/{user_id}/session` | Retoune la liste de session que l'utilisateur attends |
| PUT | `/utilisateur/{user_id}/add_session/{session_id}` | Ajoute un nouveau session à la liste de l'utilisateur |
| DELETE | `/utilisteur/{user_id}/delete` | Supprime l'utilisateur |
##### Session Resource - Admin
| Methode | URL | Description | `eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVaDlNMG8wMERKaEdTQzdTRjdmdDlFZWFDNmE4UVdKV0NPXzdENVBKeXFRIn0.eyJleHAiOjE3NjEzNDg4NzksImlhdCI6MTc2MTM0ODU3OSwianRpIjoib25ydHJvOmJiYmQyM2QwLTY2ZTctMWY0NS1iNTFiLTBiZGFjNzQzZmZiMyIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbXlzcHJpbmdib290YXBwcmVhbG0iLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiMmY5YWRhYzQtODU4Ni00NTI4LWE4Y2QtM2I3M2I5NTc0ODBiIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibXlzcHJpbmdib290YXBwIiwic2lkIjoiN2FjZmE3YWItNTk4ZC01ZmVlLTU0MzktYzMyNDYyYzFkM2JjIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJBRE1JTiIsImRlZmF1bHQtcm9sZXMtbXlzcHJpbmdib290YXBwcmVhbG0iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6IlRpYm8gUm9jaGFzIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibXl1c2VyIiwiZ2l2ZW5fbmFtZSI6IlRpYm8iLCJmYW1pbHlfbmFtZSI6IlJvY2hhcyIsImVtYWlsIjoidGlib0BjYWNhLmNvbSJ9.TrxycBI76TRjSNjA7kwDNycyKjmNwhjfMnQ2xOi0hVvBqpQN-nIH6mvm3hv6FwoTCVZz9lwwS5kpn83Z4FoYZVY5oKGYsccNR77tg42Rahn1UXOuQuCs4v9W0oqClQa5PtI8loQXO9d5P3mc8uuUvO2vClnGRrky48DqGDSis30fXPY-c26TIZvIRyi_PWPSOK2i2k9w7fkWPodkkGxdaRm4Sc45hNXCA9FT8xRJhzfxJ21ynOovx2Z9y8lILqV5Q4NqjMOTlzyVwkj6vS3veXIJkHAAk8LPdHJKoPrrqQzXXsb3ZIgTl8DyF2cYcJ58vOOle91UoGuqWi1U-pJSnw`
|---------|--------------------------------------|------------------------------------| - User
| GET | `/session` | Retourne toute la liste du session | `eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVaDlNMG8wMERKaEdTQzdTRjdmdDlFZWFDNmE4UVdKV0NPXzdENVBKeXFRIn0.eyJleHAiOjE3NjEzNDU2MjAsImlhdCI6MTc2MTM0NTMyMCwianRpIjoib25ydHJvOjJhMGIxOGZiLWE4MjEtMWI3MS1iODQ1LWE5NGY0NWY1ZDA4MSIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbXlzcHJpbmdib290YXBwcmVhbG0iLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiOTkyZTI3OTktN2ExOS00ZWY1LTk0ODItYWMzMjljNTNhNDc5IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibXlzcHJpbmdib290YXBwIiwic2lkIjoiMzFhYmVlNzYtOWJkNy02NWMyLWY0MzMtOTJiZjliODZlMDA1IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iLCJVU0VSIiwiZGVmYXVsdC1yb2xlcy1teXNwcmluZ2Jvb3RhcHByZWFsbSJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoidWlvYXpkcSB6c29rZHFzamtkIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibXl1c2VyMiIsImdpdmVuX25hbWUiOiJ1aW9hemRxIiwiZmFtaWx5X25hbWUiOiJ6c29rZHFzamtkIiwiZW1haWwiOiJva0BjYWNhLmNvbSJ9.GBNldYmb4q02AaOwnu1xoLxkF_9qvadLdw1ftjetOsaDNYSe_y_9XhqmStc1ocD11AJUVr0Ix9fqB6TACoNMBS6gegSI6xmmdjT2ABqGilcpMs3OY6edNB8qZ9LP_YFK_z6UWdBBgWmETSfr9zRGVOOfLDMFwadgxCtbeV1AxGLTmfdVLCDPOlZseN3SNKHeFbC_ApYgPR-_vO1Fjl8KE8CucWULoDzgyHBdU1zqlLttlpaOQHl6aHWS0mtb4ymvQWDp7UZd-aukVb41UT5oeVtPS9HC6w2jfd4UBxG1T2TdTfazoXXk1eGgAD7ir6QyoB2Pkv9aANiRMMrTlk0C_w`
| GET | `/session/{id}` | Retourne la session par id |
| GET | `/session/{session_id}/quizzs` | Retourne la liste de quizzs |
| GET | `/session/{session_id}/utilisateurs` | Retourne la liste de l'utilisateur |
| DELETE | `/session/{session_id}/delete` | Supprime la session |
##### Quizz Resource #### Utilisateur Resource
| Methode | URL | Description | | Methode | URL | Description |
|---------|------------------------------------------------|-----------------------------------------| |---------|----------------------------------------------------|----------------------------------------------------------------------------------------------|
| GET | `/quizz` | Retourne toute la liste du quizz | | POST | `/utilisateur/create` | Créer un utilisateur (avec aussi l'id keyloak) ("name","email et "password" dans body json) |
| GET | `/quizz/{quizz_id}/questions` | Retourne toutes questions du quizz | | GET | `/utilisateur/getAll` | retourn tout les utilisateurs (id, name, email) |
| GET | `/quizz/{quizz_id}/add_question/{question_id}` | Ajoute une nouvuelle question au quizz | | GET | `/utilisateur/getSessions/{session_id}` | Retourne les sessions de l'utilisateur |
| DELETE | `/quizz/{quizz_id}/delete` | Suprrime le quizz | | PUT | `/utilisateur/addSession/{user_id}/{session_id}` | rejoint une session à la liste de l'utilisateur |
| PUT | `/quizz/{quizz_id}/deleteQ` | Supprime toute les questions de quizz | | PUT | `/utilisateur/removeSession/{user_id}/{session_id}`| quite une session à la liste de l'utilisateur |
| PUT | `/utilisateur/update/{user_id}` | met à jour les info de l'utilisateur ("name","email et "password" dans body json) |
| DELETE | `/utilisteur/delete/{user_id}/delete` | Supprime l'utilisateur |
##### Question Resource #### Session Resource
| Methode | URL | Description |
|---------|-------------------------------------------------|---------------------------------------------------------------|
| POST | `/session/create` | créer une nouvelle session ("theme":String dans body json) |
| GET | `/session/getAll` | Retourne la liste des sessions |
| PUT | `/session/addQuizz/{session_id}/{quizz_id}` | ajoute un quizz à la session |
| PUT | `/session/removeQuizz/{session_id}/{quizz_id}` | retire un quizz à la session |
| PUT | `/session/update/{session_id}` | change le thème ("theme":String dans body json) |
| PUT | `/session/join/{session_id}` | l'utilisateur courant (keycloak) rejout la session |
| PUT | `/session/leave/{session_id}` | l'utilisateur courant (keycloak) quitte la session |
| DELETE | `/session/delete/{session_id}` | Supprime la session |
#### ReponseController
| Methode | URL | Description |
|---------|-------------------------------------------------|---------------------------------------------------------------------------|
| POST | `/reponse/create/choix` | créer un objet réponse de type choix multiple |
| POST | `/reponse/create/courte` | créer un objet réponse de type réponse courte |
| GET | `/reponse/getAll` | affiche l'id et les réponse correct de chaque réponse |
| GET | `/reponse/get/{id_reponse}` | affiche toutes les info d'un réponse |
| DELETE | `/reponse/delete/{id_reponse}` | supprime un objet réponse |
| PUT | `/reponse/removeReponse/{id_reponse} ` | retire une réponse correcte ("reponse" dans body json) |
| PUT | `/reponse/addReponse/{id_reponse} ` | ajoute une réponse correcte ("reponse" dans body json) |
| PUT | `/reponse/addChoix/{id_reponse} ` | ajoute un choix (réponse choix uniquement) ("choix":String dans body json)|
| PUT | `/reponse/removeChoix/{id_reponse}` | retire un choix (réponse choix uniquement) ("choix":String dans body json)|
#### Quizz Resource
| Methode | URL | Description |
|---------|-------------------------------------------------|----------------------------------------------------|
| POST | `/quizz/create/{utilisateur_id}` | céer un nouveau quizz par associé à un utilisateur |
| GET | `/quizz/getQuestions/{quizz_id}` | Retourne la list des questions d'un quizz |
| GET | `/quizz/getAll` | Retourne toute la liste du quizz |
| PUT | `/quizz/add_question/{quizz_id}/{question_id}` | Ajoute une nouvelle question au quizz |
| PUT | `/quizz/removeQuestion/{quizz_id}/{question_id}`| Ajoute une nouvelle question au quizz |
| DELETE | `/quizz/delete/{quizz_id}` | Suprrime le quizz |
#### Question Resource
| Methode | URL | Description | | Methode | URL | Description |
|----------|----------------------------------------------------|-----------------------------------------------------------------------| |----------|----------------------------------------------------|-----------------------------------------------------------------------|
| GET | `/question` | Retourne toute la liste du question | | GET | `/question` | Retourne toute la liste du question |
| POST | `/question/addQuestion` | Créer une question | | POST | `/question/create` | Créer une question ( "enonce":String dans body Json) |
| PUT | `/question/{question_id}/changeQuestion` | Change l'énoncé de la question | | PUT | `/question/update/{question_id}` | Change l'énoncé de la question ("enonce":String dans body JSON) |
| GET | `/question/{question_id}/getReponse` | retourne l'objet Reponse | | GET | `/question/get/{question_id}` | donne toutes les infos de la question sous forme de String |
| DELETE | `/question/{question_id}/deletReponses` | supprime toute les réponse correct | | GET | `/question/getAll` | donne l'id et l'énoncé de toutes les questions sous forme de String |
| PUT | `/question/{question_id}/addReponse` | Ajoute une réponse à Reponse | | GET | `/question/getReponse/{question_id}` | donne toutes les réponse correct sous forme de String |
| PUT | `/question/{question_id}/setReponse/choix` | créer un nouvel objet Reponse de type Choix pour la question | | PUT | `/question/setReponse/{question_id}/{reponse_id}` | met à null l'objet ponse à la question |
| PUT | `/question/{question_id}/setReponse/reponseCourte` | créer un nouvel objet Reponse de type reponse courte pour la question | | PUT | `/question/setReponse/{question_id}/{reponse_id}` | Associe un objet réponse à la question |
| PUT | `/question/{question_id}/addChoix` | rajoute un choix si Reponse est de type Choix | | PUT | `/question/delet/{question_id}` | supprime la question |
## Auteurs ## Auteurs

292
pom.xml Normal file → Executable file
View File

@@ -1,94 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>fr.istic.taa</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>jaxrs-example</artifactId> <artifactId>spring-boot-sample-data-jpa</artifactId>
<packaging>jar</packaging> <version>3.1.2</version>
<version>1.0-SNAPSHOT</version> <name>Spring Boot Data JPA Sample</name>
<name>jaxrs-example</name> <description>Spring Boot Data JPA Sample</description>
<url>http://maven.apache.org</url> <url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties> <properties>
<maven.compiler.source>11</maven.compiler.source> <main.basedir>${basedir}/../..</main.basedir>
<maven.compiler.target>11</maven.compiler.target> <maven.compiler.source>17</maven.compiler.source>
<org.mapstruct.version>1.6.3</org.mapstruct.version> <maven.compiler.target>17</maven.compiler.target>
</properties> </properties>
<dependencies> <parent>
<!-- https://mvnrepository.com/artifact/junit/junit --> <groupId>org.springframework.boot</groupId>
<dependency> <artifactId>spring-boot-starter-parent</artifactId>
<groupId>junit</groupId> <version>3.3.3</version>
<artifactId>junit</artifactId> <relativePath/>
<version>4.12</version> </parent>
<scope>test</scope>
</dependency>
<!-- ==== JPA / Hibernate ==== --> <dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.2.7.Final</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.1.0</version>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.2</version>
</dependency>
<!-- ==== REST API ==== -->
<!--https://mvnrepository.com/artifact/org.jboss.resteasy/resteasy-undertow -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-undertow</artifactId>
<version>6.2.4.Final</version>
</dependency>
<!--https://mvnrepository.com/artifact/org.jboss.resteasy/resteasy-jackson2-provider -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<version>6.2.4.Final</version>
</dependency>
<!--https://mvnrepository.com/artifact/org.jboss.resteasy/resteasy-jaxb-provider -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
<version>6.2.4.Final</version>
</dependency>
<!-- OpenAPI-->
<!--https://mvnrepository.com/artifact/io.swagger.core.v3/swagger-jaxrs2-jakarta -->
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-jakarta</artifactId>
<version>2.2.15</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-servlet-initializer-v2</artifactId>
<version>2.2.15</version>
</dependency>
<!-- ==== MapStruct/ Lombok ==== -->
<dependency> <dependency>
<groupId>org.mapstruct</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>mapstruct</artifactId> <artifactId>spring-boot-starter-web</artifactId>
<version>1.6.3</version> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.7.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<!-- <version>1.4.192</version> -->
<version>2.2.224</version>
<scope>runtime</scope>
</dependency> </dependency>
<dependency> <dependency>
@@ -98,32 +110,100 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<defaultGoal>install</defaultGoal> <plugins>
<plugins> <plugin>
<plugin> <groupId>org.springframework.boot</groupId>
<groupId>org.apache.maven.plugins</groupId> <artifactId>spring-boot-maven-plugin</artifactId>
<artifactId>maven-compiler-plugin</artifactId> <version>3.1.2</version>
<version>3.11.0</version> </plugin>
<configuration> <plugin>
<source>11</source> <groupId>org.apache.maven.plugins</groupId>
<target>11</target> <artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<useProjectReferences>false</useProjectReferences>
<additionalConfig>
<file>
<name>.settings/org.eclipse.jdt.ui.prefs</name>
<location>${main.basedir}/eclipse/org.eclipse.jdt.ui.prefs</location>
</file>
<file>
<name>.settings/org.eclipse.jdt.core.prefs</name>
<location>${main.basedir}/eclipse/org.eclipse.jdt.core.prefs</location>
</file>
</additionalConfig>
<annotationProcessorPaths> <annotationProcessorPaths>
<path> <path>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<version>1.18.42</version> <version>1.18.42</version>
</path> </path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.6.3</version>
</path>
</annotationProcessorPaths> </annotationProcessorPaths>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
</plugins> <groupId>org.apache.maven.plugins</groupId>
</build> <artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Tests.java</include>
</includes>
<excludes>
<exclude>**/Abstract*.java</exclude>
</excludes>
<systemPropertyVariables>
<java.security.egd>file:/dev/./urandom</java.security.egd>
<java.awt.headless>true</java.awt.headless>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings
only. It has no influence on the Maven build itself. -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-maven-plugin
</artifactId>
<versionRange>
[3.1.2,)
</versionRange>
<goals>
<goal>build-info</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore/>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>http://repo.spring.io/release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project> </project>

View File

@@ -1,3 +0,0 @@
mkdir data
cd data
java -cp ..\hsqldb-2.7.2.jar org.hsqldb.Server

View File

@@ -1,4 +0,0 @@
mvn dependency:copy-dependencies
mkdir data 2> /dev/null
cd data
java -cp ../target/dependency/hsqldb-2.7.2.jar org.hsqldb.Server

View File

@@ -1,2 +0,0 @@
java -cp ./target/dependency/hsqldb-2.7.2.jar org.hsqldb.util.DatabaseManagerSwing --driver org.hsqldb.jdbcDriver --url jdbc:hsqldb:hsql://localhost/ --user SA

View File

@@ -1,2 +0,0 @@
#mvn dependency:copy-dependencies
java -cp ./target/dependency/hsqldb-2.7.2.jar org.hsqldb.util.DatabaseManagerSwing --driver org.hsqldb.jdbcDriver --url jdbc:hsqldb:hsql://localhost/ --user SA

View File

@@ -1,60 +0,0 @@
package fr.istic.taa.jaxrs.DAO;
import java.io.Serializable;
import java.util.List;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityTransaction;
public abstract class AbstractJpaDao<K, T extends Serializable> implements IGenericDao<K, T> {
protected EntityManager em;
private Class<T> entityClass;
public AbstractJpaDao() {
this.em = EntityManagerHelper.getEntityManager();
}
//Pour connaitre qu'on travaille avec quelle classe
public void setClass(Class<T> class2){
this.entityClass= class2;
}
public T findOne(K id) {
return em.find(entityClass, id);
}
public List<T> findAll() {
return em.createQuery("select e from " + entityClass.getName() + " as e", entityClass).getResultList();
}
//CRUD
public void create(T entity){
EntityTransaction t = em.getTransaction();
t.begin();
em.persist(entity);
t.commit();
}
public T findById(K id) {
return em.find(entityClass, id);
}
public T update(T entity){
EntityTransaction t = em.getTransaction();
t.begin();
T T_sync = em.merge(entity);
t.commit();
return T_sync;
}
public void delete(T entity){
EntityTransaction t = em.getTransaction();
t.begin();
em.remove(entity);
t.commit();
}
public void deleteById(K id) {
T T_to_be_deleted = em.find(entityClass, id);
em.remove(T_to_be_deleted);
}
}

View File

@@ -1,57 +0,0 @@
package fr.istic.taa.jaxrs.DAO;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
public class EntityManagerHelper {
private static EntityManagerFactory emf;
private static final ThreadLocal<EntityManager> threadLocal;
static {
try {
emf = Persistence.createEntityManagerFactory("dev");
} catch (Exception e) {
emf = null;
e.printStackTrace();
}
threadLocal = new ThreadLocal<EntityManager>();
}
public static EntityManager getEntityManager() {
EntityManager em = threadLocal.get();
if (em == null) {
em = emf.createEntityManager();
threadLocal.set(em);
}
return em;
}
public static void closeEntityManager() {
EntityManager em = threadLocal.get();
if (em != null) {
em.close();
threadLocal.set(null);
}
}
public static void closeEntityManagerFactory() {
emf.close();
}
public static void beginTransaction() {
getEntityManager().getTransaction().begin();
}
public static void rollback() {
getEntityManager().getTransaction().rollback();
}
public static void commit() {
getEntityManager().getTransaction().commit();
}
}

View File

@@ -1,14 +0,0 @@
package fr.istic.taa.jaxrs.DAO;
import java.io.Serializable;
import java.util.List;
public interface IGenericDao<K, T extends Serializable> {
void create(final T entity);
T findById(final K id);
T update(final T entity);
void delete(final T entity);
void deleteById(final K id);
List<T> findAll();
T findOne(final K id);
}

View File

@@ -1,108 +0,0 @@
package fr.istic.taa.jaxrs.DAO;
import java.util.ArrayList;
import java.util.List;
import fr.istic.taa.jaxrs.metier.Choix;
import fr.istic.taa.jaxrs.metier.Question;
import fr.istic.taa.jaxrs.metier.Reponse;
import fr.istic.taa.jaxrs.metier.ReponseCourte;
import fr.istic.taa.jaxrs.metier.Session;
import fr.istic.taa.jaxrs.metier.Utilisateur;
import jakarta.persistence.EntityTransaction;
public class QuestionDAO extends AbstractJpaDao<Integer, Question> {
public QuestionDAO() {
super();
this.setClass(Question.class);
}
public void addReponse(String reponse, int questionId) {
EntityTransaction t = em.getTransaction();
try {
if (!t.isActive()) t.begin();
Question q = em.find(Question.class, questionId);
if (q != null && q.getReponse() != null) {
q.getReponse().getReponses().add(reponse);
em.merge(q);
}
t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
}
}
public void deleteReponse(int questionId) {
EntityTransaction t = em.getTransaction();
try {
if (!t.isActive()) t.begin();
Question q = em.find(Question.class, questionId);
if (q != null && q.getReponse() != null) {
q.getReponse().setReponses(new ArrayList<>());
em.merge(q);
}
t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
}
}
public void setReponse(Reponse rep, Integer id) {
EntityTransaction t = em.getTransaction();
try {
if (!t.isActive()) t.begin();
Question q = em.find(Question.class, id);
if (q != null) {
q.setReponse(rep);
em.merge(q);
}
t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
}
}
public void setChoix(Integer id) {
setReponse(new Choix(), id);
}
public void setReponseCourte(Integer id) {
setReponse(new ReponseCourte(), id);
}
public void addChoix(Integer id, String choix) {
EntityTransaction t = em.getTransaction();
try {
if (!t.isActive()) t.begin();
Question q = em.find(Question.class, id);
if (q != null && q.getReponse() instanceof Choix) {
((Choix) q.getReponse()).getChoix().add(choix);
em.merge(q);
}
t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
}
}
public void changeEnonce(String newEnonce, Integer id) {
EntityTransaction t = em.getTransaction();
try {
if (!t.isActive()) t.begin();
Question q = em.find(Question.class, id);
if (q != null) {
q.setEnonce(newEnonce);
em.merge(q);
}
t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
}
}
}

View File

@@ -1,48 +0,0 @@
package fr.istic.taa.jaxrs.DAO;
import fr.istic.taa.jaxrs.metier.Question;
import jakarta.persistence.EntityTransaction;
import fr.istic.taa.jaxrs.metier.Quizz;
public class QuizzDAO extends AbstractJpaDao<Integer, Quizz> {
public QuizzDAO(){
super();
this.setClass(Quizz.class);
}
public void deleteAllQuestion(int quizzId) {
EntityTransaction t = em.getTransaction();
try {
if (!t.isActive()) t.begin();
Quizz quizz = em.find(Quizz.class, quizzId);
if (quizz != null) {
quizz.getQuestions().clear();
em.merge(quizz);
}
t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
throw e;
}
}
public void addQuestion(int quizzId, int questionId) {
EntityTransaction t = em.getTransaction();
try {
if (!t.isActive()) t.begin();
Quizz quizz = em.find(Quizz.class, quizzId);
Question question = em.find(Question.class, questionId);
if (quizz != null && question != null) {
quizz.getQuestions().add(question);
em.merge(quizz);
}
t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
throw e;
}
}
}

View File

@@ -1,11 +0,0 @@
package fr.istic.taa.jaxrs.DAO;
import fr.istic.taa.jaxrs.metier.Reponse;
public class ReponseDAO extends AbstractJpaDao<Integer, Reponse> {
public ReponseDAO(){
super();
this.setClass(Reponse.class);
}
}

View File

@@ -1,33 +0,0 @@
package fr.istic.taa.jaxrs.DAO;
import jakarta.persistence.EntityTransaction;
import jakarta.persistence.Query;
import fr.istic.taa.jaxrs.metier.Session;
import java.util.List;
public class SessionDAO extends AbstractJpaDao<Integer, Session> {
public SessionDAO() {
super();
this.setClass(Session.class);
}
public List<Session> findByTheme(String theme) {
EntityTransaction t = em.getTransaction();
try {
if (!t.isActive()) {
t.begin();
}
Query query = em.createQuery("SELECT s FROM Session s WHERE s.theme = :theme", Session.class);
query.setParameter("theme", theme);
List<Session> sessions = query.getResultList();
t.commit();
return sessions;
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
throw e;
}
}
}

View File

@@ -1,61 +0,0 @@
package fr.istic.taa.jaxrs.DAO;
import jakarta.persistence.EntityTransaction;
import fr.istic.taa.jaxrs.metier.Session;
import fr.istic.taa.jaxrs.metier.Utilisateur;
import java.util.List;
public class UtilisateurDAO extends AbstractJpaDao<Integer, Utilisateur> {
public UtilisateurDAO() {
super();
this.setClass(Utilisateur.class);
}
public Utilisateur findByEmail(String email) {
List<Utilisateur> results = em.createQuery(
"SELECT u FROM Utilisateur u WHERE u.email = :email", Utilisateur.class)
.setParameter("email", email)
.getResultList();
return results.isEmpty() ? null : results.get(0);
}
public void addToSession(int userId, int sessionId) {
EntityTransaction t = em.getTransaction();
try {
if (!t.isActive()) {
t.begin();
}
Session s = em.find(Session.class, sessionId);
Utilisateur u = em.find(Utilisateur.class, userId);
if (s == null || u == null) {
throw new IllegalArgumentException("User or session not found");
}
if (!u.getSessions().contains(s)) {
u.getSessions().add(s);
em.merge(u);
}
t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
throw e;
}
}
@Override
public void create(Utilisateur entity) {
EntityTransaction t = em.getTransaction();
try {
if (!t.isActive()) {
t.begin();
}
em.merge(entity);
t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
throw e;
}
}
}

View File

@@ -1,13 +0,0 @@
package fr.istic.taa.jaxrs.DTO;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.Data;
import java.util.List;
@Data
@XmlRootElement
public class QuestionDTO {
private int id;
private String enonce;
}

View File

@@ -1,14 +0,0 @@
package fr.istic.taa.jaxrs.DTO;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.Data;
import java.util.List;
@Data
@XmlRootElement
public class QuizzDTO {
private int id;
private List<Integer> sessionsId;
private Integer utilisateurId;
private List<Integer> questionsId;
}

View File

@@ -1,11 +0,0 @@
package fr.istic.taa.jaxrs.DTO;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.Data;
import java.util.List;
@Data
@XmlRootElement
public class ReponseDTO {
public List<String> reponses;
}

View File

@@ -1,17 +0,0 @@
package fr.istic.taa.jaxrs.DTO;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.Data;
import java.util.List;
@Data
@XmlRootElement
public class SessionDTO {
private String theme;
private int codePIN;
private int id;
private List<Integer> quizzsId;
private List<Integer> utilisateursId;
}

View File

@@ -1,13 +0,0 @@
package fr.istic.taa.jaxrs.DTO;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.Data;
@Data
@XmlRootElement
public class UtilisateurDTO {
private int id;
private String name;
private String email;
private String password;
}

View File

@@ -1,26 +0,0 @@
package fr.istic.taa.jaxrs.Mapper;
import fr.istic.taa.jaxrs.DTO.QuestionDTO;
import fr.istic.taa.jaxrs.metier.Question;
import fr.istic.taa.jaxrs.metier.Reponse;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface QuestionMapper {
QuestionMapper INSTANCE = Mappers.getMapper( QuestionMapper.class );
QuestionDTO toDTO(Question question);
Question toEntity(QuestionDTO questionDTO);
List<QuestionDTO> toDTOs(List<Question> questionList);
default List<String> question_ReponseString(Reponse reponse){
return reponse.getReponses();
}
}

View File

@@ -1,43 +0,0 @@
package fr.istic.taa.jaxrs.Mapper;
import fr.istic.taa.jaxrs.DTO.QuizzDTO;
import fr.istic.taa.jaxrs.metier.Question;
import fr.istic.taa.jaxrs.metier.Session;
import fr.istic.taa.jaxrs.metier.Quizz;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.util.ArrayList;
import java.util.List;
@Mapper
public interface QuizzMapper {
QuizzMapper INSTANCE = Mappers.getMapper( QuizzMapper.class );
//https://www.baeldung.com/mapstruct-map-source-object-target-list
//https://mapstruct.org/
@Mapping(target="sessionsId", expression="java(function_mapS(quizz.getSessions()))")
@Mapping(target="utilisateurId", source = "createur.id")
@Mapping(target="questionsId",expression="java(function_mapQ(quizz.getQuestions()))")
QuizzDTO toDTO(Quizz quizz);
Quizz toEntity(QuizzDTO quizzDTO);
List<QuizzDTO> toDTOs(List<Quizz> quizzes);
default List<Integer> function_mapQ(List<Question> questionList){
List<Integer> list=new ArrayList<Integer>();
for(Question question : questionList){
list.add(question.getId());
}
return list;
}
default List<Integer> function_mapS(List<Session> sessionList){
List<Integer> list=new ArrayList<Integer>();
for(Session session : sessionList){
list.add(session.getId());
}
return list;
}
}

View File

@@ -1,42 +0,0 @@
package fr.istic.taa.jaxrs.Mapper;
import fr.istic.taa.jaxrs.DTO.SessionDTO;
import fr.istic.taa.jaxrs.metier.Quizz;
import fr.istic.taa.jaxrs.metier.Session;
import fr.istic.taa.jaxrs.metier.Utilisateur;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.util.ArrayList;
import java.util.List;
@Mapper
public interface SessionMapper {
SessionMapper INSTANCE = Mappers.getMapper( SessionMapper.class );
@Mapping(target="utilisateursId",expression="java(function_mapU(session.getUtilisateurs()))")
@Mapping(target="quizzsId",expression="java(function_mapQ(session.getQuizzs()))")
SessionDTO toDTO(Session session);
Session toEntity(SessionDTO sessionDTO);
List<SessionDTO> toDTOs(List<Session> sessions);
//https://www.baeldung.com/mapstruct-map-source-object-target-list
default List<Integer> function_mapU(List<Utilisateur> utilisateurList) {
List<Integer> result = new ArrayList<>();
for (Utilisateur utilisateur : utilisateurList) {
result.add(utilisateur.getId());
}
return result;
}
default List<Integer> function_mapQ(List<Quizz> quizzList) {
List<Integer> result = new ArrayList<>();
for (Quizz quizz : quizzList) {
result.add(quizz.getId());
}
return result;
}
}

View File

@@ -1,19 +0,0 @@
package fr.istic.taa.jaxrs.Mapper;
import fr.istic.taa.jaxrs.DTO.UtilisateurDTO;
import fr.istic.taa.jaxrs.metier.Utilisateur;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface UtilisateurMapper {
UtilisateurMapper INSTANCE = Mappers.getMapper(UtilisateurMapper.class);
UtilisateurDTO toDTO(Utilisateur utilisateur);
Utilisateur toEntity(UtilisateurDTO dto);
List<UtilisateurDTO> toDTOs(List<Utilisateur> utilisateurList);
}

View File

@@ -1,28 +0,0 @@
package fr.istic.taa.jaxrs;
import io.undertow.Undertow;
import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
import java.util.logging.Logger;
/**
* RESTfull microservice, based on JAX-RS and JBoss Undertow
*
*/
public class RestServer {
private static final Logger logger = Logger.getLogger(RestServer.class.getName());
public static void main(String[] args) {
UndertowJaxrsServer ut = new UndertowJaxrsServer();
TestApplication ta = new TestApplication();
ut.deploy(ta);
ut.start(
Undertow.builder()
.addHttpListener(8080, "localhost")
);
logger.info("JAX-RS based micro-service running!");
}
}

View File

@@ -1,45 +0,0 @@
/**
* JBoss, Home of Professional Open Source
* Copyright Red Hat, Inc., and individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package fr.istic.taa.jaxrs;
import java.util.HashSet;
import java.util.Set;
import fr.istic.taa.jaxrs.rest.*;
import io.swagger.v3.jaxrs2.integration.resources.OpenApiResource;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;
@ApplicationPath("/")
public class TestApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> clazzes = new HashSet<Class<?>>();
clazzes.add(OpenApiResource.class);
clazzes.add(QuestionResource.class);
clazzes.add(QuizzResource.class);
clazzes.add(UtilisateurResource.class);
clazzes.add(SessionResource.class);
clazzes.add(SwaggerResource.class);
return clazzes;
}
}

View File

@@ -1,28 +0,0 @@
package fr.istic.taa.jaxrs.metier;
import java.util.List;
import jakarta.persistence.Entity;
import jakarta.persistence.PrimaryKeyJoinColumn;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Getter
@Setter
@NoArgsConstructor
@PrimaryKeyJoinColumn(name = "Choix_Id")
public class Choix extends Reponse{
List<String> choix;
@Override
public String valHTML(){
String res = "";
for (String val : this.choix) {
res+=val+"<br/>";
}
return res;
}
}

View File

@@ -1,21 +0,0 @@
package fr.istic.taa.jaxrs.metier;
import jakarta.persistence.Entity;
import jakarta.persistence.PrimaryKeyJoinColumn;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Getter
@Setter
@NoArgsConstructor
@PrimaryKeyJoinColumn(name = "RC_Id")
public class ReponseCourte extends Reponse{
String value;
@Override
public String valHTML(){
return "INPUT";
}
}

View File

@@ -1,222 +0,0 @@
package fr.istic.taa.jaxrs.rest;
import java.util.List;
import fr.istic.taa.jaxrs.DAO.QuestionDAO;
import fr.istic.taa.jaxrs.DTO.QuestionDTO;
import fr.istic.taa.jaxrs.Mapper.QuestionMapper;
import fr.istic.taa.jaxrs.metier.Choix;
import fr.istic.taa.jaxrs.metier.Question;
import fr.istic.taa.jaxrs.metier.Reponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Response;
@Path("question")
@Consumes({"application/json", "application/xml"})
@Produces({"application/json", "application/xml"})
public class QuestionResource {
private final QuestionDAO questionDAO = new QuestionDAO();
private final QuestionMapper mapper = QuestionMapper.INSTANCE;
@GET
@Operation(summary = "List all questions",
tags = {"Questions"},
description = "List all questions.",
responses = {
@ApiResponse(description = "List of all questions", content = @Content(
array = @ArraySchema(schema = @Schema(implementation = Question.class))))
}
)
public List<QuestionDTO> listQuestion() {
List<Question> questions = questionDAO.findAll();
return mapper.toDTOs(questions);
}
@POST
@Path("/addQuestion")
@Operation(summary = "Create a new question",
tags = {"Questions"},
description = "Create a new question",
responses = {@ApiResponse(responseCode = "201", description = "Question added.")}
)
public Response addQuestion(
@Parameter(description = "The question details to be added", required = true) QuestionDTO dto) {
Question question = mapper.toEntity(dto);
questionDAO.create(question);
return Response.status(Response.Status.CREATED).entity("Question ajouté avec Succès : \"" + dto.getEnonce() + "\"").build();
}
@PUT
@Path("/{question_id}/changeQuestion/")
@Operation(summary = "Update the text of a question",
tags = {"Questions"},
description = "Update the text of a question.",
responses = {
@ApiResponse(responseCode = "201", description = "Question answer updated."),
@ApiResponse(responseCode = "404", description = "Question not found")
}
)
public Response changeQuestion(
@Parameter(description = "ID of the question to modify", required = true) @PathParam("question_id") Integer id,
@Parameter(description = "New answer for the question", required = true) String newQuestion) {
Question question = questionDAO.findById(id);
if (question == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
questionDAO.changeEnonce(newQuestion, id);
return Response.status(Response.Status.CREATED).entity("Enonce de la question mis à jour : " + newQuestion).build();
}
@GET
@Path("/{question_id}/getReponse/")
@Operation(summary = "Get the correct answer for question",
tags = {"Questions"},
description = "Get the correct answer for question by ID of question.",
responses = {
@ApiResponse(description = "The correct answer", content = @Content(
schema = @Schema(implementation = Reponse.class))),
@ApiResponse(responseCode = "404", description = "Question not found")
}
)
public Response getReponse(
@Parameter(description = "ID of the question", required = true)
@PathParam("question_id") Integer id) {
Question question = questionDAO.findById(id);
if (question == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
Reponse result = question.getReponse();
return Response.ok(result).build();
}
@PUT
@Path("/{question_id}/addReponse/")
@Operation(summary = "Add/Update the correct answer for question",
tags = {"Questions"},
description = "Add/Update the correct answer for question",
responses = {
@ApiResponse(responseCode = "201", description = "Answer text updated."),
@ApiResponse(responseCode = "404", description = "Question not found")
}
)
public Response addReponse(
@Parameter(description = "ID of the question", required = true) @PathParam("question_id") Integer id,
@Parameter(description = "The correct answer", required = true) String reponse) {
Question question = questionDAO.findById(id);
if (question == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
questionDAO.addReponse(reponse, id);
return Response.status(Response.Status.CREATED).entity("Reponse correct \"" + reponse + "\" ajouté à la question " + id).build();
}
@DELETE
@Path("/{question_id}/deletReponses/")
@Operation(summary = "Removes the correct response.",
tags = {"Questions"},
description = "Removes the correct response.",
responses = {
@ApiResponse(responseCode = "201", description = "Response deleted."),
@ApiResponse(responseCode = "404", description = "Question not found")
}
)
public Response deleteReponses(
@Parameter(description = "ID of the question", required = true)
@PathParam("question_id") Integer id) {
Question question = questionDAO.findById(id);
if (question == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
questionDAO.deleteReponse(id);
return Response.status(Response.Status.CREATED).entity("Reponses supprimé de la question " + id).build();
}
@PUT
@Path("/{question_id}/setReponse/choix")
@Operation(summary = "Set question type to multiple choice",
tags = {"Questions"},
description = "Set question type to multiple choice type. It could override old answers",
responses = {
@ApiResponse(responseCode = "201", description = "Question type set to multiple choice."),
@ApiResponse(responseCode = "404", description = "Question not found")
}
)
public Response setChoix(
@Parameter(description = "ID of the question", required = true)
@PathParam("question_id") Integer id) {
Question question = questionDAO.findById(id);
if (question == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
questionDAO.setChoix(id);
return Response.status(Response.Status.CREATED).entity("Reponses à choix multiple mise sur la question " + id).build();
}
@PUT
@Path("/{question_id}/setReponse/reponseCourte")
@Operation(summary = "Set question type to short answer",
tags = {"Questions"},
description = "Set question type to multiple short answer. It could override old answers",
responses = {
@ApiResponse(responseCode = "201", description = "Question type set to short answer."),
@ApiResponse(responseCode = "404", description = "Question not found")
}
)
public Response setReponseCourte(
@Parameter(description = "ID of the question", required = true)
@PathParam("question_id") Integer id) {
Question question = questionDAO.findById(id);
if (question == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
questionDAO.setReponseCourte(id);
return Response.status(Response.Status.CREATED).entity("Reponses courte mise sur la question " + id).build();
}
@PUT
@Path("/{question_id}/AddChoix")
@Operation(summary = "Add a choice option to a multiple-choice question",
tags = {"Questions"},
description = "Adds a new choice option to the question (Type Multiple Choice obligatoire)",
responses = {
@ApiResponse(responseCode = "201", description = "Choice added."),
@ApiResponse(responseCode = "404", description = "Question not found"),
@ApiResponse(responseCode = "400", description = "Wrong type")
}
)
public Response addChoix(
@Parameter(description = "ID of the question", required = true) @PathParam("question_id") Integer id,
@Parameter(description = "The choice", required = true) String choix){
Question question = questionDAO.findById(id);
if (question == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
if (question.getReponse() instanceof Choix) {
return Response.status(Response.Status.EXPECTATION_FAILED).build();
}
questionDAO.addChoix(id, choix);
return Response.status(Response.Status.CREATED).entity("Reponses courte mise sur la question " + id).build();
}
}

View File

@@ -1,180 +0,0 @@
package fr.istic.taa.jaxrs.rest;
import java.util.List;
import fr.istic.taa.jaxrs.DAO.QuestionDAO;
import fr.istic.taa.jaxrs.DAO.QuizzDAO;
import fr.istic.taa.jaxrs.DTO.QuestionDTO;
import fr.istic.taa.jaxrs.DTO.QuizzDTO;
import fr.istic.taa.jaxrs.Mapper.QuestionMapper;
import fr.istic.taa.jaxrs.Mapper.QuizzMapper;
import fr.istic.taa.jaxrs.metier.Question;
import fr.istic.taa.jaxrs.metier.Quizz;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Response;
@Path("quizz")
@Consumes({"application/json", "application/xml"})
@Produces({"application/json", "application/xml"})
public class QuizzResource {
public final QuizzMapper mapper = QuizzMapper.INSTANCE;
public final QuizzDAO quizzDAO = new QuizzDAO();
public final QuestionDAO questionDAO = new QuestionDAO();
@POST
@Path("/addQuizz")
@Operation(summary = "Create a new quizz",
tags = {"Quizz"},
description = "Create a new quizz",
responses = {@ApiResponse(responseCode = "201", description = "Quizz added.")}
)
public Response addQuizz(
@Parameter(description = "The quizz details to be added", required = true) QuizzDTO dto) {
Quizz quizz = mapper.toEntity(dto);
quizzDAO.create(quizz);
return Response.status(Response.Status.CREATED).entity("Quizz ajouté avec Succès : \"" + dto.getId() + "\"").build();
}
@GET
@Operation(summary = "List all quizz",
tags = {"Quizz"},
description = "List all quizz.",
responses = {
@ApiResponse(description = "List of all quizz", content = @Content(
array = @ArraySchema(schema = @Schema(implementation = Question.class))))
}
)
public List<QuizzDTO> listQuizz() {
List<Quizz> quizz = quizzDAO.findAll();
return mapper.toDTOs(quizz);
}
@GET
@Path("/{quizz_id}")
@Operation(summary = "Get a quizz by ID",
tags = {"Quizzes"},
description = "Get a quizz by ID",
responses = {
@ApiResponse(description = "The quizz by ID", content = @Content(
schema = @Schema(implementation = QuizzDTO.class))),
@ApiResponse(responseCode = "404", description = "Quizz not found")
}
)
public Response getQuizzById(
@Parameter(description = "ID of the quizz to fetch", required = true)
@PathParam("quizz_id") Integer quizzId) {
Quizz quizz = quizzDAO.findById(quizzId);
if (quizz == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
QuizzDTO dto = mapper.toDTO(quizz);
return Response.status(Response.Status.OK).entity(dto).build();
}
@GET
@Path("/{quizz_id}/questions")
@Operation(summary = "List all questions for a quizz",
tags = {"Quizzes"},
description = "List all questions by quizz ID.",
responses = {
@ApiResponse(description = "List of questions", content = @Content(
array = @ArraySchema(schema = @Schema(implementation = QuestionDTO.class)))),
@ApiResponse(responseCode = "404", description = "Quizz not found")
}
)
public Response getQuestions(
@Parameter(description = "ID of the quizz", required = true)
@PathParam("quizz_id") Integer quizzId) {
Quizz quizz = quizzDAO.findById(quizzId);
if (quizz == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
List<Question> questionList = quizz.getQuestions();
List<QuestionDTO> dtos = QuestionMapper.INSTANCE.toDTOs(questionList);
return Response.status(Response.Status.OK).entity(dtos).build();
}
@PUT
@Path("/{quizz_id}/add_question/{question_id}")
@Operation(summary = "Add a question to a quizz",
tags = {"Quizzes"},
description = "Add question to quizz by quizz ID and question ID.",
responses = {
@ApiResponse(responseCode = "200", description = "Question added successfully",
content = @Content(schema = @Schema(implementation = QuizzDTO.class))),
@ApiResponse(responseCode = "404", description = "Quizz or Question not found")
}
)
public Response addQuestion(
@Parameter(description = "ID of the quizz to update", required = true) @PathParam("quizz_id") Integer quizzId,
@Parameter(description = "ID of the question to add", required = true) @PathParam("question_id") Integer questionId) {
Quizz quizz = quizzDAO.findById(quizzId);
Question question = questionDAO.findById(questionId);
if (quizz == null || question == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
quizzDAO.addQuestion(quizzId, questionId);
quizzDAO.update(quizz);
QuizzDTO quizzDTO = mapper.toDTO(quizz);
return Response.status(Response.Status.OK).entity(quizzDTO).build();
}
@PUT
@Path("/{quizz_id}/deleteQ")
@Operation(summary = "Remove all questions from a quizz",
tags = {"Quizzes"},
description = "Removes all questions by ID of quizz.",
responses = {
@ApiResponse(responseCode = "200", description = "Removed all questions"),
@ApiResponse(responseCode = "404", description = "Quizz not found")}
)
public Response deleteQuestion(
@Parameter(description = "ID of the quizz", required = true)
@PathParam("quizz_id") Integer quizzId) {
Quizz quizz = quizzDAO.findById(quizzId);
if (quizz == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
quizzDAO.deleteAllQuestion(quizzId);
quizzDAO.update(quizz);
return Response.status(Response.Status.OK).build();
}
@DELETE
@Path("/{quizz_id}/delete")
@Operation(summary = "Delete a Quizz",
tags = {"Quizzes"},
description = "Deletes a Quizz by ID.",
responses = {
@ApiResponse(responseCode = "200", description = "Quizz deleted."),
@ApiResponse(responseCode = "404", description = "Quizz not found.")
}
)
public Response deleteQuizz(
@Parameter(description = "ID of the Quizz to delete", required = true)
@PathParam("quizz_id") Integer quizzId) {
Quizz quizz = quizzDAO.findById(quizzId);
if (quizz == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
quizzDAO.delete(quizz);
return Response.status(Response.Status.OK).build();
}
}

View File

@@ -1,158 +0,0 @@
package fr.istic.taa.jaxrs.rest;
import java.util.List;
import fr.istic.taa.jaxrs.DAO.SessionDAO;
import fr.istic.taa.jaxrs.DTO.QuizzDTO;
import fr.istic.taa.jaxrs.DTO.SessionDTO;
import fr.istic.taa.jaxrs.DTO.UtilisateurDTO;
import fr.istic.taa.jaxrs.Mapper.QuizzMapper;
import fr.istic.taa.jaxrs.Mapper.SessionMapper;
import fr.istic.taa.jaxrs.Mapper.UtilisateurMapper;
import fr.istic.taa.jaxrs.metier.Quizz;
import fr.istic.taa.jaxrs.metier.Session;
import fr.istic.taa.jaxrs.metier.Utilisateur;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Response;
@Path("session")
@Consumes({"application/json", "application/xml"})
@Produces({"application/json", "application/xml"})
public class SessionResource {
private final SessionDAO sessionDAO = new SessionDAO();
private final SessionMapper mapper = SessionMapper.INSTANCE;
@POST
@Path("/addSession")
@Operation(summary = "Create a new session",
tags = {"Session"},
description = "Create a new session",
responses = {@ApiResponse(responseCode = "201", description = "Session added.")}
)
public Response addQuizz(
@Parameter(description = "The session details to be added", required = true) SessionDTO dto) {
Session session = mapper.toEntity(dto);
sessionDAO.create(session);
return Response.status(Response.Status.CREATED).entity("Session ajouté avec Succès : \"" + dto.getTheme() + "\"").build();
}
@GET
@Operation(summary = "List all session", tags = {"Sessions"},
description = "Get a list of all sessions in BDD",
responses = {@ApiResponse(description = "List of sessions", content = @Content(
schema = @Schema(implementation = Session.class)
))
}
)
public List<SessionDTO> listSession() {
List<Session> sessions = sessionDAO.findAll();
return mapper.toDTOs(sessions);
}
@GET
@Path("/{id}")
@Operation(summary = "Get session by ID",
tags = {"Sessions"},
description = "Get session by ID.",
responses = {
@ApiResponse(description = "Session", content = @Content(
schema = @Schema(implementation = SessionDTO.class)
)),
@ApiResponse(responseCode = "404", description = "Session not found")
}
)
public Response getSession(
@Parameter(description = "ID of the session to fetch", required = true)
@PathParam("id") Integer id) {
Session session = sessionDAO.findById(id);
if (session == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
SessionDTO result = mapper.toDTO(session);
return Response.status(Response.Status.OK).entity(result).build();
}
@GET
@Path("/{session_id}/quizzs")
@Operation(summary = "Get all quizzes for a session",
tags = {"Sessions"},
description = "Get all quizzes for a session by ID of session.",
responses = {
@ApiResponse(description = "List of quizzes", content = @Content(
array = @ArraySchema(schema = @Schema(implementation = QuizzDTO.class))
)),
@ApiResponse(responseCode = "404", description = "Session not found")
}
)
public Response getQuizzs(
@Parameter(description = "ID of the session to get quizzes", required = true)
@PathParam("session_id") Integer sessionId) {
Session session = sessionDAO.findById(sessionId);
if (session == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
List<QuizzDTO> results = QuizzMapper.INSTANCE.toDTOs(session.getQuizzs());
return Response.status(Response.Status.OK).entity(results).build();
}
@GET
@Path("/{session_id}/utilisateurs")
@Operation(summary = "Get all users for a session",
tags = {"Sessions"},
description = "Get all users for a session by ID of session.",
responses = {
@ApiResponse(description = "List of users", content = @Content(
array = @ArraySchema(schema = @Schema(implementation = UtilisateurDTO.class))
)),
@ApiResponse(responseCode = "404", description = "Session not found")
}
)
public Response getUtilisateurs(
@Parameter(description = "ID of the session to get users", required = true)
@PathParam("session_id") Integer sessionId) {
Session session = sessionDAO.findById(sessionId);
if (session == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
List<Utilisateur> utilisateurList = session.getUtilisateurs();
List<UtilisateurDTO> dtos = UtilisateurMapper.INSTANCE.toDTOs(utilisateurList);
return Response.status(Response.Status.OK).entity(dtos).build();
}
@DELETE
@Path("/{session_id}/delete")
@Operation(summary = "Delete a session",
tags = {"Sessions"},
description = "Deletes a session by ID of session.",
responses = {
@ApiResponse(responseCode = "200", description = "Session deleted"),
@ApiResponse(responseCode = "404", description = "Session not found")
}
)
public Response deleteSession(
@Parameter(description = "ID of the session to delete", required = true)
@PathParam("session_id") Integer sessionId) {
Session session = sessionDAO.findById(sessionId);
if (session == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
sessionDAO.delete(session);
return Response.status(Response.Status.OK).entity("Session deleted").build();
}
}

View File

@@ -1,45 +0,0 @@
package fr.istic.taa.jaxrs.rest;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.util.logging.Logger;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.core.Response;
@Path("/api")
public class SwaggerResource {
private static final Logger logger = Logger.getLogger(SwaggerResource.class.getName());
private static final String SWAGGER_BASE_PATH = "swagger/";
@GET
public Response Get1() {
return getFileContent("index.html");
}
@GET
@Path("{path:.*}")
public Response Get(@PathParam("path") String path) {
return getFileContent(path);
}
private Response getFileContent(String fileName) {
String fullPath = SWAGGER_BASE_PATH + fileName;
try (InputStream is = getClass().getClassLoader().getResourceAsStream(fullPath)) {
if (is == null) {
logger.warning("File not found: " + fullPath);
return Response.status(Response.Status.NOT_FOUND).build(); // HTTP 404
}
return Response.ok(is.readAllBytes()).build();
} catch (IOException e) {
logger.severe("Error reading file " + fullPath + ": " + e.getMessage());
return Response.serverError().build(); // HTTP 500
}
}
}

View File

@@ -1,204 +0,0 @@
package fr.istic.taa.jaxrs.rest;
import fr.istic.taa.jaxrs.DAO.SessionDAO;
import fr.istic.taa.jaxrs.DAO.UtilisateurDAO;
import fr.istic.taa.jaxrs.DTO.SessionDTO;
import fr.istic.taa.jaxrs.DTO.UtilisateurDTO;
import fr.istic.taa.jaxrs.Mapper.SessionMapper;
import fr.istic.taa.jaxrs.Mapper.UtilisateurMapper;
import fr.istic.taa.jaxrs.metier.Question;
import fr.istic.taa.jaxrs.metier.Session;
import fr.istic.taa.jaxrs.metier.Utilisateur;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.Response;
import java.util.List;
@Path("utilisateur")
@Consumes({"application/json", "application/xml"})
@Produces({"application/json", "application/xml"})
public class UtilisateurResource {
private final UtilisateurDAO utilisateurDAO = new UtilisateurDAO();
private final UtilisateurMapper mapper = UtilisateurMapper.INSTANCE;
@GET
@Operation(summary = "List all users", tags = {"Utilisateurs"},
description = "Get a list of all users in BDD",
responses = {@ApiResponse(description = "List of users", content = @Content(
schema = @Schema(implementation = Utilisateur.class)
))
}
)
public List<UtilisateurDTO> listUtilisateur() {
List<Utilisateur> utilisateurs = utilisateurDAO.findAll();
return mapper.toDTOs(utilisateurs);
}
//https://stackoverflow.com/questions/9269040/which-http-response-code-for-this-email-is-already-registered
@POST
@Path("/register")
@Operation(summary = "Register a new user",
tags = {"Utilisateurs"},
description = "Registers a new user.",
responses = {
@ApiResponse(responseCode = "201", description = "Registration succès"),
@ApiResponse(responseCode = "409", description = "Email est déjà registré")
}
)
public Response registerUtilisateur(
@Parameter(description = "User details for registration", required = true) UtilisateurDTO dto) {
String email_verification = dto.getEmail();
Utilisateur existing = utilisateurDAO.findByEmail(email_verification);
//VERIFACTION S'IL EXISTE DANS BDD
if (existing != null) {
return Response.status(Response.Status.CONFLICT).entity("Email est déjà registré").build();
}
Utilisateur utilisateur = mapper.toEntity(dto);
utilisateurDAO.create(utilisateur);
return Response.status(Response.Status.CREATED).entity("Registration succès").build();
}
@POST
@Path("/login")
@Operation(summary = "Log in a user",
tags = {"Utilisateurs"},
description = "Authenticates a user and returns the user's details upon success.",
responses = {
@ApiResponse(responseCode = "200", description = "Successful login", content = @Content(
schema = @Schema(implementation = UtilisateurDTO.class)
)),
@ApiResponse(responseCode = "404", description = "Email n'existe pas"),
@ApiResponse(responseCode = "401", description = "Mauvais mdp")
}
)
public Response loginUtilisateur(
@Parameter(description = "User credentials (email and password)", required = true) UtilisateurDTO dto) {
Utilisateur utilisateur = utilisateurDAO.findByEmail(dto.getEmail());
if (utilisateur == null) {
return Response.status(Response.Status.NOT_FOUND).entity("Email n'existe pas").build();
} else if (!utilisateur.getPassword().equals(dto.getPassword())) {
return Response.status(Response.Status.UNAUTHORIZED).entity("Mauvais mdp").build();
}
UtilisateurDTO result = mapper.toDTO(utilisateur);
return Response.status(Response.Status.OK).entity(result).build();
}
@GET
@Path("/{id}")
@Operation(summary = "Get user by ID",
tags = {"Utilisateurs"},
description = "Get User by ID",
responses = {
@ApiResponse(description = "Utilisateur", content = @Content(
schema = @Schema(implementation = Utilisateur.class)
)),
@ApiResponse(responseCode = "400", description = "Invalid ID supplied"),
@ApiResponse(responseCode = "404", description = "User not found")
})
public Response getUtilisateur(@Parameter(
description = "ID of user that needs to be fetched",
schema = @Schema(
type = "integer",
format = "int32",
description = "param ID of user that needs to be fetched"
),
required = true)
@PathParam("id") Integer id) {
Utilisateur utilisateur = utilisateurDAO.findById(id);
if (utilisateur == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
UtilisateurDTO result = mapper.toDTO(utilisateur);
return Response.ok(result).build();
}
@PUT
@Path("/{user_id}/add_session/{session_id}")
@Operation(summary = "Add a session to a user",
tags = {"Utilisateurs"},
description = "Add a session to a user existed in BDD",
responses = {
@ApiResponse(responseCode = "200", description = "Session added successfully", content = @Content(
schema = @Schema(implementation = UtilisateurDTO.class) // Returns updated user DTO
)),
@ApiResponse(responseCode = "404", description = "User or Session not found"),
@ApiResponse(responseCode = "409", description = "User is already in the session")
}
)
public Response addSession(
@Parameter(description = "ID of the user") @PathParam("user_id") Integer user_id,
@Parameter(description = "ID of the session to add") @PathParam("session_id") Integer session_id) {
SessionDAO sessionDAO = new SessionDAO();
Session existingSession = sessionDAO.findById(session_id);
Utilisateur utilisateur = utilisateurDAO.findById(user_id);
if (existingSession == null || utilisateur == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
//If user already joined
if (utilisateur.getSessions().contains(existingSession)) {
return Response.status(Response.Status.CONFLICT).build();
}
utilisateurDAO.addToSession(user_id, session_id);
utilisateurDAO.update(utilisateur);
// We update it so have to return new DTO
UtilisateurDTO dto = mapper.toDTO(utilisateur);
return Response.status(Response.Status.OK).entity(dto).build();
}
@GET
@Path("{user_id}/session")
@Operation(summary = "List of all sessions of a user",
tags = {"Utilisateurs"},
description = "Return a response of all sessions of a user",
responses = {
@ApiResponse(responseCode = "200", description = "List of user's sessions", content = @Content(
schema = @Schema(implementation = SessionDTO.class)
)),
@ApiResponse(responseCode = "404", description = "User not found")
}
)
public Response listSession(
@Parameter(description = "ID of the user") @PathParam("user_id") Integer user_id) {
Utilisateur utilisateur = utilisateurDAO.findById(user_id);
if (utilisateur == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
List<Session> sess = utilisateur.getSessions();
List<SessionDTO> dtos = SessionMapper.INSTANCE.toDTOs(sess);
return Response.status(Response.Status.OK).entity(dtos).build();
}
@DELETE
@Path("{user_id}/delete")
@Operation(summary = "Delete a user",
tags = {"Utilisateurs"},
description = "Delete a user with ID",
responses = {
@ApiResponse(responseCode = "200", description = "User deleted"),
@ApiResponse(responseCode = "404", description = "User not found")
}
)
public Response deleteUtilisateur(
@Parameter(description = "ID of the user to delete") @PathParam("user_id") Integer user_id) {
Utilisateur existing = utilisateurDAO.findById(user_id);
if (existing == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
utilisateurDAO.delete(existing);
return Response.status(Response.Status.OK).build();
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.data.jpa;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SampleDataJpaApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleDataJpaApplication.class, args);
}
}

View File

@@ -0,0 +1,41 @@
package sample.data.jpa;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/").permitAll()
.requestMatchers("/index").hasAuthority("USER")
.requestMatchers("/admin").hasAuthority("ADMIN")
.requestMatchers("/session/**").hasAnyAuthority("USER", "ADMIN")
.requestMatchers("/quizz/**").hasAuthority("ADMIN")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtToken -> {
Map<String, Collection<String>> realmAccess = jwtToken.getClaim("realm_access");
Collection<String> roles = realmAccess.get("roles");
List<SimpleGrantedAuthority> grantedAuthorities = roles.stream()
.map(role -> new SimpleGrantedAuthority(role.toUpperCase()))
.toList();
return new JwtAuthenticationToken(jwtToken, grantedAuthorities);
}))
);
return http.build();
}
}

View File

@@ -0,0 +1,38 @@
package sample.data.jpa.controller;
import java.security.Principal;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class ViewController {
@GetMapping("/index")
@PreAuthorize("hasRole('USER')")
public ModelAndView index(JwtAuthenticationToken authentication) {
ModelAndView modelAndView = new ModelAndView("index");
authentication.getToken().getClaims().forEach((e, v) -> {
System.err.println(e + ' ' + v);
});
modelAndView.addObject("user", authentication);
return modelAndView;
}
@GetMapping("/")
public ModelAndView main() {
ModelAndView modelAndView = new ModelAndView("indexmain");
return modelAndView;
}
@GetMapping("/admin")
@PreAuthorize("hasRole('ADMIN')")
public ModelAndView admin(Principal principal) {
ModelAndView modelAndView = new ModelAndView("admin");
modelAndView.addObject("user", principal);
return modelAndView;
}
}

View File

@@ -0,0 +1,53 @@
package sample.data.jpa.metier;
import java.util.ArrayList;
import java.util.List;
import jakarta.persistence.Entity;
import jakarta.persistence.PrimaryKeyJoinColumn;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Getter
@Setter
@NoArgsConstructor
@PrimaryKeyJoinColumn(name = "Choix_Id")
public class Choix extends Reponse{
List<String> choix = new ArrayList<String>();;
@Override
public String valHTML(){
String res = "";
for (String val : this.choix) {
res+=val+"<br/>";
}
return res;
}
public String prettyPrinter(int tab){
String tabStr = "";
for(int i =0; i<tab;i++)tabStr+="\t";
String res = "";
res += tabStr+"choix : [";
for (int i = 0; i<this.choix.size(); i++) {
res += this.choix.get(i);
if(i<this.choix.size()-1) res+= ", ";
}
res += "]\n";
res += tabStr +"reponses : [";
for (int i = 0; i<this.reponses.size(); i++) {
res += this.reponses.get(i);
if(i<this.reponses.size()-1) res+= ", ";
}
res += "]\n";
return res;
}
}

View File

@@ -1,7 +1,6 @@
package fr.istic.taa.jaxrs.metier; package sample.data.jpa.metier;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
@@ -12,7 +11,6 @@ import java.io.Serializable;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@XmlRootElement
public class Question implements Serializable { public class Question implements Serializable {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -26,4 +24,16 @@ public class Question implements Serializable {
@ManyToOne @ManyToOne
@JoinColumn(name="id_quizz") @JoinColumn(name="id_quizz")
private Quizz quizz; private Quizz quizz;
public String prettyPrinter(int tab){
String res = "";
String tabStr = "";
for(int i =0; i<tab;i++)tabStr+="\t";
res += tabStr + "id : " + this.getId() + "\n";
res += tabStr + "ennonce : \"" + this.getEnonce() + "\"\n";
res += this.getReponse().prettyPrinter(tab);;
return res;
}
} }

View File

@@ -1,7 +1,6 @@
package fr.istic.taa.jaxrs.metier; package sample.data.jpa.metier;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
@@ -14,14 +13,13 @@ import java.util.List;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@XmlRootElement
public class Quizz implements Serializable { public class Quizz implements Serializable {
@Id @Id
@GeneratedValue @GeneratedValue
private int id; private int id;
@ManyToMany @ManyToMany
private List<Session> sessions; private List<Session> sessions = new ArrayList<Session>();
@ManyToOne @ManyToOne
@JoinColumn(name="id_utilisateur") @JoinColumn(name="id_utilisateur")

View File

@@ -1,4 +1,4 @@
package fr.istic.taa.jaxrs.metier; package sample.data.jpa.metier;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
@@ -28,4 +28,18 @@ public abstract class Reponse implements Serializable {
public String valHTML(){ public String valHTML(){
return ""; return "";
} }
public String prettyPrinter(int tab){
return "";
}
public String toString(){
String res = "[";
for (int i = 0; i<this.reponses.size(); i++) {
res += this.reponses.get(i);
if(i<this.reponses.size()-1) res+= ", ";
}
res += "]";
return res;
}
} }

View File

@@ -0,0 +1,37 @@
package sample.data.jpa.metier;
import jakarta.persistence.Entity;
import jakarta.persistence.PrimaryKeyJoinColumn;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Getter
@Setter
@NoArgsConstructor
@PrimaryKeyJoinColumn(name = "RC_Id")
public class ReponseCourte extends Reponse{
@Override
public String valHTML(){
return "INPUT";
}
public String prettyPrinter(int tab){
String tabStr = "";
for(int i =0; i<tab;i++)tabStr+="\t";
String res = tabStr+"INPUT\n";
res += tabStr +"reponses : [";
for (int i = 0; i<this.reponses.size(); i++) {
res += this.reponses.get(i);
if(i<this.reponses.size()-1) res+= ", ";
}
res += "]\n";
return res;
}
}

View File

@@ -1,11 +1,10 @@
package fr.istic.taa.jaxrs.metier; package sample.data.jpa.metier;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
@@ -14,7 +13,6 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@XmlRootElement
public class Session implements Serializable { public class Session implements Serializable {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -23,10 +21,10 @@ public class Session implements Serializable {
@Column(unique=true) @Column(unique=true)
private int codePIN; private int codePIN;
@ManyToMany(mappedBy="sessions", fetch = FetchType.EAGER) @ManyToMany(mappedBy="sessions")
private List<Quizz> quizzs = new ArrayList<>(); private List<Quizz> quizzs = new ArrayList<>();
@ManyToMany(mappedBy = "sessions", fetch = FetchType.EAGER) @ManyToMany(mappedBy = "sessions")
private List<Utilisateur> utilisateurs = new ArrayList<>(); private List<Utilisateur> utilisateurs = new ArrayList<>();
private String theme; private String theme;
} }

View File

@@ -1,7 +1,6 @@
package fr.istic.taa.jaxrs.metier; package sample.data.jpa.metier;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.*; import lombok.*;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
@@ -11,13 +10,16 @@ import java.util.List;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@XmlRootElement
public class Utilisateur implements Serializable { public class Utilisateur implements Serializable {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private int id; private int id;
private String name; private String name;
//Pour génénrer un sub diff pour chaque persone
@Column(unique = true)
private String keycloakId;
@Column(unique=true) @Column(unique=true)
private String email; private String email;
private String password; private String password;
@@ -28,8 +30,8 @@ public class Utilisateur implements Serializable {
joinColumns = @JoinColumn(name="utilisateur_id"), joinColumns = @JoinColumn(name="utilisateur_id"),
inverseJoinColumns = @JoinColumn(name = "session_id") inverseJoinColumns = @JoinColumn(name = "session_id")
) )
private List<Session> sessions= new ArrayList<Session>(); private List<Session> sessions= new ArrayList<>();
@OneToMany(mappedBy = "createur") @OneToMany(mappedBy = "createur")
private List<Quizz> quizzs = new ArrayList<Quizz>();; private List<Quizz> quizzs = new ArrayList<>();
} }

View File

@@ -0,0 +1,10 @@
package sample.data.jpa.service;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.transaction.annotation.Transactional;
import sample.data.jpa.metier.Question;
@Transactional
public interface QuestionDao extends JpaRepository<Question, Integer> {
}

View File

@@ -0,0 +1,11 @@
package sample.data.jpa.service;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.transaction.annotation.Transactional;
import sample.data.jpa.metier.Quizz;
@Transactional
public interface QuizzDao extends JpaRepository<Quizz, Integer> {
}

View File

@@ -0,0 +1,11 @@
package sample.data.jpa.service;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.transaction.annotation.Transactional;
import sample.data.jpa.metier.Reponse;
@Transactional
public interface ReponseDao extends JpaRepository<Reponse, Integer> {
}

View File

@@ -0,0 +1,9 @@
package sample.data.jpa.service;
import org.springframework.data.jpa.repository.JpaRepository;
import sample.data.jpa.metier.Session;
public interface SessionDao extends JpaRepository<Session, Integer> {
boolean existsByCodePIN(int codePIN);
}

View File

@@ -0,0 +1,9 @@
package sample.data.jpa.service;
import org.springframework.data.jpa.repository.JpaRepository;
import sample.data.jpa.metier.Utilisateur;
public interface UtilisateurDao extends JpaRepository<Utilisateur, Integer> {
Utilisateur findByKeycloakId(String keycloakId);
}

View File

@@ -0,0 +1,188 @@
package sample.data.jpa.web;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.security.access.prepost.PreAuthorize;
import sample.data.jpa.metier.Question;
import sample.data.jpa.metier.Reponse;
import sample.data.jpa.service.QuestionDao;
import sample.data.jpa.service.ReponseDao;
@Controller
@RequestMapping("/question")
public class QuestionController {
@Autowired
private QuestionDao qDao;
@Autowired
private ReponseDao rDao;
/*
Post /question/create param : body Jsp, "enonce"
Put /question/update/{id} param : body Jsp, "enonce"
Get /question/getAll
Get /question/get/{id}
Get /question/getReponse/{id}
Put /question/removeReponse
Put /question/setReponse/{id}/{idReponse}
Delete /question/delete/{id}
*/
/*
* Utiliser un Json pour mettre : String enonce
*/
@PostMapping("/create")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String create(@RequestBody Map<String, String> body) {
String qId = "";
Question q = new Question();
try {
if (body.containsKey("enonce")) {
q.setEnonce(body.get("enonce"));
} else q.setEnonce("");
qDao.save(q);
qId = String.valueOf(q.getId());
} catch (Exception ex) {
return "Error creating the question : " + ex.toString();
}
return "Question \"" + q.getEnonce() + "\" succesfully created with id = " + qId;
}
/*
* Utiliser un Json pour mettre le String "enonce"
* l'id se met dans l'url
*/
@PutMapping("/update/{id}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String update(@PathVariable("id") int id, @RequestBody Map<String, String> body) {
Question q;
try {
q = qDao.findById(id).get();
q.setEnonce(body.get("enonce"));
qDao.save(q);
} catch (Exception ex) {
return "Error updating the question: " + ex.toString();
}
return "Question " + id + " succesfully updated! : " + q.getEnonce();
}
@GetMapping("/get/{id}")
@ResponseBody
@PreAuthorize("hasAnyRole('ADMIN','USER')")
public String get(@PathVariable("id") int id) {
Question q;
String res = "";
try {
q = qDao.findById(id).get();
res=q.prettyPrinter(0);
}
catch (Exception ex) {
return "Erreur lors de la récupération de la question : " + ex.toString();
}
return res;
}
@GetMapping("/getAll")
@ResponseBody
@PreAuthorize("hasAnyRole('ADMIN','USER')")
public String getAll() {
try {
List<Question> questions = qDao.findAll();
String res = "";
for (Question question : questions) {
res += "id: " + question.getId() + " , ";
res += "enonce: \"" + question.getEnonce() + "\"\n";
}
return res;
} catch (Exception ex) {
return "Erreur lors de la récupération des question : " + ex.toString();
}
}
@GetMapping("/getReponses/{id}")
@ResponseBody
@PreAuthorize("hasAnyRole('ADMIN','USER')")
public String getReponses(@PathVariable("id") int id) {
try {
Question question = qDao.findById(id).get();
Reponse rep = question.getReponse();
if (rep != null) {
List<String> reponses = rep.getReponses();
String res = "[";
for (int i = 0; i < reponses.size(); i++) {
res += reponses.get(i);
if (i < reponses.size() - 1) {
res += ",";
}
}
res += "]";
return "Réponse de la question " + id + " : " + res;
} else return "Réponse non initialisée pour la question : " + id;
} catch (Exception ex) {
return "Erreur lors de la récupération de la réponse : " + ex.toString();
}
}
@PutMapping("/removeReponse/{id}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String removeReponse(@PathVariable("id") int id) {
try {
Question question = qDao.findById(id).get();
Reponse reponse = question.getReponse();
reponse.setQuestion(null);
question.setReponse(null);
qDao.save(question);
rDao.save(reponse);
return "Reponses retiré de la question " + id;
} catch (Exception ex) {
return "Erreur lors de la mise en place de la Reponse : " + ex.toString();
}
}
@PutMapping("/setReponse/{id}/{idR}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String setReponse(@PathVariable("id") int id, @PathVariable("idR") int idR) {
try {
Question question = qDao.findById(id).get();
Reponse reponse = rDao.findById(idR).get();
question.setReponse(reponse);
reponse.setQuestion(question);
qDao.save(question);
rDao.save(reponse);
return "Reponses " + idR + " mises sur la question " + id;
} catch (Exception ex) {
return "Erreur lors de la mise en place de la Reponse : " + ex.toString();
}
}
@DeleteMapping("/delete/{id}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String delete(@PathVariable("id") int id) {
try {
Question q = qDao.findById(id).get();
qDao.delete(q);
} catch (Exception ex) {
return "Error deleting the question " + id + " :" + ex.toString();
}
return "Question " + id + " succesfully deleted!";
}
}

View File

@@ -0,0 +1,179 @@
package sample.data.jpa.web;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
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.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import sample.data.jpa.metier.Question;
import sample.data.jpa.metier.Quizz;
import sample.data.jpa.metier.Reponse;
import sample.data.jpa.metier.Session;
import sample.data.jpa.metier.Utilisateur;
import sample.data.jpa.service.QuestionDao;
import sample.data.jpa.service.QuizzDao;
import sample.data.jpa.service.UtilisateurDao;
@Controller
@RequestMapping("/quizz")
public class QuizzController {
@Autowired
private QuizzDao qDao;
@Autowired
private QuestionDao qtDao;
@Autowired
private UtilisateurDao uDao;
/*
Post /quizz/create
Delete /quizz/delete/{id}
Put /quizz/addQuestion/{idQuestion}/{idQuizz}
Put /quizz/removeQuestion/{idQuestin}/{idQuizz}
Get /quizz/getAll
Get /quizz/getQuestions/{id}
*/
@PostMapping("/create/{id}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String create(@PathVariable("id") int id) {
String qId = "";
String emailU = "";
try {
Quizz q = new Quizz();
Utilisateur u = uDao.findById(id).get();
emailU = u.getEmail();
q.setCreateur(u);
qDao.save(q);
qId = String.valueOf(q.getId());
} catch (Exception ex) {
return "Error creating the Quizz : " + ex.toString();
}
return "Quizz succesfully created by "+ emailU +" with id = " + qId;
}
@DeleteMapping("/delete/{id}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String delete(@PathVariable("id") int id) {
try {
Quizz q = qDao.findById(id).get();
qDao.delete(q);
} catch (Exception ex) {
return "Error deleting the quizz " + id + " :" + ex.toString();
}
return "Quizz " + id + " succesfully deleted!";
}
@PutMapping("/addQuestion/{id}/{idQ}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String addQuestion(@PathVariable("id") int id, @PathVariable("idQ") int qId) {
try {
Quizz q = qDao.findById(id).get();
Question qt = qtDao.findById(qId).get();
q.getQuestions().add(qt);
qt.setQuizz(q);
qDao.save(q);
} catch (Exception ex) {
return "Error adding question from the quizz " + id + " :" + ex.toString();
}
return "Question " + qId + " add in Quizz " + id;
}
@PutMapping("/removeQuestion/{id}/{idQ}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String removeQuestion(@PathVariable("id") int id, @PathVariable("idQ") int qId) {
try {
Quizz q = qDao.findById(id).get();
Question qt = qtDao.findById(qId).get();
q.getQuestions().remove(qt);
qt.setQuizz(null);
qDao.save(q);
} catch (Exception ex) {
return "Error removing question from the quizz " + id + " :" + ex.toString();
}
return "Question remove from Quizz " + id;
}
@GetMapping("/get/{id}")
@ResponseBody
@PreAuthorize("hasAnyRole('ADMIN', 'USER')")
public String get(@PathVariable("id") int id){
String res = "";
try {
Quizz q = qDao.findById(id).get();
res += "id : " + id + "\n";
if(q.getCreateur()!=null){
res += "create by : " + q.getCreateur().getId() +
" (" + q.getCreateur().getEmail() + ")\n";
}
List<Session> sessions = q.getSessions();
List<Question> questions = q.getQuestions();
res += "Sessions :\n";
for(Session session : sessions){
res += "\tid : " + session.getId()
+" , theme : " + session.getTheme()
+" , nbUtilisateur : " + session.getUtilisateurs().size()
+" , PIN : " + session.getCodePIN()+"\n";
}
res += "Question :\n";
for( int i = 0; i<questions.size(); i++){
res+="\tQ"+(i+1)+"\n";
res+=questions.get(i).prettyPrinter(2);
}
}
catch (Exception ex) {
return "Error get Quizz :" + ex.toString();
}
return "Quizz : \n" + res;
}
@GetMapping("/getAll")
@ResponseBody
@PreAuthorize("hasAnyRole('ADMIN', 'USER')")
public String getAll() {
String res = "";
try {
List<Quizz> quizzs = qDao.findAll();
for (Quizz quizz : quizzs) {
res += "id: " + quizz.getId() + " , ";
res += " nbQuestion:" + quizz.getQuestions().size() + "]\n";
}
} catch (Exception ex) {
return "Error get all Quizz :" + ex.toString();
}
return "Quizzs : \n" + res;
}
@GetMapping("/getQuestions/{id}")
@ResponseBody
@PreAuthorize("hasAnyRole('ADMIN', 'USER')")
public String getQuestion(@PathVariable("id") int id) {
String res = "";
try {
;
Quizz quizz = qDao.findById(id).get();
for (Question question : quizz.getQuestions()) {
res += "id: " + question.getId() + " , ";
res += "enonce: \"" + question.getEnonce() + "\"\n";
}
} catch (Exception ex) {
return "Error get question of the Quizz :" + ex.toString();
}
return "Questions : \n" + res;
}
}

View File

@@ -0,0 +1,191 @@
package sample.data.jpa.web;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
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.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import sample.data.jpa.metier.Choix;
import sample.data.jpa.metier.Reponse;
import sample.data.jpa.metier.ReponseCourte;
import sample.data.jpa.service.ReponseDao;
@Controller
@RequestMapping("/reponse")
public class ReponseController {
@Autowired
private ReponseDao rDao;
/*
Post /reponse/create/choix
Post /reponse/create/courte
Get /reponse/getAll
Get /reponse/get/{id}
Delete /reponse/delete/{id}
Put /reponse/removeReponse/{id} param : body Jsp, "reponse"
Put /reponse/addReponse/{id} param : body Jsp, "reponse"
Put /reponse/addChoix/{id} param : body Jsp, "choix"
Put /reponse/removeChoix/{id} param : body Jsp, "choix"
*/
/*
* Créer une réponse de type Choix
*/
@PostMapping("/create/choix")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String createReponseChoix() {
try {
Choix r = new Choix();
rDao.save(r);
return "Réponses à choix multiple céée avec l'id : " + r.getId();
} catch (Exception ex) {
return "Erreur lors de la création d'une réponse à choix multiple : " + ex.toString();
}
}
/*
* Créer une réponse de type ReponseCourte
*/
@PostMapping("/create/courte")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String createReponseCourte() {
try {
ReponseCourte r = new ReponseCourte();
rDao.save(r);
return "Réponses courte céée ";
} catch (Exception ex) {
return "Erreur lors de la création d'une réponse courte : " + ex.toString();
}
}
@GetMapping("/getAll")
@ResponseBody
@PreAuthorize("hasAnyRole('ADMIN','USER')")
public String getAll() {
try {
String res = "";
List<Reponse> reponses = rDao.findAll();
for (Reponse reponse : reponses) {
res += "id : " + reponse.getId() + " , " + reponse.toString() + "\n";
}
return res;
} catch (Exception ex) {
return "Erreur lors de la récupréation de toutes les réponses : " + ex.toString();
}
}
@GetMapping("/get/{id}")
@ResponseBody
@PreAuthorize("hasAnyRole('ADMIN','USER')")
public String get(@PathVariable("id") int id) {
try {
String res = "";
Reponse reponse = rDao.findById(id).get();
res+="id : " + reponse.getId() + "\n" + reponse.prettyPrinter(1);
return res;
} catch (Exception ex) {
return "Erreur lors de la récupréation de la réponse : "+id+" : " + ex.toString();
}
}
@DeleteMapping("/delete/{id}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String delete(@PathVariable("id") int id) {
try {
Reponse r = rDao.findById(id).get();
rDao.delete(r);
} catch (Exception ex) {
return "Erreur pendant la suppression de la Reponse " + id + " :" + ex.toString();
}
return "Reponse " + id + " supprimée avec succès";
}
@PutMapping("/addReponse/{id}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String addReponse(@PathVariable("id") int id, @RequestBody Map<String, String> body) {
try {
if (body.containsKey("reponse")) {
Reponse rep = rDao.findById(id).get();
String reponse = body.get("reponse");
rep.getReponses().add(reponse);
rDao.save(rep);
return "Réponse correcte \"" + reponse + "\" ajoutée à la Reponse " + id;
} else return "Erreur : mettre \"reponse\" dans le JSOIN";
} catch (Exception ex) {
return "Erreur lors de l'ajout de la réponse : " + ex.toString();
}
}
@PutMapping("/removeReponse/{id}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String removeReponses(@PathVariable("id") int id, @RequestBody Map<String, String> body) {
try {
Reponse rep = rDao.findById(id).get();
String reponse = body.get("reponse");
rep.getReponses().remove(reponse);
rDao.save(rep);
return "Réponses correct \"" + reponse + "\" supprimée de la Reponse " + id;
} catch (Exception ex) {
return "Erreur lors de la suppression de la réponse : " + ex.toString();
}
}
@PutMapping("/addChoix/{id}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String addChoix(@PathVariable("id") int id, @RequestBody Map<String, String> body) {
try {
Reponse reponse = rDao.findById(id).get();
if (reponse instanceof Choix) {
String choix = body.get("choix");
((Choix) reponse).getChoix().add(choix);
rDao.save(reponse);
return "Choix \"" + choix + "\" ajouté à la question " + id;
} else return "Erreur : la réponse doit être a choix multiple.";
} catch (Exception ex) {
return "Erreur lors de l'ajout du choix : " + ex.toString();
}
}
@PutMapping("/removeChoix/{id}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String removeChoix(@PathVariable("id") int id, @RequestBody Map<String, String> body) {
try {
Reponse reponse = rDao.findById(id).get();
if (reponse instanceof Choix) {
String choix = body.get("choix");
((Choix) reponse).getChoix().remove(choix);
rDao.save(reponse);
return "Choix \"" + choix + "\" supprimé à la question " + id;
} else return "Erreur : la réponse doit être a choix multiple.";
} catch (Exception ex) {
return "Erreur lors de la suppression du choix : " + ex.toString();
}
}
}

View File

@@ -0,0 +1,205 @@
package sample.data.jpa.web;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.stereotype.Controller;
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.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import sample.data.jpa.metier.Quizz;
import sample.data.jpa.metier.Session;
import sample.data.jpa.metier.Utilisateur;
import sample.data.jpa.service.QuizzDao;
import sample.data.jpa.service.SessionDao;
import sample.data.jpa.service.UtilisateurDao;
@Controller
@RequestMapping("/session")
public class SessionController {
@Autowired
private SessionDao sDao;
@Autowired
private QuizzDao qDao;
@Autowired
private UtilisateurDao uDao;
/*
Post /session/create param : body Jsp, "theme"
Delete /session/delete/{id}
Get /session/getAll
Put /session/addQuizz/{id}/{idQ}
Put /session/removeQuizz/{id}/{idQ}
Put /session/update/{id} param : body Jsp, "theme"
Put /session/join/{sessionId}
Put /session/leave/{sessionId}
*/
@PostMapping("/create")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String create(@RequestBody Map<String, String> body) {
String sId = "";
Session session = new Session();
try {
session.setTheme(body.getOrDefault("theme", ""));
int codePIN;
if (body.containsKey("codePIN")) {
codePIN = Integer.parseInt(body.get("codePIN"));
if (sDao.existsByCodePIN(codePIN)) {
return "Error: codePIN already exists.";
}
} else {
do {
codePIN = new Random().nextInt(900000) + 100000;
} while (sDao.existsByCodePIN(codePIN));
}
session.setCodePIN(codePIN);
sDao.save(session);
sId = String.valueOf(session.getId());
} catch (Exception ex) {
return "Error creating the Session : " + ex.toString();
}
return "Session \"" + session.getTheme() + "\" successfully created with id = " + sId + " and codePIN = " + session.getCodePIN();
}
@DeleteMapping("/delete/{id}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String delete(@PathVariable("id") int id) {
try {
Session q = sDao.findById(id).get();
sDao.delete(q);
} catch (Exception ex) {
return "Error deleting the session " + id + " :" + ex.toString();
}
return "Session " + id + " succesfully deleted!";
}
@GetMapping("/getAll")
@ResponseBody
@PreAuthorize("hasAnyRole('ADMIN','USER')")
public String getAll() {
try {
List<Session> sessions = sDao.findAll();
String res = "";
for (Session session : sessions) {
res += "id: " + session.getId() + " , ";
res += "theme: \"" + session.getTheme() + "\" , ";
res += "nbUtilisateur :" + session.getUtilisateurs().size() + "\n";
}
return res;
} catch (Exception ex) {
return "Error get all session : " + ex.toString();
}
}
@PutMapping("/addQuizz/{id}/{qid}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String addQuizz(@PathVariable("id") int id, @PathVariable("qid") int qId) {
try {
Session s = sDao.findById(id).get();
Quizz q = qDao.findById(qId).get();
s.getQuizzs().add(q);
q.getSessions().add(s);
sDao.save(s);
qDao.save(q);
} catch (Exception ex) {
return "Error adding the quizz from the session : " + ex.toString();
}
return "Quizz " + qId + " add in Session " + id;
}
@PutMapping("/removeQuizz/{id}/{qid}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String removeQuizz(@PathVariable("id") int id, @PathVariable("qid") int qId) {
try {
Session s = sDao.findById(id).get();
Quizz q = qDao.findById(qId).get();
s.getQuizzs().remove(q);
q.getSessions().remove(s);
sDao.save(s);
qDao.save(q);
} catch (Exception ex) {
return "Error removing the quizz from the session : " + ex.toString();
}
return "Quizz " + qId + " remove from Session " + id;
}
/*
* Utiliser un Json pour mettre le String "theme"
* l'id se met dans l'url
*/
@PutMapping("/update/{id}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String updateQuestion(@PathVariable("id") int id, @RequestBody Map<String, String> body) {
Session s;
try {
s = sDao.findById(id).get();
s.setTheme(body.get("theme"));
sDao.save(s);
} catch (Exception ex) {
return "Error updating the Session: " + ex.toString();
}
return "Session " + id + " succesfully updated! : " + s.getTheme();
}
@PutMapping("/join/{sessionId}")
@ResponseBody
@PreAuthorize("hasRole('USER')")
public String joinSession(@PathVariable("sessionId") int sessionId, JwtAuthenticationToken auth) {
try {
String keycloakUserId = auth.getToken().getClaim("sub");
Utilisateur u = uDao.findByKeycloakId(keycloakUserId);
if (u == null) {
return "User not found in database.";
}
Session s = sDao.findById(sessionId).orElseThrow(() -> new Exception("Session not found"));
u.getSessions().add(s);
s.getUtilisateurs().add(u);
sDao.save(s);
uDao.save(u);
return "User " + u.getName() + " joined session " + sessionId;
} catch (Exception ex) {
return "Erreur pendant l'ajout de l'utilisateur dans la session : " + ex.toString();
}
}
@PutMapping("/leave/{sessionId}")
@ResponseBody
@PreAuthorize("hasRole('USER')")
public String leaveSession(@PathVariable("sessionId") int sessionId, JwtAuthenticationToken auth) {
try {
String keycloakUserId = auth.getToken().getClaim("sub");
Utilisateur u = uDao.findByKeycloakId(keycloakUserId);
if (u == null) {
return "User not found in database.";
}
Session s = sDao.findById(sessionId).orElseThrow(() -> new Exception("Session not found"));
u.getSessions().remove(s);
s.getUtilisateurs().remove(u);
sDao.save(s);
uDao.save(u);
return "User " + u.getName() + " left session " + sessionId;
} catch (Exception ex) {
return "Erreur pendant la suppression de l'utilisateur de la session : " + ex.toString();
}
}
}

View File

@@ -0,0 +1,167 @@
package sample.data.jpa.web;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.stereotype.Controller;
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.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import sample.data.jpa.metier.Session;
import sample.data.jpa.metier.Utilisateur;
import sample.data.jpa.service.SessionDao;
import sample.data.jpa.service.UtilisateurDao;
@Controller
@RequestMapping("/utilisateur")
public class UtilisateurController {
@Autowired
private UtilisateurDao uDao;
@Autowired
private SessionDao sDao;
/*
Post /utilisateur/create param : body Jsp, "name", "email", "password"
Delete /utilisateur/delete/{id}
Get /utilisateur/getAll
Get /utilisateur/getSessions
Put /utilisateur/addSession/{idUtilisateur}/{idSession}
Put /utilisateur/removeSession/{idUtilisateur}/{idSession}
Put /utilisateur/update/{id} param : body Jsp, "name", "email", "password"
*/
@PostMapping("/create")
@ResponseBody
@PreAuthorize("hasAnyRole('ADMIN','USER')")
public String create(@RequestBody Map<String, String> body, JwtAuthenticationToken auth) {
try {
if(body.containsKey("name") && body.containsKey("email") && body.containsKey("password")){
Utilisateur u = new Utilisateur();
String keycloakUserId = auth.getToken().getClaim("sub");
u.setName(body.get("name"));
u.setEmail(body.get("email"));
u.setPassword(body.get("password"));
u.setKeycloakId(keycloakUserId);
uDao.save(u);
String uId = String.valueOf(u.getId());
return "Utilisateur \"" + u.getName() + "\" créé avec succès avec l'id = " + uId;
} else return "Erreur, besoin de name, email et password dans le JSON";
} catch (Exception ex) {
return "Erreur durant la création de l'Utilisateur : " + ex.toString();
}
}
@DeleteMapping("/delete/{id}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String delete(@PathVariable("id") int id) {
try {
Utilisateur u = uDao.findById(id).get();
uDao.delete(u);
} catch (Exception ex) {
return "Erreur pendant la suppression de l'utilisateur " + id + " :" + ex.toString();
}
return "Utilisateur " + id + " supprimé avec succès !";
}
@GetMapping("/getAll")
@ResponseBody
@PreAuthorize("hasAnyRole('ADMIN','USER')")
public String getAll() {
try {
List<Utilisateur> utilisateurs = uDao.findAll();
String res = "";
for (Utilisateur utilisateur : utilisateurs) {
res += "id: " + utilisateur.getId() + " , ";
res += "name: " + utilisateur.getName() + " , ";
res += "email: \"" + utilisateur.getEmail() + "\"\n";
}
return res;
} catch (Exception ex) {
return "Erreur pendant la récupération des utilisateurs : " + ex.toString();
}
}
@GetMapping("/getSessions/{id}")
@ResponseBody
@PreAuthorize("hasAnyRole('ADMIN','USER')")
public String getSessions(@PathVariable("id") int id){
try {
Utilisateur u = uDao.findById(id).get();
String res = "";
for(Session s : u.getSessions()){
res += "id : "+ s.getId() + " , theme : " + s.getTheme() + "\n";
}
return res;
} catch (Exception ex) {
return "Erreur pendant la récupération les sessions de l'utilisateur : " + ex.toString();
}
}
@PutMapping("/addSession/{id}/{qid}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String addSession(@PathVariable("id") int id, @PathVariable("qid") int sId) {
try {
Utilisateur u = uDao.findById(id).get();
Session s = sDao.findById(sId).get();
u.getSessions().add(s);
s.getUtilisateurs().add(u);
sDao.save(s);
uDao.save(u);
} catch (Exception ex) {
return "Erreur pendant l'ajout de l'utilisateur dans la session : " + ex.toString();
}
return "Utilisateur " + id + " ajouté à la Session " + id;
}
@PutMapping("/removeSession/{id}/{qid}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String removeSession(@PathVariable("id") int id, @PathVariable("qid") int sId) {
try {
Utilisateur u = uDao.findById(id).get();
Session s = sDao.findById(sId).get();
u.getSessions().remove(s);
s.getUtilisateurs().remove(u);
sDao.save(s);
uDao.save(u);
} catch (Exception ex) {
return "Erreur pendant la suppression de l'utilisateur de la session : " + ex.toString();
}
return "Utilisateur " + id + " retiré de la Session " + id;
}
@PostMapping("/update/{id}")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String update(@PathVariable("id") int id, @RequestBody Map<String, String> body) {
try {
if (body.containsKey("name") && body.containsKey("email") && body.containsKey("password")) {
Utilisateur u = uDao.findById(id).get();
u.setName(body.get("name"));
u.setEmail(body.get("email"));
u.setPassword(body.get("password"));
uDao.save(u);
return "Utilisateur \"" + u.getName() + "\" mis à jour avec succès";
} else return "Erreur, besoin de name, email et password dans le JSON";
} catch (Exception ex) {
return "Erreur durant la mise à jour de de l'Utilisateur : " + ex.toString();
}
}
}

View File

@@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
version="3.0">
<persistence-unit name="dev" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<property name="jakarta.persistence.jdbc.driver"
value="org.hsqldb.jdbcDriver" />
<property name="jakarta.persistence.jdbc.url"
value="jdbc:hsqldb:hsql://localhost/" />
<property name="jakarta.persistence.jdbc.user" value="sa" />
<property name="jakarta.persistence.jdbc.password" value="" />
<property
name="jakarta.persistence.schema-generation.database.action"
value="create" />
<property name="jakarta.persistence.dialect"
value="org.hibernate.dialect.HSQLDialect" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
<persistence-unit name="prod" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<property name="jakarta.persistence.jdbc.driver"
value="org.hsqldb.jdbcDriver" />
<property name="jakarta.persistence.jdbc.url"
value="jdbc:hsqldb:hsql://localhost/" />
<property name="jakarta.persistence.jdbc.user" value="sa" />
<property name="jakarta.persistence.jdbc.password" value="" />
<property
name="jakarta.persistence.schema-generation.database.action"
value="update" />
<property name="jakarta.persistence.dialect"
value="org.hibernate.dialect.HSQLDialect" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
<persistence-unit name="mysql">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<property name="jakarta.persistence.jdbc.driver"
value="com.mysql.cj.jdbc.Driver" />
<property name="jakarta.persistence.jdbc.url"
value="jdbc:mysql://localhost/mydatabase" />
<property name="jakarta.persistence.jdbc.user" value="tlc" />
<property name="jakarta.persistence.jdbc.password" value="tlc" />
<property
name="jakarta.persistence.schema-generation.database.action"
value="update" />
<property name="jakarta.persistence.dialect"
value="org.hibernate.dialect.MySQL8Dialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.c3p0.min_size" value="5" />
<property name="hibernate.c3p0.max_size" value="20" />
<property name="hibernate.c3p0.timeout" value="300" />
<property name="hibernate.c3p0.max_statements" value="50" />
<property name="hibernate.c3p0.idle_test_period" value="3000" />
</properties>
</persistence-unit>
</persistence>

View File

@@ -0,0 +1,21 @@
server.port=8082
spring.h2.console.enabled=true
spring.h2.console.path=/h2
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.sql.init.platform=h2
spring.sql.init.mode= always
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/realms/myspringbootapprealm
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://localhost:8080/realms/myspringbootapprealm/protocol/openid-connect/certs
keycloak.realm: myspringbootapprealm
keycloak.auth-server-url: http://localhost:8080/
keycloak.resource: myspringbootapp
keycloak.credentials.secret: Y7xpKQbFalUFTGUGD9XDBcvawvs3zsWZ
keycloak.use-resource-role-mappings: true
keycloak.bearer-only: true

View File

@@ -1,92 +0,0 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css"
href="https://unpkg.com/swagger-ui-dist/swagger-ui.css">
<style>
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
background: #fafafa;
}
</style>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
style="position:absolute;width:0;height:0">
<defs>
<symbol viewBox="0 0 20 20" id="unlocked">
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path>
</symbol>
<symbol viewBox="0 0 20 20" id="locked">
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="close">
<path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow">
<path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow-down">
<path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"/>
</symbol>
<symbol viewBox="0 0 24 24" id="jump-to">
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"/>
</symbol>
<symbol viewBox="0 0 24 24" id="expand">
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>
</symbol>
</defs>
</svg>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js"></script>
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-standalone-preset.js"></script>
<script>
window.onload = function () {
// Build a system
const ui = SwaggerUIBundle({
url: "http://localhost:8080/openapi.json",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
window.ui = ui
}
</script>
</body>
</html>

View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Admin</title>
</head>
<body>
This is the admin page
<br/>
Logged user: <span th:if="${user} != null" th:text="${user.name}"></span>
<br/>
<a href="/logout">logout</a>
</body>
</html>

View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Index</title>
</head>
<body>
This is the index page.
<br/>
Logged user: <span th:if="${user} != null" th:text="${user.name}"></span>
<br/>
<a href="/admin">admin</a>
<a href="/logout">logout</a>
</body>

View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Main</title>
</head>
<body>
This is the main page.
<br/>
<a href="/index">index</a>
<br/>
<a href="/admin">admin</a>
</body>
</html>
>

View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Logout</title>
</head>
<body>
This is the logout page.
<br/>
Logged user: <span th:if="${user} != null" th:text="${user.name}"></span>
<br/>
<a href="/">main</a>
</body>
</html>

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.data.jpa;
import java.lang.management.ManagementFactory;
import javax.management.ObjectName;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Integration test to run the application.
*
* @author Oliver Gierke
* @author Dave Syer
*/
@RunWith(SpringRunner.class)
@SpringBootTest
// Enable JMX so we can test the MBeans (you can't do this in a properties file)
@TestPropertySource(properties = { "spring.jmx.enabled:true",
"spring.datasource.jmx-enabled:true" })
@ActiveProfiles("scratch")
// Separate profile for web tests to avoid clashing databases
public class SampleDataJpaApplicationTests {
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setUp() {
this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
@Test
public void testHome() throws Exception {
this.mvc.perform(get("/")).andExpect(status().isOk())
.andExpect(content().string("Bath"));
}
@Test
public void testJmx() throws Exception {
assertThat(ManagementFactory.getPlatformMBeanServer()
.queryMBeans(new ObjectName("jpa.sample:type=ConnectionPool,*"), null))
.hasSize(1);
}
}

View File

@@ -0,0 +1,2 @@
spring.datasource.name=scratchdb
spring.jmx.default-domain=jpa.sample