From 621ab8e16316ee136b6d3872a556a77971b4da11 Mon Sep 17 00:00:00 2001
From: "bedran.sezer" <bedran.sezer@etu.hesge.ch>
Date: Thu, 20 Jun 2024 23:30:32 +0200
Subject: [PATCH] update fuzzy matching

---
 .idea/.gitignore                              |   5 +
 .idea/dojocli.iml                             |  12 +
 .idea/inspectionProfiles/Project_Default.xml  |   6 +
 .idea/modules.xml                             |   8 +
 .idea/vcs.xml                                 |   9 +
 NodeApp/.env.vault                            |   8 +-
 .../src/commander/exercise/ExerciseCommand.ts |   2 +
 .../subcommands/ExerciseListCommand.ts        | 235 ++++++++++++++++++
 NodeApp/src/managers/DojoBackendManager.ts    |  66 +++++
 9 files changed, 347 insertions(+), 4 deletions(-)
 create mode 100644 .idea/.gitignore
 create mode 100644 .idea/dojocli.iml
 create mode 100644 .idea/inspectionProfiles/Project_Default.xml
 create mode 100644 .idea/modules.xml
 create mode 100644 .idea/vcs.xml
 create mode 100644 NodeApp/src/commander/exercise/subcommands/ExerciseListCommand.ts

diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..b58b603
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,5 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/dojocli.iml b/.idea/dojocli.iml
new file mode 100644
index 0000000..24643cc
--- /dev/null
+++ b/.idea/dojocli.iml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/.tmp" />
+      <excludeFolder url="file://$MODULE_DIR$/temp" />
+      <excludeFolder url="file://$MODULE_DIR$/tmp" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..03d9549
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
+  </profile>
+</component>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..4ab3051
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/dojocli.iml" filepath="$PROJECT_DIR$/.idea/dojocli.iml" />
+    </modules>
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..cdbd4ac
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="Git" />
+    <mapping directory="$PROJECT_DIR$/NodeApp/.idea/jetbrainsConfiguration" vcs="Git" />
+    <mapping directory="$PROJECT_DIR$/NodeApp/src/shared" vcs="Git" />
+    <mapping directory="$PROJECT_DIR$/NodeApp/src/sharedByClients" vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/NodeApp/.env.vault b/NodeApp/.env.vault
index 85a3476..103f5eb 100644
--- a/NodeApp/.env.vault
+++ b/NodeApp/.env.vault
@@ -1,14 +1,14 @@
 #/-------------------.env.vault---------------------/
 #/         cloud-agnostic vaulting standard         /
-#/   [how it works](https://dotenvx.com/env-vault)  /
+#/   [how it works](https://dotenv.org/env-vault)   /
 #/--------------------------------------------------/
 
 # development
-DOTENV_VAULT_DEVELOPMENT="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"
+DOTENV_VAULT_DEVELOPMENT="xWZfuXiO1nWw4qDf/vY90xPpLhb7l2cyOYK7v7K2WPOjlSuJBL74nWHaphDeslFUpJYiIjNe2QOn7z5nqn6DWw4PqYkjEPTjYGLfXmig3QoQtehYyYDErFH9RYRzCSE34NZzk2GP+F6vNGKJ0fA+ua4sTPfzPuhuoSC6Oz6TXsUwmDz7PpsrRDSsf1Y8e2GRHUiyYYb5W5lLKtFn2wCRNMU41nHgOsZip4/gmoz/6wD3vpJptLnMXMWUO7EZ87cyWXKZxVHCP19WmW1Fncdb4bo297VL1vH4b2yYcGwtgBAlsrMHhEzJH3QcXZucDdvIsN5A39CuIreQPM5szUonUJZIXcwXga8cmvuioszNO4zvrnG+BpMxOmLxa5XYYjUepfuSdP260zeMcLnAg0Mbylg6PlcaoA8fjKHiJZeAt2KMH5aL5dMLi5VMlleF2Wq0XbklZwyflfxzjULYJ6XNnrUJNea63Su1vzj7gPTA05eAfYnlKlNF8zc76qlY/G5Wigz0InOim3omo1JrLB4uBWCSkJvM6dxnB15DJfHjWHSJETI0desojXremJ11cnqabH6miC/hKH6A9YOEax4zdMIrRTMFa24xFuHjHqbTe/1/G6URW1kKKmyi9r8hNBKEyAYq1PYnf2BiGBYRj5KMybkYwqB+C0xLucAXYIXgOamw91vuN3SVpuLQ2adz7KLiZbe5xiXZALXhzXj08j195A7sZUoz5yWfqZcVE9o0EkGzX6xAGqVADg1mbgw9dRbm+Ux9u0/qAMzpTbK93lRtC94ZBKenGtJc+Sdc6rYmUKj/+3mmIGYGQjX6VAV2ApoC+yJxyG1WBy/Ae0BeoGtuevuCbYjM55KHWy5cFh3s71I3eJVfcJxf7+bi3VQudOOLE8ZhK42Oa6tY/Aqgr2oyjcfBvA+B0R/wJBy+ZIOKtZgtcH9mIl8Srw3FgGEPch/F4r3ndooM1TuDD/yVyFK0crstir8iD+nMExj9ll8fi2TmcAQ5CC0/0QteCEb9qeVCwa0mO0xIk8IVxC9hVlrInk+yw1A4uZLYwe9ppIjlSGf0zLqIJPiOY8mPTpCucgrYV+BhybIhUKGIdCbXu+JR/LZ7babQAUXfeA86kkKhcNc2HVEpx8ms7kvju3d06rTMdxCz/isEpmzVobm0ZEzXzBe+VBk71YP6liVDrGO0YXPz/ew000fZOyhcZbEryCjZO9WjES5w3uPiTo6MGLmuKfjRDgrJQuQ05wYrDdH7YnXKY0jrzSibSEkuywdXjVgq4YgTMnLKtsc8AIVlB/CzI4Xq8w5gPPz0kZVo/xmThziwjkk0TIlRKpFjlito/QBKquZ38YmXhkOBbSGpCsEOtQfThtbnArKhojhQLcSOruAwIE8wQBJDr1yW+/WtqeWi80E9C/QI91zMKNM/DsD/JSZmkZAXwyV0R7/IVoZlX2JQgTGxD0VjGI1Tsr3mGfU2zUOBif9Ff6tcYhWBfUrVIv1InTa905tpZ/1DObYE9a3+stFERtGgKICdq801fSwKjvXq4ijFgJEwD0sGAj6E52X995qTxftyMcCkByWmTiTltZfHeNOYBRODhl2y15rHvsBh2XjERiuN1NyVUhytinHCqx6+OMRvQ0TOLplSuR0XEBL9v3Iz3zvkJ6K6t12FXD5TzjlIKUfUVgHUHcZVZo1HuGxvuS4Ymo5qAJzgv8g+yZfEml+AMDkZfBCP6KO9f8wi6X+X4Z54dDDxrXNyyBwmv58a9GMWyFDiQNTH8caCs4T2h2uzB56yJkjL2DDMeZtw9WL5mFQ0kUxeaO7J1iLsccbJ58yRHsowHY4Y/wSNaeNEHKNCRFyIEC7nHSQawqmZZXmCX1Dgs83V5sLM5pBjHnWQ2xI="
 
 # production
-DOTENV_VAULT_PRODUCTION="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"
+DOTENV_VAULT_PRODUCTION="geUVFVOsvd0vRIIfeu1i6pKoAr3/2nwB63oO4gxe/ug3GnFBEh+Rf8I7DwM4qcD10PBqaMV7tJiYVIBqAUviHrQSGEJw5aK4Le4ndXf/1yPpsRf6YdMNfL/oU5I2aMMXlCCGTylbgon67Vrw2SgmZbCD1vkr9wmdJqATANcNSfNbJL+mf790rZyUXYC4piUIfdGDnjJpeSTozfpZeTh3yEp0pRbjRsU6NlXIPH/mDVFJkWMT31jZJ1kyePu6b1qWWh2uZRwWaaOOTclpKGnLRaT/N3Z+M1OJbB1Kjp0uUoLIz4VytTGcYRjS8wbfzBnl4wg9HSPR49UKShX5SNtQ9ov/7vmRpYH59SNuwV55S6Bv5pgOUVjBgdl+4tzXuh7Z8FD2867a2k7vXBpXoOBgi6yujlSmEoul3XMa5a3zyWHB+kz0GwEtlyZyAFR5xXyIWdURkXw4RRLLhHaI5y6LGKPCFHyFPdEUX4uRroFB261+ft5IT51ZwTujeymC6qkC2KlsrpViyySTjE4LynLzitIsLP5I7PiZ6tH227BfzcwmUdHlSuiHIQMWPKl2oFLyhEkfWgUxCRUfUxYMgCRjPkrXf7zPhvhgbtOOTBLlZsMBQxFoM7kXECzhnnyqp6JVQxfOMAGPTcgLQP3HAqVLVfAYzRpfoTROxuoZ6nuikIdR8rO4BAasH2/6Z0hWEGKUMsnhDHb8l3xDNB3IAH00y+t1WM0Yre49s3RrtTz+I8K3nZ1hCCT6UqfDxRkefltXngdd47qNU49FpWS2MKitUapLvlqTccAxYrCUmAkl/giDMNrRaLFbWSeiA8tyOEhdp8eqVz5ygLalkecdZTr3x3qwFbLam++MqLph1JXeFWzBoekLyJUrtWEYNBXb/g+eQlfHKEbd0AbbYsSaqVZz9R8hjqcryq/O+pMETx7F8DV7l8oR1xMaFeDBc+rJPLXka5plc91mdstU3E0FgviScUvaE1dclEuPGW3M/1MXR+oxIZ81dl4j1uUYcSUueKv7QsOS8jFuJhQQXzNyBrFtJCb8jV8V9/0vXKUN+Zj9Bfdn0IuUxXN8VfaoSNBOA2fTssEAPSvCBOJPSQsL7YsSye/1koMCifYy+c2RDSDxxD72bfsij9U1srjJgGJAqRI2WetUjH9HgqESJ+oPQouKhHwEinnsNVSweoLLN0nD02RSjm3iIeCy/5R0B/23yALZ4YWTxdS4kJs22mue0cUyGY6on3eCmwF5d+7H9/r737sbLYODBLn6eArXvHAvIS72mtvveTiviXhzU8c0ntu562zpDDMTn8useCWHgsEukRm2eumpMiXSMCiFSotV4T+GFNSAkm3J6mGAzZFp1QOgZHnImjrERsLaKRweQblNT2ZYxaZNbCNMlrj248EIIIbSPH+/4wgUyl5tbhnyPYO58Z0V1kLOvofuzIIVXGoeScHaTDEMlx1ZmN9Mtl0CuYNIyzvzxRee2j2EUu6ivLwOArR1SDZILd540y3ONOMObAVZhJCB1vUqzTdBrz5BRxy1knwhhQRbQQHcVVp+zqxSVtRrUWgAzHzCP655ilDqXJwkV0Sy/naBr5I8Hjs0euVLj0Qq7XlcyIHtch8Lcm+rfJiDo0bYJlHfgoeRrvum0N/w+qoEVbuGpzNztGO7ISbhxeitLoP/cu7tDYxLVXuzXYCVYn2MJwjeLtlytZy74jQoKiDRLt2Zy32JSbg8hR1utaFkN8BA9OmAhbXTmdsJgleyWxlQDl3YeLaN4+L1rLrgpmmyTIBcM6oNhO9GTstjvzrwXKPHb6CmzEwFkyzBPS36bN1glcZHF5auiybAJkMMlKHMbupA7244Gw=="
 
 # test
-DOTENV_VAULT_TEST="CYDEOpA8aIlJs245eFTFon8fcioqqLopkdOco1dRb5g70jfXSvgOJQ5GYuFFGOPfZkv0Q5yTHvABPiUzMP8RS0m2x+88BKpfd2TS/9ojTq/UASfOJH0/OaR2Pfj72nKqKN3PuAE6Gf0GQsjzypa25B8z0b3eRbaV/wvCxSbV+Y2F4kkw/+mm9TtYtG3oWFHyBzcAD/zGyFcXqmRDi2tIw0IHEWzD4emIS1rJDK/8Y85xILSrALAtfyPr+a2tvSNapg8kH1dv+BG5DIZBz/8xERxJQNO68altEkpsDEoue23rGEReP3gcIfF0E7/y55PEXkPUQl2RQNXIPW9DdMa0tb94ToHiOgMmOxo6oW+liIShD6ERTZIIzcA4yD+jEEFP739evtfouEHw5SeGVp++EjWN4PwB9qmow6mNgDDQyFolxzlbRvfsWQEvTGe0urXzthE+0THbHHX128XUS3NwVWLLTZEECZRvz9ZeiuAPadKoqCdydDLg5s+ufajlmw0fFJVhMQc+AP533ttlHC2vT4xVjjN59Z2yE94kap3i4HtyGqKMq7bFJWAiLT4B615xrg9zZUarlE1qM7ZqXsGpyU3kyAm+/wf4/s2hGYl8uK/ff5rmXU4X+9gobmuV77H07iuWUJESbg3dl1NQK0X4y1zA9EWcU3OB7LFrwi3ydzgi84Aq/tvOnhxn0n1PRvMwqsX4qVj3JCynUSAM3RA8ukO9RL7CcMjNnNvHi58UhLUJVCJLyZ4MS3Hcx+GdnpQ92KQvIEUFtwcLX9SaEQSRBdRJ+Knxq711E2pJrcv1uHMi7fJbaBuPsnP/ntkcWrxqmp7EqcHl29bGzOVs9js0sjlBpnW9RjvJ0AIug3ze2JzG1qoT42jSWjVVNiVTAGGPOXIFqrzx5eaTYt2bE0oWNlQCY+0bJAPqtpBJWX2sxnnuKOtYjOYXMx7uz92WJDdtmzvXZ5ymOOs0Ye7RxxBvZUSEyBws1MCP39VuOJcMidUfQGLMhiNv7EkVaPudwYQ1pD8Fvav/oQQmRNOiIo5UrbC7dZ9fd/RrS+65mDhCxHj7nni7O959reDd1y0xo+zKmD64JChJVTWN2/YyhFdqieGL8Lmtz3Z9rkigch3q4HnpVfFJmCcBGjP/KenftIW2AWU9LMHUwwEggLTU4XyO5AhhwFzzWaYWrUqxbVxhS0gsTYw/2lm+PWXFMBI7FQgax2Y9sp/eMeKGjgkykmyftqhHfmet3C7ALzdbygpkERkq9JjXQdigtmgSP1lFxxf8LkmSdWYQqHNvrTeXDJyQdL3m2m9o0zUMBnDjtd64LnslWjUBPk7uLARd3cKIK4lPGP66+jgvMJKoGJTjFcD67xko++M+/2R/ip919uTxJ+/y1mtJXFnSL/FA4jl2UsU3YaiOISO726Zv1l4AuoKfRq6x1KlfJKemh2MQVdXwXIqvqfvOIHz6/P3Eie4cwt00WDV1GbVQgR4FEAT6uQxxMaSXTGJwi4g48TprsKN+zWmmCXzAF/Zmpy9O8GNrW9of8WY6hGe9ZpMhANhTSOIH2ey3Zenkl4ZoYKZ9ywbK6db0pSFPr9SXdzzPVOeriQzQ57ij0YX7YIZJA3YROqMRRQ+xnQTnxQlxRGTJPd5abU01KVNWy9GVu/Win7wQuWg0QeDWEIS5ga3tNb4txtWzyFam9RHVPA76YjOUIgL9NMrHq4t5iE3HAr1QU4pMZ5BEeFA/nqY7kO8rNGPYrwe41cd5RcwBajPxyGH0HGxT8ovd3U2vN6fpje6NuB4e3Uz8Go2CP4U5x/b29MoR245iPjtzhn0Q/AhIMr5MVEN8Zt8DcLBtxo2E11KQMHqXuadsqT/mS65PlshVeqgITl34IIV/tf8flC143FLQNlNECqgHgE9GLEJvuTKSHLFhDC6pHstGLEyPe8gtMikN4DlyqdZ/pqV4hhNG1E+jeL3x"
+DOTENV_VAULT_TEST="NjWlOUWT5HZM4whZTpS/sqrHLsWiJKV6xSQcrU2Pm4m8csvh/PJ9iQgyME+eltgHAFAdGZIrwZadFws7kCHQSQxikYq1hz513wlLhhVqk9QGuHUdM352OtsoySuHYS7SwwKog8MAsLQuJpIjmvJaCFvQ+Q15KjbHGjXgQghXELel87IEy0+lxibd1JUMfHNPzyA4EXZe3LGSVNgIfNRZWcE1vWQ+UAhDxCA1M5Y9yEQO+TB2FHyEZaFgSHC+uLgybK5SbFwyDxPY8RzLBbHtlAB5Ez2NnLWkj6wLLRNZW75wa7TserUaArVyBy8nBPqtDGpMCpMXubVHxKzFDxUHqgbhn/eVDaD7FWhVYT0PWijOpLKjtASTebEj24ea46NuLZAjMxIhb2Vr5s06PU7wmACNIi2ajdMFD+MSwKyRIvWlhcw+q2jUcZYcnqUM2F/AKp3qdSY3wLbnYr6F+dEYqXVk1A6pw+JC33eBdGVFPtskuxttg+//VfEuZOKSC7uLPHywQ8ldoljCqFLUt/+oKuhE8gzeNkX7Eb+O1scK9J4SHD2veVSafUZqBNewDjRnixGt8SMMv82XNqHbfpS7GqQKBNz5koO9wOJVvdDwSfGYY1e+RFreTUFsZtLUi6noai9+mQcwSe/cjsM77qewpfYSF+mdp4noKc3mlZTwkoVxF2zNO80uIvvkXmWraC0zqS5A+C05ppZZrjbcMN/CcKHSc1ERJaeWmbfWjjrsZlPwRtiOxLZu4Mohxl6CrZkln57lyryfhJNzjjV2/CyGhgb2VuolZp5s/hckCuSmGH7O4Uk4wiD8WaIA3j6c2YtRJ6/bWnXRVmLK+NBn50N6C0iEzixEl4nPyb8rfvI8ueDiXase28vPmXMwY8OU1uGn0L+K9M/ySSK0whxu6yLG75mv1ZLs3qQ+Z1HxUN6ZTYTNQmTAw2W2l12ZB2yZgR7Qi+uGMuI6zzLSrl7Ru+S7SIGV4PUyOc6QAtuKFx1XPNgj0ZA8Kfqx9iMnj1aHtDS1GsONuzSHOsUzW8vr1YMGEG4knEspRbIzlC7NVP4aChO/Mo4WmjZAu+oZaXxyyNXEwgxmWO4AArrsdgVCulWarr4Y1dV4639ATz81QjtjV+UieluJsAuCxqBz4p8Kw+/2k4EUBiu9FaO4pw9CDE1y2d/y9H1I+8l2NU11mPvqnNzXZgLJOLK4qV3tOFPheEK0de0WzTt4PZsneFSQbZNWmlbJDluEn53VheVfJOcUXq9KEWKwKDnzn+1dYUyWuAW6y7uXnx2ECWz1xM9DzaIwUcjv8/62NdspsSHNag8RxZ/KzHffH6ePoxpfhAogfaRjlgX+P1fpjxujY2/1LmdnH3/0kHyFuU+D/2IQC1cJMGpU7mD754JXfGS/g2d4ISVFEOTfDEv7ZwC8gRrkIMrUnk4xR4WYE3MSewZzWAQ1NcgdYrDpcSA8/wPUXnNcaP6GHZKzPoYq9SbEdOlVNkExOH+AueKGWtPm0VqprhwFOsveSsdwwAF79CKIzk1XJFCyLD+3aX7+ZvAAn/3734ggO+0tjBCy+N2pZ8+4UDABjSHA3d/UD3dNr78kzZY67xhkUu6fQSpS4nFezGgek9YpDTR8ukUbTiyovqtTmgXeb5HDBH5sZ/kaoEFgI+kskWb1u7Mk+5iZoVmPZXw2DFs7Ng2iQ+cS+KOPID534AmJ+mt8PrM92hVBlXmc96hrP4XqhIqQAImb6t9GQoDxdA8hsCUB4LQf8gKuZx4DDtrSronheYCFBLaNFNnixhFI1sVdK55VnS4/6zma6g7YRw=="
 
diff --git a/NodeApp/src/commander/exercise/ExerciseCommand.ts b/NodeApp/src/commander/exercise/ExerciseCommand.ts
index 8089092..1138f67 100644
--- a/NodeApp/src/commander/exercise/ExerciseCommand.ts
+++ b/NodeApp/src/commander/exercise/ExerciseCommand.ts
@@ -2,6 +2,7 @@ import CommanderCommand          from '../CommanderCommand.js';
 import ExerciseCreateCommand     from './subcommands/ExerciseCreateCommand.js';
 import ExerciseRunCommand        from './subcommands/ExerciseRunCommand.js';
 import ExerciseCorrectionCommand from './subcommands/ExerciseCorrectionCommand.js';
+import ExerciseListCommand from "./subcommands/ExerciseListCommand";
 
 
 class ExerciseCommand extends CommanderCommand {
@@ -16,6 +17,7 @@ class ExerciseCommand extends CommanderCommand {
         ExerciseCreateCommand.registerOnCommand(this.command);
         ExerciseRunCommand.registerOnCommand(this.command);
         ExerciseCorrectionCommand.registerOnCommand(this.command);
+        ExerciseListCommand.registerOnCommand(this.command);
     }
 
     protected async commandAction(): Promise<void> {
diff --git a/NodeApp/src/commander/exercise/subcommands/ExerciseListCommand.ts b/NodeApp/src/commander/exercise/subcommands/ExerciseListCommand.ts
new file mode 100644
index 0000000..14ec7d3
--- /dev/null
+++ b/NodeApp/src/commander/exercise/subcommands/ExerciseListCommand.ts
@@ -0,0 +1,235 @@
+// ExerciseListCommand.ts
+import CommanderCommand from '../../CommanderCommand';
+import chalk from 'chalk';
+import ora from 'ora';
+import DojoBackendManager from '../../../managers/DojoBackendManager';
+import AccessesHelper from '../../../helpers/AccessesHelper';
+import Exercise from '../../../sharedByClients/models/Exercise';
+import inquirer from 'inquirer';
+import Table from 'cli-table3';
+
+import Fuse from 'fuse.js';
+import User from '../../../sharedByClients/models/User';
+
+class ExerciseListCommand extends CommanderCommand {
+    protected commandName: string = 'list';
+
+    protected defineCommand(): void {
+        this.command
+            .description('list your exercises')
+            .action(this.commandAction.bind(this));
+    }
+
+    protected async commandAction(): Promise<void> {
+        console.log(chalk.cyan('Please wait while we retrieve your exercises...'));
+
+        // Check access
+        if (!await AccessesHelper.checkStudent()) {
+            return;
+        }
+
+        // Fetch user's exercises
+        const userExercises: Exercise[] | undefined = await DojoBackendManager.getUserExercises();
+
+        if (!userExercises || userExercises.length === 0) {
+            ora().info('You have no exercises yet.');
+            return;
+        }
+
+        // Display the list of exercises
+        this.displayExerciseList(userExercises);
+
+        // Ask the user for further actions
+        await this.askUserForActions(userExercises);
+    }
+
+    private async askUserForActions(exercises: Exercise[]): Promise<void> {
+        const { action } = await inquirer.prompt([
+            {
+                type: 'list',
+                name: 'action',
+                message: 'Que souhaitez-vous faire ?',
+                choices: [
+                    { name: 'Voir les détails d\'exercice', value: 'details'},
+                    { name: 'Filter les exercises', value: 'filter' },
+                    { name: 'Exit', value: 'exit' },
+                ],
+            },
+        ]);
+
+        if (action === 'details') {
+            await this.selectExerciseForDetails(exercises);
+        } else if (action === 'filter') {
+            await this.filterExercises(exercises);
+        } else {
+            ora().info('No further actions selected.');
+        }
+    }
+
+    private async selectExerciseForDetails(exercises: Exercise[]): Promise<void> {
+        const { selectedExercise } = await inquirer.prompt([{
+            type: 'list',
+            name: 'selectedExercise',
+            message: 'Selectionner un exercice :',
+            choices: [
+                ...exercises.map(exercise => ({
+                    name: exercise.name,
+                    value: exercise.id,
+                })),
+                { name: 'Exit', value: 'exit' },
+            ],
+        }]);
+
+        if (selectedExercise === 'exit') {
+            ora().info('Pas de détails requis: détails dispo  avec la commande `dojo exercise info <id>`.');
+            return;
+        }
+
+        const selected = exercises.find(ex => ex.id === selectedExercise);
+        if (selected) {
+            await this.displayExerciseDetails(selected);
+        } else {
+            ora().info('Invalid selection. No exercise details to show.');
+        }
+    }
+
+    private async filterExercises(exercises: Exercise[]): Promise<void> {
+        const { filterType } = await inquirer.prompt([
+            {
+                type: 'list',
+                name: 'filterType',
+                message: 'Comment souhaitez-vous filtrer les exercices ?',
+                choices: [
+                    { name: 'Par saisie texte', value: 'fuzzy' },
+                    { name: 'Par professeurs', value: 'professor' },
+                    { name: 'Exit', value: 'exit' },
+                ],
+            },
+        ]);
+
+        if (filterType === 'fuzzy') {
+            await this.fuzzySearchExercises(exercises);
+        } else if (filterType === 'professor') {
+            await this.filterByProfessor(exercises);
+        } else {
+            ora().info('No filtering selected.');
+        }
+    }
+
+    private async fuzzySearchExercises(exercises: Exercise[]): Promise<void> {
+        const { searchQuery } = await inquirer.prompt([
+            {
+                type: 'input',
+                name: 'searchQuery',
+                message: 'Entrez le nom de l\'exercice (laisser vide pour la liste complète) :',
+            },
+        ]);
+
+        if (!searchQuery) {
+            this.displayExerciseList(exercises);
+            return;
+        }
+
+        const fuse = new Fuse(exercises, {
+            keys: ['name'],
+            threshold: 0.5,
+            distance: 150,
+        });
+
+        const searchResults = fuse.search(searchQuery).map(result => result.item);
+
+        if (searchResults.length === 0) {
+            ora().info('Aucun exercice trouvé correspondant à votre recherche.');
+            return;
+        }
+
+        if (searchResults.length === 1) {
+            // Display details and members for the single matching exercise
+            const singleExercise = searchResults[0];
+            this.displayExerciseDetails(singleExercise);
+        } else {
+            // Display only exercise names and info about viewing details
+            ora().info(' Plusieurs exercices trouvés correspondant à votre recherche :');
+            const exerciseNames = searchResults.map(exercise => exercise.name);
+            console.log('  ', exerciseNames.join('\n   '));
+
+            ora().info('Les détails sont disponibles avec la commande : `dojo exercise info <id>`.');
+        }
+    }
+
+    private async filterByProfessor(exercises: Exercise[]): Promise<void> {
+
+        const professors: User[] | undefined = await DojoBackendManager.getProfessors();
+
+        if (!professors || professors.length === 0) {
+            ora().info('No professors found.');
+            return;
+        }
+
+        const professorChoices = professors.map(professor => ({
+            name: `${professor.gitlabUsername}`,
+            value: professor // Use the professor object as the value
+        }));
+
+        const { selectedProfessor } = await inquirer.prompt([
+            {
+                type: 'list',
+                name: 'selectedProfessor',
+                message: 'Selectionnez un professeur:',
+                choices: professorChoices
+            }
+        ]);
+
+        console.log(`Selected professor: ${selectedProfessor.gitlabUsername}`);
+        ora().info('Filter by professor is not yet implemented.');
+    }
+
+    private displayExerciseList(exercises: Exercise[]): void {
+        const headers = ['Exercise Name', 'GitLab Link'];
+
+        // Calculate the maximum width for each column
+        const maxWidths = headers.map(header => header.length);
+
+        exercises.forEach(exercise => {
+            maxWidths[0] = Math.max(maxWidths[0], exercise.name.length);
+            maxWidths[1] = Math.max(maxWidths[1], exercise.gitlabLink.length);
+        });
+
+        const table = new Table({
+            head: headers,
+        });
+
+        exercises.forEach((exercise) => {
+            table.push([
+                exercise.name,
+                exercise.gitlabLink,
+            ]);
+        });
+
+        ora().info('Your exercises:');
+        console.log(table.toString());
+    }
+
+    private async displayExerciseDetails(exercise: Exercise): Promise<void> {
+        ora().info(`Detail of Exercise with ID: ${exercise.id}`);
+        console.log(chalk.magenta('  - Exercise Name:'), exercise.name);
+        console.log(chalk.magenta('  - Assignment Name:'), exercise.assignmentName);
+        console.log(chalk.magenta('  - GitLab ID:'), exercise.gitlabId);
+        console.log(chalk.magenta('  - GitLab Link:'), chalk.blue.underline(exercise.gitlabLink));
+        console.log(chalk.magenta('  - GitLab Last Info Date:'), exercise.gitlabLastInfoDate);
+
+        // Fetch exercise members
+        const exerciseMembers = await DojoBackendManager.getExerciseMembers(exercise.id);
+
+        if (exerciseMembers && exerciseMembers.length > 0) {
+            ora().info('Exercise Members:');
+            exerciseMembers.forEach(member => {
+                console.log(chalk.magenta(`  - ${member.id} ${member.name}`));
+            });
+        } else {
+            ora().info('No members found for this exercise.');
+        }
+    }
+}
+
+export default new ExerciseListCommand();
\ No newline at end of file
diff --git a/NodeApp/src/managers/DojoBackendManager.ts b/NodeApp/src/managers/DojoBackendManager.ts
index 8c8a5a9..c48da6e 100644
--- a/NodeApp/src/managers/DojoBackendManager.ts
+++ b/NodeApp/src/managers/DojoBackendManager.ts
@@ -11,6 +11,7 @@ import DojoStatusCode        from '../shared/types/Dojo/DojoStatusCode.js';
 import * as Gitlab           from '@gitbeaker/rest';
 import DojoBackendHelper     from '../sharedByClients/helpers/Dojo/DojoBackendHelper.js';
 import GitlabPipelineStatus  from '../shared/types/Gitlab/GitlabPipelineStatus.js';
+import Result from "../sharedByClients/models/Result";
 
 
 class DojoBackendManager {
@@ -249,6 +250,71 @@ class DojoBackendManager {
             return false;
         }
     }
+
+    public async getUserExercises(): Promise<Exercise[] | undefined> {
+        try {
+            const response = await axios.get<DojoBackendResponse<Exercise[]>>(DojoBackendHelper.getApiUrl(ApiRoute.EXERCISE_LIST));
+            return response.data.data;
+        } catch (error) {
+            console.error('Error fetching user exercises:', error);
+            return undefined;
+        }
+    }
+
+    public async getExerciseDetail(exerciseId: string): Promise<Exercise | undefined> {
+        try {
+
+            const response = await axios.get<Exercise>(DojoBackendHelper.getApiUrl(ApiRoute.EXERCISE_DETAIL).replace('{{exerciseId}}', String(exerciseId)));
+            return response.data;
+        } catch (error) {
+            console.error('Error fetching exercise details:', error);
+            return undefined;
+        }
+    }
+
+
+
+
+    public async deleteExercise(exerciseId: string): Promise<Exercise> {
+        return (await axios.patch<DojoBackendResponse<Exercise>>(DojoBackendHelper.getApiUrl(ApiRoute.EXERCISE_DELETE).replace('{{exerciseId}}', exerciseId))).data.data;
+    }
+
+
+
+
+
+
+
+
+
+
+    public async getExerciseMembers(exerciseId: string): Promise<Array<User>> {
+        return (await axios.get<DojoBackendResponse<Array<User>>>(DojoBackendHelper.getApiUrl(ApiRoute.EXERCISE_MEMBER).replace('{{exerciseId}}', exerciseId))).data.data;
+    }
+
+
+
+    public async getExerciseResults(exerciseId: string): Promise<Result[]> {
+        try {
+            const response = await axios.get(DojoBackendHelper.getApiUrl(ApiRoute.EXERCISE_RESULTS).replace('{{idOrLink}}', exerciseId));
+            //console.log('response.data:', response.data);
+            return response.data as Result[];
+        } catch (error) {
+            console.error('Error fetching exercise results:', error);
+            return [];
+        }
+    }
+
+    public async getProfessors(): Promise<User[] | undefined> {
+        try {
+            const response = await axios.get<DojoBackendResponse<User[]>>(DojoBackendHelper.getApiUrl(ApiRoute.TEACHERS));
+            const users = response.data.data;
+            return users
+        } catch (error) {
+            console.error('Error fetching professors:', error);
+            return undefined;
+        }
+    }
 }
 
 
-- 
GitLab