From 4c82e70c0475a4cd6ba3cd1c466f0874b7099942 Mon Sep 17 00:00:00 2001 From: joewilko17 <joewilko17@gmail.com> Date: Thu, 25 Apr 2024 09:01:41 +0100 Subject: [PATCH] Final Submission Ready --- .vscode/settings.json | 3 +- DISPticketing/front/extraInformation.html | 87 ++--- DISPticketing/front/index.html | 276 --------------- DISPticketing/front/issueFormPortal.html | 317 ++++++++++++++++++ DISPticketing/front/reviewInformation.html | 130 +++---- DISPticketing/front/surveyInformation.html | 125 +++---- DISPticketing/pom.xml | 25 -- .../src/main/java/com/disp/Worker.java | 146 +++++--- .../main/java/com/disp/email/EmailConfig.java | 19 +- .../java/com/disp/email/EmailListener.java | 45 ++- .../java/com/disp/email/EmailRequest.java | 12 +- .../java/com/disp/email/EmailService.java | 5 +- .../main/java/com/disp/forms/FormData.java | 84 ++++- .../src/main/java/com/disp/ticket/Ticket.java | 53 ++- .../com/disp/ticket/TicketCamundaManager.java | 43 ++- .../java/com/disp/ticket/TicketDBManager.java | 155 +++++++-- .../src/main/resources/application.yaml | 11 + DISPticketing/target/classes/application.yaml | 11 + .../target/classes/com/disp/Worker.class | Bin 10497 -> 12335 bytes .../classes/com/disp/email/EmailRequest.class | Bin 2193 -> 2431 bytes ticketStorage.db | Bin 20480 -> 24576 bytes 21 files changed, 956 insertions(+), 591 deletions(-) delete mode 100644 DISPticketing/front/index.html create mode 100644 DISPticketing/front/issueFormPortal.html diff --git a/.vscode/settings.json b/.vscode/settings.json index c5f3f6b..0153b31 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "java.configuration.updateBuildConfiguration": "interactive" + "java.configuration.updateBuildConfiguration": "interactive", + "java.compile.nullAnalysis.mode": "disabled" } \ No newline at end of file diff --git a/DISPticketing/front/extraInformation.html b/DISPticketing/front/extraInformation.html index c74e9b1..d5441d4 100644 --- a/DISPticketing/front/extraInformation.html +++ b/DISPticketing/front/extraInformation.html @@ -12,9 +12,16 @@ </style> </head> -<body> - <div id="form"></div> - +<body style="background-color: lightblue;"> + <div + style="display: flex; flex-direction: column; justify-content: center; align-items: center; margin: 0; background-color: lightblue;"> + <h1>Extra Information Form</h1> + <div + style="padding: 20px; border: 2px solid black; border-radius: 10px; background-color: white; max-width: 800px; height: 450px;"> + <div id="form"> + </div> + </div> + </div> <!-- add your form schema to this script tag alternatively, load it asynchronously from anywhere @@ -52,7 +59,7 @@ "id": "Textarea_4", "label": "Detailed Description of the Issue", "validate": { - "minLength": 10, + "minLength": 2, "maxLength": 500, "required": true }, @@ -94,47 +101,45 @@ }) form.importSchema(schema) - - - - - - form.on('submit', (event) => { - event.preventDefault(); // Prevent the default form submission - - let formData = event.data; // Accessing the data object from the event - formData.emailType = "ExtraEmailReplied"; - console.log(formData); - formData = JSON.stringify(formData); - - fetch('http://localhost:8080/submission', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: formData - }) - .then(response => { - if (!response.ok) { - throw new Error('Network response was not ok'); - } - return response.json(); + const errors = form.validate(); + if (Object.keys(errors).length) { + console.error("Form has errors", errors); + } else { + event.preventDefault(); // Prevent the default form submission + + let formData = event.data; // Accessing the data object from the event + formData.emailType = "ExtraEmailReplied"; + console.log(formData); + formData = JSON.stringify(formData); + + fetch('http://localhost:8080/submission', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: formData }) - .then(data => { - if (data) { - console.log('Form submitted successfully', data); - } else { - console.log('Form submitted successfully'); - } - }) - .catch(error => { - console.error('There was a problem submitting the form', error); - }); + .then(response => { + if (!response.ok) { + throw new Error('Network response was not ok'); + } + return response.json(); + }) + .then(data => { + if (data) { + console.log('Form submitted successfully', data); + } else { + console.log('Form submitted successfully'); + } + }) + .catch(error => { + console.error('There was a problem submitting the form', error); + }); + form.reset(); + } }); - - </script> </body> diff --git a/DISPticketing/front/index.html b/DISPticketing/front/index.html deleted file mode 100644 index 0adc85c..0000000 --- a/DISPticketing/front/index.html +++ /dev/null @@ -1,276 +0,0 @@ -<html> - -<head> - <!-- - required viewer styles - --> - <link rel="stylesheet" href="https://unpkg.com/@bpmn-io/form-js@1.7.3/dist/assets/form-js.css"> - <style> - #form { - max-width: 800px; - } - </style> -</head> - -<body> - <div id="form"></div> - - <!-- - add your form schema to this script tag - alternatively, load it asynchronously from anywhere - --> - <script type="application/form-schema"> - { - "executionPlatform": "Camunda Cloud", - "executionPlatformVersion": "8.5.0", - "exporter": { - "name": "Camunda Web Modeler", - "version": "8c03b57" - }, - "schemaVersion": 16, - "id": "complete-issue-form-0x1n9i1", - "components": [ - { - "text": "### Report an Issue", - "type": "text", - "id": "Heading_0", - "layout": { - "columns": 16, - "row": "Row_0c7idvx" - } - }, - { - "text": "##### Your Details ", - "type": "text", - "id": "Subheading_1", - "layout": { - "row": "row_0", - "columns": null - } - }, - { - "type": "textfield", - "id": "Textfield_2", - "label": "User Name", - "validate": { - "minLength": 2, - "required": true - }, - "key": "fieldName", - "layout": { - "row": "row_1", - "columns": null - } - }, - { - "type": "textfield", - "id": "Textfield_3", - "label": "Contact Number", - "validate": { - "minLength": 8, - "maxLength": 15, - "required": true - }, - "key": "fieldContactNumber", - "layout": { - "row": "row_1", - "columns": null - } - }, - { - "values": [ - { - "value": "IT", - "label": "IT" - }, - { - "value": "HR", - "label": "HR" - }, - { - "value": "Finance", - "label": "Finance" - }, - { - "value": "Operations", - "label": "Operations" - } - ], - "type": "select", - "id": "Select_4", - "label": "Department", - "validate": { - "required": true - }, - "key": "fieldDepartment", - "layout": { - "row": "row_2", - "columns": 16 - } - }, - { - "text": "##### What is the Issue?", - "type": "text", - "id": "Subheading_5", - "layout": { - "row": "row_3", - "columns": null - } - }, - { - "type": "textfield", - "id": "Textfield_6", - "label": "Issue Title", - "validate": { - "minLength": 5, - "maxLength": 50, - "required": true - }, - "key": "fieldTitle", - "layout": { - "row": "row_4", - "columns": null - } - }, - { - "type": "textarea", - "id": "Textarea_7", - "label": "Issue Description", - "validate": { - "minLength": 10, - "maxLength": 300, - "required": true - }, - "key": "fieldDescription", - "layout": { - "row": "Row_0vwv1n8", - "columns": null - } - }, - { - "values": [ - { - "label": "Non-Urgent, Low Priority", - "value": "Non-Urgent, Low Priority" - }, - { - "label": "Medium Urgency, Low Priority", - "value": "Medium Urgency, Low Priority" - }, - { - "label": "High Urgency, Low Priority", - "value": "High Urgency, Low Priority" - }, - { - "label": "Non-Urgent, Medium Priority", - "value": "Non-Urgent, Medium Priority" - }, - { - "label": "Non-Urgent, High Priority", - "value": "Non-Urgent, High Priority" - }, - { - "label": "Medium Urgency, Medium Priority", - "value": "Medium Urgency, Medium Priority" - }, - { - "label": "Medium Urgency, High Priority", - "value": "Medium Urgency, High Priority" - }, - { - "label": "High Urgency, Medium Priority", - "value": "High Urgency, Medium Priority" - }, - { - "label": "High Urgency, High Priority", - "value": "High Urgency, High Priority" - } - ], - "label": "Severity of Issue", - "type": "select", - "layout": { - "row": "Row_0bzl8je", - "columns": null - }, - "id": "Field_0rbo5w8", - "key": "fieldSLA", - "validate": { - "required": true - } - }, - { - "values": [ - { - "label": "IT", - "value": "IT" - }, - { - "label": "Development", - "value": "Development" - } - ], - "label": "Issue Department", - "type": "select", - "layout": { - "row": "Row_0bzl8je", - "columns": null - }, - "id": "Field_16wtr7u", - "key": "assignedDepartment", - "validate": { - "required": true - } - }, - { - "action": "submit", - "label": "Submit", - "type": "button", - "layout": { - "row": "Row_0fs2y8h", - "columns": null - }, - "id": "Field_1dolsqn" - } - ], - "generated": true, - "type": "default" - } - </script> - - - <!-- - required viewer script - --> - <script src="https://unpkg.com/@bpmn-io/form-js@1.7.3/dist/form-viewer.umd.js"></script> - <script> - const schema = JSON.parse( - document.querySelector('[type="application/form-schema"]').textContent - ); - const container = document.querySelector('#form'); - - const form = new FormViewer.Form({ - container - }) - form.importSchema(schema) - - - - - - - - // add event listeners - form.on('submit', (event) => { - const errors = form.validate(); - if (Object.keys(errors).length) { - - console.error("Form has errors", errors); - }else - console.log('Form <submit>', event); - }); - - - </script> -</body> - -</html> \ No newline at end of file diff --git a/DISPticketing/front/issueFormPortal.html b/DISPticketing/front/issueFormPortal.html new file mode 100644 index 0000000..fad8b15 --- /dev/null +++ b/DISPticketing/front/issueFormPortal.html @@ -0,0 +1,317 @@ +<html> + +<head> + <!-- + required viewer styles + --> + <link rel="stylesheet" href="https://unpkg.com/@bpmn-io/form-js@1.7.3/dist/assets/form-js.css"> + <style> + #form { + max-width: 800px; + } + </style> +</head> + +<body style="background-color: lightblue;"> + <div + style="display: flex; flex-direction: column; justify-content: center; align-items: center; margin: 0; background-color: lightblue;"> + <h1>Employee Web Portal</h1> + <div + style="padding: 20px; border: 2px solid black; border-radius: 10px; background-color: white; max-width: 800px; height: 810px;"> + <div id="form"> + </div> + </div> + </div> + <!-- + add your form schema to this script tag + alternatively, load it asynchronously from anywhere + --> + <script type="application/form-schema"> + { + "executionPlatform": "Camunda Cloud", + "executionPlatformVersion": "8.5.0", + "exporter": { + "name": "Camunda Web Modeler", + "version": "8c4dae7" + }, + "schemaVersion": 16, + "id": "complete-issue-form-0x1n9i1", + "components": [ + { + "text": "### Raise an Issue", + "type": "text", + "id": "Heading_0", + "layout": { + "columns": 16, + "row": "Row_0c7idvx" + } + }, + { + "text": "##### Your Employee Details ", + "type": "text", + "id": "Subheading_1", + "layout": { + "row": "row_0", + "columns": null + } + }, + { + "type": "textfield", + "id": "Textfield_2", + "label": "Username", + "validate": { + "minLength": 2, + "required": true, + "maxLength": 20 + }, + "key": "fieldName", + "layout": { + "row": "row_1", + "columns": 7 + } + }, + { + "label": "Employee Email Address", + "type": "textfield", + "layout": { + "row": "row_1", + "columns": 8 + }, + "id": "Field_1kct5bo", + "key": "fieldEmail", + "validate": { + "required": true, + "validationType": "email" + } + }, + { + "type": "textfield", + "id": "Textfield_3", + "label": "Contact Number", + "validate": { + "required": true, + "validationType": "phone" + }, + "key": "fieldContactNumber", + "layout": { + "row": "Row_0sh0red", + "columns": 7 + } + }, + { + "values": [ + { + "value": "IT", + "label": "IT" + }, + { + "value": "HR", + "label": "HR" + }, + { + "value": "Finance", + "label": "Finance" + }, + { + "value": "Operations", + "label": "Operations" + } + ], + "type": "select", + "id": "Select_4", + "label": "Department", + "validate": { + "required": true + }, + "key": "fieldDepartment", + "layout": { + "row": "Row_0sh0red", + "columns": 8 + } + }, + { + "text": "##### What is Your Issue?", + "type": "text", + "id": "Subheading_5", + "layout": { + "row": "row_3", + "columns": 15 + } + }, + { + "type": "textfield", + "id": "Textfield_6", + "label": "Issue Title", + "validate": { + "minLength": 2, + "maxLength": 50, + "required": true + }, + "key": "fieldTitle", + "layout": { + "row": "row_4", + "columns": 15 + } + }, + { + "type": "textarea", + "id": "Textarea_7", + "label": "Issue Description", + "validate": { + "maxLength": 300, + "required": true, + "minLength": 10 + }, + "key": "fieldDescription", + "layout": { + "row": "Row_0vwv1n8", + "columns": 15 + } + }, + { + "values": [ + { + "label": "Non-Urgent, Low Priority", + "value": "Non-Urgent, Low Priority" + }, + { + "label": "Medium Urgency, Low Priority", + "value": "Medium Urgency, Low Priority" + }, + { + "label": "High Urgency, Low Priority", + "value": "High Urgency, Low Priority" + }, + { + "label": "Non-Urgent, Medium Priority", + "value": "Non-Urgent, Medium Priority" + }, + { + "label": "Non-Urgent, High Priority", + "value": "Non-Urgent, High Priority" + }, + { + "label": "Medium Urgency, Medium Priority", + "value": "Medium Urgency, Medium Priority" + }, + { + "label": "Medium Urgency, High Priority", + "value": "Medium Urgency, High Priority" + }, + { + "label": "High Urgency, Medium Priority", + "value": "High Urgency, Medium Priority" + }, + { + "label": "High Urgency, High Priority", + "value": "High Urgency, High Priority" + } + ], + "label": "Severity of Issue", + "type": "select", + "layout": { + "row": "Row_0bzl8je", + "columns": 7 + }, + "id": "Field_0rbo5w8", + "key": "fieldSLA", + "validate": { + "required": true + } + }, + { + "values": [ + { + "label": "IT", + "value": "IT" + }, + { + "label": "Development", + "value": "Development" + } + ], + "label": "Type of Ticket?", + "type": "select", + "layout": { + "row": "Row_0bzl8je", + "columns": 8 + }, + "id": "Field_16wtr7u", + "key": "assignedDepartment", + "validate": { + "required": true + } + }, + { + "action": "submit", + "label": "Submit", + "type": "button", + "layout": { + "row": "Row_0fs2y8h", + "columns": null + }, + "id": "Field_1dolsqn" + } + ], + "generated": true, + "type": "default" + } + + </script> + + <!-- + required viewer script + --> + <script src="https://unpkg.com/@bpmn-io/form-js@1.7.3/dist/form-viewer.umd.js"></script> + <script> + const schema = JSON.parse( + document.querySelector('[type="application/form-schema"]').textContent + ); + const container = document.querySelector('#form'); + + const form = new FormViewer.Form({ + container + }) + form.importSchema(schema) + + form.on('submit', (event) => { + const errors = form.validate(); + if (Object.keys(errors).length) { + console.error("Form has errors", errors); + } else { + event.preventDefault(); // Prevent the default form submission + + let formData = event.data; // Accessing the data object from the event + console.log(formData); + formData = JSON.stringify(formData); + + fetch('http://localhost:8080/issueSubmission', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: formData + }) + .then(response => { + if (!response.ok) { + throw new Error('Network response was not ok'); + } + return response.json(); + }) + .then(data => { + if (data) { + console.log('Form submitted successfully', data); + } else { + console.log('Form submitted successfully'); + } + }) + .catch(error => { + console.error('There was a problem submitting the form', error); + }); + form.reset(); + } + }); + </script> +</body> + +</html> \ No newline at end of file diff --git a/DISPticketing/front/reviewInformation.html b/DISPticketing/front/reviewInformation.html index c615a95..f91c396 100644 --- a/DISPticketing/front/reviewInformation.html +++ b/DISPticketing/front/reviewInformation.html @@ -1,25 +1,32 @@ <html> <head> - <!-- + <!-- required viewer styles --> - <link rel="stylesheet" href="https://unpkg.com/@bpmn-io/form-js@1.7.3/dist/assets/form-js.css"> - <style> - #form { - max-width: 800px; - } - </style> + <link rel="stylesheet" href="https://unpkg.com/@bpmn-io/form-js@1.7.3/dist/assets/form-js.css"> + <style> + #form { + max-width: 800px; + } + </style> </head> -<body> - <div id="form"></div> - - <!-- +<body style="background-color: lightblue;"> + <div + style="display: flex; flex-direction: column; justify-content: center; align-items: center; margin: 0; background-color: lightblue;"> + <h1>Review Completion Form</h1> + <div + style="padding: 20px; border: 2px solid black; border-radius: 10px; background-color: white; max-width: 800px; height: 550px;"> + <div id="form"> + </div> + </div> + </div> + <!-- add your form schema to this script tag alternatively, load it asynchronously from anywhere --> - <script type="application/form-schema"> + <script type="application/form-schema"> { "executionPlatform": "Camunda Cloud", "executionPlatformVersion": "8.5.0", @@ -71,7 +78,7 @@ "row": "row_7", "columns": null }, - "defaultValue": "yes" + "defaultValue": "" }, { "type": "textarea", @@ -108,63 +115,60 @@ } </script> - <!-- + <!-- required viewer script --> - <script src="https://unpkg.com/@bpmn-io/form-js@1.7.3/dist/form-viewer.umd.js"></script> - <script> - const schema = JSON.parse( - document.querySelector('[type="application/form-schema"]').textContent - ); - const container = document.querySelector('#form'); - - const form = new FormViewer.Form({ - container - }) - form.importSchema(schema) - + <script src="https://unpkg.com/@bpmn-io/form-js@1.7.3/dist/form-viewer.umd.js"></script> + <script> + const schema = JSON.parse( + document.querySelector('[type="application/form-schema"]').textContent + ); + const container = document.querySelector('#form'); + const form = new FormViewer.Form({ + container + }) + form.importSchema(schema) + form.on('submit', (event) => { + const errors = form.validate(); + if (Object.keys(errors).length) { + console.error("Form has errors", errors); + } else { + event.preventDefault(); // Prevent the default form submission + let formData = event.data; // Accessing the data object from the event + formData.emailType = "ReviewEmailReplied" + console.log(formData); + formData = JSON.stringify(formData); - - - form.on('submit', (event) => { - event.preventDefault(); // Prevent the default form submission - - let formData = event.data; // Accessing the data object from the event - formData.emailType = "ReviewEmailReplied"; - console.log(formData); - formData = JSON.stringify(formData); - - fetch('http://localhost:8080/submission', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: formData + fetch('http://localhost:8080/submission', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: formData + }) + .then(response => { + if (!response.ok) { + throw new Error('Network response was not ok'); + } + return response.json(); }) - .then(response => { - if (!response.ok) { - throw new Error('Network response was not ok'); - } - return response.json(); - }) - .then(data => { - if (data) { - console.log('Form submitted successfully', data); - } else { - console.log('Form submitted successfully'); - } - }) - .catch(error => { - console.error('There was a problem submitting the form', error); - }); - }); - - - - </script> + .then(data => { + if (data) { + console.log('Form submitted successfully', data); + } else { + console.log('Form submitted successfully'); + } + }) + .catch(error => { + console.error('There was a problem submitting the form', error); + }); + form.reset(); + } + }); + </script> </body> </html> \ No newline at end of file diff --git a/DISPticketing/front/surveyInformation.html b/DISPticketing/front/surveyInformation.html index e6d79a5..6b75e86 100644 --- a/DISPticketing/front/surveyInformation.html +++ b/DISPticketing/front/surveyInformation.html @@ -1,25 +1,33 @@ <html> <head> - <!-- + <!-- required viewer styles --> - <link rel="stylesheet" href="https://unpkg.com/@bpmn-io/form-js@1.7.3/dist/assets/form-js.css"> - <style> - #form { - max-width: 800px; - } - </style> + <link rel="stylesheet" href="https://unpkg.com/@bpmn-io/form-js@1.7.3/dist/assets/form-js.css"> + <style> + #form { + max-width: 800px; + } + </style> </head> -<body> - <div id="form"></div> +<body style="background-color: lightblue;"> + <div + style="display: flex; flex-direction: column; justify-content: center; align-items: center; margin: 0; background-color: lightblue;"> + <h1>Completion Survey</h1> + <div + style="padding: 20px; border: 2px solid black; border-radius: 10px; background-color: white; max-width: 800px; height: 500px;"> + <div id="form"> + </div> + </div> + </div> - <!-- + <!-- add your form schema to this script tag alternatively, load it asynchronously from anywhere --> - <script type="application/form-schema"> + <script type="application/form-schema"> { "executionPlatform": "Camunda Cloud", "executionPlatformVersion": "8.5.0", @@ -113,62 +121,61 @@ "type": "default" } </script> - - <!-- + <!-- required viewer script --> - <script src="https://unpkg.com/@bpmn-io/form-js@1.7.3/dist/form-viewer.umd.js"></script> - <script> - const schema = JSON.parse( - document.querySelector('[type="application/form-schema"]').textContent - ); - const container = document.querySelector('#form'); - - const form = new FormViewer.Form({ - container - }) - form.importSchema(schema) - - - + <script src="https://unpkg.com/@bpmn-io/form-js@1.7.3/dist/form-viewer.umd.js"></script> + <script> + const schema = JSON.parse( + document.querySelector('[type="application/form-schema"]').textContent + ); + const container = document.querySelector('#form'); + const form = new FormViewer.Form({ + container + }) + form.importSchema(schema) + form.on('submit', (event) => { + const errors = form.validate(); + if (Object.keys(errors).length) { + console.error("Form has errors", errors); + } else { + event.preventDefault(); // Prevent the default form submission + let formData = event.data; // Accessing the data object from the event + formData.emailType = "SurveyEmailReplied" + console.log(formData); + formData = JSON.stringify(formData); - form.on('submit', (event) => { - event.preventDefault(); // Prevent the default form submission - - let formData = event.data; // Accessing the data object from the event - formData.emailType = "SurveyEmailReplied"; - console.log(formData); - formData = JSON.stringify(formData); - - fetch('http://localhost:8080/submission', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: formData + fetch('http://localhost:8080/submission', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: formData + }) + .then(response => { + if (!response.ok) { + throw new Error('Network response was not ok'); + } + return response.json(); }) - .then(response => { - if (!response.ok) { - throw new Error('Network response was not ok'); - } - return response.json(); - }) - .then(data => { - if (data) { - console.log('Form submitted successfully', data); - } else { - console.log('Form submitted successfully'); - } - }) - .catch(error => { - console.error('There was a problem submitting the form', error); - }); - }); + .then(data => { + if (data) { + console.log('Form submitted successfully', data); + } else { + console.log('Form submitted successfully'); + } + }) + .catch(error => { + console.error('There was a problem submitting the form', error); + }); + form.reset(); + } + }); - </script> + </script> </body> </html> \ No newline at end of file diff --git a/DISPticketing/pom.xml b/DISPticketing/pom.xml index bf76487..94f5e7e 100644 --- a/DISPticketing/pom.xml +++ b/DISPticketing/pom.xml @@ -69,31 +69,6 @@ <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> - - <dependency> - <groupId>com.sun.mail</groupId> - <artifactId>javax.mail</artifactId> - <version>1.6.2</version> - </dependency> - - <dependency> - <groupId>com.sun.activation</groupId> - <artifactId>javax.activation</artifactId> - <version>1.2.0</version> - </dependency> - - <dependency> - <groupId>org.eclipse.angus</groupId> - <artifactId>jakarta.mail</artifactId> - <version>2.0.3</version> - <exclusions> - <exclusion> - <groupId>org.eclipse.angus</groupId> - <artifactId>angus-activation</artifactId> - </exclusion> - </exclusions> - </dependency> - </dependencies> <build> diff --git a/DISPticketing/src/main/java/com/disp/Worker.java b/DISPticketing/src/main/java/com/disp/Worker.java index 609bdec..f5baa70 100644 --- a/DISPticketing/src/main/java/com/disp/Worker.java +++ b/DISPticketing/src/main/java/com/disp/Worker.java @@ -2,14 +2,12 @@ package com.disp; import java.util.HashMap; import java.util.Map; - import com.disp.email.EmailRequest; import com.disp.email.EmailService; import com.disp.forms.FormData; import com.disp.ticket.Ticket; import com.disp.ticket.TicketCamundaManager; import com.disp.ticket.TicketDBManager; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -17,10 +15,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; - import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; - import io.camunda.zeebe.client.ZeebeClient; import io.camunda.zeebe.client.api.response.ActivatedJob; import io.camunda.zeebe.client.api.worker.JobClient; @@ -46,6 +42,7 @@ public class Worker { return new RestTemplate(); } + // creates a ticket and stores within the database @JobWorker(type = "createTicket", autoComplete = false) public void createTicket(final JobClient client, final ActivatedJob job) { // get the process instance variables and creates a ticket object @@ -57,7 +54,18 @@ public class Worker { TicketDBManager ticketCRUD = new TicketDBManager(); ticketCRUD.createTicket(ticket); variableMap.put("ticketID", ticket.getId()); - variableMap.put("ticketStatus", "active"); + variableMap.put("creationDate", ticket.getCreationDate()); + variableMap.put("loggedTime", ticket.getLoggedTime()); + variableMap.put("ticketStatus", "Open"); + + // send email notifying that the ticket has been closed + String sender = "joewilko17@gmail.com"; + String subject = "Ticket Open!"; + String body = "Hello " + ticket.getName() + + ", Your ticket is now open and being worked on! Kind Regards, Your Company"; + String recipient = ticket.getEmail(); + emailService.sendEmail(subject, body, sender, recipient); + System.out.println(variableMap); // complete task and return all variables @@ -66,6 +74,7 @@ public class Worker { .send(); } + // updates a ticket with variables taken from the process engine @JobWorker(type = "updateTicket", autoComplete = false) public void updateTicket(final JobClient client, final ActivatedJob job) { // get the process instance variables and creates a ticket object @@ -75,11 +84,25 @@ public class Worker { // make changes to the database TicketDBManager ticketDBManager = new TicketDBManager(); - ticketDBManager.updateTicket(ticket.getId(), ticket); + // Check if the ticket needs to be moved from Email_Tickets to the appropriate + // department table + if (ticket.getAssignedDepartment() != null) { + if (ticketDBManager.ticketExistsInEmailTickets(ticket.getId())) { + ticketDBManager.moveTicketToDepartment(ticket.getId(), ticket); + } else { + ticketDBManager.updateTicket(ticket.getId(), ticket); + } + } else { + ticketDBManager.updateTicket(ticket.getId(), ticket); + } // complete the task updating the variables in the camunda process instance variableMap.put("fieldManagerReviewDescription", ticketDBManager.getGeneratedDescription(ticket.getId(), ticket)); + // update the logged time as new value calculated when getTicketFromEngine() + // called + variableMap.put("ticketID", ticket.getId()); + variableMap.put("loggedTime", ticket.getLoggedTime()); // complete task and return all variables client.newCompleteCommand(job.getKey()) @@ -87,6 +110,7 @@ public class Worker { .send(); } + // sets the status of a ticket to closed @JobWorker(type = "closeTicket", autoComplete = false) public void closeTicket(final JobClient client, final ActivatedJob job) { // get the ticket from camunda process variables, using getTicketFromEngine() @@ -95,7 +119,7 @@ public class Worker { Ticket ticket = ticketCamundaManager.getTicketFromEngine(variableMap); // set the ticket status to closed - ticket.setStatus("closed"); + ticket.setStatus("Closed"); // make changes to the database TicketDBManager ticketDBManager = new TicketDBManager(); @@ -104,12 +128,22 @@ public class Worker { // complete the task updating the variables in the camunda process instance variableMap.put("ticketStatus", ticket.getStatus()); + // send email notifying that the ticket has been closed + String sender = "joewilko17@gmail.com"; + String subject = "Ticket Closed: Inactive 2 Weeks"; + String body = "Hello " + ticket.getName() + + ", Your ticket has been inactive for two weeks and has been closed! Kind Regards, Your Company"; + String recipient = ticket.getEmail(); + emailService.sendEmail(subject, body, sender, recipient); + System.out.println("Ticket Closed"); + // complete task client.newCompleteCommand(job.getKey()) .variables(variableMap) .send(); } + // sets the status of a ticket to complete @JobWorker(type = "completeTicket", autoComplete = false) public void completeTicket(final JobClient client, final ActivatedJob job) { // get the ticket from camunda process variables, using getTicketFromEngine() @@ -118,7 +152,7 @@ public class Worker { Ticket ticket = ticketCamundaManager.getTicketFromEngine(variableMap); // set the ticket status to complete - ticket.setStatus("completed"); + ticket.setStatus("Completed"); TicketDBManager ticketDBManager = new TicketDBManager(); ticketDBManager.updateTicket(ticket.getId(), ticket); @@ -126,12 +160,23 @@ public class Worker { // complete the task updating the variables in the camunda process instance variableMap.put("ticketStatus", ticket.getStatus()); + // send email notifying that the ticket has been closed + String sender = "joewilko17@gmail.com"; + String subject = "Ticket Complete!"; + String body = "Hello " + ticket.getName() + + ", Your ticket has been successfuly solved and has been completed! Kind Regards, Your Company"; + String recipient = ticket.getEmail(); + emailService.sendEmail(subject, body, sender, recipient); + + System.out.println("Ticket Completed"); // complete task client.newCompleteCommand(job.getKey()) .variables(variableMap) .send(); } + // method which sends an email to the end user based on the type of email + // needing to be sent using switch/case statements @JobWorker(type = "sendEmail", autoComplete = false) public void sendEmail(final JobClient client, final ActivatedJob job) { // get the email details to send from the header type @@ -143,10 +188,9 @@ public class Worker { String sender = "joewilko17@gmail.com"; String subject = ""; String body = ""; - // change to ticket.getEmail(); - String recipient = ticket.getName(); + String recipient = ticket.getEmail(); - // Determine recipient based on the emailType header + // determine recipient based on the emailType header switch (emailType) { case "Survey": // survey email contents @@ -161,7 +205,7 @@ public class Worker { case "ExtraInfo": // extra information email contents subject = "We Require More Info!"; - body = "Please fill out the form: <a href=\'http://localhost:8000/extraInformation.html'>This link will take you to the form!</a>"; + body = ticket.getMoreDescription() + ". Please fill out the form: <a href=\'http://localhost:8000/extraInformation.html'>This link will take you to the form!</a>"; break; default: break; @@ -169,6 +213,7 @@ public class Worker { // send email emailService.sendEmail(subject, body, sender, recipient); + System.out.println("Sending Email of Type: " + emailType); // complete the task client.newCompleteCommand(job.getKey()) @@ -176,42 +221,20 @@ public class Worker { .join(); } - // defunct remove in a bit - @JobWorker(type = "saveSurvey", autoComplete = false) - public void saveSurvey(final JobClient client, final ActivatedJob job) { - // get the ticket from camunda process variables, using getTicketFromEngine() - Map<String, Object> variableMap = job.getVariablesAsMap(); - TicketCamundaManager ticketCamundaManager = new TicketCamundaManager(); - Ticket ticket = ticketCamundaManager.getTicketFromEngine(variableMap); - - TicketDBManager ticketDBManager = new TicketDBManager(); - ticketDBManager.updateTicket(ticket.getId(), ticket); - - // complete the task updating the variables in the camunda process instance - variableMap.put("fieldSatisfactionLevel", ticket.getSatisfactionLevel()); - variableMap.put("fieldComments", ticket.getComments()); - - // complete task - client.newCompleteCommand(job.getKey()) - .variables(variableMap) - .send(); - } - + // method by which email can be recieved from a sender for submitting an issue @PostMapping("/email") public void receiveEmail(@RequestBody EmailRequest emailRequest) { // gets the values from the email and stores to variable - System.out.println("Email received:"); - System.out.println("Sender: " + emailRequest.getSender()); - System.out.println("Subject: " + emailRequest.getSubject()); - System.out.println("Body: " + emailRequest.getBody()); + System.out.println("Email received: Sending to Database and Process Engine"); String sender = emailRequest.getSender(); - String contactDetails = "N/A"; - String department = "N/A"; + String contactDetails = emailRequest.getContactDetails(); + String department = emailRequest.getDepartment(); String serviceLevelAgreement = emailRequest.getServiceLevelAgreement(); String assignedDepartment = emailRequest.getAssignedDepartment(); String subject = emailRequest.getSubject(); String body = emailRequest.getBody(); + String email = emailRequest.getEmail(); // loads a variable map with the content from the email Map<String, Object> emailContents = new HashMap<>(); @@ -222,6 +245,14 @@ public class Worker { emailContents.put("assignedDepartment", assignedDepartment); emailContents.put("fieldTitle", subject); emailContents.put("fieldDescription", body); + emailContents.put("fieldEmail", email); + emailContents.put("ticketStatus", "Open"); + + // // save the email into a ticket, to send to database + // TicketCamundaManager TicketCamundaManager = new TicketCamundaManager(); + // Ticket ticket = TicketCamundaManager.getTicketFromEmail(emailContents); + // TicketDBManager ticketCRUD = new TicketDBManager(); + // ticketCRUD.createTicket(ticket); // triggers the email recieved boundary event zClient.newPublishMessageCommand() @@ -231,6 +262,39 @@ public class Worker { .send(); } + @PostMapping("/issueSubmission") + public ResponseEntity<String> recieveIssueForm(@RequestBody FormData formData) { + + String fieldName = formData.getFieldName(); + String fieldEmail = formData.getFieldEmail(); + String fieldContactNumber = formData.getFieldContactNumber(); + String fieldDepartment = formData.getFieldDepartment(); + String fieldTitle = formData.getFieldTitle(); + String fieldDescription = formData.getFieldDescription(); + String fieldSLA = formData.getFieldSLA(); + String assignedDepartment = formData.getAssignedDepartment(); + + Map<String, Object> formContents = new HashMap<>(); + formContents.put("fieldName", fieldName); + formContents.put("fieldEmail", fieldEmail); + formContents.put("fieldContactNumber", fieldContactNumber); + formContents.put("fieldDepartment", fieldDepartment); + formContents.put("fieldTitle", fieldTitle); + formContents.put("fieldDescription", fieldDescription); + formContents.put("fieldSLA", fieldSLA); + formContents.put("assignedDepartment", assignedDepartment); + + System.out.println("Issue form data has been retrieved"); + + zClient.newPublishMessageCommand() + .messageName("issueFormRecieved") + .correlationKey("Recieved") + .variables(formContents) + .send(); + return ResponseEntity.ok("{\"message\": \"Form submitted successfully\"}"); + } + + // method to retrieve external form data sent by email to the end user @PostMapping("/submission") public ResponseEntity<String> receiveFormData(@RequestBody FormData formData) { // find out which email type this is recieving data from @@ -261,8 +325,8 @@ public class Worker { formContents.put("fieldComments", comments); } - // finish any recieve tasks waiting on an email based on which header was - // requested + System.out.println("Form Data Recieved from " + emailType); + zClient.newPublishMessageCommand() .messageName(emailType) .correlationKey("Reply") diff --git a/DISPticketing/src/main/java/com/disp/email/EmailConfig.java b/DISPticketing/src/main/java/com/disp/email/EmailConfig.java index 3e3391f..8e142f3 100644 --- a/DISPticketing/src/main/java/com/disp/email/EmailConfig.java +++ b/DISPticketing/src/main/java/com/disp/email/EmailConfig.java @@ -10,11 +10,6 @@ import org.springframework.mail.javamail.JavaMailSenderImpl; @Configuration public class EmailConfig { - - private String userName = "joewilko17@gmail.com"; - - private String password = "hqwkhcbqztnlcfhd"; - @Bean public JavaMailSender mailSender() { @@ -22,21 +17,15 @@ public class EmailConfig { mailSender.setHost("smtp.gmail.com"); mailSender.setPort(587); - mailSender.setUsername(userName); - mailSender.setPassword(password); + mailSender.setUsername("joewilko17@gmail.com"); + mailSender.setPassword("hqwkhcbqztnlcfhd"); Properties javaMailProperties = new Properties(); - javaMailProperties.put("mail.smtp.auth", "true"); // Change to string value - javaMailProperties.put("mail.smtp.starttls.enable", "true"); // Change to string value + javaMailProperties.put("mail.smtp.auth", "true"); + javaMailProperties.put("mail.smtp.starttls.enable", "true"); mailSender.setJavaMailProperties(javaMailProperties); return mailSender; } - - //only one getter so that emails can be sent from the correct address in Worker.java - public String getUserName() { - return userName; - } - } diff --git a/DISPticketing/src/main/java/com/disp/email/EmailListener.java b/DISPticketing/src/main/java/com/disp/email/EmailListener.java index 0561531..6595b48 100644 --- a/DISPticketing/src/main/java/com/disp/email/EmailListener.java +++ b/DISPticketing/src/main/java/com/disp/email/EmailListener.java @@ -1,24 +1,19 @@ package com.disp.email; -import javax.mail.*; -import javax.mail.event.*; -import javax.mail.internet.MimeMultipart; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; - import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; - import jakarta.annotation.PostConstruct; - +import jakarta.mail.*; +import jakarta.mail.event.*; +import jakarta.mail.internet.MimeMultipart; import java.io.IOException; import java.util.Properties; import java.util.Timer; import java.util.TimerTask; - @Service public class EmailListener { @@ -62,6 +57,9 @@ public class EmailListener { for (Message message : messages) { try { String sender = message.getFrom()[0].toString(); + String[] senderParts = parseSender(sender); + String name = senderParts[0]; + String email = senderParts[1]; String subject = message.getSubject(); Object content = message.getContent(); String body = ""; @@ -75,7 +73,8 @@ public class EmailListener { System.out.println(subject); System.out.println(body); // Send email data to the API endpoint - EmailRequest emailRequest = new EmailRequest(sender, null, null, null, null, subject, body); + EmailRequest emailRequest = new EmailRequest(name, null, null, null, null, subject, body, + email); restTemplate.postForObject(EMAIL_RECEIVE_ENDPOINT, emailRequest, Void.class); } catch (Exception ex) { ex.printStackTrace(); @@ -85,22 +84,20 @@ public class EmailListener { @Override public void messagesRemoved(MessageCountEvent e) { - // Not used in this example } }); - // Check for new messages every 10 seconds Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { try { - inbox.getMessageCount(); // Triggers MessageCountListener + inbox.getMessageCount(); } catch (MessagingException e) { e.printStackTrace(); } } - }, 0, 10000); // Check every 10 seconds + }, 0, 1000); } catch (Exception e) { e.printStackTrace(); @@ -114,13 +111,27 @@ public class EmailListener { for (int i = 0; i < count; i++) { BodyPart bodyPart = multipart.getBodyPart(i); if (bodyPart.getContent() instanceof MimeMultipart) { - // Recursively process nested multiparts textContent.append(getTextFromMimeMultipart((MimeMultipart) bodyPart.getContent())); - } else if (bodyPart.isMimeType("text/*")) { - // If the body part is text, append it to the text content - textContent.append(bodyPart.getContent().toString()); + } else if (bodyPart.isMimeType("text/plain")) { + String text = bodyPart.getContent().toString() + .replaceAll("\\r\\n|\\r|\\n|\\t|\\f|\\b", " "); + textContent.append(text); } } return textContent.toString(); } + + // Method to parse sender name and email address + private static String[] parseSender(String sender) { + String name = ""; + String email = ""; + String[] parts = sender.split("<"); + if (parts.length > 1) { + name = parts[0].trim(); + email = parts[1].replaceAll(">", "").trim(); + } else { + email = sender.trim(); + } + return new String[] { name, email }; + } } diff --git a/DISPticketing/src/main/java/com/disp/email/EmailRequest.java b/DISPticketing/src/main/java/com/disp/email/EmailRequest.java index c189ddb..c99858a 100644 --- a/DISPticketing/src/main/java/com/disp/email/EmailRequest.java +++ b/DISPticketing/src/main/java/com/disp/email/EmailRequest.java @@ -9,11 +9,11 @@ public class EmailRequest { private String assignedDepartment; private String subject; private String body; - + private String email; public EmailRequest(String sender, String contactDetails, String department, String serviceLevelAgreement, - String assignedDepartment, String subject, String body) { + String assignedDepartment, String subject, String body, String email) { this.sender = sender; this.contactDetails = contactDetails; this.department = department; @@ -21,6 +21,7 @@ public class EmailRequest { this.assignedDepartment = assignedDepartment; this.subject = subject; this.body = body; + this.email = email; } // getters and setters public String getSender() { @@ -65,6 +66,11 @@ public class EmailRequest { public void setBody(String body) { this.body = body; } + public String getEmail() { + return email; + } + public void setEmail(String email) { + this.email = email; + } - } diff --git a/DISPticketing/src/main/java/com/disp/email/EmailService.java b/DISPticketing/src/main/java/com/disp/email/EmailService.java index cc192d4..23eb8fe 100644 --- a/DISPticketing/src/main/java/com/disp/email/EmailService.java +++ b/DISPticketing/src/main/java/com/disp/email/EmailService.java @@ -13,15 +13,14 @@ public class EmailService { private JavaMailSender mailSender; public void sendEmail(String subject, String messageBody, String from, String to) { - // Define your email details - // Create a MimeMessagePreparator using a lambda expression + // Create a MimeMessagePreparator MimeMessagePreparator messagePreparator = mimeMessage -> { MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage); messageHelper.setTo(to); messageHelper.setFrom(from); messageHelper.setSubject(subject); - messageHelper.setText(messageBody, true); // Set to true if using HTML content + messageHelper.setText(messageBody, true); }; // Send the email diff --git a/DISPticketing/src/main/java/com/disp/forms/FormData.java b/DISPticketing/src/main/java/com/disp/forms/FormData.java index 4306065..fc1a6f1 100644 --- a/DISPticketing/src/main/java/com/disp/forms/FormData.java +++ b/DISPticketing/src/main/java/com/disp/forms/FormData.java @@ -2,36 +2,108 @@ package com.disp.forms; public class FormData { + // form data variables private String emailType; - + private String fieldName; + private String fieldEmail; + private String fieldContactNumber; + private String fieldDepartment; + private String fieldTitle; + private String fieldDescription; + private String fieldSLA; + private String assignedDepartment; private String fieldDetailedDescription; private String issueResolved; private String fieldUnresolvedReason; private String fieldSatisfactionLevel; private String fieldComments; + // getter and setters public String getEmailType() { return emailType; } - + public void setEmailType(String emailType) { + this.emailType = emailType; + } + public String getFieldName() { + return fieldName; + } + public void setFieldName(String fieldName) { + this.fieldName = fieldName; + } + public String getFieldEmail() { + return fieldEmail; + } + public void setFieldEmail(String fieldEmail) { + this.fieldEmail = fieldEmail; + } + public String getFieldContactNumber() { + return fieldContactNumber; + } + public void setFieldContactNumber(String fieldContactNumber) { + this.fieldContactNumber = fieldContactNumber; + } + public String getFieldDepartment() { + return fieldDepartment; + } + public void setFieldDepartment(String fieldDepartment) { + this.fieldDepartment = fieldDepartment; + } + public String getFieldTitle() { + return fieldTitle; + } + public void setFieldTitle(String fieldTitle) { + this.fieldTitle = fieldTitle; + } + public String getFieldDescription() { + return fieldDescription; + } + public void setFieldDescription(String fieldDescription) { + this.fieldDescription = fieldDescription; + } + public String getFieldSLA() { + return fieldSLA; + } + public void setFieldSLA(String fieldSLA) { + this.fieldSLA = fieldSLA; + } + public String getAssignedDepartment() { + return assignedDepartment; + } + public void setAssignedDepartment(String assignedDepartment) { + this.assignedDepartment = assignedDepartment; + } public String getFieldDetailedDescription() { return fieldDetailedDescription; } - + public void setFieldDetailedDescription(String fieldDetailedDescription) { + this.fieldDetailedDescription = fieldDetailedDescription; + } public String getIssueResolved() { return issueResolved; } - + public void setIssueResolved(String issueResolved) { + this.issueResolved = issueResolved; + } public String getFieldUnresolvedReason() { return fieldUnresolvedReason; } - + public void setFieldUnresolvedReason(String fieldUnresolvedReason) { + this.fieldUnresolvedReason = fieldUnresolvedReason; + } public String getFieldSatisfactionLevel() { return fieldSatisfactionLevel; } - + public void setFieldSatisfactionLevel(String fieldSatisfactionLevel) { + this.fieldSatisfactionLevel = fieldSatisfactionLevel; + } public String getFieldComments() { return fieldComments; } + public void setFieldComments(String fieldComments) { + this.fieldComments = fieldComments; + } + + } diff --git a/DISPticketing/src/main/java/com/disp/ticket/Ticket.java b/DISPticketing/src/main/java/com/disp/ticket/Ticket.java index 30b1b3f..a45fe28 100644 --- a/DISPticketing/src/main/java/com/disp/ticket/Ticket.java +++ b/DISPticketing/src/main/java/com/disp/ticket/Ticket.java @@ -2,12 +2,13 @@ package com.disp.ticket; public class Ticket { private String name; + private String email; private String contactNumber; private String department; private String ticketTitle; private String ticketDescription; private String serviceLevelAgreement; - private String assignedDepartment; + private String assignedDepartment; private Integer id; private String status; private String assignedEmployee; @@ -16,10 +17,13 @@ public class Ticket { private String unresolvedReason; private String satisfactionLevel; private String comments; + private String creationDate; + private String loggedTime; // default constructor - public Ticket(){ + public Ticket() { this.name = null; + this.email = null; this.contactNumber = null; this.department = null; this.ticketTitle = null; @@ -34,13 +38,20 @@ public class Ticket { this.unresolvedReason = null; this.satisfactionLevel = null; this.comments = null; + this.creationDate = null; + this.loggedTime = null; + } // constructor for ticket creation - public Ticket(String name, String contactNumber, String department, String ticketTitle, String ticketDescription, - String serviceLevelAgreement, String assignedDepartment, Integer id, String status, String assignedEmployee,String moreDescription, - String detailedDescription,String unresolvedReason,String satisfactionLevel, String comments) { + public Ticket(String name, String email, String contactNumber, String department, String ticketTitle, + String ticketDescription, + String serviceLevelAgreement, String assignedDepartment, Integer id, String status, String assignedEmployee, + String moreDescription, + String detailedDescription, String unresolvedReason, String satisfactionLevel, String comments, + String creationDate, String loggedTime) { this.name = name; + this.email = email; this.contactNumber = contactNumber; this.department = department; this.ticketTitle = ticketTitle; @@ -48,13 +59,16 @@ public class Ticket { this.serviceLevelAgreement = serviceLevelAgreement; this.assignedDepartment = assignedDepartment; this.id = id; - this.status = status; + this.status = status; this.assignedEmployee = assignedEmployee; this.moreDescription = moreDescription; this.detailedDescription = detailedDescription; this.unresolvedReason = unresolvedReason; this.satisfactionLevel = satisfactionLevel; this.comments = comments; + this.creationDate = creationDate; + this.loggedTime = loggedTime; + } // function to return a singular ticket description for camunda process instance @@ -85,7 +99,7 @@ public class Ticket { } } - // getter & setter methods + // getter & setter methods public String getName() { return name; } @@ -94,6 +108,14 @@ public class Ticket { this.name = name; } + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + public String getContactNumber() { return contactNumber; } @@ -205,4 +227,21 @@ public class Ticket { public void setComments(String comments) { this.comments = comments; } + + public String getCreationDate() { + return creationDate; + } + + public void setCreationDate(String creationDate) { + this.creationDate = creationDate; + } + + public String getLoggedTime() { + return loggedTime; + } + + public void setLoggedTime(String loggedTime) { + this.loggedTime = loggedTime; + } + } diff --git a/DISPticketing/src/main/java/com/disp/ticket/TicketCamundaManager.java b/DISPticketing/src/main/java/com/disp/ticket/TicketCamundaManager.java index 21f76df..0b2427a 100644 --- a/DISPticketing/src/main/java/com/disp/ticket/TicketCamundaManager.java +++ b/DISPticketing/src/main/java/com/disp/ticket/TicketCamundaManager.java @@ -1,5 +1,8 @@ package com.disp.ticket; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.Map; public class TicketCamundaManager { @@ -8,6 +11,7 @@ public class TicketCamundaManager { // variableMap) int ticketID = variableMap.containsKey("ticketID") ? (int) variableMap.get("ticketID") : 0; String name = (String) variableMap.get("fieldName"); + String email = (String) variableMap.get("fieldEmail"); String contactNumber = (String) variableMap.get("fieldContactNumber"); String department = (String) variableMap.get("fieldDepartment"); String ticketTitle = (String) variableMap.get("fieldTitle"); @@ -21,10 +25,45 @@ public class TicketCamundaManager { String unresolvedReason = (String) variableMap.get("fieldUnresolvedReason"); String satisfactionLevel = (String) variableMap.get("fieldSatisfactionLevel"); String comments = (String) variableMap.get("fieldComments"); + String creationDate = (String) variableMap.get("creationDate"); + String loggedTime = (String) variableMap.get("loggedTime"); + + if (creationDate == null) { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date date = new Date(); + creationDate = formatter.format(date); + } + loggedTime = calculateTimeDifference(creationDate); // create and return a new ticket object with these values - return new Ticket(name, contactNumber, department, ticketTitle, ticketDescription, sla, + return new Ticket(name, email, contactNumber, department, ticketTitle, ticketDescription, sla, assignedDepartment, ticketID, status, - assignedEmployee, moreDescription, detailedDescription, unresolvedReason, satisfactionLevel, comments); + assignedEmployee, moreDescription, detailedDescription, unresolvedReason, satisfactionLevel, comments, + creationDate, loggedTime); + } + + private static String calculateTimeDifference(String creationDate) { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date currentDate = new Date(); + String loggedTime = ""; + + try { + // Parse creationDate + Date dateCreationDate = formatter.parse(creationDate); + + // Calculate the difference between currentDate and dateCreationDate + long difference = currentDate.getTime() - dateCreationDate.getTime(); + long seconds = difference / 1000 % 60; + long minutes = difference / (60 * 1000) % 60; + long hours = difference / (60 * 60 * 1000); + + // Format the difference into HH:mm:ss format + loggedTime = String.format("%02d:%02d:%02d", hours, minutes, seconds); + } catch (ParseException e) { + e.printStackTrace(); + } + + return loggedTime; } + } diff --git a/DISPticketing/src/main/java/com/disp/ticket/TicketDBManager.java b/DISPticketing/src/main/java/com/disp/ticket/TicketDBManager.java index 2f9c811..d7ab79c 100644 --- a/DISPticketing/src/main/java/com/disp/ticket/TicketDBManager.java +++ b/DISPticketing/src/main/java/com/disp/ticket/TicketDBManager.java @@ -10,10 +10,10 @@ public class TicketDBManager { public void createTicket(Ticket ticket) { // first create the ticketStorage database if it doesnt already exist // then add the ticket to that database - + // get the correct table to add ticket String tableName; - if(ticket.getAssignedDepartment() != null){ + if (ticket.getAssignedDepartment() != null) { if (ticket.getAssignedDepartment().equals("Development")) { tableName = "Development_Tickets"; } else if (ticket.getAssignedDepartment().equals("IT")) { @@ -22,35 +22,36 @@ public class TicketDBManager { System.err.println("Invalid department: " + ticket.getAssignedDepartment()); return; } - } - else{ + } else { tableName = "Email_Tickets"; } - - String createTicket = "INSERT INTO "+ tableName + " (name, contactNumber, department, ticketTitle, ticketDescription, serviceLevelAgreement, status) " - + "VALUES (?, ?, ?, ?, ?, ?,?)"; + String createTicket = "INSERT INTO " + tableName + + " (name, email, contactNumber, department, ticketTitle, ticketDescription, serviceLevelAgreement, status, creationDate, loggedTime) " + + "VALUES (?, ?, ?, ?, ?, ?, ?,?,?,?)"; try (Connection connection = SQLiteConnection.connect(); PreparedStatement statement = connection.prepareStatement(createTicket, Statement.RETURN_GENERATED_KEYS)) { // set the parameters of the INSERT statement statement.setString(1, ticket.getName()); - statement.setString(2, ticket.getContactNumber()); - statement.setString(3, ticket.getDepartment()); - statement.setString(4, ticket.getTicketTitle()); - statement.setString(5, ticket.getTicketDescription()); - statement.setString(6, ticket.getServiceLevelAgreement()); - statement.setString(7, "active"); - - // execute the INSERT statement + statement.setString(2, ticket.getEmail()); + statement.setString(3, ticket.getContactNumber()); + statement.setString(4, ticket.getDepartment()); + statement.setString(5, ticket.getTicketTitle()); + statement.setString(6, ticket.getTicketDescription()); + statement.setString(7, ticket.getServiceLevelAgreement()); + statement.setString(8, "Open"); + statement.setString(9, ticket.getCreationDate()); + statement.setString(10, ticket.getLoggedTime()); + + statement.executeUpdate(); // get the ticketId generated by the database and assign it to this ticket - // object ResultSet generatedKeys = statement.getGeneratedKeys(); if (generatedKeys.next()) { - ticket.setId(generatedKeys.getInt(1)); // Assuming the ID is of type long + ticket.setId(generatedKeys.getInt(1)); System.out.println("Generated Ticket ID: " + ticket.getId()); } else { System.out.println("Failed to retrieve generated Ticket ID."); @@ -64,6 +65,95 @@ public class TicketDBManager { } + public void moveTicketToDepartment(int ticketID, Ticket ticket) { + // move the ticket from Email_Tickets to the appropriate department table + String sourceTableName = "Email_Tickets"; + String destinationTableName; + + if (ticket.getAssignedDepartment().equals("Development")) { + destinationTableName = "Development_Tickets"; + } else if (ticket.getAssignedDepartment().equals("IT")) { + destinationTableName = "IT_Tickets"; + } else { + System.err.println("Invalid department: " + ticket.getAssignedDepartment()); + return; + } + + String selectSql = "SELECT * FROM " + sourceTableName + " WHERE ticketID = ?"; + String insertSql = "INSERT INTO " + destinationTableName + + " (name, email, contactNumber, department, ticketTitle, ticketDescription, serviceLevelAgreement, status, creationDate, loggedTime) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + String deleteSql = "DELETE FROM " + sourceTableName + " WHERE ticketID = ?"; + + try (Connection connection = SQLiteConnection.connect(); + PreparedStatement selectStatement = connection.prepareStatement(selectSql); + PreparedStatement insertStatement = connection.prepareStatement(insertSql); + PreparedStatement deleteStatement = connection.prepareStatement(deleteSql)) { + + // select ticket from Email_Tickets + selectStatement.setInt(1, ticketID); + ResultSet resultSet = selectStatement.executeQuery(); + + // if ticket found in Email_Tickets, move it to the department table + if (resultSet.next()) { + insertStatement.setString(1, resultSet.getString("name")); + insertStatement.setString(2, resultSet.getString("email")); + insertStatement.setString(3, resultSet.getString("contactNumber")); + insertStatement.setString(4, resultSet.getString("department")); + insertStatement.setString(5, resultSet.getString("ticketTitle")); + insertStatement.setString(6, resultSet.getString("ticketDescription")); + insertStatement.setString(7, resultSet.getString("serviceLevelAgreement")); + insertStatement.setString(8, resultSet.getString("status")); + insertStatement.setString(9, resultSet.getString("creationDate")); + insertStatement.setString(10, resultSet.getString("loggedTime")); + + insertStatement.executeUpdate(); + + // delete the ticket from Email_Tickets + deleteStatement.setInt(1, ticketID); + deleteStatement.executeUpdate(); + + // update the ticket ID in the Ticket object + ticket.setId(getLastInsertedID(connection)); + + System.out.println( + "Ticket moved from Email_Tickets to " + destinationTableName + " with ID: " + ticket.getId()); + } else { + System.err.println("Ticket not found in Email_Tickets."); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + + private int getLastInsertedID(Connection connection) throws SQLException { + String sql = "SELECT last_insert_rowid()"; + try (Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery(sql)) { + return resultSet.getInt(1); + } + } + + public boolean ticketExistsInEmailTickets(int ticketID) { + String selectSql = "SELECT COUNT(*) AS count FROM Email_Tickets WHERE ticketID = ?"; + try (Connection connection = SQLiteConnection.connect(); + PreparedStatement selectStatement = connection.prepareStatement(selectSql)) { + // set the parameter of the SELECT statement + selectStatement.setInt(1, ticketID); + + // execute the SELECT statement + try (ResultSet resultSet = selectStatement.executeQuery()) { + // if a result is found, return true + if (resultSet.next()) { + return resultSet.getInt("count") > 0; + } + } + } catch (SQLException e) { + e.printStackTrace(); + } + return false; + } + public void updateTicket(int ticketID, Ticket ticket) { // update the ticket in the database relative to the ticketID // with the variables from this passed in ticket object @@ -79,29 +169,30 @@ public class TicketDBManager { return; } - // generate the new ticket description - String newTicketDescription = getGeneratedDescription(ticketID, ticket); - // SQL query to update the ticket - String updateSql = "UPDATE "+ tableName + " SET name = ?, contactNumber = ?, department = ?, ticketTitle = ?, " + + String updateSql = "UPDATE " + tableName + + " SET name = ?, email = ?, contactNumber = ?, department = ?, ticketTitle = ?, " + "ticketDescription = ?, serviceLevelAgreement = ?, status = ?, assignedEmployee = ?, " + - "satisfactionLevel = ?, comments = ? WHERE ticketID = ?"; + "satisfactionLevel = ?, comments = ?, creationDate = ?, loggedTime = ? WHERE ticketID = ?"; try (Connection connection = SQLiteConnection.connect(); PreparedStatement updateStatement = connection.prepareStatement(updateSql)) { // set the parameters of the UPDATE statement updateStatement.setString(1, ticket.getName()); - updateStatement.setString(2, ticket.getContactNumber()); - updateStatement.setString(3, ticket.getDepartment()); - updateStatement.setString(4, ticket.getTicketTitle()); - updateStatement.setString(5, newTicketDescription); - updateStatement.setString(6, ticket.getServiceLevelAgreement()); - updateStatement.setString(7, ticket.getStatus()); - updateStatement.setString(8, ticket.getAssignedEmployee()); - updateStatement.setString(9, ticket.getSatisfactionLevel()); - updateStatement.setString(10, ticket.getComments()); - updateStatement.setInt(11, ticketID); + updateStatement.setString(2, ticket.getEmail()); + updateStatement.setString(3, ticket.getContactNumber()); + updateStatement.setString(4, ticket.getDepartment()); + updateStatement.setString(5, ticket.getTicketTitle()); + updateStatement.setString(6, ticket.getTicketDescription()); + updateStatement.setString(7, ticket.getServiceLevelAgreement()); + updateStatement.setString(8, ticket.getStatus()); + updateStatement.setString(9, ticket.getAssignedEmployee()); + updateStatement.setString(10, ticket.getSatisfactionLevel()); + updateStatement.setString(11, ticket.getComments()); + updateStatement.setString(12, ticket.getCreationDate()); + updateStatement.setString(13, ticket.getLoggedTime()); + updateStatement.setInt(14, ticketID); // execute the UPDATE statement updateStatement.executeUpdate(); diff --git a/DISPticketing/src/main/resources/application.yaml b/DISPticketing/src/main/resources/application.yaml index dad1a01..f868374 100644 --- a/DISPticketing/src/main/resources/application.yaml +++ b/DISPticketing/src/main/resources/application.yaml @@ -1,3 +1,14 @@ +spring.h2.console.enabled: true +spring.mail: + host: smtp.gmail.com + port: 587 + username: joewilko17@gmail.com + password: hqwkhcbqztnlcfhd + protocol: smtp + properties.mail.smtp: + auth: true + starttls.enable: true + zeebe: client: cloud: diff --git a/DISPticketing/target/classes/application.yaml b/DISPticketing/target/classes/application.yaml index dad1a01..f868374 100644 --- a/DISPticketing/target/classes/application.yaml +++ b/DISPticketing/target/classes/application.yaml @@ -1,3 +1,14 @@ +spring.h2.console.enabled: true +spring.mail: + host: smtp.gmail.com + port: 587 + username: joewilko17@gmail.com + password: hqwkhcbqztnlcfhd + protocol: smtp + properties.mail.smtp: + auth: true + starttls.enable: true + zeebe: client: cloud: diff --git a/DISPticketing/target/classes/com/disp/Worker.class b/DISPticketing/target/classes/com/disp/Worker.class index 6e6dfa5505de7a2f8b317bd66a6739f246ec1226..87b32ade780bd1d38714b12ae2713342270dcb8a 100644 GIT binary patch literal 12335 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 delta 4712 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 NPR16-HpUJHNdTt>@7w?Y diff --git a/DISPticketing/target/classes/com/disp/email/EmailRequest.class b/DISPticketing/target/classes/com/disp/email/EmailRequest.class index dd5c80e9240d78e6ecfcc0943fc8b8c56c1c4241..d5b9de1929ed23e70c86f9df668195e4adba6197 100644 GIT binary patch literal 2431 zcmX^0Z`VEs1_nn4TXqH}Mh5BR{9OH%%;Ez5)ZE0(9DP?18I)RBnp#}K&cMRRAdr<< zmZ+bTn3t~apOlrFT*An}R-Brbl3K*bAmoFP3@$0k%uBasWZ+BA&nrnxE^$dMNzBYC zW@O+>Ni9e$D#=aFD`8|1Elw>e%S=x7Ni9pwaZE2tO@)XHB^DQFrst)mxF9KJFD`{z z$&!?xQpw1`3U(wT1Dj1|US^3MBg143OeYMih-Mfg1B-KhN-7rvGlLKh10RDhBLlOB zW*8>}BZDXp11kd?h$YU$zz$(a@-T2fSkgQUoDh~Q4+9s3CC|ga4PhzrFz`TF$~+9b z3~Y=H{63j^seYxoNvTC4iAg!Bpa{uNPRt2QEXoA&p@J+W8JWe546;6WqS~5~LBKb) zBqKj1Ah9ShH?<_SsF;y~Gd;B=7#i0i8k(2^%gDf4j8GzqB{D$4A()<8;*6Fk1dB1n zc+*o$kfWcs7?m#pb`I9$BLQ{>Rw>c+)DlN5iA%H?yEqrf7FfFD0+|cru&1Y%IDyk4 zdohf~k)B!t&NGY*9K~=ZS8#r5QF5wVCMZ$_!Sc{Nr3cC}42lel49pA+3>*whpaj9d zz`z7b4q%#tfelP^LTN52%?+h_pfoR-7Gz*#;A7xtU}6wpU|_hwz{J4Gz`$UnwVgpw zOM5GWh?dS)1~Dz&tqc-ck}O*pq_iYiw=&3RNwRHakkgW6-^!q%CCRasL1`n{P89|Q z1}z3I1_lOx1{MZE22KVcPy%KUW)NYJWDsSLXAomhWe{i3W{_YoWRPS~Wnf^4f!N5P z#-Pps0!CmTF@jtH_7fAB1@aZh$3~ze&cFf|1Nn><%mVoh<ZB~P5@%osi-G*d!Jxsw zz@W&%08$1L=3rm|TL*F?Hv<C$4+8@OF9QPuBZDS`76T(V5cC-s89>&vYHeW<*#P$! z8(2^V>}DP?n-%J2Mh0yL9cT#JF)%TJT+9XzJw&K*fkovRSQ!++CWwLgY)}&z7}%h` z2Dz7&5$s+@23@Rf5<_>B64*p^H|b$_lNh?2R2e}20L28Ro7fpZzJ|I96n=~h`dHm0 zf$k;^tZp*E?j{LzH)%7lGU$L!z;qKRB`|{Hm6eeJ6rYR?hFIMsh3+Oju!-p5WQ5&K zQs{0nWME}50-J#8CQx33y9tzm7#WPQx=9AzO(tLy(cNT%-Ayv+ZZc<JWv~F7faxYs z?tr@ql-?N`OtHF24&6;wU=z{ZWQN^Ma_DZdWng8n1Dk;9CQv?wy9t#47#Ym5x=8`u zO%7la(cNT$-AxMUZgOT|WpDwTfaxYsc?fqCs61d~u*B*nC3H8rflWkrlNEM1A(fDj cvcQvpmB9;a0;ZclWf$B{kn+hIToBm+0D$^hlK=n! literal 2193 zcmX^0Z`VEs1_nn43w8!3Mh5BR{9OH%%;Ez5)ZE0(9DP?18I)RBnp#}K&cMRRAdr<< zmZ+bTn3t~apOlrFT*An}R-Brbl3K*bAmoFP3@$0k%uBasWZ+BA&nrnxE^$dMNzBYC zW@O+>Ni9e$D#=aFD`8|1Elw>e%S=x7Ni9pwaZE2tO@)XHB^DQFrst)mxF9KJFD`{z z$&!?xQpw1`W|NthSz^b?(5QiFH9bW%!x$M@obyvsxfqxk1bG;E8H5-am^C!RI2jlj zM0glj8Q4H9F&+kX2up&8fdj&l;$h%~uw-}`xF9S!9tLg*OM!=hhk=cef!`-HFV(L! zHz~C!Brz!`6%^R{$%#2(iA9+pK2(sUBqOt!kwMl6Pc&LHG6?vlmSp6o1SA$E=BAdU z78NrxaHgl01ViIdL_-rZ@E935ixEmhu>?3M5CqdxOPtXnT(B5Zj5j^C1UYJXi&6O! zVCP^>8WLb<V3iV0Pc3o8l5j+ev5RwoY=NaIE|9q}4tsiPi4!=Du@}QwT*3LJMaijd znV{eoM9vv{pmfim$iT?J%)r3F&cFnUa0UhjCQx*PX$}T9FwF_2xu7&Rl;#1`{0xi? zybOE{Obq-C3=Df1m>4)17#MW4wlfH5X>Vl^*3#L^AgZOil|fufl4UD{q?RP>Rt9M; zNw%#FvRabtTN&gxf^AV`U|>*V;ACK6;AdcA5M<zF5MtnC5M~f&5MhvH5M_{O5Mxkf z5NFV4kYG?^U|<M>*u$XApuzwGI$-xRg6szSfC<b3`2plV9Z-U0U;&GP{J{!lfqVk; zqYfy+GO#nKGB7a6vNM1r*%=tX7JwYY#lXP8&A`CG!@$76$e_lc&cF!vtUd!H1IR*F ztt||~8{ocR0}D!nUC9GxvqD|T$e_WX2@NSb1||lO8`;32ga`vJu&5jZD}y}P1Tiq5 z4Qc`d0~^$zAh)tIg5Ao<poP^<qUdf?1e=KNCT;9)5=D2D3Ii*HD%b=}H?cE-d<}II zDC`&+bg;Tf9NkUoU=z{Zq>J56;^=PDVqj&^2AhECCQ#fng5#8x5geC{40>4IB#G`O zU9gGhZqmo@CP{QR88EOi7=lf}bQ35q!QBK(TZ{|_SluLz?j~cfiRf-J#O@|(bT^qX zurio~O~7;$C_lj61WN0S3`SVpB#Z7QOR$OPZZgL1CRubh*)Xs&*n&;KbQ36N!rcVQ ydyEVwSluL#?k0P%iRf-J#qK7gvImmyoETUcoWUkwx(QU?!QBKY3(UZo-W&i{?mx!> diff --git a/ticketStorage.db b/ticketStorage.db index 38fb517547ee9a5f2a3eb3134148cea977a85644..f6f789d9a9c29989ccf4f869f479ed3ea0d5ac2e 100644 GIT binary patch literal 24576 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 delta 2503 zcmZoTz}T>Wae}m9DFXuoD+2<sPt-9MEoIOPPT=KR%fQ0<hk-Ae=M#4x=bz1j3LTtW zP5G?s;_B**t+JB^IOHea<m8`h$05MTJ9z_}r~oe)r&3;GZmJSzh-*ZM4)5d!4skJ% zU`lF1Vo^zMYF-Ik%8*}_k$3U|4rxZ-$%*{(LLg<uC5a`a#c(ADd8HV6C*S6k76C~n z=jVb9KuF(ZSLfyB(rjjAVHY<xW^C1*ypB_Qayd8u<QJS`1L>lsG-h^jMMcI|@yQo> zBpF#Izv2P;azH|ek#}<>-vUNMRyJ@P^MazAXDS1K4c~9RTAnXFQ<=@N!_8U(uh`U5 zhys%fV&v-+lS?woQu#UAn;6_xrTs%~B^ekPitzyp19J-l3v)1X%gjs6OHRe79KRel zlJsQ9D7kumPPPXOwyJ{WP4cdi`V0(7H~_LMJc4j2f(t8XD<tCr3fc;Y;0lE@6|@yH z%Tg8c^2-&HGZORCQ&SX5GBS%5Qc{bP6_Sz_%2O5cQd3hDa`TH)6*BYE@)fid5;GJs z6^c_+6-v?MiY7mdQj&)|2FBp$WWCAYt}5u+m~Sg-KUqLttUeJ2kiF*_0uv>ZR?t>} z*@=%<&{oGCN+_WRjwzgu;pb$z!Jw-u?cXTv42r_y;*|8_l=PHhC_?rdGy&l>3nqc- zZc{WNd{K;W{N%Y}()GzX`NgRziNz^tiN$HfiBPhbpOb}~L0?tSwK3gR(wKpvI3uYz zB_ksv1DYmMkR9$B0uv>H)=mR~$!Q+alOKq2F=|gv^iTk?CObw+ut8ik`J$L`5<e%i z5`(;|pkbn`q#^@@M`}(^enx6eKC%Nmf-=(6ic>OD(lb)hGEzW9Mn+l+gq2bZ;-`U# zlr-&>VrcloBcd3TB4dlwU=hR5$uxyQTvgGx(wRY+fx$5+Gdb1Lz{1kP(h@{i_!p!W zC6;97=M|?EXQibSXXhZuob0qLkVslqc5y5#4@0Q1u&6tO<m5&>^~v?Jy1dP7EW8Yn z!ot=qxeSt<zuVL>a@R2PFoc?$^E-o;6?4}!f%$?EZGn?R>{WRh85zNXP_qI}OHzwV zN{V^8Y*I4I6jCyaY?X3Kij?e1if!~$GRy3ExgbRusH|k>Kf=KOf&V)Hk<Ee%v-u}Z zkWLb0VOD2!%}vbAi4Vz4&Q2{UW)){<HfD55ElbVGF96k1FbQTpCT2xO&kz`&pO^0n z13!l>16Mh}KZh(|EuS*)8Qx@GPM-BV4%}<F9XPLW`f{w>EU56Eowtz>>^BDfNLxwK z$^U#?d1Ux`7)(_Kb!%NEMJMY;OyX^1;p1V@R25VWw3XDId?BKWtx<uOhe3aGw&Yx% zMmI)YP$D#Mv~-+YAZanV+P{@Gi-(6neKMa^2A?1|4}+n+pklPWys)O|WCKw@SHJu` z-O!@+)VvZM1&_@1426KA%>1IvlFH=#+=86clGK!v{M@kAqDqC}#FEV7w9M2LP*CP_ z@i0iL3Q8;5%1dfWPyXm*JGtGLUlCPdNNRCOW?p&(CqnJy_dfO@l{^s~SOnAAA%ga{ z@{*I^`>0P|;lmF~-C!M|Y!FFBTS<_lH%|mBOaQDJVs0o4Oc1QfUILOaA~ORs^U@g@ z7^)$zhDh3>Nvc34r5P9^^YhXJGfhm)O-;<r42_LVjXi=wQXBP{ctO!&+sN)JDLYv} z-e&SSzjQuus^Lpz;P2#T<4fHvs1VM_+bGA(!(gZ?Xqas)X*@YcZVFE$0~0tdZEam8 xCr|XVo$Mpe$&XZnftaA2#aGJ61CB&vS5S32d7-52<TnwLlQ&2TPTn7>1OS$!>y7{b -- GitLab