From 67f04ecd7c414d218b16a8478a1450a8a7d5aaff Mon Sep 17 00:00:00 2001
From: Joel von der Weid <joel.von-der-weid@hesge.ch>
Date: Tue, 2 Apr 2024 14:28:14 +0200
Subject: [PATCH] Create sonar project on assignment creation

---
 ExpressAPI/.env.vault                         |  6 +-
 .../migration.sql                             |  7 +++
 ExpressAPI/prisma/schema.prisma               |  8 ++-
 ExpressAPI/src/helpers/GlobalHelper.ts        | 18 ------
 ExpressAPI/src/managers/SonarManager.ts       | 58 +++++++++++++++++++
 ExpressAPI/src/routes/AssignmentRoutes.ts     | 33 +++++++----
 ExpressAPI/src/routes/BaseRoutes.ts           |  3 +-
 7 files changed, 98 insertions(+), 35 deletions(-)
 create mode 100644 ExpressAPI/prisma/migrations/20240325151023_add_sonar_infos/migration.sql
 create mode 100644 ExpressAPI/src/managers/SonarManager.ts

diff --git a/ExpressAPI/.env.vault b/ExpressAPI/.env.vault
index c28cb64..941844f 100644
--- a/ExpressAPI/.env.vault
+++ b/ExpressAPI/.env.vault
@@ -4,11 +4,11 @@
 #/--------------------------------------------------/
 
 # development
-DOTENV_VAULT_DEVELOPMENT="wV1mMYrxqWTL2Wj96VczZ0UYNUBtFDVOopa5U5UmB4eF2mZ37ZvClwEWQweRzQYxWUgAw4gH8syFzXZ+SReEYdanIoYNGn7zSvwtiOUX8kSv9CXOrD7NfCCgz5UEQm/D8ZfI2yaAaZ/YX+oFibloejnhAvNTlATLv/PNbKBe9af5JhLZQ2BKKy2N9FUS+FK1rZvfStdAhOmPSGnY9gAwKT4sHfF80LTaG2r0HLTO7icbSM1R7ro2P7U7JMPKuC9AJwj4fKmf5lkw50Lsc2DUI5/WsJScg/1SntGsnsCewJOv2ciz1HZNAq2r2Iko9z264eG6DA7+PUSn35M/NgxWkfqYHGzaGzs/4nOw9YcaxyKUr8fw+hvqUivx979eYAAkQRrzLDA4N5jWQX0TZXEhw9mY8jsBLnYdwz7fERfkyHTZKHXDDsnq99NArBI2k0iiFZkNkG2vkVRhBFd7X42XEVfxhfrYl8DExzWyXKxiLWHFvTf4JOTDNaWdmHRxbFHG/ONz8sxBZuTzeV2pXQSFmWP1sBUwksr8NX80SqZDfGK+CXA6h9oi2+KdFUS9a5/0hgHRt4JzrpHvniQaEF5n1+MLGN0m4jFxEFefzUV/5WF/e5KoBgODAlgr8o8t+p1GTj85skmaYD2Y8uSQtRGyjSyay55txOz8V3XiOiksOjGeP/0tRjcbWL0Oxpzgy7OKbGOJauPMaHyL49P+GJ5/P7S5O2whu11L7VlbtwwuI06Vm4+hPrE2XybO+1EcaKFDBSgd138pK+e2c23uG2vg/6JPqKGUESivD+wEnl2MKo4bwpPT4KsQLyYer6QjMLHiQFkCE8Kf1bPQKiKbjQLNf9tBWegj9R/tH43X6e+lT7gdmqWQAMJOWj0wG+vcJ9F0urHFE45K5p57rEZJKXUJ84AKVRHtW+fgpVbLKxalIHqNJCpoR33W1z6D1qEMGHguLx1VbiWxofGRLFUMHMeEMlxmVjr5MVWFfh9o4cmsdJfUZAqDgtR6GDNMkhXsoFPul5ucbA84RBUeHP1XhD1rVB5jwdS7zxagrMxZrnadzS26IAldHcHyEJyeWNrdbGiGSW9y9Yom6e9q94eK2UbhPKV6NbcIeHcTi7DQgxrVuKdd3dvqEvyHrt93e7/t5iKWAKXZhw3nqQm/h8mMs92YSyO3meKNht8mDeOC65Ot/86dDN/OfRCGqkvjPUgQGUVmXDOv8gTqkZyN5/+tSaIRI3gWkd7iwOhhEwJjxwuRwP9XA5eygXgvcn8je/Oi2k0pkyBQiram+IlOAoHQmMTosvsiKJi3fR4dzP/mGjOKmSE0vm3IGUxLu7gyqswBTW0ZS+wqZrXsFJpJ8LStf2F73cSg+meOxNR/HiryDVJVTNHi0qv9aoM/wQMVxKT18QLN1CFNo5qKXf5IaViLhQH0q+9BcT4LdmBqw5TzrMUOgWBR3YyLEGQgsYPO4NTtMfKKd4loUXLehFtxG1EjtdCmILA+yTMbjJ6yKCqoLQTpHc7VeSIGzE+87WDocum2N9Fo6TAoFeheNXMNIuNd1pcKoYNVSIzG4d82VVzT7lgdMkpE6KKAHKjUhM3GsL8kB2gU81bnqFj5HvCZJRUdC4wIEORWB/HOYUIY5z9jwFnMUJpflqFPLM4JXIvPBw++3xNCs9cMUISdBosRNRu8hp8O16kfNe+gojkfWAqyCdAttfolpLa5YSIUsf/rnxRTewHLYpJAf9JIjWzAu6pmmoHARZ9SLwOH7FNfV4qH0jQlVj+mgYEjH4pkcDzH3nowpbbDvy4wDxXlKBCX2jJJx6tIYxEFJmxCPXFudMdNvu6zOoK52aQDRzLWz+x/FBD/hO12HRNrCN49nEFOcjaAdrwrj1ELWKRH3eRm85p6nVrxDUs="
+DOTENV_VAULT_DEVELOPMENT="ZvCYPoF3NQFsrwjQaKg6RILh8P1yds7Pnxt2n70AGCfOYqwMuXBb237X/v7yzPSvQywpiJphSG61NtZXoMZiNcCX3q2DrO51+oagh+XGuF30S8ImzfEBeFk+IEbPb+ZvnY+iLB8uZZakKokN5UpRA94aos4ooCGEkoFHLJrJFq2QGeKsceyBbEDOWDaWcpj2JhgxlBa89vz1fhuKnBkFvKq3K16eEgAF4hjBZGWI3oChJMPH6wtBYqnDIchStCcBPHlEQ1MbikO7/wSCDu3JhuRnQafEwr3StlIBHvBk933/X2coJooi8Etz36oWd8T8JseJ9mK7GBujMgXOLCAcqLFqLB9DF5pRJYIvrnCxZ+pekI+9WMmZiSZaxK7blvtdb4bYX59JU4QmScbVPNgfwUwwmplVVGfVWkB35a7vS/z5Nd4989WZgxRhvSMb/PW7C63MOtpgTTubwl7IRgNq6yqBy7EEjPnEVkd7F5d2XMrDsVD+kD3BNgGpozwDH9SZQDr1v2xbzJzNox3rLLQXuMDjXojR7rwqggkQfWDmm8WgA87piV9fchWSaVoz+KQKunYsavZQ8bmKXwuW2uqJVktS2WlmQZxwYBEOD7n7mZxvKO9vkuhem7VAo9XyFMsnC/8H3/nNw3eiFTLz/HPnTnCDsAO5lj9ICxx7hW3KwpNkjVl5+KS5uqN3cQCLnaJzZNF2utktnzNCIbYyzq1xy9sjY6TktWqAu81BYBlTrdAnNTB17bDBfcrAL+H2JU2ehzqrECeeUEvgZ16GolkZs3YiLUOTy4+KZtC/MmTIGY5sD4JQ9Y37eWkE0E8x2x4v1MhxEGuQ7eEd7NHlzGJI6hM+XqDmb5t+2a2B5g1xpoLuEJfQxBqYmLW6UwRpC6PklK9BDvduVTHXjsb47VAkR6whLjrk81vLshMgT7hwYoBsdaA4caEdgizluDARgH2FpjgYomAHXyEes1Su+ZrIyySg9SLLOFqtjAnPMMy3eoPY/Pqs2hyYpdVqo65oAXMWSwEVWpv+Rbwb5Ns+UT0DS2M/Z0uBq7Jc9fws8i+IqcGojhEE+gzhATe0qtM0f1IFg5IEDLOhM7/4UKKFnnUTnM7m5ThFfGsmiXCUnh7F2/Lpls2KRalDlEubIRBza18Oc9JZjo96yU9bXPNiuow1orN1tcvMuXNl7T/Brz0eVuoRUA9zWcjxMKpwIez/WLmxmZhCdEe310dMcjj5zGHkcL8pEhkxDOM5zRXnt0HS+Z0+egKx0fQQhmcJ+T2Ym4+mgDTik85fKBztAZdDjP+ERvpmclvS8OHbVNnkMOHrYPIPNmU54b7RRKRg0XVxVhyPOSEsER6fDA4+4CpsmsFdaGjeyKoVkHNdPCRvnqTTX658er0ksi+bcUKRjXzsyJ4QXHuriMPK1Lbjyef0nutLu8MOphWM50eZx4qh1DAyF5Sk5ihuuwepCAaqNwqaS4QGtf6M+/cLr+AhzbfS8pwtc27NzGEvwxKTHOhtjricsaZoKCRMycr9pK1ATb+jcjNXBoS/uScXtuBgnHLVQXTAUe3tvYbbxe6rLMCPunbI41NO3VZwGaPPBef+LR0ii8FK/7qeclXtn9CZmbsLb68ZfglVmQ6RcWuOiZ/MhsQ2aNC+Vq9J4JpP9Vw2NkKIW+K8y0JLMcfox09cOVm7ub3zggLhPZ3+UV3nxYkYcGm+2BCllrl3zWH2d1OFPcsSeuMB3yjWbn9wCx3JuZZESTM2GE5muiec1gDanRN9Is6uZckEA4f+fQanb8/FEqx16G8XbqF0J0lwuFselnp0BGg5ZLTzf+/fsj8qXoZTHfduadL0G6C0bhNRw85EH4xhxF+z44DCFk3OQFLNoTQnmBLkMnXSx/8z7c4foEa95PE4Um/FhnzSPplQbtSr0El5+J4gBrdn3+xvN48sHnbkpi93i6RUxlOa7ayycbl/1OhdIA/WG8jy/U+et7Q="
 
 # production
-DOTENV_VAULT_PRODUCTION="1Q6Ywlc8nD2awsBAkACqpP1fpmxJGBvQrVaIiioJZHMk5ho/TpIO8m+24D4orDiIf9eBEtzcZBp3gyT7suEHRh/AKTVeH1ronQtCX0iTQhxb1QYmnULYqRqczl5/yt6j8i6Cjz9PpRHJIPuEUl1nZg1OGbxaVMs2gk+IHrH8dgu6sfppPV7OfMs9tB/wg8vG67W1ppZOrBgAZAtCGLhfElLrHV+J4gs17WjLdsmdPIxvkA4fLQakbccUPS938tmxJIA7ViKVamcTKK7BqYGSBhyPX9YfRlBgUvL+G+wS4/QcD2MHF1aoojhVg2DPFlVX3ELO6mVH4621wu+G13ca5gtYtxbZrvenKId8yFhF3mDoEU4doLayw8uRs5qHkEw9KWgynrN3p7I1X0u9kxf0hfWIJN6HoptGdbemjL8+ptxQuDD7bJt4zNYHDmEz7ZKfmYCGz5PphHLiMsdcidlxkpbt/Ktk1mktXNJXswdq2XXmPNP98tR7ixzd47c6CG5RMjT9FyyvsWhXEUHwCy0SJ2glLk9I7JcA3sK9iOU1BTRXjSFbk6+DE1rqUkd1dJTHGAusV7ej9Po9Yb0GWX6Hm6nxXuockpXBxPV21ByCPPJRBhv/5tBKqg2vtqPvBCAEjomJFO2/zvQR0sAPrykViU5Qyi2G+ISVXxhPz2k1PO0i887hM2WwtJIDaKv2K5WZfURohkDTh2JCQ6LAZEUu3KInfIbtQyo+ZWMWipdAe+CQAuYAsP8UV19sRaBYI72SRzxQJVOVu4dXLCXn7yTAzTZz9fvCke66aRKz4LWeICBEWyd+6BzgjFyBtxIA1WqmT6cyVN0/RjdYf6zpJdli4jNZnrYNbAqQUgYX1rI9JaCdnHZwF9uUu5INaHwGZ1Sq7Huv10V68UUW9HBzeR/C1I5ZzRSLjTlCnWN+VkQwydRARnx0oPXP4kPv70j9TE0Yjh2F4p0NwVlyRr9ImPeUtY1LAlO5YGZnexRNk2Q9F5juZ5bxzMUbXVVdM9kaFHJrlKkJHwFjsnS79YYmj1ZTHHokI+eN7k/3i6Md/e96Ylfnm12oOsKOQ6EmAqR/+kh0NIyFrszb4a3AxQE7jq5fpl6A8vUtZv1SB1G/ssQhB4pA5qUpUNBtzxml2j87unYPjZgpPIKSKcANQEIn4kCg5xkg4dMZgzCEfvliTHTQ84gVYh0+jZOnH/QtXvLt01yajVnYCuJPUXUfjyHb5NQH04AOPvG+eea4p7z9YI4LyK5LdMhIfgha5Rx3JPbBKQuZ/b3cy6m07Bh2PsWX6hPrs0w14XPbWojglkJR4nV+9d9jT9tyts+VZLlvG4yDlZULhm0vBK6zHZ2O+3DGRhQOPrj59Qw81jKgqwTdkWW7tjRbfGXsuaCfA/nABgW/CCC0khWpGcfr4u7bIdP6hMsADlg6Xv7/BHedc2RznBvTUeJRVd/9azYT67I4bgfXDmzA2mHRbV8QMXQZ+xo/d5Fr69Cs6gSkRZiImW3cwi4ovGbg1UqE8Pl2B887PCJIoEtldcKNFO1oovLa1Z/SyCrQg1ESFmNKtA0CmImAwIWgi3tUzD/SFxo5hyoe1GAp+3LmpRwSeJhOx/33Aobld2o04+yaydH+npUEryc6fE5vlXRjA5shW9xJIDa+LuBao60iQID2fU9CKmEjx1zrCn3afQbhPvN3LAAUnu8HUCqQzT43pH4lVedm5Em0aDMYh2qMSzZLwCW0cSrIhqFT38YsaDg4cl1R5aoJngCBw85Ra40kygBrvOdxlKk3fDtBqEDPmcWT61EIbUqSlZ857GEhvhRoM6okfpF7ksyQNRzNOx875D9f5hn9cfrO2R8dV5GuVmvdcTGTX5D93UORt6Pg0FzLHiPerqVJdSr2LX4v3iqqs3vDhdRt0ph/"
+DOTENV_VAULT_PRODUCTION="hjMeK1eTUQoQ4NeGSeCeQ+JRgrGeQHkuLBcM+oOEJ7EwfwD0O+EimvR0WIH5My/RbEe76LNa9GF8mKC23/PgWBagSYapGDsGyaX0oZEfdS7lrFNMAoPXXp5r4J4VQ5xelkALtrA6HhITaUkOAWaDHF6gQtoSGAHG0kNs7axutt5e+BizCpn1SUV6iUVwxEaPNi/9KEpAw2GVLtJIe2AWlQ1ub/91/5MfqzA68xfncBkm6UAB+YcgNPq/t/So/gN31jtUnjAjkZw60QXz1s4x4cjLHrbBwA+spM8Q1jcCy+G5I9KcTEI6juZi1M+/zrVO9er7iWvySQA1rcAJiKhizd0lAL2aoLKV0kuQgkwRFdiQZvyiczMsMKFTMjWGr5U5CGETuG//iX7/CvVUILTqGdK3PzGlca23PRCOcDr/103zaUE0Zmkk1qePg577k2lvNuJGaInChD2J8ASI4CgsKUxaR8r5tl5DDZbcQMPNRL0AsMdzqiGLLspoZIsN9vGS2Tw+rrDkGVdsWoS+De4HygD3Zz1qjjHs1AuUqPG/avrlpwrNGK7W0GuMMZKGPP4Xhj8j6etu3iqCWcdp3hv8jZ/wxzIwILHAiph0UT8l7sIdf0C/KkjPW/GFZKFplxr6aC05nDy3JrSsIM3xOEntPHsNm45XxanMX5ZHObniPVGkmQqkuJ7ZARkJvCZKllsOt3PLxduaZdflfkLAth0jJOr+dH1fiU1799bntf0a7aO2RAcQZ2FNO0xqM6cR5zqMx3Y0R/BmHWk4ESi7Oyr25mHQWhNnyi0SckaSnVpGD93w8+zQuBnjgf136OthMMdvBH0oxQg1Mxy5s3WgRvVZjRXhsFCKiBk6rTFcRF14x4HIquptYwNSRwAdWPh2uLER90v3X4OcFAXcqCR0tQne87BXIwlBdXT8Dbbv2BbzD7XnMyCelxzrmC8gHAKv8KcgmCo4cvHrH3lHDNkAGJIn+ETcfXkrjvngJV9mWHHWmwWPNFl1rn/UvdMcEK8UU/BkmSACzJrGH2+5VFdFyDzVs0cXSL76jypP5kJMOegdVZvWwLZym9nE1ZI55heuX64P4xje/+ck6wKnLGk8k2VymkbZ3WC9NhL6+yi9jE/6HN/NBUKVQ0fEqvTh2AbDialJqivUtQ7TRtCBW2QmXeNJQYXL1LOG2AGhwt7d3tRJU38WlcN6DDGctnNntG2gFTTOdZL7LFR/bpe3GHBRFbbv5lnzzjeijVTjAM4jaqfLjJG78rDIZWbraJNvvpL7AVfuj8bn2s2q+UANjTg3qMEbtGyA8Ak5pG23u7XGqcMrUkdA/5JTJknIhgdEiYuo51vPfDnp3/Lx5hdFxxMIkTLovmH80vzJyXlu1vQ9xOqsH558OYo3r5xZ68cx1IUIiZO+joJXr/5fB8o25mykvY3JipzUrSeMCi8hDOsjMyr1LFaoJExiN7EzmyMzbSW6X5fPOoiL7+OppTEl2+/uIJeVvp5p4SBAv5C9FqsJQEwRJ0nD0J8ve9RjUwmOoYYsRGCU5ylzvfGoEn1eBpPjMnYaDJQLfphhVFwem1C66s5D3xBXSjHHsHVsgAEyeGk7EWXADMhtE2mjJq+VUES7eGkqIvcwBos9qbyPo0uifvbySzEG3GUdIBHyz4i2rmaayl1O4lhV9kX3FbrPaukNMVaZkcPAlHKVEbTel82957vrB+fT7qQkf16regBg7PqmflfmHha8dszRpCxvelMmD+gVsOls1ykVQk0KBgfHmf9PfQ/AnNxh+JA2nHK430RJO69Z7/FOK1nMN8p0mDVS+mxujx54HJx4C0IukXVevr4+u/YpZI05Yx0l9VcbRWWHpi+L3B3/3gvdvqKpQ9kbx/12dbPX33mg2yLFrRSe9GqWeNaRcS5GQbdTKscjV8jyWZZhxkzKidajxrnwJrVEqA3kqmV/NbjqvoxYO+iQd7Bf+eeUrAQZeokMSmwTVM7yRG6RXrr0"
 
 # test
-DOTENV_VAULT_TEST="1+zTbDzJhNzZftiNfawwioYqlzqnVxHH2pvd1rRFMUvdVXoqhG+/qJpTkXlgIhys6PkWPGSYOy7492mHFxVrT3aMomUYWGMQf+o1hDdDY4p2X0td/mM+SLcrhJFGV6Vqj3vho9bPwi0PNhludbEmXH5NFtHrlnEkFE4Gx8Y+5R5dVtet5XPAEdaeNV4XuFhMengUjovpS2ZC3Tl6AR3kKXeV3s0TKNmGEGYdh00/uEUKkCUKWduJKMbT5S6sY2OZ3E20KvyNhSOGvJvvn5/ubphItZeJCEjQCTAeoJg1/LnZw9w96odcctlUI3Mk6GHJfsXgf/aD2f75wHaNmqIB88D3mkv23mpaQJF64/UU6MQtmXpTx6effhO0VY41FVeIIlQYos5/hdWo7dnJ+6M06RVmeepKDSXJwuSpd7sr02GkOfAo+FsyMavFfhh/KXhmMuSpG9cesrN6UV8jfMOMjrZR/TegaHNzvr3OVU8u/16QdtUiAV/oOHMbWIM7CLHvn6wTCMltpdUqwAV8B8sPQcMk7R8L15sfkXD3PaasxdSKy8xdn06afJ8GcrxUy4ggvTgJU4GUJS6E0AIVa1fs9amtTENARwIzxHi5FV3Vsl98u6M+i6W6DTZwOkGoTcJ17F38Bw1evLPxGA6n8G6kPjW7QzWxNAG7vIF/OoYhADMqLS6sm0+FCucIciM42r9LHNKDizZfsAdGcnYRzcp1cFTSHXqKyFuNma79Gxo95qJL4rfYnxrSZdJ2WJURPMuhFXBIqTsiK5bbCLBkhn5U9Ef8nJAjz/dMw8K1x9VbYWbEETF01MT5Ay5KhNqXeeLGbrR25yKnTuKcHY2bIE/dlgBmGbxmnw2KAcrhn1HCmNlzEbjyaoVfV6EiHnT2wmiT5xpy66MWj0XgNio/Ujjqkjydtd28iCdcJkfneyB3PO7jfSNP0pm+9XSLCFx3KkQ20BLnm6vgQ0pbuoDs+v6lswOfAktd0mon7T4ZUEY2qTmozEzdrCSy8Ef2hoSb5sdUiO5AwF1ec+qXn3FiOpl0/hunrSSeEIv6GOJxnpGrZ7aOATRru3oUB90du9wb9jDn0UCQF3OaJSXERvlK7IX06JPC11inStwzwnObUdnFNEHJucOg9vdIx27b2H5unDiu6VzGsjpvg4J8dYHjhkkjtzWtpXFEcdjezlZqhJCuprdu9x71JUW2FwCMJt70H9R+W8VUtnDTGD+zYJqzELCCP9C0Kji8tYkuKP6X7N1K3wUWqbi6TePpKEu9B1TxyF84ANlg6k4Zkh6Sj09uARbw5uA0yegYyojRC9N/JxBhr/dI13wWH5ClGLUApv08KE/EIAX5NznLWgMRWukW9kt1fJ0Tz43odgeh/ovyvasLoeg+QFLnd9NJbpqiC5UULbgYMF/qG9ko7JeXGZPrnL6pgCmxOfZB7vhb5b60aQWmjLiKLvGV3GbIu6TRvR/1OY0AWlljK0zYP0Qk/cEwAQEp/rqcIrZwPMgb764PoIzQNWR2hOXj3POGVsDXGJcOoTa/dsC+vZUYWOeQErBaILUACvvLizIZS/RgpKzotEFe/IEtRVMuW4RcVctjl0ykYAIiTbcyB/byG9lSzlDEy31uKU64Cnwk/4/88T3kIVHZUy9LEMtr8t4QymqKYnEkRuj0GB0/hcsK7lsnSMwzro/jju4coPgplP/UQ9efxmwtNE5BUdcgPEFot4+x4jtxSxWrJsAOqImN+GBMD/yIvzZb6t5p24lKyJorsNjFBKlNpHNrrx2L1ujySUZaGsJx6CWpLkIvSzveuaPkRgzh2RfU1LM5BY/q1jYKtnVMP3UsqwUqdS5UJgOWXyAZ5Eg/jYAMQxUfpap6lrBf8ET7r+GlDObJ6Ca4DYvOnrir3mgeAfy5tEy7vQIKt3tkCwOf7Q+w"
+DOTENV_VAULT_TEST="hftwN1f7KKCcI06HRZKAGPdGYqvZQ7V6EuoDHRImnqCIoCOEEgCA875GXVQ7q70JVlg7aNa4fmLh+o1d2OJjCU89yThWpnyppBDrvZhXsV9rpubclvQdvdivWI4WBWK3myCgLDQ6F44VJJy7BW/K1PNqg+DCMkxYn+ECE9sm7F1WF6soChAnHBZSOywsu8uq7TiYfID25RHNmxxIzoWiLvc+xv7fMLyeQ2cKWY3hU8DDf6r6nhniWgFPJreJEea84vwLZ5Cj8BJ66TcHMuupCgismqoX/Dw2H/ZaU8r25FozuIqGdnwdgii8iYjJtIIItdb2IyFbeMdFqpdEggvcFziV5GlTQyF1mAXsp35XGuvSg2x0Kf3+t1HP6g3a9oNMWyeT4xXf02odsRHLDc3LReNok/KVkg5jybUbeWKexPOxW18HZLaIEOxlJZ+lcZsT1I2Q9OLXXxspTpxrw9lcuDxKTiGR0k3KHCqzEn3mac8HkQgbBSf545Pl7MeApXRaXO82F5yLRSyrZw5DOHJs4mCviHwBi2PfRpgiE02D1nWx/TlxcUhPjWp/7/zlNG0vjNTvUaaCV3p9pvUegAbVUTEkwkRTF8Xx334QF/yJm/YjmszEyK1LLSh7d1TxPPWloa6SYF5i8gzQpkicaZhg1cKiLi7IYeT2y9xlVzSH6HCocKjJSeRoxhlchL4hsNzSR7HyoN6Bg4tAoG6yceO71XXPrYViDuhru+mIXuezcTkud740zoUQYO6AKvfIPzhXbTomC+yxKDyJVjd/P/gFdLuVvjLnP4CA1yuO21b6pqdtzODgiWQJbtDu8rznI/i4qzdkwZpv6YXgQbjf2TvdYEIs1qMcGq2c18IvBnhoU2cCSute5+zHni3hlczugIuRpMk5qbLUqlI17Avov92Wp/aEDlMNZMqj4WpOLEif+2ZSmiBEiTR7QjCdRgdBTG0eutQYR1Fra8IJ54LTUUp4vkiB4pWMAQ0v16IvI3IM4tJFVUKpNhnhtSWkdQwbZo/nHFbXj56cPtkJJF+KewSFNmWpZ/RBK4jzXUyycgGvh2Q88XMNUUv255l/HJ+1tRoUlSR7sW3XzB8J9NFSD3gWmXIa4vBmZyuMAgtnVjMSf+tJLGpWIaY/0Wh9Q0qptylHmeEPjbsKKcj8HEmbHPRKnfBJCIKL3R8YZrvWsjX0ADbx97c5L7IvDl5fHaSoYVo6Ky57nsDnpjdtc00jpDDBDz01dwyDQIHH5Bfh2uLvVj5LVoK7fyq/e+aA7IT8TjBkd9NAkIHRStp7W97rrT9bkTLB6noB14l2Yp6wcy3jpLGTcwFm2jjL9RCgFJFH+eHCDXEZihWQErMkd4S09Lr4k7DEFCf25Uy64Z8chkfM9cS2meDPAw2GQn3v7jCabA2qo81iBGiQPrdVqvUVEafDbCrtg+IgtkfvU/mtY0pX3KfunYRCwMJIESWFPesjw16Wsl/FBQ46pgZ20PJRbV0HI8Ry+1prUvAjM7wB4VmG1eKEFhPnepwPrg0s68S8UUfWeG7tIzKyD2X9dV1Ui8nOm6O0T6T2aD5Vwx0mTaIEf2b7/ZyC1g1uIjqGT2B+FUruG4cqlcoezZkuoOChWi7Njap1pzs12XTs5W+ij43Yd+rWYfsgidID6xRSrvAPGX0EO3LjMmVU6HzAzLXJyk/XUQUGkit1uUIRS2petAsWCRvKQzALuG9l/36J7+RN8BOIzT8UDiwbnoAp7A0pAEUFqbFx4DJuYkCD1JuhwA9eRWwONAHkqqp7ITwEZxbmHpmhZ/acTZMIZnVSb6iO5woEQSjpcY7WFlO3dImtRg85LDku6SIIKcFp85MIhBkYzhRn3g+NyyUdkvhJJrNiHCfF2ewQi9I4CdZ5VvGCPs+g227vYiJxe7J+CFL+qDP89J1pdzVWjUX5GDNcV4UQGCuqUoNmM+4uqvpwhDxsY00XHQw+AfCBndgFht+jsvD+ahktJr2m0MPWsSE6"
 
diff --git a/ExpressAPI/prisma/migrations/20240325151023_add_sonar_infos/migration.sql b/ExpressAPI/prisma/migrations/20240325151023_add_sonar_infos/migration.sql
new file mode 100644
index 0000000..d2cfe2a
--- /dev/null
+++ b/ExpressAPI/prisma/migrations/20240325151023_add_sonar_infos/migration.sql
@@ -0,0 +1,7 @@
+-- AlterTable
+ALTER TABLE `Assignment` ADD COLUMN `sonarCreationInfo` JSON NULL,
+    ADD COLUMN `sonarKey` VARCHAR(191) NULL;
+
+-- AlterTable
+ALTER TABLE `Exercise` ADD COLUMN `sonarCreationInfo` JSON NULL,
+    ADD COLUMN `sonarKey` VARCHAR(191) NULL;
diff --git a/ExpressAPI/prisma/schema.prisma b/ExpressAPI/prisma/schema.prisma
index 5f2f6e8..2d894bb 100644
--- a/ExpressAPI/prisma/schema.prisma
+++ b/ExpressAPI/prisma/schema.prisma
@@ -42,9 +42,12 @@ model Assignment {
     gitlabLastInfo     Json     @db.Json
     gitlabLastInfoDate DateTime
     published          Boolean  @default(false)
-    useSonar           Boolean  @default(false)
     language           Language @default(other)
 
+    useSonar          Boolean @default(false)
+    sonarKey          String?
+    sonarCreationInfo Json?   @db.Json
+
     exercises Exercise[]
     staff     User[]
     tags      Tag[]
@@ -63,6 +66,9 @@ model Exercise {
     gitlabLastInfoDate DateTime
     deleted            Boolean  @default(false)
 
+    sonarKey          String?
+    sonarCreationInfo Json?   @db.Json
+
     correctionCommit      Json?   @db.Json
     correctionDescription String? @db.VarChar(80)
 
diff --git a/ExpressAPI/src/helpers/GlobalHelper.ts b/ExpressAPI/src/helpers/GlobalHelper.ts
index 266108c..9d5e5e8 100644
--- a/ExpressAPI/src/helpers/GlobalHelper.ts
+++ b/ExpressAPI/src/helpers/GlobalHelper.ts
@@ -5,9 +5,6 @@ import DojoStatusCode            from '../shared/types/Dojo/DojoStatusCode.js';
 import { StatusCodes }           from 'http-status-codes';
 import { GitbeakerRequestError } from '@gitbeaker/requester-utils';
 import * as Gitlab               from '@gitbeaker/rest';
-import axios, { AxiosError } from 'axios';
-import SharedConfig     from '../shared/config/SharedConfig';
-import * as https from 'https';
 
 
 class GlobalHelper {
@@ -58,21 +55,6 @@ class GlobalHelper {
             }
         };
     }
-
-    async isSonarSupported(): Promise<boolean> {
-        try {
-            // Use custom instance to allow self-signed certificates
-            const instance = axios.create({
-                httpsAgent: new https.Agent({
-                    rejectUnauthorized: false
-                })
-            });
-            const sonar = await instance.get(SharedConfig.sonar.url);
-            return SharedConfig.sonar.enabled && sonar.status == 200;
-        } catch ( error ) {
-            return false;
-        }
-    }
 }
 
 
diff --git a/ExpressAPI/src/managers/SonarManager.ts b/ExpressAPI/src/managers/SonarManager.ts
new file mode 100644
index 0000000..3bfdc9e
--- /dev/null
+++ b/ExpressAPI/src/managers/SonarManager.ts
@@ -0,0 +1,58 @@
+import SharedConfig from '../shared/config/SharedConfig';
+import SonarRoute               from '../shared/types/Sonar/SonarRoute';
+import axios, { AxiosInstance } from 'axios';
+import Config                   from '../config/Config';
+import SonarProjectCreation from '../shared/types/Sonar/SonarProjectCreation';
+import https from 'https';
+
+
+class SonarManager {
+    private instance: AxiosInstance = axios.create({
+          httpsAgent: new https.Agent({
+              rejectUnauthorized: false
+          })
+    });
+
+    private getApiUrl(route: SonarRoute): string {
+        return `${ SharedConfig.sonar.url }${ route }`;
+    }
+
+    /**
+     * Assign a Gitlab Personal Access Token to a Sonar account (needed for any other request linked to gitlab)
+     * @private
+     */
+    private async setPAT() {
+        const formData = new FormData();
+        formData.append('almSetting', 'dojo');
+        formData.append('pat', Config.gitlab.account.token);
+
+        await this.instance.post(this.getApiUrl(SonarRoute.SET_PAT), formData, {
+            headers: {
+                Authorization: `Basic ${ btoa(SharedConfig.sonar.token + ":") }`
+            }
+        });
+    }
+
+    private async executePostRequest<T>(url: string, data?: FormData) {
+        console.log("dhdidid");
+        await this.setPAT(); // Always set PAT to be sure it has been set
+        console.log("hehe",btoa(SharedConfig.sonar.token));
+
+        return (await this.instance.post<T>(url, data, {
+            headers: {
+                Authorization: `Basic ${ btoa(SharedConfig.sonar.token + ":") }`
+            }
+        })).data;
+    }
+
+    async createProjectFromGitlab(projectId: number) {
+        const formData = new FormData();
+        formData.append('almSetting', 'dojo');
+        formData.append('gitlabProjectId', projectId.toString());
+        console.log(formData);
+
+        return await this.executePostRequest<SonarProjectCreation>(this.getApiUrl(SonarRoute.PROJECT_CREATE_GITLAB), formData)
+    }
+}
+
+export default new SonarManager();
\ No newline at end of file
diff --git a/ExpressAPI/src/routes/AssignmentRoutes.ts b/ExpressAPI/src/routes/AssignmentRoutes.ts
index 93faa05..dd9ca30 100644
--- a/ExpressAPI/src/routes/AssignmentRoutes.ts
+++ b/ExpressAPI/src/routes/AssignmentRoutes.ts
@@ -10,7 +10,7 @@ import GitlabManager               from '../managers/GitlabManager.js';
 import Config                      from '../config/Config.js';
 import logger                      from '../shared/logging/WinstonLogger.js';
 import DojoValidators              from '../helpers/DojoValidators.js';
-import { Prisma }                  from '@prisma/client';
+import { Language, Prisma }        from '@prisma/client';
 import db                          from '../helpers/DatabaseHelper.js';
 import { Assignment, Exercise }    from '../types/DatabaseTypes.js';
 import AssignmentManager           from '../managers/AssignmentManager.js';
@@ -23,32 +23,33 @@ import DojoModelsHelper            from '../helpers/DojoModelsHelper.js';
 import * as Gitlab                 from '@gitbeaker/rest';
 import { GitbeakerRequestError }   from '@gitbeaker/requester-utils';
 import SharedConfig                from '../shared/config/SharedConfig.js';
-import { AxiosError, HttpStatusCode } from 'axios';
-import { Language, Prisma }           from '@prisma/client';
+import SharedSonarManager          from '../shared/managers/SharedSonarManager';
+import SonarProjectCreation        from '../shared/types/Sonar/SonarProjectCreation';
+import SonarManager                from '../managers/SonarManager';
 
 
 class AssignmentRoutes implements RoutesManager {
     private readonly assignmentValidator: ExpressValidator.Schema = {
-        name     : {
+        name    : {
             trim    : true,
             notEmpty: true
         },
-        members  : {
+        members : {
             trim           : true,
             notEmpty       : true,
             customSanitizer: DojoValidators.jsonSanitizer
         },
-        template : {
+        template: {
             trim           : true,
             custom         : DojoValidators.templateUrlValidator,
             customSanitizer: DojoValidators.templateUrlSanitizer
         },
-        useSonar : {
+        useSonar: {
             trim     : true,
             notEmpty : true,
-            isBoolean: true,
+            isBoolean: true
         },
-        language : {
+        language: {
             trim    : true,
             notEmpty: true,
             custom  : DojoValidators.supportedLanguageValidator
@@ -149,7 +150,7 @@ class AssignmentRoutes implements RoutesManager {
         params.members = [ await req.session.profile.gitlabProfile.value, ...params.members ];
         params.members = params.members.removeObjectDuplicates(gitlabUser => gitlabUser.id);
 
-        if (useSonar && !(await GlobalHelper.isSonarSupported())) {
+        if ( useSonar && !(await SharedSonarManager.isSonarSupported()) ) {
             return req.session.sendResponse(res, StatusCodes.UNPROCESSABLE_ENTITY, {}, `Sonar integration is not supported`, DojoStatusCode.ASSIGNMENT_CREATION_SONAR_ERROR);
         }
 
@@ -189,6 +190,12 @@ class AssignmentRoutes implements RoutesManager {
 
             await repoCreationFnExec(() => Promise.all(params.members.map(member => member.id).map(GlobalHelper.addRepoMember(repository.id))), 'Add repository members error');
 
+            // Create Sonar project
+            let sonarProject: SonarProjectCreation | undefined = undefined;
+            if ( useSonar ) {
+                sonarProject = await GlobalHelper.repoCreationFnExecCreator(req, res, DojoStatusCode.ASSIGNMENT_CREATION_SONAR_ERROR, DojoStatusCode.ASSIGNMENT_CREATION_INTERNAL_ERROR, repository)(() => SonarManager.createProjectFromGitlab(repository.id), 'Sonar project creation error') as SonarProjectCreation;
+            }
+
             const assignment: Assignment = await repoCreationFnExec(() => db.assignment.create({
                                                                                                    data: {
                                                                                                        name              : repository.name,
@@ -199,6 +206,8 @@ class AssignmentRoutes implements RoutesManager {
                                                                                                        gitlabLastInfo    : repository as unknown as Prisma.JsonObject,
                                                                                                        gitlabLastInfoDate: new Date(),
                                                                                                        useSonar          : useSonar,
+                                                                                                       sonarKey          : sonarProject?.project.key,
+                                                                                                       sonarCreationInfo : sonarProject?.project,
                                                                                                        language          : Language[params.language as keyof typeof Language],
                                                                                                        staff             : {
                                                                                                            connectOrCreate: [ ...params.members.map(gitlabUser => {
@@ -215,8 +224,8 @@ class AssignmentRoutes implements RoutesManager {
                                                                                                        }
                                                                                                    }
                                                                                                }), 'Database error') as Assignment;
-                                                                        
-            req.session.sendResponse(res, StatusCodes.OK, assignment);                                                                        
+
+            req.session.sendResponse(res, StatusCodes.OK, assignment);
         } catch ( error ) {
             /* Empty */
         }
diff --git a/ExpressAPI/src/routes/BaseRoutes.ts b/ExpressAPI/src/routes/BaseRoutes.ts
index ee028a8..3f60383 100644
--- a/ExpressAPI/src/routes/BaseRoutes.ts
+++ b/ExpressAPI/src/routes/BaseRoutes.ts
@@ -5,6 +5,7 @@ import RoutesManager               from '../express/RoutesManager.js';
 import Config                      from '../config/Config';
 import SharedConfig    from '../shared/config/SharedConfig';
 import GlobalHelper    from '../helpers/GlobalHelper';
+import SharedSonarManager from '../shared/managers/SharedSonarManager';
 
 
 class BaseRoutes implements RoutesManager {
@@ -37,7 +38,7 @@ class BaseRoutes implements RoutesManager {
 
     private async sonar(req: express.Request, res: express.Response) {
         const data = {
-            sonarEnabled: await GlobalHelper.isSonarSupported()
+            sonarEnabled: await SharedSonarManager.isSonarSupported()
         };
         return req.session.sendResponse(res, StatusCodes.OK, data);
     }
-- 
GitLab