Vincent GUFFON 3 anni fa
parent
commit
9f1171ec6d

+ 16 - 0
.env

@@ -83,3 +83,19 @@ MERCURE_PUBLIC_URL=https://local.mercure.opentalent.fr/.well-known/mercure
 # The secret key used to sign the JWTs
 MERCURE_PUBLISHER_JWT_KEY=NQEupdREijrfYvCmF2mnvZQFL9zLKDH9RCYter6tUWzjemPqzicffhc2fSf0yEmM
 ###< symfony/mercure-bundle ###
+
+###> AdminAssos configuration ###
+DATABASE_ADMINASSOS_URL=mysql://root:mysql660@db:3306/adminassos?serverVersion=5.7
+###< AdminAssos configuration ###
+
+###> Audit configuration ###
+DATABASE_AUDIT_URL=mysql://root:mysql660@db:3306/audit?serverVersion=5.7
+###< Audit configuration ###
+
+###> typo3 client ###
+TYPO3_BASE_URI=http://docker.sub.opentalent.fr
+###< typo3 client ###
+
+###> dolibarr client ###
+DOLIBARR_API_BASE_URI=https://dev-erp.2iopenservice.com/api/index.php/
+###< dolibarr client ###

+ 1694 - 0
assets/styles/foundation-emails.css

@@ -0,0 +1,1694 @@
+.wrapper {
+    width: 100%;
+}
+
+#outlook a {
+    padding: 0;
+}
+
+body {
+    width: 100% !important;
+    min-width: 100%;
+    -webkit-text-size-adjust: 100%;
+    -ms-text-size-adjust: 100%;
+    margin: 0;
+    Margin: 0;
+    padding: 0;
+    -moz-box-sizing: border-box;
+    -webkit-box-sizing: border-box;
+    box-sizing: border-box;
+}
+
+.ExternalClass {
+    width: 100%;
+}
+.ExternalClass,
+.ExternalClass p,
+.ExternalClass span,
+.ExternalClass font,
+.ExternalClass td,
+.ExternalClass th,
+.ExternalClass div {
+    line-height: 100%;
+}
+
+#backgroundTable {
+    margin: 0;
+    Margin: 0;
+    padding: 0;
+    width: 100% !important;
+    line-height: 100% !important;
+}
+
+img {
+    outline: none;
+    text-decoration: none;
+    -ms-interpolation-mode: bicubic;
+    width: auto;
+    max-width: 100%;
+    clear: both;
+    display: block;
+}
+
+center {
+    width: 100%;
+}
+
+a img {
+    border: none;
+}
+
+table {
+    border-spacing: 0;
+    border-collapse: collapse;
+}
+
+td, th {
+    word-wrap: break-word;
+    -webkit-hyphens: auto;
+    -moz-hyphens: auto;
+    hyphens: auto;
+    border-collapse: collapse !important;
+    -moz-box-sizing: border-box;
+    -webkit-box-sizing: border-box;
+    box-sizing: border-box;
+}
+
+table, tr, td, th {
+    padding: 0;
+    vertical-align: top;
+    text-align: left;
+}
+
+@media only screen {
+    html {
+        min-height: 100%;
+        background: #f3f3f3;
+    }
+}
+table.body {
+    background: #f3f3f3;
+    height: 100%;
+    width: 100%;
+}
+table.container {
+    background: #fefefe;
+    width: 580px;
+    margin: 0 auto;
+    Margin: 0 auto;
+    text-align: inherit;
+}
+table.row {
+    padding: 0;
+    width: 100%;
+    position: relative;
+}
+table.spacer {
+    width: 100%;
+}
+table.spacer td {
+    mso-line-height-rule: exactly;
+}
+
+table.container table.row {
+    display: table;
+}
+
+td.columns,
+td.column,
+th.columns,
+th.column {
+    margin: 0 auto;
+    Margin: 0 auto;
+    padding-left: 16px;
+    padding-bottom: 16px;
+}
+td.columns .column.first,
+td.columns .columns.first,
+td.column .column.first,
+td.column .columns.first,
+th.columns .column.first,
+th.columns .columns.first,
+th.column .column.first,
+th.column .columns.first {
+    padding-left: 0 !important;
+}
+td.columns .column.last,
+td.columns .columns.last,
+td.column .column.last,
+td.column .columns.last,
+th.columns .column.last,
+th.columns .columns.last,
+th.column .column.last,
+th.column .columns.last {
+    padding-right: 0 !important;
+}
+td.columns .column:not([class*=large-offset]),
+td.columns .columns:not([class*=large-offset]),
+td.column .column:not([class*=large-offset]),
+td.column .columns:not([class*=large-offset]),
+th.columns .column:not([class*=large-offset]),
+th.columns .columns:not([class*=large-offset]),
+th.column .column:not([class*=large-offset]),
+th.column .columns:not([class*=large-offset]) {
+    padding-left: 0 !important;
+    padding-right: 0 !important;
+}
+
+td.columns.last,
+td.column.last,
+th.columns.last,
+th.column.last {
+    padding-right: 16px;
+}
+
+td.columns table,
+td.column table,
+th.columns table,
+th.column table {
+    width: 100%;
+}
+td.columns table.button,
+td.column table.button,
+th.columns table.button,
+th.column table.button {
+    width: auto;
+}
+td.columns table.button.expand, td.columns table.button.expanded,
+td.column table.button.expand,
+td.column table.button.expanded,
+th.columns table.button.expand,
+th.columns table.button.expanded,
+th.column table.button.expand,
+th.column table.button.expanded {
+    width: 100%;
+}
+
+td.large-1,
+th.large-1 {
+    width: 32.3333333333px;
+    padding-left: 8px;
+    padding-right: 8px;
+}
+
+td.large-1.first,
+th.large-1.first {
+    padding-left: 16px;
+}
+
+td.large-1.last,
+th.large-1.last {
+    padding-right: 16px;
+}
+
+.collapse > tbody > tr > td.large-1:not([class*=large-offset]),
+.collapse > tbody > tr > th.large-1:not([class*=large-offset]) {
+    padding-right: 0;
+    padding-left: 0;
+    width: 48.3333333333px;
+}
+.collapse > tbody > tr td.large-1.first,
+.collapse > tbody > tr th.large-1.first,
+.collapse > tbody > tr td.large-1.last,
+.collapse > tbody > tr th.large-1.last {
+    width: 56.3333333333px;
+}
+
+.body .columns td.large-1,
+.body .column td.large-1,
+.body .columns th.large-1,
+.body .column th.large-1 {
+    width: 8.333333%;
+}
+
+td.large-2,
+th.large-2 {
+    width: 80.6666666667px;
+    padding-left: 8px;
+    padding-right: 8px;
+}
+
+td.large-2.first,
+th.large-2.first {
+    padding-left: 16px;
+}
+
+td.large-2.last,
+th.large-2.last {
+    padding-right: 16px;
+}
+
+.collapse > tbody > tr > td.large-2:not([class*=large-offset]),
+.collapse > tbody > tr > th.large-2:not([class*=large-offset]) {
+    padding-right: 0;
+    padding-left: 0;
+    width: 96.6666666667px;
+}
+.collapse > tbody > tr td.large-2.first,
+.collapse > tbody > tr th.large-2.first,
+.collapse > tbody > tr td.large-2.last,
+.collapse > tbody > tr th.large-2.last {
+    width: 104.6666666667px;
+}
+
+.body .columns td.large-2,
+.body .column td.large-2,
+.body .columns th.large-2,
+.body .column th.large-2 {
+    width: 16.666666%;
+}
+
+td.large-3,
+th.large-3 {
+    width: 129px;
+    padding-left: 8px;
+    padding-right: 8px;
+}
+
+td.large-3.first,
+th.large-3.first {
+    padding-left: 16px;
+}
+
+td.large-3.last,
+th.large-3.last {
+    padding-right: 16px;
+}
+
+.collapse > tbody > tr > td.large-3:not([class*=large-offset]),
+.collapse > tbody > tr > th.large-3:not([class*=large-offset]) {
+    padding-right: 0;
+    padding-left: 0;
+    width: 145px;
+}
+.collapse > tbody > tr td.large-3.first,
+.collapse > tbody > tr th.large-3.first,
+.collapse > tbody > tr td.large-3.last,
+.collapse > tbody > tr th.large-3.last {
+    width: 153px;
+}
+
+.body .columns td.large-3,
+.body .column td.large-3,
+.body .columns th.large-3,
+.body .column th.large-3 {
+    width: 25%;
+}
+
+td.large-4,
+th.large-4 {
+    width: 177.3333333333px;
+    padding-left: 8px;
+    padding-right: 8px;
+}
+
+td.large-4.first,
+th.large-4.first {
+    padding-left: 16px;
+}
+
+td.large-4.last,
+th.large-4.last {
+    padding-right: 16px;
+}
+
+.collapse > tbody > tr > td.large-4:not([class*=large-offset]),
+.collapse > tbody > tr > th.large-4:not([class*=large-offset]) {
+    padding-right: 0;
+    padding-left: 0;
+    width: 193.3333333333px;
+}
+.collapse > tbody > tr td.large-4.first,
+.collapse > tbody > tr th.large-4.first,
+.collapse > tbody > tr td.large-4.last,
+.collapse > tbody > tr th.large-4.last {
+    width: 201.3333333333px;
+}
+
+.body .columns td.large-4,
+.body .column td.large-4,
+.body .columns th.large-4,
+.body .column th.large-4 {
+    width: 33.333333%;
+}
+
+td.large-5,
+th.large-5 {
+    width: 225.6666666667px;
+    padding-left: 8px;
+    padding-right: 8px;
+}
+
+td.large-5.first,
+th.large-5.first {
+    padding-left: 16px;
+}
+
+td.large-5.last,
+th.large-5.last {
+    padding-right: 16px;
+}
+
+.collapse > tbody > tr > td.large-5:not([class*=large-offset]),
+.collapse > tbody > tr > th.large-5:not([class*=large-offset]) {
+    padding-right: 0;
+    padding-left: 0;
+    width: 241.6666666667px;
+}
+.collapse > tbody > tr td.large-5.first,
+.collapse > tbody > tr th.large-5.first,
+.collapse > tbody > tr td.large-5.last,
+.collapse > tbody > tr th.large-5.last {
+    width: 249.6666666667px;
+}
+
+.body .columns td.large-5,
+.body .column td.large-5,
+.body .columns th.large-5,
+.body .column th.large-5 {
+    width: 41.666666%;
+}
+
+td.large-6,
+th.large-6 {
+    width: 274px;
+    padding-left: 8px;
+    padding-right: 8px;
+}
+
+td.large-6.first,
+th.large-6.first {
+    padding-left: 16px;
+}
+
+td.large-6.last,
+th.large-6.last {
+    padding-right: 16px;
+}
+
+.collapse > tbody > tr > td.large-6:not([class*=large-offset]),
+.collapse > tbody > tr > th.large-6:not([class*=large-offset]) {
+    padding-right: 0;
+    padding-left: 0;
+    width: 290px;
+}
+.collapse > tbody > tr td.large-6.first,
+.collapse > tbody > tr th.large-6.first,
+.collapse > tbody > tr td.large-6.last,
+.collapse > tbody > tr th.large-6.last {
+    width: 298px;
+}
+
+.body .columns td.large-6,
+.body .column td.large-6,
+.body .columns th.large-6,
+.body .column th.large-6 {
+    width: 50%;
+}
+
+td.large-7,
+th.large-7 {
+    width: 322.3333333333px;
+    padding-left: 8px;
+    padding-right: 8px;
+}
+
+td.large-7.first,
+th.large-7.first {
+    padding-left: 16px;
+}
+
+td.large-7.last,
+th.large-7.last {
+    padding-right: 16px;
+}
+
+.collapse > tbody > tr > td.large-7:not([class*=large-offset]),
+.collapse > tbody > tr > th.large-7:not([class*=large-offset]) {
+    padding-right: 0;
+    padding-left: 0;
+    width: 338.3333333333px;
+}
+.collapse > tbody > tr td.large-7.first,
+.collapse > tbody > tr th.large-7.first,
+.collapse > tbody > tr td.large-7.last,
+.collapse > tbody > tr th.large-7.last {
+    width: 346.3333333333px;
+}
+
+.body .columns td.large-7,
+.body .column td.large-7,
+.body .columns th.large-7,
+.body .column th.large-7 {
+    width: 58.333333%;
+}
+
+td.large-8,
+th.large-8 {
+    width: 370.6666666667px;
+    padding-left: 8px;
+    padding-right: 8px;
+}
+
+td.large-8.first,
+th.large-8.first {
+    padding-left: 16px;
+}
+
+td.large-8.last,
+th.large-8.last {
+    padding-right: 16px;
+}
+
+.collapse > tbody > tr > td.large-8:not([class*=large-offset]),
+.collapse > tbody > tr > th.large-8:not([class*=large-offset]) {
+    padding-right: 0;
+    padding-left: 0;
+    width: 386.6666666667px;
+}
+.collapse > tbody > tr td.large-8.first,
+.collapse > tbody > tr th.large-8.first,
+.collapse > tbody > tr td.large-8.last,
+.collapse > tbody > tr th.large-8.last {
+    width: 394.6666666667px;
+}
+
+.body .columns td.large-8,
+.body .column td.large-8,
+.body .columns th.large-8,
+.body .column th.large-8 {
+    width: 66.666666%;
+}
+
+td.large-9,
+th.large-9 {
+    width: 419px;
+    padding-left: 8px;
+    padding-right: 8px;
+}
+
+td.large-9.first,
+th.large-9.first {
+    padding-left: 16px;
+}
+
+td.large-9.last,
+th.large-9.last {
+    padding-right: 16px;
+}
+
+.collapse > tbody > tr > td.large-9:not([class*=large-offset]),
+.collapse > tbody > tr > th.large-9:not([class*=large-offset]) {
+    padding-right: 0;
+    padding-left: 0;
+    width: 435px;
+}
+.collapse > tbody > tr td.large-9.first,
+.collapse > tbody > tr th.large-9.first,
+.collapse > tbody > tr td.large-9.last,
+.collapse > tbody > tr th.large-9.last {
+    width: 443px;
+}
+
+.body .columns td.large-9,
+.body .column td.large-9,
+.body .columns th.large-9,
+.body .column th.large-9 {
+    width: 75%;
+}
+
+td.large-10,
+th.large-10 {
+    width: 467.3333333333px;
+    padding-left: 8px;
+    padding-right: 8px;
+}
+
+td.large-10.first,
+th.large-10.first {
+    padding-left: 16px;
+}
+
+td.large-10.last,
+th.large-10.last {
+    padding-right: 16px;
+}
+
+.collapse > tbody > tr > td.large-10:not([class*=large-offset]),
+.collapse > tbody > tr > th.large-10:not([class*=large-offset]) {
+    padding-right: 0;
+    padding-left: 0;
+    width: 483.3333333333px;
+}
+.collapse > tbody > tr td.large-10.first,
+.collapse > tbody > tr th.large-10.first,
+.collapse > tbody > tr td.large-10.last,
+.collapse > tbody > tr th.large-10.last {
+    width: 491.3333333333px;
+}
+
+.body .columns td.large-10,
+.body .column td.large-10,
+.body .columns th.large-10,
+.body .column th.large-10 {
+    width: 83.333333%;
+}
+
+td.large-11,
+th.large-11 {
+    width: 515.6666666667px;
+    padding-left: 8px;
+    padding-right: 8px;
+}
+
+td.large-11.first,
+th.large-11.first {
+    padding-left: 16px;
+}
+
+td.large-11.last,
+th.large-11.last {
+    padding-right: 16px;
+}
+
+.collapse > tbody > tr > td.large-11:not([class*=large-offset]),
+.collapse > tbody > tr > th.large-11:not([class*=large-offset]) {
+    padding-right: 0;
+    padding-left: 0;
+    width: 531.6666666667px;
+}
+.collapse > tbody > tr td.large-11.first,
+.collapse > tbody > tr th.large-11.first,
+.collapse > tbody > tr td.large-11.last,
+.collapse > tbody > tr th.large-11.last {
+    width: 539.6666666667px;
+}
+
+.body .columns td.large-11,
+.body .column td.large-11,
+.body .columns th.large-11,
+.body .column th.large-11 {
+    width: 91.666666%;
+}
+
+td.large-12,
+th.large-12 {
+    width: 564px;
+    padding-left: 8px;
+    padding-right: 8px;
+}
+
+td.large-12.first,
+th.large-12.first {
+    padding-left: 16px;
+}
+
+td.large-12.last,
+th.large-12.last {
+    padding-right: 16px;
+}
+
+.collapse > tbody > tr > td.large-12:not([class*=large-offset]),
+.collapse > tbody > tr > th.large-12:not([class*=large-offset]) {
+    padding-right: 0;
+    padding-left: 0;
+    width: 580px;
+}
+.collapse > tbody > tr td.large-12.first,
+.collapse > tbody > tr th.large-12.first,
+.collapse > tbody > tr td.large-12.last,
+.collapse > tbody > tr th.large-12.last {
+    width: 588px;
+}
+
+.body .columns td.large-12,
+.body .column td.large-12,
+.body .columns th.large-12,
+.body .column th.large-12 {
+    width: 100%;
+}
+
+td.large-offset-1,
+td.large-offset-1.first,
+td.large-offset-1.last,
+th.large-offset-1,
+th.large-offset-1.first,
+th.large-offset-1.last {
+    padding-left: 64.3333333333px;
+}
+
+td.large-offset-2,
+td.large-offset-2.first,
+td.large-offset-2.last,
+th.large-offset-2,
+th.large-offset-2.first,
+th.large-offset-2.last {
+    padding-left: 112.6666666667px;
+}
+
+td.large-offset-3,
+td.large-offset-3.first,
+td.large-offset-3.last,
+th.large-offset-3,
+th.large-offset-3.first,
+th.large-offset-3.last {
+    padding-left: 161px;
+}
+
+td.large-offset-4,
+td.large-offset-4.first,
+td.large-offset-4.last,
+th.large-offset-4,
+th.large-offset-4.first,
+th.large-offset-4.last {
+    padding-left: 209.3333333333px;
+}
+
+td.large-offset-5,
+td.large-offset-5.first,
+td.large-offset-5.last,
+th.large-offset-5,
+th.large-offset-5.first,
+th.large-offset-5.last {
+    padding-left: 257.6666666667px;
+}
+
+td.large-offset-6,
+td.large-offset-6.first,
+td.large-offset-6.last,
+th.large-offset-6,
+th.large-offset-6.first,
+th.large-offset-6.last {
+    padding-left: 306px;
+}
+
+td.large-offset-7,
+td.large-offset-7.first,
+td.large-offset-7.last,
+th.large-offset-7,
+th.large-offset-7.first,
+th.large-offset-7.last {
+    padding-left: 354.3333333333px;
+}
+
+td.large-offset-8,
+td.large-offset-8.first,
+td.large-offset-8.last,
+th.large-offset-8,
+th.large-offset-8.first,
+th.large-offset-8.last {
+    padding-left: 402.6666666667px;
+}
+
+td.large-offset-9,
+td.large-offset-9.first,
+td.large-offset-9.last,
+th.large-offset-9,
+th.large-offset-9.first,
+th.large-offset-9.last {
+    padding-left: 451px;
+}
+
+td.large-offset-10,
+td.large-offset-10.first,
+td.large-offset-10.last,
+th.large-offset-10,
+th.large-offset-10.first,
+th.large-offset-10.last {
+    padding-left: 499.3333333333px;
+}
+
+td.large-offset-11,
+td.large-offset-11.first,
+td.large-offset-11.last,
+th.large-offset-11,
+th.large-offset-11.first,
+th.large-offset-11.last {
+    padding-left: 547.6666666667px;
+}
+
+td.expander,
+th.expander {
+    visibility: hidden;
+    width: 0;
+    padding: 0 !important;
+}
+
+table.container.radius {
+    border-radius: 0;
+    border-collapse: separate;
+}
+
+.block-grid {
+    width: 100%;
+    max-width: 580px;
+}
+.block-grid td {
+    display: inline-block;
+    padding: 8px;
+}
+
+.up-2 td {
+    width: 274px !important;
+}
+
+.up-3 td {
+    width: 177px !important;
+}
+
+.up-4 td {
+    width: 129px !important;
+}
+
+.up-5 td {
+    width: 100px !important;
+}
+
+.up-6 td {
+    width: 80px !important;
+}
+
+.up-7 td {
+    width: 66px !important;
+}
+
+.up-8 td {
+    width: 56px !important;
+}
+
+table.text-center,
+th.text-center,
+td.text-center,
+h1.text-center,
+h2.text-center,
+h3.text-center,
+h4.text-center,
+h5.text-center,
+h6.text-center,
+p.text-center,
+span.text-center {
+    text-align: center;
+}
+table.text-left,
+th.text-left,
+td.text-left,
+h1.text-left,
+h2.text-left,
+h3.text-left,
+h4.text-left,
+h5.text-left,
+h6.text-left,
+p.text-left,
+span.text-left {
+    text-align: left;
+}
+table.text-right,
+th.text-right,
+td.text-right,
+h1.text-right,
+h2.text-right,
+h3.text-right,
+h4.text-right,
+h5.text-right,
+h6.text-right,
+p.text-right,
+span.text-right {
+    text-align: right;
+}
+
+span.text-center {
+    display: block;
+    width: 100%;
+    text-align: center;
+}
+
+@media only screen and (max-width: 596px) {
+    .small-float-center {
+        margin: 0 auto !important;
+        float: none !important;
+        text-align: center !important;
+    }
+
+    .small-text-center {
+        text-align: center !important;
+    }
+
+    .small-text-left {
+        text-align: left !important;
+    }
+
+    .small-text-right {
+        text-align: right !important;
+    }
+}
+img.float-left {
+    float: left;
+    text-align: left;
+}
+
+img.float-right {
+    float: right;
+    text-align: right;
+}
+
+img.float-center,
+img.text-center {
+    margin: 0 auto;
+    Margin: 0 auto;
+    float: none;
+    text-align: center;
+}
+
+table.float-center,
+td.float-center,
+th.float-center {
+    margin: 0 auto;
+    Margin: 0 auto;
+    float: none;
+    text-align: center;
+}
+
+td.columns[valign=bottom],
+td.column[valign=bottom],
+th.columns[valign=bottom],
+th.column[valign=bottom] {
+    vertical-align: bottom;
+}
+
+td.columns[valign=middle],
+td.column[valign=middle],
+th.columns[valign=middle],
+th.column[valign=middle] {
+    vertical-align: middle;
+}
+
+.hide-for-large {
+    display: none;
+    mso-hide: all;
+    overflow: hidden;
+    max-height: 0;
+    font-size: 0;
+    width: 0;
+    line-height: 0;
+}
+@media only screen and (max-width: 596px) {
+    .hide-for-large {
+        display: block !important;
+        width: auto !important;
+        overflow: visible !important;
+        max-height: none !important;
+        font-size: inherit !important;
+        line-height: inherit !important;
+    }
+}
+
+table.body table.container .hide-for-large * {
+    mso-hide: all;
+}
+
+@media only screen and (max-width: 596px) {
+    table.body table.container .hide-for-large,
+    table.body table.container .row.hide-for-large {
+        display: table !important;
+        width: 100% !important;
+    }
+}
+
+@media only screen and (max-width: 596px) {
+    table.body table.container .callout-inner.hide-for-large {
+        display: table-cell !important;
+        width: 100% !important;
+    }
+}
+
+@media only screen and (max-width: 596px) {
+    table.body table.container .show-for-large {
+        display: none !important;
+        width: 0;
+        mso-hide: all;
+        overflow: hidden;
+    }
+}
+
+body,
+table.body,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+p,
+td,
+th {
+    color: #0a0a0a;
+    font-family: Helvetica, Arial, sans-serif;
+    font-weight: normal;
+    padding: 0;
+    margin: 0;
+    Margin: 0;
+    text-align: left;
+    line-height: 130%;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+    color: inherit;
+    word-wrap: normal;
+    font-family: Helvetica, Arial, sans-serif;
+    font-weight: normal;
+    margin-bottom: 10px;
+    Margin-bottom: 10px;
+}
+
+h1 {
+    font-size: 34px;
+}
+
+h2 {
+    font-size: 30px;
+}
+
+h3 {
+    font-size: 28px;
+}
+
+h4 {
+    font-size: 24px;
+}
+
+h5 {
+    font-size: 19px;
+}
+
+h6 {
+    font-size: 18px;
+}
+
+body,
+table.body,
+p,
+td,
+th {
+    font-size: 16px;
+    line-height: 130%;
+}
+
+p {
+    margin-bottom: 10px;
+    Margin-bottom: 10px;
+}
+p.lead {
+    font-size: 20px;
+    line-height: 160%;
+}
+p.subheader {
+    margin-top: 4px;
+    margin-bottom: 8px;
+    Margin-top: 4px;
+    Margin-bottom: 8px;
+    font-weight: normal;
+    line-height: 1.4;
+    color: #8a8a8a;
+}
+p a {
+    margin: default;
+    Margin: default;
+}
+
+.text-xs {
+    font-size: 11.1111111111px;
+}
+
+.text-sm {
+    font-size: 13.3333333333px;
+}
+
+.text-lg {
+    font-size: 19.2px;
+}
+
+.text-xl {
+    font-size: 23.04px;
+}
+
+.text-xxl {
+    font-size: 27.648px;
+}
+
+small,
+.small {
+    font-size: 80%;
+    color: #cacaca;
+}
+
+a {
+    color: #2199e8;
+    text-decoration: none;
+    font-family: Helvetica, Arial, sans-serif;
+    font-weight: normal;
+    padding: 0;
+    text-align: left;
+    line-height: 130%;
+}
+a:hover {
+    color: #147dc2;
+}
+a:active {
+    color: #147dc2;
+}
+a:visited {
+    color: #2199e8;
+}
+
+h1 a,
+h1 a:visited,
+h2 a,
+h2 a:visited,
+h3 a,
+h3 a:visited,
+h4 a,
+h4 a:visited,
+h5 a,
+h5 a:visited,
+h6 a,
+h6 a:visited {
+    color: #2199e8;
+}
+
+pre {
+    background: #f3f3f3;
+    margin: 30px 0;
+    Margin: 30px 0;
+}
+pre code {
+    color: #cacaca;
+}
+pre code span.callout {
+    color: #8a8a8a;
+    font-weight: bold;
+}
+pre code span.callout-strong {
+    color: #ff6908;
+    font-weight: bold;
+}
+
+td.columns table.hr table, td.column table.hr table, th.columns table.hr table, th.column table.hr table,
+td.columns table.h-line table,
+td.column table.h-line table,
+th.columns table.h-line table,
+th.column table.h-line table {
+    width: auto;
+}
+
+table.hr th,
+table.h-line th {
+    padding-bottom: 20px;
+    text-align: center;
+}
+table.hr table,
+table.h-line table {
+    display: inline-block;
+    margin: 0;
+    Margin: 0;
+}
+table.hr th,
+table.h-line th {
+    width: 580px;
+    height: 0;
+    padding-top: 20px;
+    clear: both;
+    border-top: 0;
+    border-right: 0;
+    border-bottom: 1px solid #0a0a0a;
+    border-left: 0;
+    font-size: 0;
+    line-height: 0;
+}
+
+.stat {
+    font-size: 40px;
+    line-height: 1;
+}
+p + .stat {
+    margin-top: -16px;
+    Margin-top: -16px;
+}
+
+span.preheader {
+    display: none !important;
+    visibility: hidden;
+    mso-hide: all !important;
+    font-size: 1px;
+    color: #f3f3f3;
+    line-height: 1px;
+    max-height: 0px;
+    max-width: 0px;
+    opacity: 0;
+    overflow: hidden;
+}
+
+@media only screen {
+    a[x-apple-data-detectors] {
+        color: inherit !important;
+        text-decoration: none !important;
+        font-size: inherit !important;
+        font-family: inherit !important;
+        font-weight: inherit !important;
+        line-height: inherit !important;
+    }
+}
+table.button {
+    width: auto;
+    margin: 0 0 16px 0;
+    Margin: 0 0 16px 0;
+}
+table.button table td {
+    text-align: left;
+    color: #fefefe;
+    background: #2199e8;
+    border: 2px solid #2199e8;
+}
+table.button table td a {
+    font-family: Helvetica, Arial, sans-serif;
+    font-size: 16px;
+    font-weight: bold;
+    color: #fefefe;
+    text-decoration: none;
+    text-align: left;
+    display: inline-block;
+    padding: 8px 16px 8px 16px;
+    border: 0 solid #2199e8;
+    border-radius: 3px;
+}
+table.button.radius table td {
+    border-radius: 3px;
+    border: none;
+}
+table.button.rounded table td {
+    border-radius: 500px;
+    border: none;
+}
+
+table.button:not(.expand):not(.expanded) table {
+    width: auto;
+}
+
+table.button:hover table tr td a,
+table.button:active table tr td a,
+table.button table tr td a:visited,
+table.button.tiny:hover table tr td a,
+table.button.tiny:active table tr td a,
+table.button.tiny table tr td a:visited,
+table.button.small:hover table tr td a,
+table.button.small:active table tr td a,
+table.button.small table tr td a:visited,
+table.button.large:hover table tr td a,
+table.button.large:active table tr td a,
+table.button.large table tr td a:visited {
+    color: #fefefe;
+}
+
+table.button.tiny table td,
+table.button.tiny table a {
+    padding: 4px 8px 4px 8px;
+}
+table.button.tiny table a {
+    font-size: 10px;
+    font-weight: normal;
+}
+
+table.button.small table td,
+table.button.small table a {
+    padding: 5px 10px 5px 10px;
+    font-size: 12px;
+}
+
+table.button.large table a {
+    padding: 10px 20px 10px 20px;
+    font-size: 20px;
+}
+
+table.button.expand,
+table.button.expanded {
+    width: 100%;
+}
+table.button.expand table,
+table.button.expanded table {
+    width: 100%;
+}
+table.button.expand table a,
+table.button.expanded table a {
+    text-align: center;
+    width: 100%;
+    padding-left: 0;
+    padding-right: 0;
+}
+table.button.expand center,
+table.button.expanded center {
+    min-width: 0;
+}
+
+table.button:hover table td,
+table.button:visited table td,
+table.button:active table td {
+    background: #147dc2;
+    color: #fefefe;
+}
+
+table.button:hover table a,
+table.button:visited table a,
+table.button:active table a {
+    border: 0 solid #147dc2;
+}
+
+table.button.secondary table td {
+    background: #777777;
+    color: #fefefe;
+    border: 0px solid #777777;
+}
+table.button.secondary table a {
+    color: #fefefe;
+    border: 0 solid #777777;
+}
+
+table.button.secondary:hover table td {
+    background: #919191;
+    color: #fefefe;
+}
+table.button.secondary:hover table a {
+    border: 0 solid #919191;
+}
+
+table.button.secondary:hover table td a {
+    color: #fefefe;
+}
+
+table.button.secondary:active table td a {
+    color: #fefefe;
+}
+
+table.button.secondary table td a:visited {
+    color: #fefefe;
+}
+
+table.button.success table td {
+    background: #3adb76;
+    border: 0px solid #3adb76;
+}
+table.button.success table a {
+    border: 0 solid #3adb76;
+}
+
+table.button.success:hover table td {
+    background: #23bf5d;
+}
+table.button.success:hover table a {
+    border: 0 solid #23bf5d;
+}
+
+table.button.alert table td {
+    background: #ec5840;
+    border: 0px solid #ec5840;
+}
+table.button.alert table a {
+    border: 0 solid #ec5840;
+}
+
+table.button.alert:hover table td {
+    background: #e23317;
+}
+table.button.alert:hover table a {
+    border: 0 solid #e23317;
+}
+
+table.button.warning table td {
+    background: #ffae00;
+    border: 0px solid #ffae00;
+}
+table.button.warning table a {
+    border: 0px solid #ffae00;
+}
+
+table.button.warning:hover table td {
+    background: #cc8b00;
+}
+table.button.warning:hover table a {
+    border: 0px solid #cc8b00;
+}
+
+table.callout {
+    margin-bottom: 16px;
+    Margin-bottom: 16px;
+}
+
+th.callout-inner {
+    width: 100%;
+    border: 1px solid #cbcbcb;
+    padding: 10px;
+    background: #fefefe;
+}
+th.callout-inner.primary {
+    background: #def0fc;
+    border: 1px solid #0f5f94;
+    color: #0a0a0a;
+}
+th.callout-inner.secondary {
+    background: #ebebeb;
+    border: 1px solid #444444;
+    color: #0a0a0a;
+}
+th.callout-inner.success {
+    background: #e1faea;
+    border: 1px solid #1b9448;
+    color: #0a0a0a;
+}
+th.callout-inner.warning {
+    background: #fff3d9;
+    border: 1px solid #996800;
+    color: #0a0a0a;
+}
+th.callout-inner.alert {
+    background: #fce6e2;
+    border: 1px solid #b42912;
+    color: #0a0a0a;
+}
+
+.thumbnail {
+    border: solid 4px #fefefe;
+    box-shadow: 0 0 0 1px rgba(10, 10, 10, 0.2);
+    display: inline-block;
+    line-height: 0;
+    max-width: 100%;
+    transition: box-shadow 200ms ease-out;
+    border-radius: 3px;
+    margin-bottom: 16px;
+}
+.thumbnail:hover, .thumbnail:focus {
+    box-shadow: 0 0 6px 1px rgba(33, 153, 232, 0.5);
+}
+
+table.menu {
+    width: 580px;
+}
+table.menu td.menu-item,
+table.menu th.menu-item {
+    padding-top: 10px;
+    padding-right: 10px;
+    padding-bottom: 10px;
+    padding-left: 10px;
+}
+table.menu td.menu-item a,
+table.menu th.menu-item a {
+    color: #2199e8;
+}
+
+table.menu.vertical td.menu-item,
+table.menu.vertical th.menu-item {
+    padding-top: 10px;
+    padding-right: 0;
+    padding-bottom: 10px;
+    padding-left: 10px;
+    display: block;
+}
+table.menu.vertical td.menu-item a,
+table.menu.vertical th.menu-item a {
+    width: 100%;
+}
+table.menu.vertical td.menu-item table.menu.vertical td.menu-item,
+table.menu.vertical td.menu-item table.menu.vertical th.menu-item,
+table.menu.vertical th.menu-item table.menu.vertical td.menu-item,
+table.menu.vertical th.menu-item table.menu.vertical th.menu-item {
+    padding-left: 10px;
+}
+
+table.menu.text-center a {
+    text-align: center;
+}
+
+.menu[align=center] {
+    width: auto;
+}
+
+.menu[align=center] tr {
+    text-align: center;
+}
+
+.menu:not(.float-center) .menu-item:first-child {
+    padding-left: 0 !important;
+}
+.menu:not(.float-center) .menu-item:last-child {
+    padding-right: 0 !important;
+}
+
+.menu.vertical .menu-item {
+    padding-left: 0 !important;
+    padding-right: 0 !important;
+}
+
+@media only screen and (max-width: 596px) {
+    .menu.small-vertical .menu-item {
+        padding-left: 0 !important;
+        padding-right: 0 !important;
+    }
+}
+body.outlook p {
+    display: inline !important;
+}
+
+@media only screen and (max-width: 596px) {
+    table.body img {
+        width: auto;
+        height: auto;
+    }
+
+    table.body center {
+        min-width: 0 !important;
+    }
+
+    table.body .container {
+        width: 95% !important;
+    }
+
+    table.body .columns,
+    table.body .column {
+        height: auto !important;
+        -moz-box-sizing: border-box;
+        -webkit-box-sizing: border-box;
+        box-sizing: border-box;
+        padding-left: 16px !important;
+        padding-right: 16px !important;
+    }
+
+    table.body .collapse > tbody > tr > .columns, table.body .collapse > tbody > tr > .column {
+        padding-left: 0 !important;
+        padding-right: 0 !important;
+    }
+
+    td.small-1,
+    th.small-1 {
+        display: inline-block !important;
+        width: 8.333333% !important;
+    }
+
+    td.small-2,
+    th.small-2 {
+        display: inline-block !important;
+        width: 16.666666% !important;
+    }
+
+    td.small-3,
+    th.small-3 {
+        display: inline-block !important;
+        width: 25% !important;
+    }
+
+    td.small-4,
+    th.small-4 {
+        display: inline-block !important;
+        width: 33.333333% !important;
+    }
+
+    td.small-5,
+    th.small-5 {
+        display: inline-block !important;
+        width: 41.666666% !important;
+    }
+
+    td.small-6,
+    th.small-6 {
+        display: inline-block !important;
+        width: 50% !important;
+    }
+
+    td.small-7,
+    th.small-7 {
+        display: inline-block !important;
+        width: 58.333333% !important;
+    }
+
+    td.small-8,
+    th.small-8 {
+        display: inline-block !important;
+        width: 66.666666% !important;
+    }
+
+    td.small-9,
+    th.small-9 {
+        display: inline-block !important;
+        width: 75% !important;
+    }
+
+    td.small-10,
+    th.small-10 {
+        display: inline-block !important;
+        width: 83.333333% !important;
+    }
+
+    td.small-11,
+    th.small-11 {
+        display: inline-block !important;
+        width: 91.666666% !important;
+    }
+
+    td.small-12,
+    th.small-12 {
+        display: inline-block !important;
+        width: 100% !important;
+    }
+
+    .columns td.small-12,
+    .column td.small-12,
+    .columns th.small-12,
+    .column th.small-12 {
+        display: block !important;
+        width: 100% !important;
+    }
+
+    table.body td.small-offset-1,
+    table.body th.small-offset-1 {
+        margin-left: 8.333333% !important;
+        Margin-left: 8.333333% !important;
+    }
+
+    table.body td.small-offset-2,
+    table.body th.small-offset-2 {
+        margin-left: 16.666666% !important;
+        Margin-left: 16.666666% !important;
+    }
+
+    table.body td.small-offset-3,
+    table.body th.small-offset-3 {
+        margin-left: 25% !important;
+        Margin-left: 25% !important;
+    }
+
+    table.body td.small-offset-4,
+    table.body th.small-offset-4 {
+        margin-left: 33.333333% !important;
+        Margin-left: 33.333333% !important;
+    }
+
+    table.body td.small-offset-5,
+    table.body th.small-offset-5 {
+        margin-left: 41.666666% !important;
+        Margin-left: 41.666666% !important;
+    }
+
+    table.body td.small-offset-6,
+    table.body th.small-offset-6 {
+        margin-left: 50% !important;
+        Margin-left: 50% !important;
+    }
+
+    table.body td.small-offset-7,
+    table.body th.small-offset-7 {
+        margin-left: 58.333333% !important;
+        Margin-left: 58.333333% !important;
+    }
+
+    table.body td.small-offset-8,
+    table.body th.small-offset-8 {
+        margin-left: 66.666666% !important;
+        Margin-left: 66.666666% !important;
+    }
+
+    table.body td.small-offset-9,
+    table.body th.small-offset-9 {
+        margin-left: 75% !important;
+        Margin-left: 75% !important;
+    }
+
+    table.body td.small-offset-10,
+    table.body th.small-offset-10 {
+        margin-left: 83.333333% !important;
+        Margin-left: 83.333333% !important;
+    }
+
+    table.body td.small-offset-11,
+    table.body th.small-offset-11 {
+        margin-left: 91.666666% !important;
+        Margin-left: 91.666666% !important;
+    }
+
+    table.body table.columns td.expander,
+    table.body table.columns th.expander {
+        display: none !important;
+    }
+
+    table.body .right-text-pad,
+    table.body .text-pad-right {
+        padding-left: 10px !important;
+    }
+
+    table.body .left-text-pad,
+    table.body .text-pad-left {
+        padding-right: 10px !important;
+    }
+
+    table.menu {
+        width: 100% !important;
+    }
+    table.menu td,
+    table.menu th {
+        width: auto !important;
+        display: inline-block !important;
+    }
+    table.menu.vertical td,
+    table.menu.vertical th, table.menu.small-vertical td,
+    table.menu.small-vertical th {
+        display: block !important;
+    }
+
+    table.menu[align=center] {
+        width: auto !important;
+    }
+
+    table.button.small-expand,
+    table.button.small-expanded {
+        width: 100% !important;
+    }
+    table.button.small-expand table,
+    table.button.small-expanded table {
+        width: 100%;
+    }
+    table.button.small-expand table a,
+    table.button.small-expanded table a {
+        text-align: center !important;
+        width: 100% !important;
+        padding-left: 0 !important;
+        padding-right: 0 !important;
+    }
+    table.button.small-expand center,
+    table.button.small-expanded center {
+        min-width: 0;
+    }
+
+    th.callout-inner {
+        padding: 10px !important;
+    }
+}

+ 4 - 0
composer.json

@@ -25,6 +25,7 @@
         "knplabs/knp-snappy-bundle": "^1.9",
         "lcobucci/jwt": "^4.1",
         "lexik/jwt-authentication-bundle": "^2.8",
+        "lorenzo/pinky": "^1.0",
         "myclabs/php-enum": "^1.7",
         "nelmio/cors-bundle": "^2.1",
         "odolbeau/phone-number-bundle": "^3.1",
@@ -54,6 +55,9 @@
         "symfony/twig-bundle": "^5.4",
         "symfony/validator": "5.4.*",
         "symfony/yaml": "5.4.*",
+        "twig/cssinliner-extra": "^3.4",
+        "twig/extra-bundle": "^3.4",
+        "twig/inky-extra": "^3.4",
         "vincent/foselastica": "1.2",
         "webonyx/graphql-php": "^14.3"
     },

+ 610 - 1
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "33f34a695bb495d5bb86099e78f2670d",
+    "content-hash": "e403ff9a6e83cf9bb6571a11e3837da7",
     "packages": [
         {
             "name": "api-platform/core",
@@ -2803,6 +2803,59 @@
             ],
             "time": "2022-04-08T12:31:19+00:00"
         },
+        {
+            "name": "lorenzo/pinky",
+            "version": "1.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/lorenzo/pinky.git",
+                "reference": "61de35ec6a17badea8b0922e65a979472c886d01"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/lorenzo/pinky/zipball/61de35ec6a17badea8b0922e65a979472c886d01",
+                "reference": "61de35ec6a17badea8b0922e65a979472c886d01",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-libxml": "*",
+                "ext-xsl": "*",
+                "php": ">=5.6.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.21 || ^9.5.10"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/pinky.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jose Lorenzo Rodriguez",
+                    "email": "jose.zap@gmail.com"
+                }
+            ],
+            "description": "A Foundation for Emails (Inky) template transpiler",
+            "keywords": [
+                "email",
+                "foundation",
+                "inky",
+                "template",
+                "zurb"
+            ],
+            "support": {
+                "issues": "https://github.com/lorenzo/pinky/issues",
+                "source": "https://github.com/lorenzo/pinky/tree/1.0.6"
+            },
+            "time": "2022-03-17T12:11:56+00:00"
+        },
         {
             "name": "monolog/monolog",
             "version": "2.6.0",
@@ -4401,6 +4454,72 @@
             ],
             "time": "2022-05-18T06:17:34+00:00"
         },
+        {
+            "name": "symfony/css-selector",
+            "version": "v5.4.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/css-selector.git",
+                "reference": "b0a190285cd95cb019237851205b8140ef6e368e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/css-selector/zipball/b0a190285cd95cb019237851205b8140ef6e368e",
+                "reference": "b0a190285cd95cb019237851205b8140ef6e368e",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/polyfill-php80": "^1.16"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\CssSelector\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Jean-François Simon",
+                    "email": "jeanfrancois.simon@sensiolabs.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Converts CSS selectors to XPath expressions",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/css-selector/tree/v5.4.3"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-01-02T09:53:40+00:00"
+        },
         {
             "name": "symfony/dependency-injection",
             "version": "v5.4.9",
@@ -9256,6 +9375,496 @@
             ],
             "time": "2022-01-26T16:32:32+00:00"
         },
+        {
+            "name": "tijsverkoyen/css-to-inline-styles",
+            "version": "2.2.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git",
+                "reference": "da444caae6aca7a19c0c140f68c6182e337d5b1c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/da444caae6aca7a19c0c140f68c6182e337d5b1c",
+                "reference": "da444caae6aca7a19c0c140f68c6182e337d5b1c",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-libxml": "*",
+                "php": "^5.5 || ^7.0 || ^8.0",
+                "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^7.5 || ^8.5.21 || ^9.5.10"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.2.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "TijsVerkoyen\\CssToInlineStyles\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Tijs Verkoyen",
+                    "email": "css_to_inline_styles@verkoyen.eu",
+                    "role": "Developer"
+                }
+            ],
+            "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.",
+            "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles",
+            "support": {
+                "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues",
+                "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/2.2.4"
+            },
+            "time": "2021-12-08T09:12:39+00:00"
+        },
+        {
+            "name": "twig/cssinliner-extra",
+            "version": "v3.4.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/twigphp/cssinliner-extra.git",
+                "reference": "1fe012dcae6b04fc37715296c10a72f8d941bc65"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/twigphp/cssinliner-extra/zipball/1fe012dcae6b04fc37715296c10a72f8d941bc65",
+                "reference": "1fe012dcae6b04fc37715296c10a72f8d941bc65",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1.3",
+                "tijsverkoyen/css-to-inline-styles": "^2.0",
+                "twig/twig": "^2.7|^3.0"
+            },
+            "require-dev": {
+                "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Twig\\Extra\\CssInliner\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                }
+            ],
+            "description": "A Twig extension to allow inlining CSS",
+            "homepage": "https://twig.symfony.com",
+            "keywords": [
+                "css",
+                "inlining",
+                "twig"
+            ],
+            "support": {
+                "source": "https://github.com/twigphp/cssinliner-extra/tree/v3.4.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/twig/twig",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-01-02T10:02:25+00:00"
+        },
+        {
+            "name": "twig/extra-bundle",
+            "version": "v3.4.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/twigphp/twig-extra-bundle.git",
+                "reference": "2e58256b0e9fe52f30149347c0547e4633304765"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/2e58256b0e9fe52f30149347c0547e4633304765",
+                "reference": "2e58256b0e9fe52f30149347c0547e4633304765",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/framework-bundle": "^4.4|^5.0|^6.0",
+                "symfony/twig-bundle": "^4.4|^5.0|^6.0",
+                "twig/twig": "^2.7|^3.0"
+            },
+            "require-dev": {
+                "league/commonmark": "^1.0|^2.0",
+                "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0",
+                "twig/cache-extra": "^3.0",
+                "twig/cssinliner-extra": "^2.12|^3.0",
+                "twig/html-extra": "^2.12|^3.0",
+                "twig/inky-extra": "^2.12|^3.0",
+                "twig/intl-extra": "^2.12|^3.0",
+                "twig/markdown-extra": "^2.12|^3.0",
+                "twig/string-extra": "^2.12|^3.0"
+            },
+            "type": "symfony-bundle",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Twig\\Extra\\TwigExtraBundle\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                }
+            ],
+            "description": "A Symfony bundle for extra Twig extensions",
+            "homepage": "https://twig.symfony.com",
+            "keywords": [
+                "bundle",
+                "extra",
+                "twig"
+            ],
+            "support": {
+                "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.4.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/twig/twig",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-01-04T13:58:53+00:00"
+        },
+        {
+            "name": "twig/inky-extra",
+            "version": "v3.4.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/twigphp/inky-extra.git",
+                "reference": "b515e6f7c1fede76f9f507dbd1bb369f46aa726b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/twigphp/inky-extra/zipball/b515e6f7c1fede76f9f507dbd1bb369f46aa726b",
+                "reference": "b515e6f7c1fede76f9f507dbd1bb369f46aa726b",
+                "shasum": ""
+            },
+            "require": {
+                "lorenzo/pinky": "^1.0.5",
+                "php": ">=7.1.3",
+                "twig/twig": "^2.7|^3.0"
+            },
+            "require-dev": {
+                "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Twig\\Extra\\Inky\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                }
+            ],
+            "description": "A Twig extension for the inky email templating engine",
+            "homepage": "https://twig.symfony.com",
+            "keywords": [
+                "email",
+                "emails",
+                "inky",
+                "twig"
+            ],
+            "support": {
+                "source": "https://github.com/twigphp/inky-extra/tree/v3.4.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/twig/twig",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-01-02T10:02:25+00:00"
+        },
+        {
+            "name": "twig/intl-extra",
+            "version": "v3.4.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/twigphp/intl-extra.git",
+                "reference": "8dca6f4c5a00cdd3c43b6bd080f50d32aca33a84"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/twigphp/intl-extra/zipball/8dca6f4c5a00cdd3c43b6bd080f50d32aca33a84",
+                "reference": "8dca6f4c5a00cdd3c43b6bd080f50d32aca33a84",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1.3",
+                "symfony/intl": "^4.4|^5.0|^6.0",
+                "twig/twig": "^2.7|^3.0"
+            },
+            "require-dev": {
+                "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Twig\\Extra\\Intl\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                }
+            ],
+            "description": "A Twig extension for Intl",
+            "homepage": "https://twig.symfony.com",
+            "keywords": [
+                "intl",
+                "twig"
+            ],
+            "support": {
+                "source": "https://github.com/twigphp/intl-extra/tree/v3.4.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/twig/twig",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-01-02T10:02:25+00:00"
+        },
+        {
+            "name": "twig/extra-bundle",
+            "version": "v3.4.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/twigphp/twig-extra-bundle.git",
+                "reference": "2e58256b0e9fe52f30149347c0547e4633304765"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/2e58256b0e9fe52f30149347c0547e4633304765",
+                "reference": "2e58256b0e9fe52f30149347c0547e4633304765",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/framework-bundle": "^4.4|^5.0|^6.0",
+                "symfony/twig-bundle": "^4.4|^5.0|^6.0",
+                "twig/twig": "^2.7|^3.0"
+            },
+            "require-dev": {
+                "league/commonmark": "^1.0|^2.0",
+                "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0",
+                "twig/cache-extra": "^3.0",
+                "twig/cssinliner-extra": "^2.12|^3.0",
+                "twig/html-extra": "^2.12|^3.0",
+                "twig/inky-extra": "^2.12|^3.0",
+                "twig/intl-extra": "^2.12|^3.0",
+                "twig/markdown-extra": "^2.12|^3.0",
+                "twig/string-extra": "^2.12|^3.0"
+            },
+            "type": "symfony-bundle",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Twig\\Extra\\TwigExtraBundle\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                }
+            ],
+            "description": "A Symfony bundle for extra Twig extensions",
+            "homepage": "https://twig.symfony.com",
+            "keywords": [
+                "bundle",
+                "extra",
+                "twig"
+            ],
+            "support": {
+                "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.4.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/twig/twig",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-01-04T13:58:53+00:00"
+        },
+        {
+            "name": "twig/intl-extra",
+            "version": "v3.4.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/twigphp/intl-extra.git",
+                "reference": "8dca6f4c5a00cdd3c43b6bd080f50d32aca33a84"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/twigphp/intl-extra/zipball/8dca6f4c5a00cdd3c43b6bd080f50d32aca33a84",
+                "reference": "8dca6f4c5a00cdd3c43b6bd080f50d32aca33a84",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1.3",
+                "symfony/intl": "^4.4|^5.0|^6.0",
+                "twig/twig": "^2.7|^3.0"
+            },
+            "require-dev": {
+                "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Twig\\Extra\\Intl\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                }
+            ],
+            "description": "A Twig extension for Intl",
+            "homepage": "https://twig.symfony.com",
+            "keywords": [
+                "intl",
+                "twig"
+            ],
+            "support": {
+                "source": "https://github.com/twigphp/intl-extra/tree/v3.4.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/twig/twig",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-01-02T10:02:25+00:00"
+        },
         {
             "name": "twig/twig",
             "version": "v3.4.1",

+ 1 - 0
config/bundles.php

@@ -19,5 +19,6 @@ return [
     Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
     Symfony\Bundle\DebugBundle\DebugBundle::class => ['docker' => true],
     Symfony\Bundle\MercureBundle\MercureBundle::class => ['all' => true],
+    Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
     DH\AuditorBundle\DHAuditorBundle::class => ['all' => true],
 ];

+ 1 - 1
config/packages/docker/mailer.yaml

@@ -3,7 +3,7 @@ framework:
     # @see https://symfony.com/doc/5.4/mailer.html#development-debugging
 
     # Disable the mailing in dev mode
-    dsn: 'null://null'
+#    dsn: 'null://null'
 
     # Or send all mails to the same address:
     #envelope:

+ 2 - 2
config/packages/messenger.yaml

@@ -11,9 +11,9 @@ framework:
 
         routing:
             # Route your messages to the transports
+            'App\Message\Command\MailerCommand': async
             'App\Message\Command\Parameters\AverageChange': async
             'App\Message\Command\Export': async
             'App\Message\Command\Typo3\Typo3UpdateCommand': async
             'App\Message\Command\Typo3\Typo3DeleteCommand': async
-            'App\Message\Command\Typo3\Typo3UndeleteCommand': async
-            'Symfony\Component\Mailer\Messenger\SendEmailMessage': async
+            'App\Message\Command\Typo3\Typo3UndeleteCommand': async

+ 2 - 0
config/packages/twig.yaml

@@ -1,3 +1,5 @@
 twig:
     paths:
         '%kernel.project_dir%/templates': templates
+        '%kernel.project_dir%/assets/images': images
+        '%kernel.project_dir%/assets/styles': styles

+ 8 - 0
config/services.yaml

@@ -50,6 +50,10 @@ services:
         bind:
             $opentalentNoReplyEmailAddress: 'noreply@opentalent.fr'
 
+    App\Service\Mailer\Mailer:
+        bind:
+            $opentalentNoReplyEmailAddress: 'noreply@opentalent.fr'
+
     #########################################
     ##  TAG Services ##
     _instanceof:
@@ -61,6 +65,8 @@ services:
             tags: ['app.exporter']
         App\Service\Export\Encoder\EncoderInterface:
             tags: ['app.encoder']
+        App\Service\Mailer\Builder\BuilderInterface:
+            tags: [ 'app.mailer.builder' ]
 
     App\Service\ServiceIterator\CurrentAccessExtensionIterator:
         - !tagged_iterator app.extensions.access
@@ -70,6 +76,8 @@ services:
         - !tagged_iterator app.exporter
     App\Service\ServiceIterator\EncoderIterator:
         - !tagged_iterator app.encoder
+    App\Service\ServiceIterator\Mailer\BuilderIterator:
+        - !tagged_iterator app.mailer.builder
 
     App\Service\Dolibarr\DolibarrSyncService:
         tags:

+ 16 - 0
symfony.lock

@@ -31,6 +31,19 @@
     "cyclonedx/cyclonedx-php-composer": {
         "version": "v3.4.1"
     },
+    "damienharper/auditor-bundle": {
+        "version": "5.0",
+        "recipe": {
+            "repo": "github.com/symfony/recipes-contrib",
+            "branch": "main",
+            "version": "4.0",
+            "ref": "694b129ef686d68a4c9ca6b3cafbeb3dec0c9c2d"
+        },
+        "files": [
+            "config/packages/dh_auditor.yaml",
+            "config/routes/dh_auditor.yaml"
+        ]
+    },
     "doctrine/annotations": {
         "version": "1.0",
         "recipe": {
@@ -630,6 +643,9 @@
     "symfony/yaml": {
         "version": "v5.1.7"
     },
+    "twig/extra-bundle": {
+        "version": "v3.4.0"
+    },
     "twig/twig": {
         "version": "v3.0.5"
     },

+ 0 - 12
templates/base.html.twig

@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="UTF-8">
-        <title>{% block title %}Welcome!{% endblock %}</title>
-        {% block stylesheets %}{% endblock %}
-    </head>
-    <body>
-        {% block body %}{% endblock %}
-        {% block javascripts %}{% endblock %}
-    </body>
-</html>

+ 96 - 0
templates/emails/base.html.twig

@@ -0,0 +1,96 @@
+{% apply inky_to_html|inline_css(source('@styles/foundation-emails.css'))|inline_css %}
+
+    <style>
+        {% block style %}
+        .container *{
+            font-family: Arial;
+        }
+        .white{
+            color: #FFFFFF !important;
+        }
+        .black{
+            color: #000000 !important;
+        }
+        .container{
+            border: 2px solid #324250;
+            border-radius: 5px;
+            margin-top: 20px;
+        }
+        .header{
+            background: #324250;
+        }
+        .footer{
+            background: #1ead8f;
+            padding: 10px;
+            color: #FFFFFF;
+            font-weight: bold;
+        }
+        {% endblock %}
+    </style>
+
+    <container>
+        {% block header %}
+            <row>
+                <columns small="12" class="header">
+                    <spacer size="10"></spacer>
+                    <p class="white">{{ organization.name }}</p>
+                </columns>
+            </row>
+        {% endblock %}
+
+
+        {% block content %}
+            {{ content }}
+        {% endblock %}
+
+
+        {% block antispam %}
+            <row>
+                <columns small="12">
+                    <p>
+                        <small class="black">
+                            Cet e-mail a été envoyé automatiquement à
+                            #__#ANTISPAM_PERSON_EMAIL#__#
+                            par le logiciel Opentalent utilisé par votre structure.
+                            Merci de ne pas y répondre.
+                        </small>
+                    </p>
+                </columns>
+            </row>
+        {% endblock %}
+
+        {% block footer %}
+            <row>
+                <columns small="12" class="footer">
+                    <center>
+                        <menu>
+                            <small>
+                                <item href="https://support.opentalent.fr" class="white">Aide du logiciel</item>
+                                -
+                                <item href="https://www.opentalent.fr/login" class="white">Se connecter au logiciel</item>
+                            </small>
+                        </menu>
+                    </center>
+                </columns>
+            </row>
+        {% endblock %}
+
+        {% block footer_signature %}
+
+            <row>
+                <columns small="12">
+                    <spacer size="10"></spacer>
+                    <p class="text-center">
+                        <small class="black">
+                            &copy; Opentalent - {{ "now"|date("Y") }} - La plateforme culturelle : agenda culturel et logiciels pour les structures culturelles -
+                            <a href="https://www.opentalent.fr/agenda">www.opentalent.fr/agenda</a>
+                        </small>
+                    </p>
+                </columns>
+            </row>
+
+        {% endblock %}
+
+    </container>
+
+{% endapply %}

+ 38 - 0
templates/emails/report.html.twig

@@ -0,0 +1,38 @@
+{% if delivered is not empty  %}
+    <p>Le message a bien été envoyé aux {{ delivered|length }} contacts suivants : </p>
+
+    <ul>
+        {% for contact in delivered %}
+            <li>
+                {% if contact.name is not empty %}
+                    {{ contact.name }}
+                {% else %}
+                    {{ contact.emailAddress }}
+                {% endif %}
+            </li>
+        {% endfor %}
+    </ul>
+{% endif %}
+
+{% if unDelivered is not empty  %}
+    <p>Le message n'a pu être envoyé aux {{ unDelivered|length }} contacts suivants : </p>
+
+    <ul>
+        {% for contact in unDelivered %}
+            <li>
+                {% if contact.name is not empty %}
+                    {{ contact.name }}
+                {% else %}
+                    {{ contact.emailAddress }}
+                {% endif %}
+            </li>
+        {% endfor %}
+    </ul>
+{% endif %}
+
+<p>
+    Ci dessous un exemple du message que les destinataires ont reçu.<br />
+    Dans le cas d'un publipostage, un des destinataires est sélectionné pour l'exemple :
+</p>
+
+{{ email_example.text | raw }}

+ 13 - 0
templates/emails/test.html.twig

@@ -0,0 +1,13 @@
+{% extends 'emails/base.html.twig' %}
+
+{% block content %}
+
+    <row>
+        <columns small="12">
+            <spacer size="100"></spacer>
+            text
+            <spacer size="100"></spacer>
+        </columns>
+    </row>
+
+{% endblock %}