diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index dfe0770..0000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Auto detect text files and perform LF normalization -* text=auto diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/Spring-Framework.iml b/.idea/Spring-Framework.iml new file mode 100644 index 0000000..5d5d390 --- /dev/null +++ b/.idea/Spring-Framework.iml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/artifacts/08_Spring_Web_MVC_Web_exploded.xml b/.idea/artifacts/08_Spring_Web_MVC_Web_exploded.xml deleted file mode 100644 index 328b16c..0000000 --- a/.idea/artifacts/08_Spring_Web_MVC_Web_exploded.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - $PROJECT_DIR$/out/artifacts/08_Spring_Web_MVC_Web_exploded - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/artifacts/09_RestControllers_Web_exploded.xml b/.idea/artifacts/09_RestControllers_Web_exploded.xml deleted file mode 100644 index c7bf76a..0000000 --- a/.idea/artifacts/09_RestControllers_Web_exploded.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - $PROJECT_DIR$/out/artifacts/09_RestControllers_Web_exploded - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/artifacts/10_BackEnd_Web_exploded.xml b/.idea/artifacts/10_BackEnd_Web_exploded.xml deleted file mode 100644 index 0b1343a..0000000 --- a/.idea/artifacts/10_BackEnd_Web_exploded.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - $PROJECT_DIR$/out/artifacts/10_BackEnd_Web_exploded - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/artifacts/12_Spring_Data_JPA_Web_exploded.xml b/.idea/artifacts/12_Spring_Data_JPA_Web_exploded.xml deleted file mode 100644 index 6b8cfa5..0000000 --- a/.idea/artifacts/12_Spring_Data_JPA_Web_exploded.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - $PROJECT_DIR$/out/artifacts/12_Spring_Data_JPA_Web_exploded - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 13f3e99..757c0ec 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -2,33 +2,42 @@ + + - + - - - + + - + + + + + + - - - + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml index 36f1451..2fa46a7 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -3,8 +3,6 @@ - - @@ -13,14 +11,17 @@ - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/.idea/material_theme_project_new.xml b/.idea/material_theme_project_new.xml new file mode 100644 index 0000000..e99ec0d --- /dev/null +++ b/.idea/material_theme_project_new.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 04fe76a..8018085 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -20,6 +20,13 @@ - + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index bb92f4d..1200b38 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,8 +2,8 @@ - - + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..439e169 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,215 @@ + + + + + + + + + + + + + { + "lastFilter": { + "state": "OPEN", + "assignee": "ChamathDilshanC" + } +} + { + "selectedUrlAndAccountId": { + "url": "https://github.com/ChamathDilshanC/Spring-Framework.git", + "accountId": "c78509a1-72d5-470a-8e06-93ca28f027ab" + } +} + { + "customColor": "", + "associatedIndex": 0 +} + + + + + + + { + "keyToString": { + "ASKED_ADD_EXTERNAL_FILES": "true", + "DefaultHtmlFileTemplate": "HTML File", + "JavaScript Debug.customer.html.executor": "Run", + "JavaScript Debug.dashboard.html.executor": "Run", + "JavaScript Debug.index.html.executor": "Run", + "JavaScript Debug.login.html.executor": "Run", + "JavaScript Debug.register.html.executor": "Run", + "Node.js.login.js.executor": "Run", + "Node.js.register.js.executor": "Run", + "RequestMappingsPanelOrder0": "0", + "RequestMappingsPanelOrder1": "1", + "RequestMappingsPanelWidth0": "75", + "RequestMappingsPanelWidth1": "75", + "RunOnceActivity.ShowReadmeOnStart": "true", + "SHARE_PROJECT_CONFIGURATION_FILES": "true", + "Spring Boot.Application.executor": "Run", + "Spring Boot.SpringSecurityApplicationWork.executor": "Run", + "Spring Boot.SpringwithjwtApplication.executor": "Run", + "Spring Boot.Z15SpringSequrityApplication.executor": "Run", + "Spring Boot.Z17SpringbootBeanValidationApplication.executor": "Run", + "Spring Boot.Z18SpringbootLoginsApplication.executor": "Run", + "deletionFromPopupRequiresConfirmation": "false", + "git-widget-placeholder": "main", + "jdk.selected.JAVA_MODULE": "21", + "js.last.introduce.type": "CONST", + "kotlin-language-version-configured": "true", + "last_opened_file_path": "C:/Users/dilsh/Desktop/Spring-Framework/Z16_Frontend/src/main/java/lk/ijse/JQuery", + "list.type.of.created.stylesheet": "CSS", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "nodejs_package_manager_path": "npm", + "project.structure.last.edited": "Modules", + "project.structure.proportion": "0.21679688", + "project.structure.side.proportion": "0.39649844", + "run.configurations.included.in.services": "true", + "settings.editor.selected.configurable": "preferences.pluginManager", + "vue.rearranger.settings.migration": "true" + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1740668802399 + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+ + +
+ + + + + + + +
+

Are you sure you want to delete this item? This action cannot be undone.

+
+ + +
+
+ + + + + +
+
+

Item List

+
+
+
+
+ + +
+
+ Total: 0 items +
+
+ +
+ + + + + + + + + + + + + +
IDNamePriceQtyActions
+
+
+ +
+

No items found

+
+
+
+
+ + + + +
+ + + + + \ No newline at end of file diff --git a/14_Springboot_Frontend/src/main/java/lk/ijse/componnent/components.js b/14_Springboot_Frontend/src/main/java/lk/ijse/componnent/components.js new file mode 100644 index 0000000..5dd04ba --- /dev/null +++ b/14_Springboot_Frontend/src/main/java/lk/ijse/componnent/components.js @@ -0,0 +1,100 @@ +// Define your navigation component HTML +const navComponent = ` + + +`; + +// Function to load components +function loadComponents() { + // Insert navigation + const navPlaceholder = document.getElementById('nav-placeholder'); + if (navPlaceholder) { + navPlaceholder.innerHTML = navComponent; + } + + // Set active link based on current page + const currentPage = window.location.pathname.split('/').pop(); + const navLinks = document.querySelectorAll('.navbar-nav .nav-link'); + + navLinks.forEach(link => { + const href = link.getAttribute('href'); + if (href === currentPage) { + link.classList.add('active'); + } else { + link.classList.remove('active'); + } + }); +} + +// Load components when DOM is ready +document.addEventListener('DOMContentLoaded', loadComponents); \ No newline at end of file diff --git a/14_Springboot_Frontend/src/main/java/lk/ijse/css/customer.css b/14_Springboot_Frontend/src/main/java/lk/ijse/css/customer.css new file mode 100644 index 0000000..41e9407 --- /dev/null +++ b/14_Springboot_Frontend/src/main/java/lk/ijse/css/customer.css @@ -0,0 +1,324 @@ +:root { + --primary: #2563eb; + --primary-dark: #1d4ed8; + --danger: #ef4444; + --success: #10b981; + --dark: #1e293b; + --light: #f8fafc; + --gray: #e2e8f0; + --text: #334155; + --border: #cbd5e1; + --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); + --radius: 8px; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; + background-color: #f1f5f9; + color: var(--text); + line-height: 1.5; + padding: 2rem; +} + +.container { + max-width: 1200px; + margin: 0 auto; +} + +header { + margin-bottom: 2rem; +} + +h1 { + color: var(--dark); + font-size: 1.875rem; + margin-bottom: 0.5rem; +} + +.content-wrapper { + display: grid; + grid-template-columns: 350px 1fr; + gap: 1.5rem; +} + +@media (max-width: 992px) { + .content-wrapper { + grid-template-columns: 1fr; + } +} + +.card { + background-color: white; + border-radius: var(--radius); + box-shadow: var(--shadow); + overflow: hidden; +} + +.card-header { + padding: 1rem; + border-bottom: 1px solid var(--gray); +} + +.card-title { + font-size: 1.25rem; + font-weight: 600; + color: var(--dark); +} + +.card-body { + padding: 1.5rem; +} + +/* Form */ +.form-group { + margin-bottom: 1.25rem; +} + +label { + display: block; + margin-bottom: 0.5rem; + font-weight: 500; + color: var(--dark); + font-size: 0.875rem; +} + +.form-control { + width: 100%; + padding: 0.625rem 0.875rem; + border: 1px solid var(--border); + border-radius: var(--radius); + font-size: 0.875rem; +} + +.form-control:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1); +} + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.625rem 1rem; + background-color: var(--primary); + color: white; + border: none; + border-radius: var(--radius); + font-weight: 500; + font-size: 0.875rem; + cursor: pointer; + transition: background-color 0.2s, transform 0.1s; +} + +.btn:hover { + background-color: var(--primary-dark); +} + +.btn:active { + transform: translateY(1px); +} + +.btn i { + margin-right: 0.5rem; +} + +.btn-block { + width: 100%; +} + +.btn-danger { + background-color: var(--danger); +} + +.btn-sm { + padding: 0.375rem 0.75rem; + font-size: 0.75rem; +} + +.btn-icon { + width: 2rem; + height: 2rem; + padding: 0; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.btn-icon i { + margin-right: 0; +} + +/* Table */ +.table-controls { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; +} + +.search-container { + position: relative; + width: 250px; +} + +.search-input { + width: 100%; + padding: 0.5rem 1rem 0.5rem 2.25rem; + border: 1px solid var(--border); + border-radius: var(--radius); + font-size: 0.875rem; +} + +.search-icon { + position: absolute; + left: 0.75rem; + top: 50%; + transform: translateY(-50%); + color: #94a3b8; +} + +table { + width: 100%; + border-collapse: collapse; +} + +th, td { + text-align: left; + padding: 0.75rem 1rem; + border-bottom: 1px solid var(--gray); + font-size: 0.875rem; +} + +th { + font-weight: 600; + color: var(--dark); + background-color: #f8fafc; +} + +tr:last-child td { + border-bottom: none; +} + +tr:hover { + background-color: #f8fafc; +} + +.action-cell { + width: 120px; + white-space: nowrap; +} + +.empty-table { + padding: 3rem 1rem; + text-align: center; + color: #64748b; +} + +.empty-icon { + font-size: 2.5rem; + color: #94a3b8; + margin-bottom: 1rem; +} + +/* Toast Notification */ +.toast-container { + position: fixed; + bottom: 1.5rem; + right: 1.5rem; + z-index: 1010; +} + +.toast { + display: flex; + align-items: center; + padding: 0.75rem 1rem; + background-color: white; + border-radius: var(--radius); + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); + margin-top: 0.75rem; + transform: translateX(150%); + transition: transform 0.3s; + max-width: 350px; +} + +.toast.show { + transform: translateX(0); +} + +.toast.success .toast-icon { + background-color: #dcfce7; + color: #166534; +} + +.toast.error .toast-icon { + background-color: #fee2e2; + color: #991b1b; +} + +.toast-icon { + width: 2rem; + height: 2rem; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + margin-right: 0.75rem; + flex-shrink: 0; +} + +.toast-content { + flex-grow: 1; +} + +.toast-title { + font-weight: 600; + font-size: 0.875rem; + margin-bottom: 0.25rem; +} + +.toast-message { + font-size: 0.8125rem; + color: #64748b; +} + +.toast-close { + background: none; + border: none; + color: #94a3b8; + cursor: pointer; + padding: 0.5rem; + margin: -0.5rem; + flex-shrink: 0; +} + +/* Confirmations */ +.confirm-delete { + display: none; + background-color: #fee2e2; + border: 1px solid #fecaca; + border-radius: var(--radius); + padding: 0.75rem; + margin-top: 0.5rem; +} + +.confirm-delete.show { + display: block; +} + +.confirm-message { + color: #991b1b; + font-size: 0.875rem; + margin-bottom: 0.75rem; +} + +.confirm-actions { + display: flex; + gap: 0.5rem; +} diff --git a/14_Springboot_Frontend/src/main/java/lk/ijse/css/dashboard.css b/14_Springboot_Frontend/src/main/java/lk/ijse/css/dashboard.css new file mode 100644 index 0000000..f539a26 --- /dev/null +++ b/14_Springboot_Frontend/src/main/java/lk/ijse/css/dashboard.css @@ -0,0 +1,180 @@ +:root { + --primary: #4361ee; + --dark: #2b2d42; + --light: #f8f9fa; + --gray: #e9ecef; + --shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + --transition: all 0.3s ease; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; + background-color: var(--gray); + color: var(--dark); + padding: 2rem; + line-height: 1.5; +} + +.container { + max-width: 1200px; + margin: 0 auto; +} + +header { + text-align: center; + margin-bottom: 3rem; +} + +h1 { + font-size: 2.5rem; + margin-bottom: 0.5rem; + color: var(--dark); +} + +.subtitle { + font-size: 1.1rem; + color: #6c757d; + margin-bottom: 1rem; +} + +.cards-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 2rem; +} + +.card { + background-color: white; + border-radius: 12px; + box-shadow: var(--shadow); + overflow: hidden; + transition: var(--transition); + cursor: pointer; + text-decoration: none; + color: inherit; + height: 100%; + display: flex; + flex-direction: column; +} + +.card:hover { + transform: translateY(-5px); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); +} + +.card:active { + transform: translateY(-2px); +} + +.card-icon { + background-color: var(--primary); + color: white; + height: 120px; + display: flex; + align-items: center; + justify-content: center; +} + +.card-icon i { + font-size: 3rem; +} + +.card-content { + padding: 1.5rem; + flex: 1; +} + +.card-title { + font-size: 1.4rem; + font-weight: 600; + margin-bottom: 0.5rem; +} + +.card-description { + color: #6c757d; + font-size: 0.95rem; +} + +.card-footer { + display: flex; + align-items: center; + padding: 1rem 1.5rem; + background-color: #f8f9fa; + border-top: 1px solid #e9ecef; +} + +.card-footer span { + color: #6c757d; + font-size: 0.9rem; +} + +.card-footer i { + margin-left: auto; + color: var(--primary); +} + +@media (max-width: 768px) { + body { + padding: 1rem; + } + + .cards-grid { + grid-template-columns: 1fr; + gap: 1.5rem; + } + + h1 { + font-size: 2rem; + } +} + +/* Page Content Styling */ +.page { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: white; + z-index: 100; + overflow-y: auto; + padding: 2rem; +} + +.page.active { + display: block; +} + +.page-header { + display: flex; + align-items: center; + margin-bottom: 2rem; +} + +.back-button { + background: none; + border: none; + color: var(--primary); + font-size: 1.2rem; + cursor: pointer; + display: flex; + align-items: center; + margin-right: 1rem; +} + +.page-title { + font-size: 1.8rem; + font-weight: 600; +} + +.page-content { + max-width: 1000px; + margin: 0 auto; +} diff --git a/14_Springboot_Frontend/src/main/java/lk/ijse/css/item.css b/14_Springboot_Frontend/src/main/java/lk/ijse/css/item.css new file mode 100644 index 0000000..df3be6f --- /dev/null +++ b/14_Springboot_Frontend/src/main/java/lk/ijse/css/item.css @@ -0,0 +1,258 @@ +:root { + --primary: #2563eb; + --primary-dark: #1d4ed8; + --danger: #ef4444; + --success: #10b981; + --dark: #1e293b; + --light: #f8fafc; + --gray: #e2e8f0; + --text: #334155; + --border: #cbd5e1; + --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); + --radius: 8px; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; + background-color: #f1f5f9; + color: var(--text); + line-height: 1.5; + padding: 2rem; +} + +.container { + max-width: 1200px; + margin: 0 auto; +} + +header { + margin-bottom: 2rem; +} + +h1 { + color: var(--dark); + font-size: 1.875rem; + margin-bottom: 0.5rem; +} + +.content-wrapper { + display: grid; + grid-template-columns: 350px 1fr; + gap: 1.5rem; +} + +@media (max-width: 992px) { + .content-wrapper { + grid-template-columns: 1fr; + } +} + +.card { + background-color: white; + border-radius: var(--radius); + box-shadow: var(--shadow); + overflow: hidden; +} + +.card-header { + padding: 1rem; + border-bottom: 1px solid var(--gray); +} + +.card-title { + font-size: 1.25rem; + font-weight: 600; + color: var(--dark); +} + +.card-body { + padding: 1.5rem; +} + +/* Form */ +.form-group { + margin-bottom: 1.25rem; +} + +label { + display: block; + margin-bottom: 0.5rem; + font-weight: 500; + color: var(--dark); + font-size: 0.875rem; +} + +.form-control { + width: 100%; + padding: 0.625rem 0.875rem; + border: 1px solid var(--border); + border-radius: var(--radius); + font-size: 0.875rem; +} + +.form-control:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1); +} + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.625rem 1rem; + background-color: var(--primary); + color: white; + border: none; + border-radius: var(--radius); + font-weight: 500; + font-size: 0.875rem; + cursor: pointer; + transition: background-color 0.2s, transform 0.1s; +} + +.btn:hover { + background-color: var(--primary-dark); +} + +.btn:active { + transform: translateY(1px); +} + +.btn i { + margin-right: 0.5rem; +} + +.btn-block { + width: 100%; +} + +.btn-danger { + background-color: var(--danger); +} + +.btn-sm { + padding: 0.375rem 0.75rem; + font-size: 0.75rem; +} + + +.btn-icon i { + margin-right: 0; +} + +/* Table */ +.table-controls { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; +} + +.search-container { + position: relative; + width: 250px; +} + +.search-input { + width: 100%; + padding: 0.5rem 1rem 0.5rem 2.25rem; + border: 1px solid var(--border); + border-radius: var(--radius); + font-size: 0.875rem; +} + +.search-icon { + position: absolute; + left: 0.75rem; + top: 50%; + transform: translateY(-50%); + color: #94a3b8; +} + +table { + width: 100%; + border-collapse: collapse; +} + +th, td { + text-align: left; + padding: 0.75rem 1rem; + border-bottom: 1px solid var(--gray); + font-size: 0.875rem; +} + +th { + font-weight: 600; + color: var(--dark); + background-color: #f8fafc; +} + +tr:last-child td { + border-bottom: none; +} + +tr:hover { + background-color: #f8fafc; +} + +.empty-table { + padding: 3rem 1rem; + text-align: center; + color: #64748b; +} + +.empty-icon { + font-size: 2.5rem; + color: #94a3b8; + margin-bottom: 1rem; +} + +/* Toast Notification */ +.toast-container { + position: fixed; + bottom: 1.5rem; + right: 1.5rem; + z-index: 1010; +} + +.toast.success .toast-icon { + background-color: #dcfce7; + color: #166534; +} + +.toast.error .toast-icon { + background-color: #fee2e2; + color: #991b1b; +} + +/* Confirmations */ +.confirm-delete { + display: none; + background-color: #fee2e2; + border: 1px solid #fecaca; + border-radius: var(--radius); + padding: 0.75rem; + margin-top: 0.5rem; +} + +.confirm-delete.show { + display: block; +} + +.confirm-message { + color: #991b1b; + font-size: 0.875rem; + margin-bottom: 0.75rem; +} + +.confirm-actions { + display: flex; + gap: 0.5rem; +} diff --git a/14_Springboot_Frontend/src/main/java/lk/ijse/css/order.css b/14_Springboot_Frontend/src/main/java/lk/ijse/css/order.css new file mode 100644 index 0000000..7f1f0b8 --- /dev/null +++ b/14_Springboot_Frontend/src/main/java/lk/ijse/css/order.css @@ -0,0 +1,359 @@ +:root { + --primary: #4f46e5; + --primary-light: #6366f1; + --primary-dark: #4338ca; + --secondary: #0ea5e9; + --success: #10b981; + --danger: #ef4444; + --warning: #f59e0b; + --light: #f8fafc; + --dark: #0f172a; +} + +body { + font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; + background-color: #f1f5f9; + color: var(--text); + line-height: 1.5; + padding: 2rem 2rem 0 2rem; +} + + +.app-container { + max-width: 1400px; + margin: 0 auto; +} + +.page-header { + padding: 0 1rem 1rem 1rem; + margin-bottom: 2rem; +} + +.card { + border: none; + border-radius: 1rem; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05); + transition: all 0.3s ease; + overflow: hidden; + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(10px); + margin-bottom: 1.5rem; +} + +.card:hover { + transform: translateY(-5px); + box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1); +} + +.card-header { + background: transparent; + border-bottom: 1px solid rgba(0, 0, 0, 0.05); + padding: 1.5rem; +} + +.card-body { + padding: 1.5rem; +} + +.card-title { + font-weight: 600; + margin-bottom: 1.25rem; + display: flex; + align-items: center; + color: var(--primary); +} + +.card-title i { + margin-right: 0.75rem; + font-size: 1.25rem; +} + +.form-control, .form-select { + border: 2px solid rgba(0, 0, 0, 0.05); + border-radius: 0.75rem; + padding: 0.75rem 1rem; + font-size: 1rem; + transition: all 0.2s ease; + background-color: rgba(255, 255, 255, 0.8); +} + +.form-control:focus, .form-select:focus { + border-color: var(--primary-light); + box-shadow: 0 0 0 0.25rem rgba(99, 102, 241, 0.15); +} + +.form-control-lg, .form-select-lg { + height: 3.5rem; + font-size: 1rem; +} + +.btn { + padding: 0.75rem 1.5rem; + border-radius: 0.75rem; + font-weight: 500; + letter-spacing: 0.3px; + transition: all 0.3s ease; +} + +.btn-primary { + background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%); + border: none; +} + +.btn-primary:hover { + background: linear-gradient(135deg, var(--primary-dark) 0%, var(--primary-dark) 100%); + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(79, 70, 229, 0.3); +} + +.btn-success { + background: linear-gradient(135deg, var(--success) 0%, #059669 100%); + border: none; +} + +.btn-success:hover { + background: linear-gradient(135deg, #059669 0%, #047857 100%); + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(16, 185, 129, 0.3); +} + +.btn-danger { + background: linear-gradient(135deg, var(--danger) 0%, #dc2626 100%); + border: none; +} + +.btn-danger:hover { + background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%); + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(239, 68, 68, 0.3); +} + +.btn-icon { + display: inline-flex; + align-items: center; + justify-content: center; +} + +.btn-icon i { + margin-right: 0.5rem; +} + +.details-panel { + background: rgba(79, 70, 229, 0.03); + border-radius: 0.75rem; + padding: 1.5rem; + border: 1px solid rgba(79, 70, 229, 0.1); + height: 100%; +} + +.details-panel h6 { + color: var(--primary); + font-weight: 600; + margin-bottom: 1.25rem; + padding-bottom: 0.75rem; + border-bottom: 1px solid rgba(79, 70, 229, 0.1); +} + +.details-panel .detail-item { + display: flex; + justify-content: space-between; + margin-bottom: 1rem; + padding-bottom: 1rem; + border-bottom: 1px solid rgba(0, 0, 0, 0.05); +} + +.details-panel .detail-item:last-child { + margin-bottom: 0; + padding-bottom: 0; + border-bottom: none; +} + +.details-panel .detail-label { + color: #64748b; + font-size: 0.925rem; +} + +.details-panel .detail-value { + font-weight: 500; + text-align: right; +} + +.table { + border-radius: 0.75rem; + overflow: hidden; + margin-bottom: 0; +} + +.table th { + font-weight: 600; + color: #1e293b; + background-color: rgba(241, 245, 249, 0.8); + padding: 1rem; +} + +.table td { + padding: 1rem; + vertical-align: middle; +} + +.badge { + padding: 0.5rem 0.75rem; + font-weight: 500; + border-radius: 0.5rem; +} + +.remove-btn { + color: var(--danger); + background: rgba(239, 68, 68, 0.05); + border: none; + border-radius: 0.5rem; + padding: 0.5rem 0.75rem; + transition: all 0.2s ease; + font-size: 0.875rem; +} + +.remove-btn:hover { + background: rgba(239, 68, 68, 0.1); + color: #b91c1c; +} + +.total-section { + background: linear-gradient(135deg, rgba(79, 70, 229, 0.05) 0%, rgba(14, 165, 233, 0.05) 100%); + border-radius: 0.75rem; + padding: 1.5rem; + margin-top: 1.5rem; + border: 1px solid rgba(79, 70, 229, 0.1); +} + +.total-amount { + font-size: 1.5rem; + font-weight: 700; + color: var(--primary-dark); +} + +#toastContainer { + position: fixed; + top: 20px; + right: 20px; + z-index: 1050; +} + +.toast { + background: white; + border-radius: 0.75rem; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); + margin-bottom: 1rem; + padding: 1rem 1.25rem; + display: flex; + align-items: center; + min-width: 300px; + transform: translateX(120%); + transition: transform 0.3s ease; + border-left: 4px solid transparent; +} + +.toast.show { + transform: translateX(0); +} + +.toast.success { + border-left-color: var(--success); +} + +.toast.error { + border-left-color: var(--danger); +} + +.toast-content { + flex-grow: 1; + margin: 0 0.75rem; +} + +.toast-close { + background: none; + border: none; + color: #94a3b8; + cursor: pointer; + transition: color 0.2s ease; + padding: 0.25rem; +} + +.toast-close:hover { + color: #475569; +} + +.order-id-container { + background: rgba(79, 70, 229, 0.05); + border: 1px solid rgba(79, 70, 229, 0.1); + border-radius: 0.75rem; + padding: 1rem 1.5rem; + margin-bottom: 1.5rem; +} + +.order-id-label { + display: block; + font-size: 0.875rem; + font-weight: 500; + color: #64748b; + margin-bottom: 0.5rem; +} + +.order-id-value { + font-size: 1.25rem; + font-weight: 600; + color: var(--primary); + letter-spacing: 0.5px; +} + +@media (max-width: 992px) { + .app-container { + padding: 1rem; + } + + .page-header { + padding: 1.5rem 0; + } + + .order-id-container { + margin-top: 1rem; + } +} + +/* Loading spinner for selects */ +.select-loading::after { + content: ""; + position: absolute; + right: 10px; + top: 50%; + transform: translateY(-50%); + width: 20px; + height: 20px; + border-radius: 50%; + border: 2px solid rgba(79, 70, 229, 0.2); + border-top-color: var(--primary); + animation: spin 0.8s linear infinite; +} + +@keyframes spin { + to { + transform: translateY(-50%) rotate(360deg); + } +} + +/* Empty cart illustration */ +.empty-cart { + text-align: center; + padding: 2rem; + color: #94a3b8; +} + +.empty-cart i { + font-size: 3rem; + margin-bottom: 1rem; + opacity: 0.5; +} + +.empty-cart p { + font-size: 1.125rem; + margin-bottom: 1.5rem; +} \ No newline at end of file diff --git a/14_Springboot_Frontend/src/main/java/lk/ijse/customer.html b/14_Springboot_Frontend/src/main/java/lk/ijse/customer.html new file mode 100644 index 0000000..106d81a --- /dev/null +++ b/14_Springboot_Frontend/src/main/java/lk/ijse/customer.html @@ -0,0 +1,135 @@ + + + + + + Customer Management + + + + + + + + + + +
+
+

Customer Management

+
+ + +
+ +
+
+

Add New Customer

+
+
+
+
+ + +
+
+ + +
+
+ + +
+ + + + + + + + +
+

Are you sure you want to delete this customer? This action cannot be undone.

+
+ + +
+
+
+
+
+ + +
+
+

Customer List

+
+
+
+
+ + +
+
+ +
+ + + + + + + + + + + + +
IDNameAddressActions
+ +
+
+ +
+

No customers found

+
+
+
+
+
+
+ +
+ + + + + + + + \ No newline at end of file diff --git a/14_Springboot_Frontend/src/main/java/lk/ijse/dashboard.html b/14_Springboot_Frontend/src/main/java/lk/ijse/dashboard.html new file mode 100644 index 0000000..d1388f2 --- /dev/null +++ b/14_Springboot_Frontend/src/main/java/lk/ijse/dashboard.html @@ -0,0 +1,146 @@ + + + + + + Dashboard + + + + + + + + + \ No newline at end of file diff --git a/14_Springboot_Frontend/src/main/java/lk/ijse/js/customer.js b/14_Springboot_Frontend/src/main/java/lk/ijse/js/customer.js new file mode 100644 index 0000000..4b67728 --- /dev/null +++ b/14_Springboot_Frontend/src/main/java/lk/ijse/js/customer.js @@ -0,0 +1,284 @@ +$("#saveCustomerBtn").click(function(event) { + event.preventDefault(); + + if (!$("#customerName").val() || !$("#customerAddress").val()) { + showToast('Please fill all the fields', 'error'); + return; + } + + var customerID = $("#customerId").val(); + var customerName = $("#customerName").val(); + var customerAddress = $("#customerAddress").val(); + + var customer = { + "id": customerID, + "name": customerName, + "address": customerAddress + } + + $.ajax({ + method: "POST", + url: "http://localhost:8080/api/v1/customer/save", + contentType: "application/json", + data: JSON.stringify(customer), + success: function(response) { + if (response.code === 201) { + showToast('Customer saved successfully', 'success'); + $("#customerForm")[0].reset(); + loadCustomers(); + generateNextCustomerId(); + } else { + showToast('Failed to save the customer','error'); + } + }, + error: function(xhr, status, error) { + showToast('Error saving customer: ' + error, 'error'); + console.error("AJAX Error: " + status + " - " + error); + } + }); +}); + +$("#updateCustomerBtn").click(function(event) { + event.preventDefault(); + + if (!$("#customerName").val() || !$("#customerAddress").val()) { + showToast('Please fill all the fields', 'error'); + return; + } + + var customerID = $("#customerId").val(); + var customerName = $("#customerName").val(); + var customerAddress = $("#customerAddress").val(); + + var customer = { + "id": customerID, + "name": customerName, + "address": customerAddress + } + $.ajax({ + method: "PUT", + url: "http://localhost:8080/api/v1/customer/update", + contentType: "application/json", + data: JSON.stringify(customer), + success: function(response) { + if (response.code === 201) { + showToast('Customer updated successfully', 'success'); + resetForm(); + loadCustomers(); + } else { + showToast('Failed to update the customer', 'error'); + } + }, + error: function(xhr, status, error) { + showToast('Error updating customer: ' + error, 'error'); + } + }) +}); + +function loadCustomers() { + $.ajax({ + method: "GET", + url: "http://localhost:8080/api/v1/customer/getAll", + success: function(response) { + const customers = response.data; + if (customers && customers.length > 0) { + $("#emptyTable").hide(); + $("#customerTable").show(); + + var tbody = $("#customerTableBody"); + tbody.empty(); + + $.each(customers, function(index, customer) { + var row = $(""); + row.append($("").text(customer.id || "-")); + row.append($("").text(customer.name || "-")); + row.append($("").text(customer.address || "-")); + + var actionsCell = $("").addClass("action-cell"); + + var editBtn = $(" + + `); + + $("#toastContainer").append(toast); + setTimeout(() => toast.addClass('show'), 100); + + toast.find('.toast-close').click(function() { + toast.removeClass('show'); + setTimeout(() => toast.remove(), 300); + }); + + setTimeout(() => { + toast.removeClass('show'); + setTimeout(() => toast.remove(), 300); + }, 3000); +} + +function getNextItemId() { + $.ajax({ + method: "GET", + url: "http://localhost:8080/api/v1/item/generateNextId", + success: function(response) { + if(response.data) { + $("#itemId").val(response.data); + } + }, + error: function(xhr, status, error) { + showToast("Error getting next ID", "error"); + } + }); +} + +function loadItems() { + $.ajax({ + method: "GET", + url: "http://localhost:8080/api/v1/item/getAll", + success: function(response) { + if(response.data) { + $("#itemTableBody").empty(); + response.data.forEach(function(item) { + $("#itemTableBody").append( + ` + ${item.itemCode} + ${item.name} + ${item.price} + ${item.qty} + + + + + ` + ); + }); + updateTotalItems() + $("#emptyTable").hide(); + } + }, + error: function(xhr, status, error) { + showToast("Error loading items", "error"); + } + }); +} + +function updateTotalItems() { + const visibleRows = $("#itemTableBody tr:visible").length; + $("#totalItems").text(`Total: ${visibleRows} items`); +} + +$("#saveItemBtn").click(function(event) { + event.preventDefault(); + + if(!$("#itemName").val() || !$("#itemPrice").val() || !$("#itemQty").val()) { + showToast("Please fill all the fields", "error"); + return; + } + + var item = { + "itemCode": $("#itemId").val(), + "name": $("#itemName").val(), + "price": $("#itemPrice").val(), + "qty": $("#itemQty").val() + } + + $.ajax({ + method: "POST", + url: "http://localhost:8080/api/v1/item/save", + contentType: "application/json", + data: JSON.stringify(item), + success: function(response) { + if(response.code === 201) { + showToast("Item saved successfully", "success"); + $("#itemForm")[0].reset(); + loadItems(); + getNextItemId(); + } else { + showToast("Failed to save item", "error"); + } + }, + error: function(xhr, status, error) { + showToast("Error saving item", "error"); + } + }); +}); + +function editItem(item) { + $("#formTitle").text("Edit Item"); + $("#itemId").val(item.itemCode).prop("disabled", true); + $("#itemName").val(item.name); + $("#itemPrice").val(item.price); + $("#itemQty").val(item.qty); + $("#saveItemBtn").hide(); + $("#updateItemBtn").show(); + + if (window.innerWidth < 992) { + $("#itemForm")[0].scrollIntoView({ behavior: 'smooth' }); + } +} + +function deleteItem(item) { + $("#formTitle").text("Delete Item"); + $("#itemId").val(item.itemCode).prop("disabled", true); + $("#itemName").val(item.name); + $("#itemPrice").val(item.price); + $("#itemQty").val(item.qty); + $("#saveItemBtn").prop("disabled", true); + $("#confirmDelete").addClass("show"); +} + +$("#updateItemBtn").click(function(event) { + event.preventDefault(); + + if(!$("#itemName").val() || !$("#itemPrice").val() || !$("#itemQty").val()) { + showToast("Please fill all the fields", "error"); + return; + } + + var item = { + "itemCode": $("#itemId").val(), + "name": $("#itemName").val(), + "price": $("#itemPrice").val(), + "qty": $("#itemQty").val() + } + + $.ajax({ + method: "PUT", + url: "http://localhost:8080/api/v1/item/update", + contentType: "application/json", + data: JSON.stringify(item), + success: function(response) { + if(response.code === 201) { + showToast("Item updated successfully", "success"); + resetForm(); + loadItems(); + } else { + showToast("Failed to update item", "error"); + } + }, + error: function(xhr, status, error) { + showToast("Error updating item", "error"); + } + }); +}); + +$("#confirmDeleteBtn").click(function() { + var itemCode = $("#itemId").val(); + + $.ajax({ + method: "DELETE", + url: "http://localhost:8080/api/v1/item/delete/" + itemCode, + success: function(response) { + if(response.code === 201) { + showToast("Item deleted successfully", "success"); + resetForm(); + loadItems(); + } else { + showToast("Failed to delete item", "error"); + } + }, + error: function(xhr, status, error) { + showToast("Error deleting item", "error"); + } + }); +}); + +$("#cancelDeleteBtn").click(function() { + resetForm(); +}); + +function resetForm() { + $("#formTitle").text("Add New Item"); + $("#itemForm")[0].reset(); + $("#itemId").prop("disabled", false); + $("#saveItemBtn").show().prop("disabled", false); + $("#updateItemBtn").hide(); + $("#confirmDelete").removeClass("show"); + getNextItemId(); +} \ No newline at end of file diff --git a/14_Springboot_Frontend/src/main/java/lk/ijse/js/jquery-3.7.1.min.js b/14_Springboot_Frontend/src/main/java/lk/ijse/js/jquery-3.7.1.min.js new file mode 100644 index 0000000..7f37b5d --- /dev/null +++ b/14_Springboot_Frontend/src/main/java/lk/ijse/js/jquery-3.7.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0 response.text()) + .then(data => { + // Find where to insert the navigation + const navPlaceholder = document.getElementById('nav-placeholder'); + if (navPlaceholder) { + navPlaceholder.innerHTML = data; + } + }) + .catch(error => console.error('Error loading navigation component:', error)); +}); \ No newline at end of file diff --git a/14_Springboot_Frontend/src/main/java/lk/ijse/js/order.js b/14_Springboot_Frontend/src/main/java/lk/ijse/js/order.js new file mode 100644 index 0000000..3f89dde --- /dev/null +++ b/14_Springboot_Frontend/src/main/java/lk/ijse/js/order.js @@ -0,0 +1,486 @@ +let cartItems = []; + +$(document).ready(function() { + initializeApp(); + + if (!$('#toastContainer').length) { + $('body').append('
'); + } +}); + +function initializeApp() { + generateNextOrderId(); + + loadCustomers(); + loadItems(); + + initializeEventHandlers(); + + updateCartTable(); +} + +function generateNextOrderId() { + $("#orderIdDisplay").html('Generating...'); + + $.ajax({ + method: "GET", + url: "http://localhost:8080/api/v1/order/generateNextId", + success: function (response) { + if (response.code === 201 && response.data) { + $("#orderId").val(response.data); + $("#orderIdDisplay").text(response.data); + console.log("Next order ID:", response.data); + } else { + showError("Failed to generate order ID"); + $("#orderIdDisplay").text("Error"); + console.error("Error response:", response); + } + }, + error: function (xhr, status, error) { + showError("Failed to generate order ID"); + $("#orderIdDisplay").text("Error"); + console.error("Error details:", {xhr, status, error}); + } + }); +} + +function loadCustomers() { + $("#customerDetailsSelect") + .prop('disabled', true) + .html(''); + + $.ajax({ + method: "GET", + url: "http://localhost:8080/api/v1/customer/getAll", + success: function(response) { + if (response.code === 200 && response.data && response.data.length > 0) { + const customers = response.data; + + $("#customerDetailsSelect") + .empty() + .append(''); + + customers.forEach(customer => { + $("#customerDetailsSelect").append( + `` + ); + }); + + window.customersData = customers; + } else { + $("#customerDetailsSelect") + .empty() + .append(''); + + showError("No customers found in the system"); + } + }, + error: function(xhr, status, error) { + $("#customerDetailsSelect") + .empty() + .append(''); + + showError("Failed to load customers. Please check server connection."); + console.error("Error details:", {xhr, status, error}); + }, + complete: function() { + $("#customerDetailsSelect").prop('disabled', false); + } + }); +} + +function loadItems() { + $("#ItemDetailsSelect") + .prop('disabled', true) + .html(''); + + $.ajax({ + method: "GET", + url: "http://localhost:8080/api/v1/item/getAll", + success: function(response) { + if (response.code === 200 && response.data && response.data.length > 0) { + const items = response.data; + + $("#ItemDetailsSelect") + .empty() + .append(''); + + items.forEach(item => { + $("#ItemDetailsSelect").append( + `` + ); + }); + + window.itemsData = items; + } else { + $("#ItemDetailsSelect") + .empty() + .append(''); + + showError("No items found in the system"); + } + }, + error: function(xhr, status, error) { + $("#ItemDetailsSelect") + .empty() + .append(''); + + showError("Failed to load items. Please check server connection."); + console.error("Error details:", {xhr, status, error}); + }, + complete: function() { + $("#ItemDetailsSelect").prop('disabled', false); + } + }); +} + +function initializeEventHandlers() { + $("#customerDetailsSelect").on('change', function() { + const selectedId = $(this).val(); + + if (!selectedId) { + clearCustomerDetails(); + return; + } + + const selectedCustomer = window.customersData?.find( + c => c.id.toString() === selectedId + ); + + if (selectedCustomer) { + updateCustomerDetails(selectedCustomer); + } else { + showError("Customer data not found"); + clearCustomerDetails(); + } + }); + + $("#ItemDetailsSelect").on('change', function() { + const selectedCode = $(this).val(); + + if (!selectedCode) { + clearItemDetails(); + return; + } + + const selectedItem = window.itemsData?.find( + i => i.itemCode.toString() === selectedCode + ); + + if (selectedItem) { + updateItemDetails(selectedItem); + } else { + showError("Item data not found"); + clearItemDetails(); + } + }); + + $("#addToCartBtn").on('click', function() { + const selectedItemCode = $("#ItemDetailsSelect").val(); + if (!selectedItemCode) { + showError("Please select an item first"); + return; + } + + const selectedItem = window.itemsData?.find( + i => i.itemCode.toString() === selectedItemCode + ); + + if (!selectedItem) { + showError("Selected item not found"); + return; + } + + const existingItem = cartItems.find(item => item.itemCode === selectedItem.itemCode); + + if (existingItem) { + if (existingItem.quantity + 1 > selectedItem.qty) { + showError(`Not enough stock available for ${selectedItem.name}`); + return; + } + existingItem.quantity += 1; + existingItem.total = existingItem.quantity * existingItem.unitPrice; + showSuccess(`Increased ${selectedItem.name} quantity to ${existingItem.quantity}`); + } else { + if (selectedItem.qty < 1) { + showError(`${selectedItem.name} is out of stock`); + return; + } + cartItems.push({ + itemCode: selectedItem.itemCode, + name: selectedItem.name, + quantity: 1, + unitPrice: selectedItem.price, + total: selectedItem.price + }); + showSuccess(`Added ${selectedItem.name} to cart`); + } + + updateCartTable(); + updateTotalAmount(); + }); + + $("#placeOrderButton").on('click', function() { + if (validateOrder()) { + $(this).html('Processing...').prop('disabled', true); + placeOrder(); + } + }); +} + +function validateOrder() { + const selectedCustomerId = $("#customerDetailsSelect").val(); + if (!selectedCustomerId) { + showError("Please select a customer"); + return false; + } + + if (cartItems.length === 0) { + showError("Cart is empty. Please add items to cart"); + return false; + } + + const orderId = $("#orderId").val(); + if (!orderId) { + showError("Invalid order ID"); + return false; + } + + return true; +} + +function updateCustomerDetails(customer) { + $("#customerDetailsName").text(customer.name || 'N/A'); + $("#customerDetailsAddress").text(customer.address || 'N/A'); +} + +function clearCustomerDetails() { + $("#customerDetailsName").text('Select a customer'); + $("#customerDetailsAddress").text('Address will appear here'); +} + +function updateItemDetails(item) { + $("#ItemDetailsName").text(item.name || 'N/A'); + $("#ItemDetailsPrice").text(`$${item.price.toFixed(2)}` || 'N/A'); + + const stockLevel = item.qty || 0; + let stockBadge = ''; + + if (stockLevel > 10) { + stockBadge = `${stockLevel} in stock`; + } else if (stockLevel > 0) { + stockBadge = `Low stock: ${stockLevel}`; + } else { + stockBadge = `Out of stock`; + } + + $("#ItemDetailsStock").html(stockBadge); +} + +function clearItemDetails() { + $("#ItemDetailsName").text('Select an item'); + $("#ItemDetailsPrice").text('Price will appear here'); + $("#ItemDetailsStock").text('Stock will appear here'); +} + +function updateCartTable() { + const tbody = $("#cartTableBody"); + tbody.empty(); + + if (cartItems.length === 0) { + tbody.html(` + + +
+ +

Your cart is empty

+ Select items to add to your order +
+ + + `); + return; + } + + cartItems.forEach((item, index) => { + tbody.append(` + + + ${item.itemCode} + + + ${item.name} + + +
+ + ${item.quantity} + +
+ + $${item.unitPrice.toFixed(2)} + + $${item.total.toFixed(2)} + + + + + + `); + }); +} + +function removeFromCart(itemCode) { + const itemToRemove = cartItems.find(item => item.itemCode === itemCode); + if (itemToRemove) { + cartItems = cartItems.filter(item => item.itemCode !== itemCode); + updateCartTable(); + updateTotalAmount(); + showSuccess(`Removed ${itemToRemove.name} from cart`); + } +} + +function updateQuantity(itemCode, change) { + const selectedItem = cartItems.find(item => item.itemCode === itemCode); + if (!selectedItem) return; + + const inventoryItem = window.itemsData?.find(i => i.itemCode.toString() === itemCode); + if (!inventoryItem) return; + + const newQuantity = selectedItem.quantity + change; + + if (newQuantity < 1) { + return; + } + + if (change > 0 && newQuantity > inventoryItem.qty) { + showError(`Not enough stock available for ${selectedItem.name}`); + return; + } + + selectedItem.quantity = newQuantity; + selectedItem.total = selectedItem.quantity * selectedItem.unitPrice; + + updateCartTable(); + updateTotalAmount(); +} + +function updateTotalAmount() { + const total = cartItems.reduce((sum, item) => sum + item.total, 0); + $("#totalAmount").text(`Total: $${total.toFixed(2)}`); + + $("#placeOrderButton").prop('disabled', cartItems.length === 0); +} + +function showToast(message, type = 'success') { + const toast = $('
').addClass('toast').addClass(type); + + const iconClass = type === 'success' ? 'bi-check-circle' : 'bi-exclamation-triangle'; + const toastIcon = $('').addClass(`bi ${iconClass} me-2`); + + const toastContent = $('
').addClass('toast-content'); + const toastTitle = $('
').addClass('fw-semibold mb-1').text( + type === 'success' ? 'Success' : 'Error' + ); + const toastMessage = $('
').addClass('text-secondary small').text(message); + toastContent.append(toastTitle, toastMessage); + + const closeBtn = $(' +
+
+
+
+ + +
+
+
+
+ Shopping Cart +
+
+
+
+ + + + + + + + + + + + + + + + + +
Item CodeNameQuantityUnit PriceTotalAction
+
+ +

Your cart is empty

+ Select items to add to your order +
+
+
+ +
+
+
+ Total: $0.00 +
+
+ +
+
+
+
+
+
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/14_Springboot_Frontend/target/classes/lk/ijse/Item.html b/14_Springboot_Frontend/target/classes/lk/ijse/Item.html new file mode 100644 index 0000000..15b1d98 --- /dev/null +++ b/14_Springboot_Frontend/target/classes/lk/ijse/Item.html @@ -0,0 +1,127 @@ + + + + + + Item Management + + + + + + + + + + + +
+
+

Item Management

+
+ +
+ +
+
+

Add New Item

+
+
+
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+ + + + + + + +
+

Are you sure you want to delete this item? This action cannot be undone.

+
+ + +
+
+
+
+
+ + +
+
+

Item List

+
+
+
+
+ + +
+
+ Total: 0 items +
+
+ +
+ + + + + + + + + + + + + +
IDNamePriceQtyActions
+
+
+ +
+

No items found

+
+
+
+
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/14_Springboot_Frontend/target/classes/lk/ijse/componnent/components.js b/14_Springboot_Frontend/target/classes/lk/ijse/componnent/components.js new file mode 100644 index 0000000..5dd04ba --- /dev/null +++ b/14_Springboot_Frontend/target/classes/lk/ijse/componnent/components.js @@ -0,0 +1,100 @@ +// Define your navigation component HTML +const navComponent = ` + + +`; + +// Function to load components +function loadComponents() { + // Insert navigation + const navPlaceholder = document.getElementById('nav-placeholder'); + if (navPlaceholder) { + navPlaceholder.innerHTML = navComponent; + } + + // Set active link based on current page + const currentPage = window.location.pathname.split('/').pop(); + const navLinks = document.querySelectorAll('.navbar-nav .nav-link'); + + navLinks.forEach(link => { + const href = link.getAttribute('href'); + if (href === currentPage) { + link.classList.add('active'); + } else { + link.classList.remove('active'); + } + }); +} + +// Load components when DOM is ready +document.addEventListener('DOMContentLoaded', loadComponents); \ No newline at end of file diff --git a/14_Springboot_Frontend/target/classes/lk/ijse/css/customer.css b/14_Springboot_Frontend/target/classes/lk/ijse/css/customer.css new file mode 100644 index 0000000..41e9407 --- /dev/null +++ b/14_Springboot_Frontend/target/classes/lk/ijse/css/customer.css @@ -0,0 +1,324 @@ +:root { + --primary: #2563eb; + --primary-dark: #1d4ed8; + --danger: #ef4444; + --success: #10b981; + --dark: #1e293b; + --light: #f8fafc; + --gray: #e2e8f0; + --text: #334155; + --border: #cbd5e1; + --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); + --radius: 8px; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; + background-color: #f1f5f9; + color: var(--text); + line-height: 1.5; + padding: 2rem; +} + +.container { + max-width: 1200px; + margin: 0 auto; +} + +header { + margin-bottom: 2rem; +} + +h1 { + color: var(--dark); + font-size: 1.875rem; + margin-bottom: 0.5rem; +} + +.content-wrapper { + display: grid; + grid-template-columns: 350px 1fr; + gap: 1.5rem; +} + +@media (max-width: 992px) { + .content-wrapper { + grid-template-columns: 1fr; + } +} + +.card { + background-color: white; + border-radius: var(--radius); + box-shadow: var(--shadow); + overflow: hidden; +} + +.card-header { + padding: 1rem; + border-bottom: 1px solid var(--gray); +} + +.card-title { + font-size: 1.25rem; + font-weight: 600; + color: var(--dark); +} + +.card-body { + padding: 1.5rem; +} + +/* Form */ +.form-group { + margin-bottom: 1.25rem; +} + +label { + display: block; + margin-bottom: 0.5rem; + font-weight: 500; + color: var(--dark); + font-size: 0.875rem; +} + +.form-control { + width: 100%; + padding: 0.625rem 0.875rem; + border: 1px solid var(--border); + border-radius: var(--radius); + font-size: 0.875rem; +} + +.form-control:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1); +} + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.625rem 1rem; + background-color: var(--primary); + color: white; + border: none; + border-radius: var(--radius); + font-weight: 500; + font-size: 0.875rem; + cursor: pointer; + transition: background-color 0.2s, transform 0.1s; +} + +.btn:hover { + background-color: var(--primary-dark); +} + +.btn:active { + transform: translateY(1px); +} + +.btn i { + margin-right: 0.5rem; +} + +.btn-block { + width: 100%; +} + +.btn-danger { + background-color: var(--danger); +} + +.btn-sm { + padding: 0.375rem 0.75rem; + font-size: 0.75rem; +} + +.btn-icon { + width: 2rem; + height: 2rem; + padding: 0; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.btn-icon i { + margin-right: 0; +} + +/* Table */ +.table-controls { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; +} + +.search-container { + position: relative; + width: 250px; +} + +.search-input { + width: 100%; + padding: 0.5rem 1rem 0.5rem 2.25rem; + border: 1px solid var(--border); + border-radius: var(--radius); + font-size: 0.875rem; +} + +.search-icon { + position: absolute; + left: 0.75rem; + top: 50%; + transform: translateY(-50%); + color: #94a3b8; +} + +table { + width: 100%; + border-collapse: collapse; +} + +th, td { + text-align: left; + padding: 0.75rem 1rem; + border-bottom: 1px solid var(--gray); + font-size: 0.875rem; +} + +th { + font-weight: 600; + color: var(--dark); + background-color: #f8fafc; +} + +tr:last-child td { + border-bottom: none; +} + +tr:hover { + background-color: #f8fafc; +} + +.action-cell { + width: 120px; + white-space: nowrap; +} + +.empty-table { + padding: 3rem 1rem; + text-align: center; + color: #64748b; +} + +.empty-icon { + font-size: 2.5rem; + color: #94a3b8; + margin-bottom: 1rem; +} + +/* Toast Notification */ +.toast-container { + position: fixed; + bottom: 1.5rem; + right: 1.5rem; + z-index: 1010; +} + +.toast { + display: flex; + align-items: center; + padding: 0.75rem 1rem; + background-color: white; + border-radius: var(--radius); + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); + margin-top: 0.75rem; + transform: translateX(150%); + transition: transform 0.3s; + max-width: 350px; +} + +.toast.show { + transform: translateX(0); +} + +.toast.success .toast-icon { + background-color: #dcfce7; + color: #166534; +} + +.toast.error .toast-icon { + background-color: #fee2e2; + color: #991b1b; +} + +.toast-icon { + width: 2rem; + height: 2rem; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + margin-right: 0.75rem; + flex-shrink: 0; +} + +.toast-content { + flex-grow: 1; +} + +.toast-title { + font-weight: 600; + font-size: 0.875rem; + margin-bottom: 0.25rem; +} + +.toast-message { + font-size: 0.8125rem; + color: #64748b; +} + +.toast-close { + background: none; + border: none; + color: #94a3b8; + cursor: pointer; + padding: 0.5rem; + margin: -0.5rem; + flex-shrink: 0; +} + +/* Confirmations */ +.confirm-delete { + display: none; + background-color: #fee2e2; + border: 1px solid #fecaca; + border-radius: var(--radius); + padding: 0.75rem; + margin-top: 0.5rem; +} + +.confirm-delete.show { + display: block; +} + +.confirm-message { + color: #991b1b; + font-size: 0.875rem; + margin-bottom: 0.75rem; +} + +.confirm-actions { + display: flex; + gap: 0.5rem; +} diff --git a/14_Springboot_Frontend/target/classes/lk/ijse/css/dashboard.css b/14_Springboot_Frontend/target/classes/lk/ijse/css/dashboard.css new file mode 100644 index 0000000..f539a26 --- /dev/null +++ b/14_Springboot_Frontend/target/classes/lk/ijse/css/dashboard.css @@ -0,0 +1,180 @@ +:root { + --primary: #4361ee; + --dark: #2b2d42; + --light: #f8f9fa; + --gray: #e9ecef; + --shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + --transition: all 0.3s ease; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; + background-color: var(--gray); + color: var(--dark); + padding: 2rem; + line-height: 1.5; +} + +.container { + max-width: 1200px; + margin: 0 auto; +} + +header { + text-align: center; + margin-bottom: 3rem; +} + +h1 { + font-size: 2.5rem; + margin-bottom: 0.5rem; + color: var(--dark); +} + +.subtitle { + font-size: 1.1rem; + color: #6c757d; + margin-bottom: 1rem; +} + +.cards-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 2rem; +} + +.card { + background-color: white; + border-radius: 12px; + box-shadow: var(--shadow); + overflow: hidden; + transition: var(--transition); + cursor: pointer; + text-decoration: none; + color: inherit; + height: 100%; + display: flex; + flex-direction: column; +} + +.card:hover { + transform: translateY(-5px); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); +} + +.card:active { + transform: translateY(-2px); +} + +.card-icon { + background-color: var(--primary); + color: white; + height: 120px; + display: flex; + align-items: center; + justify-content: center; +} + +.card-icon i { + font-size: 3rem; +} + +.card-content { + padding: 1.5rem; + flex: 1; +} + +.card-title { + font-size: 1.4rem; + font-weight: 600; + margin-bottom: 0.5rem; +} + +.card-description { + color: #6c757d; + font-size: 0.95rem; +} + +.card-footer { + display: flex; + align-items: center; + padding: 1rem 1.5rem; + background-color: #f8f9fa; + border-top: 1px solid #e9ecef; +} + +.card-footer span { + color: #6c757d; + font-size: 0.9rem; +} + +.card-footer i { + margin-left: auto; + color: var(--primary); +} + +@media (max-width: 768px) { + body { + padding: 1rem; + } + + .cards-grid { + grid-template-columns: 1fr; + gap: 1.5rem; + } + + h1 { + font-size: 2rem; + } +} + +/* Page Content Styling */ +.page { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: white; + z-index: 100; + overflow-y: auto; + padding: 2rem; +} + +.page.active { + display: block; +} + +.page-header { + display: flex; + align-items: center; + margin-bottom: 2rem; +} + +.back-button { + background: none; + border: none; + color: var(--primary); + font-size: 1.2rem; + cursor: pointer; + display: flex; + align-items: center; + margin-right: 1rem; +} + +.page-title { + font-size: 1.8rem; + font-weight: 600; +} + +.page-content { + max-width: 1000px; + margin: 0 auto; +} diff --git a/14_Springboot_Frontend/target/classes/lk/ijse/css/item.css b/14_Springboot_Frontend/target/classes/lk/ijse/css/item.css new file mode 100644 index 0000000..df3be6f --- /dev/null +++ b/14_Springboot_Frontend/target/classes/lk/ijse/css/item.css @@ -0,0 +1,258 @@ +:root { + --primary: #2563eb; + --primary-dark: #1d4ed8; + --danger: #ef4444; + --success: #10b981; + --dark: #1e293b; + --light: #f8fafc; + --gray: #e2e8f0; + --text: #334155; + --border: #cbd5e1; + --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); + --radius: 8px; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; + background-color: #f1f5f9; + color: var(--text); + line-height: 1.5; + padding: 2rem; +} + +.container { + max-width: 1200px; + margin: 0 auto; +} + +header { + margin-bottom: 2rem; +} + +h1 { + color: var(--dark); + font-size: 1.875rem; + margin-bottom: 0.5rem; +} + +.content-wrapper { + display: grid; + grid-template-columns: 350px 1fr; + gap: 1.5rem; +} + +@media (max-width: 992px) { + .content-wrapper { + grid-template-columns: 1fr; + } +} + +.card { + background-color: white; + border-radius: var(--radius); + box-shadow: var(--shadow); + overflow: hidden; +} + +.card-header { + padding: 1rem; + border-bottom: 1px solid var(--gray); +} + +.card-title { + font-size: 1.25rem; + font-weight: 600; + color: var(--dark); +} + +.card-body { + padding: 1.5rem; +} + +/* Form */ +.form-group { + margin-bottom: 1.25rem; +} + +label { + display: block; + margin-bottom: 0.5rem; + font-weight: 500; + color: var(--dark); + font-size: 0.875rem; +} + +.form-control { + width: 100%; + padding: 0.625rem 0.875rem; + border: 1px solid var(--border); + border-radius: var(--radius); + font-size: 0.875rem; +} + +.form-control:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1); +} + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.625rem 1rem; + background-color: var(--primary); + color: white; + border: none; + border-radius: var(--radius); + font-weight: 500; + font-size: 0.875rem; + cursor: pointer; + transition: background-color 0.2s, transform 0.1s; +} + +.btn:hover { + background-color: var(--primary-dark); +} + +.btn:active { + transform: translateY(1px); +} + +.btn i { + margin-right: 0.5rem; +} + +.btn-block { + width: 100%; +} + +.btn-danger { + background-color: var(--danger); +} + +.btn-sm { + padding: 0.375rem 0.75rem; + font-size: 0.75rem; +} + + +.btn-icon i { + margin-right: 0; +} + +/* Table */ +.table-controls { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; +} + +.search-container { + position: relative; + width: 250px; +} + +.search-input { + width: 100%; + padding: 0.5rem 1rem 0.5rem 2.25rem; + border: 1px solid var(--border); + border-radius: var(--radius); + font-size: 0.875rem; +} + +.search-icon { + position: absolute; + left: 0.75rem; + top: 50%; + transform: translateY(-50%); + color: #94a3b8; +} + +table { + width: 100%; + border-collapse: collapse; +} + +th, td { + text-align: left; + padding: 0.75rem 1rem; + border-bottom: 1px solid var(--gray); + font-size: 0.875rem; +} + +th { + font-weight: 600; + color: var(--dark); + background-color: #f8fafc; +} + +tr:last-child td { + border-bottom: none; +} + +tr:hover { + background-color: #f8fafc; +} + +.empty-table { + padding: 3rem 1rem; + text-align: center; + color: #64748b; +} + +.empty-icon { + font-size: 2.5rem; + color: #94a3b8; + margin-bottom: 1rem; +} + +/* Toast Notification */ +.toast-container { + position: fixed; + bottom: 1.5rem; + right: 1.5rem; + z-index: 1010; +} + +.toast.success .toast-icon { + background-color: #dcfce7; + color: #166534; +} + +.toast.error .toast-icon { + background-color: #fee2e2; + color: #991b1b; +} + +/* Confirmations */ +.confirm-delete { + display: none; + background-color: #fee2e2; + border: 1px solid #fecaca; + border-radius: var(--radius); + padding: 0.75rem; + margin-top: 0.5rem; +} + +.confirm-delete.show { + display: block; +} + +.confirm-message { + color: #991b1b; + font-size: 0.875rem; + margin-bottom: 0.75rem; +} + +.confirm-actions { + display: flex; + gap: 0.5rem; +} diff --git a/14_Springboot_Frontend/target/classes/lk/ijse/css/order.css b/14_Springboot_Frontend/target/classes/lk/ijse/css/order.css new file mode 100644 index 0000000..7f1f0b8 --- /dev/null +++ b/14_Springboot_Frontend/target/classes/lk/ijse/css/order.css @@ -0,0 +1,359 @@ +:root { + --primary: #4f46e5; + --primary-light: #6366f1; + --primary-dark: #4338ca; + --secondary: #0ea5e9; + --success: #10b981; + --danger: #ef4444; + --warning: #f59e0b; + --light: #f8fafc; + --dark: #0f172a; +} + +body { + font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; + background-color: #f1f5f9; + color: var(--text); + line-height: 1.5; + padding: 2rem 2rem 0 2rem; +} + + +.app-container { + max-width: 1400px; + margin: 0 auto; +} + +.page-header { + padding: 0 1rem 1rem 1rem; + margin-bottom: 2rem; +} + +.card { + border: none; + border-radius: 1rem; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05); + transition: all 0.3s ease; + overflow: hidden; + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(10px); + margin-bottom: 1.5rem; +} + +.card:hover { + transform: translateY(-5px); + box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1); +} + +.card-header { + background: transparent; + border-bottom: 1px solid rgba(0, 0, 0, 0.05); + padding: 1.5rem; +} + +.card-body { + padding: 1.5rem; +} + +.card-title { + font-weight: 600; + margin-bottom: 1.25rem; + display: flex; + align-items: center; + color: var(--primary); +} + +.card-title i { + margin-right: 0.75rem; + font-size: 1.25rem; +} + +.form-control, .form-select { + border: 2px solid rgba(0, 0, 0, 0.05); + border-radius: 0.75rem; + padding: 0.75rem 1rem; + font-size: 1rem; + transition: all 0.2s ease; + background-color: rgba(255, 255, 255, 0.8); +} + +.form-control:focus, .form-select:focus { + border-color: var(--primary-light); + box-shadow: 0 0 0 0.25rem rgba(99, 102, 241, 0.15); +} + +.form-control-lg, .form-select-lg { + height: 3.5rem; + font-size: 1rem; +} + +.btn { + padding: 0.75rem 1.5rem; + border-radius: 0.75rem; + font-weight: 500; + letter-spacing: 0.3px; + transition: all 0.3s ease; +} + +.btn-primary { + background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%); + border: none; +} + +.btn-primary:hover { + background: linear-gradient(135deg, var(--primary-dark) 0%, var(--primary-dark) 100%); + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(79, 70, 229, 0.3); +} + +.btn-success { + background: linear-gradient(135deg, var(--success) 0%, #059669 100%); + border: none; +} + +.btn-success:hover { + background: linear-gradient(135deg, #059669 0%, #047857 100%); + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(16, 185, 129, 0.3); +} + +.btn-danger { + background: linear-gradient(135deg, var(--danger) 0%, #dc2626 100%); + border: none; +} + +.btn-danger:hover { + background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%); + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(239, 68, 68, 0.3); +} + +.btn-icon { + display: inline-flex; + align-items: center; + justify-content: center; +} + +.btn-icon i { + margin-right: 0.5rem; +} + +.details-panel { + background: rgba(79, 70, 229, 0.03); + border-radius: 0.75rem; + padding: 1.5rem; + border: 1px solid rgba(79, 70, 229, 0.1); + height: 100%; +} + +.details-panel h6 { + color: var(--primary); + font-weight: 600; + margin-bottom: 1.25rem; + padding-bottom: 0.75rem; + border-bottom: 1px solid rgba(79, 70, 229, 0.1); +} + +.details-panel .detail-item { + display: flex; + justify-content: space-between; + margin-bottom: 1rem; + padding-bottom: 1rem; + border-bottom: 1px solid rgba(0, 0, 0, 0.05); +} + +.details-panel .detail-item:last-child { + margin-bottom: 0; + padding-bottom: 0; + border-bottom: none; +} + +.details-panel .detail-label { + color: #64748b; + font-size: 0.925rem; +} + +.details-panel .detail-value { + font-weight: 500; + text-align: right; +} + +.table { + border-radius: 0.75rem; + overflow: hidden; + margin-bottom: 0; +} + +.table th { + font-weight: 600; + color: #1e293b; + background-color: rgba(241, 245, 249, 0.8); + padding: 1rem; +} + +.table td { + padding: 1rem; + vertical-align: middle; +} + +.badge { + padding: 0.5rem 0.75rem; + font-weight: 500; + border-radius: 0.5rem; +} + +.remove-btn { + color: var(--danger); + background: rgba(239, 68, 68, 0.05); + border: none; + border-radius: 0.5rem; + padding: 0.5rem 0.75rem; + transition: all 0.2s ease; + font-size: 0.875rem; +} + +.remove-btn:hover { + background: rgba(239, 68, 68, 0.1); + color: #b91c1c; +} + +.total-section { + background: linear-gradient(135deg, rgba(79, 70, 229, 0.05) 0%, rgba(14, 165, 233, 0.05) 100%); + border-radius: 0.75rem; + padding: 1.5rem; + margin-top: 1.5rem; + border: 1px solid rgba(79, 70, 229, 0.1); +} + +.total-amount { + font-size: 1.5rem; + font-weight: 700; + color: var(--primary-dark); +} + +#toastContainer { + position: fixed; + top: 20px; + right: 20px; + z-index: 1050; +} + +.toast { + background: white; + border-radius: 0.75rem; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); + margin-bottom: 1rem; + padding: 1rem 1.25rem; + display: flex; + align-items: center; + min-width: 300px; + transform: translateX(120%); + transition: transform 0.3s ease; + border-left: 4px solid transparent; +} + +.toast.show { + transform: translateX(0); +} + +.toast.success { + border-left-color: var(--success); +} + +.toast.error { + border-left-color: var(--danger); +} + +.toast-content { + flex-grow: 1; + margin: 0 0.75rem; +} + +.toast-close { + background: none; + border: none; + color: #94a3b8; + cursor: pointer; + transition: color 0.2s ease; + padding: 0.25rem; +} + +.toast-close:hover { + color: #475569; +} + +.order-id-container { + background: rgba(79, 70, 229, 0.05); + border: 1px solid rgba(79, 70, 229, 0.1); + border-radius: 0.75rem; + padding: 1rem 1.5rem; + margin-bottom: 1.5rem; +} + +.order-id-label { + display: block; + font-size: 0.875rem; + font-weight: 500; + color: #64748b; + margin-bottom: 0.5rem; +} + +.order-id-value { + font-size: 1.25rem; + font-weight: 600; + color: var(--primary); + letter-spacing: 0.5px; +} + +@media (max-width: 992px) { + .app-container { + padding: 1rem; + } + + .page-header { + padding: 1.5rem 0; + } + + .order-id-container { + margin-top: 1rem; + } +} + +/* Loading spinner for selects */ +.select-loading::after { + content: ""; + position: absolute; + right: 10px; + top: 50%; + transform: translateY(-50%); + width: 20px; + height: 20px; + border-radius: 50%; + border: 2px solid rgba(79, 70, 229, 0.2); + border-top-color: var(--primary); + animation: spin 0.8s linear infinite; +} + +@keyframes spin { + to { + transform: translateY(-50%) rotate(360deg); + } +} + +/* Empty cart illustration */ +.empty-cart { + text-align: center; + padding: 2rem; + color: #94a3b8; +} + +.empty-cart i { + font-size: 3rem; + margin-bottom: 1rem; + opacity: 0.5; +} + +.empty-cart p { + font-size: 1.125rem; + margin-bottom: 1.5rem; +} \ No newline at end of file diff --git a/14_Springboot_Frontend/target/classes/lk/ijse/customer.html b/14_Springboot_Frontend/target/classes/lk/ijse/customer.html new file mode 100644 index 0000000..106d81a --- /dev/null +++ b/14_Springboot_Frontend/target/classes/lk/ijse/customer.html @@ -0,0 +1,135 @@ + + + + + + Customer Management + + + + + + + + + + +
+
+

Customer Management

+
+ + +
+ +
+
+

Add New Customer

+
+
+
+
+ + +
+
+ + +
+
+ + +
+ + + + + + + + +
+

Are you sure you want to delete this customer? This action cannot be undone.

+
+ + +
+
+
+
+
+ + +
+
+

Customer List

+
+
+
+
+ + +
+
+ +
+ + + + + + + + + + + + +
IDNameAddressActions
+ +
+
+ +
+

No customers found

+
+
+
+
+
+
+ +
+ + + + + + + + \ No newline at end of file diff --git a/14_Springboot_Frontend/target/classes/lk/ijse/dashboard.html b/14_Springboot_Frontend/target/classes/lk/ijse/dashboard.html new file mode 100644 index 0000000..d1388f2 --- /dev/null +++ b/14_Springboot_Frontend/target/classes/lk/ijse/dashboard.html @@ -0,0 +1,146 @@ + + + + + + Dashboard + + + + + + + + + \ No newline at end of file diff --git a/14_Springboot_Frontend/target/classes/lk/ijse/js/customer.js b/14_Springboot_Frontend/target/classes/lk/ijse/js/customer.js new file mode 100644 index 0000000..4b67728 --- /dev/null +++ b/14_Springboot_Frontend/target/classes/lk/ijse/js/customer.js @@ -0,0 +1,284 @@ +$("#saveCustomerBtn").click(function(event) { + event.preventDefault(); + + if (!$("#customerName").val() || !$("#customerAddress").val()) { + showToast('Please fill all the fields', 'error'); + return; + } + + var customerID = $("#customerId").val(); + var customerName = $("#customerName").val(); + var customerAddress = $("#customerAddress").val(); + + var customer = { + "id": customerID, + "name": customerName, + "address": customerAddress + } + + $.ajax({ + method: "POST", + url: "http://localhost:8080/api/v1/customer/save", + contentType: "application/json", + data: JSON.stringify(customer), + success: function(response) { + if (response.code === 201) { + showToast('Customer saved successfully', 'success'); + $("#customerForm")[0].reset(); + loadCustomers(); + generateNextCustomerId(); + } else { + showToast('Failed to save the customer','error'); + } + }, + error: function(xhr, status, error) { + showToast('Error saving customer: ' + error, 'error'); + console.error("AJAX Error: " + status + " - " + error); + } + }); +}); + +$("#updateCustomerBtn").click(function(event) { + event.preventDefault(); + + if (!$("#customerName").val() || !$("#customerAddress").val()) { + showToast('Please fill all the fields', 'error'); + return; + } + + var customerID = $("#customerId").val(); + var customerName = $("#customerName").val(); + var customerAddress = $("#customerAddress").val(); + + var customer = { + "id": customerID, + "name": customerName, + "address": customerAddress + } + $.ajax({ + method: "PUT", + url: "http://localhost:8080/api/v1/customer/update", + contentType: "application/json", + data: JSON.stringify(customer), + success: function(response) { + if (response.code === 201) { + showToast('Customer updated successfully', 'success'); + resetForm(); + loadCustomers(); + } else { + showToast('Failed to update the customer', 'error'); + } + }, + error: function(xhr, status, error) { + showToast('Error updating customer: ' + error, 'error'); + } + }) +}); + +function loadCustomers() { + $.ajax({ + method: "GET", + url: "http://localhost:8080/api/v1/customer/getAll", + success: function(response) { + const customers = response.data; + if (customers && customers.length > 0) { + $("#emptyTable").hide(); + $("#customerTable").show(); + + var tbody = $("#customerTableBody"); + tbody.empty(); + + $.each(customers, function(index, customer) { + var row = $(""); + row.append($("").text(customer.id || "-")); + row.append($("").text(customer.name || "-")); + row.append($("").text(customer.address || "-")); + + var actionsCell = $("").addClass("action-cell"); + + var editBtn = $(" + + `); + + $("#toastContainer").append(toast); + setTimeout(() => toast.addClass('show'), 100); + + toast.find('.toast-close').click(function() { + toast.removeClass('show'); + setTimeout(() => toast.remove(), 300); + }); + + setTimeout(() => { + toast.removeClass('show'); + setTimeout(() => toast.remove(), 300); + }, 3000); +} + +function getNextItemId() { + $.ajax({ + method: "GET", + url: "http://localhost:8080/api/v1/item/generateNextId", + success: function(response) { + if(response.data) { + $("#itemId").val(response.data); + } + }, + error: function(xhr, status, error) { + showToast("Error getting next ID", "error"); + } + }); +} + +function loadItems() { + $.ajax({ + method: "GET", + url: "http://localhost:8080/api/v1/item/getAll", + success: function(response) { + if(response.data) { + $("#itemTableBody").empty(); + response.data.forEach(function(item) { + $("#itemTableBody").append( + ` + ${item.itemCode} + ${item.name} + ${item.price} + ${item.qty} + + + + + ` + ); + }); + updateTotalItems() + $("#emptyTable").hide(); + } + }, + error: function(xhr, status, error) { + showToast("Error loading items", "error"); + } + }); +} + +function updateTotalItems() { + const visibleRows = $("#itemTableBody tr:visible").length; + $("#totalItems").text(`Total: ${visibleRows} items`); +} + +$("#saveItemBtn").click(function(event) { + event.preventDefault(); + + if(!$("#itemName").val() || !$("#itemPrice").val() || !$("#itemQty").val()) { + showToast("Please fill all the fields", "error"); + return; + } + + var item = { + "itemCode": $("#itemId").val(), + "name": $("#itemName").val(), + "price": $("#itemPrice").val(), + "qty": $("#itemQty").val() + } + + $.ajax({ + method: "POST", + url: "http://localhost:8080/api/v1/item/save", + contentType: "application/json", + data: JSON.stringify(item), + success: function(response) { + if(response.code === 201) { + showToast("Item saved successfully", "success"); + $("#itemForm")[0].reset(); + loadItems(); + getNextItemId(); + } else { + showToast("Failed to save item", "error"); + } + }, + error: function(xhr, status, error) { + showToast("Error saving item", "error"); + } + }); +}); + +function editItem(item) { + $("#formTitle").text("Edit Item"); + $("#itemId").val(item.itemCode).prop("disabled", true); + $("#itemName").val(item.name); + $("#itemPrice").val(item.price); + $("#itemQty").val(item.qty); + $("#saveItemBtn").hide(); + $("#updateItemBtn").show(); + + if (window.innerWidth < 992) { + $("#itemForm")[0].scrollIntoView({ behavior: 'smooth' }); + } +} + +function deleteItem(item) { + $("#formTitle").text("Delete Item"); + $("#itemId").val(item.itemCode).prop("disabled", true); + $("#itemName").val(item.name); + $("#itemPrice").val(item.price); + $("#itemQty").val(item.qty); + $("#saveItemBtn").prop("disabled", true); + $("#confirmDelete").addClass("show"); +} + +$("#updateItemBtn").click(function(event) { + event.preventDefault(); + + if(!$("#itemName").val() || !$("#itemPrice").val() || !$("#itemQty").val()) { + showToast("Please fill all the fields", "error"); + return; + } + + var item = { + "itemCode": $("#itemId").val(), + "name": $("#itemName").val(), + "price": $("#itemPrice").val(), + "qty": $("#itemQty").val() + } + + $.ajax({ + method: "PUT", + url: "http://localhost:8080/api/v1/item/update", + contentType: "application/json", + data: JSON.stringify(item), + success: function(response) { + if(response.code === 201) { + showToast("Item updated successfully", "success"); + resetForm(); + loadItems(); + } else { + showToast("Failed to update item", "error"); + } + }, + error: function(xhr, status, error) { + showToast("Error updating item", "error"); + } + }); +}); + +$("#confirmDeleteBtn").click(function() { + var itemCode = $("#itemId").val(); + + $.ajax({ + method: "DELETE", + url: "http://localhost:8080/api/v1/item/delete/" + itemCode, + success: function(response) { + if(response.code === 201) { + showToast("Item deleted successfully", "success"); + resetForm(); + loadItems(); + } else { + showToast("Failed to delete item", "error"); + } + }, + error: function(xhr, status, error) { + showToast("Error deleting item", "error"); + } + }); +}); + +$("#cancelDeleteBtn").click(function() { + resetForm(); +}); + +function resetForm() { + $("#formTitle").text("Add New Item"); + $("#itemForm")[0].reset(); + $("#itemId").prop("disabled", false); + $("#saveItemBtn").show().prop("disabled", false); + $("#updateItemBtn").hide(); + $("#confirmDelete").removeClass("show"); + getNextItemId(); +} \ No newline at end of file diff --git a/14_Springboot_Frontend/target/classes/lk/ijse/js/jquery-3.7.1.min.js b/14_Springboot_Frontend/target/classes/lk/ijse/js/jquery-3.7.1.min.js new file mode 100644 index 0000000..7f37b5d --- /dev/null +++ b/14_Springboot_Frontend/target/classes/lk/ijse/js/jquery-3.7.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0 response.text()) + .then(data => { + // Find where to insert the navigation + const navPlaceholder = document.getElementById('nav-placeholder'); + if (navPlaceholder) { + navPlaceholder.innerHTML = data; + } + }) + .catch(error => console.error('Error loading navigation component:', error)); +}); \ No newline at end of file diff --git a/14_Springboot_Frontend/target/classes/lk/ijse/js/order.js b/14_Springboot_Frontend/target/classes/lk/ijse/js/order.js new file mode 100644 index 0000000..3f89dde --- /dev/null +++ b/14_Springboot_Frontend/target/classes/lk/ijse/js/order.js @@ -0,0 +1,486 @@ +let cartItems = []; + +$(document).ready(function() { + initializeApp(); + + if (!$('#toastContainer').length) { + $('body').append('
'); + } +}); + +function initializeApp() { + generateNextOrderId(); + + loadCustomers(); + loadItems(); + + initializeEventHandlers(); + + updateCartTable(); +} + +function generateNextOrderId() { + $("#orderIdDisplay").html('Generating...'); + + $.ajax({ + method: "GET", + url: "http://localhost:8080/api/v1/order/generateNextId", + success: function (response) { + if (response.code === 201 && response.data) { + $("#orderId").val(response.data); + $("#orderIdDisplay").text(response.data); + console.log("Next order ID:", response.data); + } else { + showError("Failed to generate order ID"); + $("#orderIdDisplay").text("Error"); + console.error("Error response:", response); + } + }, + error: function (xhr, status, error) { + showError("Failed to generate order ID"); + $("#orderIdDisplay").text("Error"); + console.error("Error details:", {xhr, status, error}); + } + }); +} + +function loadCustomers() { + $("#customerDetailsSelect") + .prop('disabled', true) + .html(''); + + $.ajax({ + method: "GET", + url: "http://localhost:8080/api/v1/customer/getAll", + success: function(response) { + if (response.code === 200 && response.data && response.data.length > 0) { + const customers = response.data; + + $("#customerDetailsSelect") + .empty() + .append(''); + + customers.forEach(customer => { + $("#customerDetailsSelect").append( + `` + ); + }); + + window.customersData = customers; + } else { + $("#customerDetailsSelect") + .empty() + .append(''); + + showError("No customers found in the system"); + } + }, + error: function(xhr, status, error) { + $("#customerDetailsSelect") + .empty() + .append(''); + + showError("Failed to load customers. Please check server connection."); + console.error("Error details:", {xhr, status, error}); + }, + complete: function() { + $("#customerDetailsSelect").prop('disabled', false); + } + }); +} + +function loadItems() { + $("#ItemDetailsSelect") + .prop('disabled', true) + .html(''); + + $.ajax({ + method: "GET", + url: "http://localhost:8080/api/v1/item/getAll", + success: function(response) { + if (response.code === 200 && response.data && response.data.length > 0) { + const items = response.data; + + $("#ItemDetailsSelect") + .empty() + .append(''); + + items.forEach(item => { + $("#ItemDetailsSelect").append( + `` + ); + }); + + window.itemsData = items; + } else { + $("#ItemDetailsSelect") + .empty() + .append(''); + + showError("No items found in the system"); + } + }, + error: function(xhr, status, error) { + $("#ItemDetailsSelect") + .empty() + .append(''); + + showError("Failed to load items. Please check server connection."); + console.error("Error details:", {xhr, status, error}); + }, + complete: function() { + $("#ItemDetailsSelect").prop('disabled', false); + } + }); +} + +function initializeEventHandlers() { + $("#customerDetailsSelect").on('change', function() { + const selectedId = $(this).val(); + + if (!selectedId) { + clearCustomerDetails(); + return; + } + + const selectedCustomer = window.customersData?.find( + c => c.id.toString() === selectedId + ); + + if (selectedCustomer) { + updateCustomerDetails(selectedCustomer); + } else { + showError("Customer data not found"); + clearCustomerDetails(); + } + }); + + $("#ItemDetailsSelect").on('change', function() { + const selectedCode = $(this).val(); + + if (!selectedCode) { + clearItemDetails(); + return; + } + + const selectedItem = window.itemsData?.find( + i => i.itemCode.toString() === selectedCode + ); + + if (selectedItem) { + updateItemDetails(selectedItem); + } else { + showError("Item data not found"); + clearItemDetails(); + } + }); + + $("#addToCartBtn").on('click', function() { + const selectedItemCode = $("#ItemDetailsSelect").val(); + if (!selectedItemCode) { + showError("Please select an item first"); + return; + } + + const selectedItem = window.itemsData?.find( + i => i.itemCode.toString() === selectedItemCode + ); + + if (!selectedItem) { + showError("Selected item not found"); + return; + } + + const existingItem = cartItems.find(item => item.itemCode === selectedItem.itemCode); + + if (existingItem) { + if (existingItem.quantity + 1 > selectedItem.qty) { + showError(`Not enough stock available for ${selectedItem.name}`); + return; + } + existingItem.quantity += 1; + existingItem.total = existingItem.quantity * existingItem.unitPrice; + showSuccess(`Increased ${selectedItem.name} quantity to ${existingItem.quantity}`); + } else { + if (selectedItem.qty < 1) { + showError(`${selectedItem.name} is out of stock`); + return; + } + cartItems.push({ + itemCode: selectedItem.itemCode, + name: selectedItem.name, + quantity: 1, + unitPrice: selectedItem.price, + total: selectedItem.price + }); + showSuccess(`Added ${selectedItem.name} to cart`); + } + + updateCartTable(); + updateTotalAmount(); + }); + + $("#placeOrderButton").on('click', function() { + if (validateOrder()) { + $(this).html('Processing...').prop('disabled', true); + placeOrder(); + } + }); +} + +function validateOrder() { + const selectedCustomerId = $("#customerDetailsSelect").val(); + if (!selectedCustomerId) { + showError("Please select a customer"); + return false; + } + + if (cartItems.length === 0) { + showError("Cart is empty. Please add items to cart"); + return false; + } + + const orderId = $("#orderId").val(); + if (!orderId) { + showError("Invalid order ID"); + return false; + } + + return true; +} + +function updateCustomerDetails(customer) { + $("#customerDetailsName").text(customer.name || 'N/A'); + $("#customerDetailsAddress").text(customer.address || 'N/A'); +} + +function clearCustomerDetails() { + $("#customerDetailsName").text('Select a customer'); + $("#customerDetailsAddress").text('Address will appear here'); +} + +function updateItemDetails(item) { + $("#ItemDetailsName").text(item.name || 'N/A'); + $("#ItemDetailsPrice").text(`$${item.price.toFixed(2)}` || 'N/A'); + + const stockLevel = item.qty || 0; + let stockBadge = ''; + + if (stockLevel > 10) { + stockBadge = `${stockLevel} in stock`; + } else if (stockLevel > 0) { + stockBadge = `Low stock: ${stockLevel}`; + } else { + stockBadge = `Out of stock`; + } + + $("#ItemDetailsStock").html(stockBadge); +} + +function clearItemDetails() { + $("#ItemDetailsName").text('Select an item'); + $("#ItemDetailsPrice").text('Price will appear here'); + $("#ItemDetailsStock").text('Stock will appear here'); +} + +function updateCartTable() { + const tbody = $("#cartTableBody"); + tbody.empty(); + + if (cartItems.length === 0) { + tbody.html(` + + +
+ +

Your cart is empty

+ Select items to add to your order +
+ + + `); + return; + } + + cartItems.forEach((item, index) => { + tbody.append(` + + + ${item.itemCode} + + + ${item.name} + + +
+ + ${item.quantity} + +
+ + $${item.unitPrice.toFixed(2)} + + $${item.total.toFixed(2)} + + + + + + `); + }); +} + +function removeFromCart(itemCode) { + const itemToRemove = cartItems.find(item => item.itemCode === itemCode); + if (itemToRemove) { + cartItems = cartItems.filter(item => item.itemCode !== itemCode); + updateCartTable(); + updateTotalAmount(); + showSuccess(`Removed ${itemToRemove.name} from cart`); + } +} + +function updateQuantity(itemCode, change) { + const selectedItem = cartItems.find(item => item.itemCode === itemCode); + if (!selectedItem) return; + + const inventoryItem = window.itemsData?.find(i => i.itemCode.toString() === itemCode); + if (!inventoryItem) return; + + const newQuantity = selectedItem.quantity + change; + + if (newQuantity < 1) { + return; + } + + if (change > 0 && newQuantity > inventoryItem.qty) { + showError(`Not enough stock available for ${selectedItem.name}`); + return; + } + + selectedItem.quantity = newQuantity; + selectedItem.total = selectedItem.quantity * selectedItem.unitPrice; + + updateCartTable(); + updateTotalAmount(); +} + +function updateTotalAmount() { + const total = cartItems.reduce((sum, item) => sum + item.total, 0); + $("#totalAmount").text(`Total: $${total.toFixed(2)}`); + + $("#placeOrderButton").prop('disabled', cartItems.length === 0); +} + +function showToast(message, type = 'success') { + const toast = $('
').addClass('toast').addClass(type); + + const iconClass = type === 'success' ? 'bi-check-circle' : 'bi-exclamation-triangle'; + const toastIcon = $('').addClass(`bi ${iconClass} me-2`); + + const toastContent = $('
').addClass('toast-content'); + const toastTitle = $('
').addClass('fw-semibold mb-1').text( + type === 'success' ? 'Success' : 'Error' + ); + const toastMessage = $('
').addClass('text-secondary small').text(message); + toastContent.append(toastTitle, toastMessage); + + const closeBtn = $(' +
+
+
+
+ + +
+
+
+
+ Shopping Cart +
+
+
+
+ + + + + + + + + + + + + + + + + +
Item CodeNameQuantityUnit PriceTotalAction
+
+ +

Your cart is empty

+ Select items to add to your order +
+
+
+ +
+
+
+ Total: $0.00 +
+
+ +
+
+
+
+
+
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/15_Spring_Security/.gitattributes b/15_Spring_Security/.gitattributes new file mode 100644 index 0000000..3b41682 --- /dev/null +++ b/15_Spring_Security/.gitattributes @@ -0,0 +1,2 @@ +/mvnw text eol=lf +*.cmd text eol=crlf diff --git a/15_Spring_Security/.gitignore b/15_Spring_Security/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/15_Spring_Security/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/15_Spring_Security/.mvn/wrapper/maven-wrapper.properties b/15_Spring_Security/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..d58dfb7 --- /dev/null +++ b/15_Spring_Security/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/15_Spring_Security/mvnw b/15_Spring_Security/mvnw new file mode 100644 index 0000000..19529dd --- /dev/null +++ b/15_Spring_Security/mvnw @@ -0,0 +1,259 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.2 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/15_Spring_Security/mvnw.cmd b/15_Spring_Security/mvnw.cmd new file mode 100644 index 0000000..249bdf3 --- /dev/null +++ b/15_Spring_Security/mvnw.cmd @@ -0,0 +1,149 @@ +<# : batch portion +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.2 +@REM +@REM Optional ENV vars +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output +@REM ---------------------------------------------------------------------------- + +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) +) +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' +$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" +if ($env:MAVEN_USER_HOME) { + $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" +} +$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/15_Spring_Security/pom.xml b/15_Spring_Security/pom.xml new file mode 100644 index 0000000..a1743ab --- /dev/null +++ b/15_Spring_Security/pom.xml @@ -0,0 +1,80 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.3 + + + lk.ijse + Spring_Security + 0.0.1-SNAPSHOT + Spring_Security + Spring_Security + + + + + + + + + + + + + + + 17 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + com.h2database + h2 + runtime + + + + mysql + mysql-connector-java + 8.0.33 + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/15_Spring_Security/src/main/java/lk/ijse/spring_security/SpringSecurityApplicationWork.java b/15_Spring_Security/src/main/java/lk/ijse/spring_security/SpringSecurityApplicationWork.java new file mode 100644 index 0000000..2d4d980 --- /dev/null +++ b/15_Spring_Security/src/main/java/lk/ijse/spring_security/SpringSecurityApplicationWork.java @@ -0,0 +1,13 @@ +package lk.ijse.spring_security; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringSecurityApplicationWork { + + public static void main(String[] args) { + SpringApplication.run(SpringSecurityApplicationWork.class, args); + } + +} diff --git a/15_Spring_Security/src/main/resources/application.properties b/15_Spring_Security/src/main/resources/application.properties new file mode 100644 index 0000000..b912f52 --- /dev/null +++ b/15_Spring_Security/src/main/resources/application.properties @@ -0,0 +1,9 @@ +#spring.datasource.url=jdbc:mysql://localhost:3306/rapotortask +#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +#spring.datasource.username=root +#spring.datasource.password=Ijse@123 +#spring.jpa.hibernate.ddl-auto=update +#spring.jpa.show-sql=true + +spring.security.user.name=Chamath +spring.security.user.password=1234 diff --git a/15_Spring_Security/src/test/java/lk/ijse/spring_security/SpringSecurityApplicationTests.java b/15_Spring_Security/src/test/java/lk/ijse/spring_security/SpringSecurityApplicationTests.java new file mode 100644 index 0000000..3d4eb51 --- /dev/null +++ b/15_Spring_Security/src/test/java/lk/ijse/spring_security/SpringSecurityApplicationTests.java @@ -0,0 +1,13 @@ +package lk.ijse.spring_security; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SpringSecurityApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/LICENSE b/LICENSE index bd47baa..e863350 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Chamath +Copyright (c) 2025 Chamath Dilshan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md new file mode 100644 index 0000000..d1c683b --- /dev/null +++ b/README.md @@ -0,0 +1,375 @@ +# 🛍️ Spring Boot E-Commerce Core API + +
+ +[![Java](https://img.shields.io/badge/Java-17-orange?style=for-the-badge&logo=java)](https://www.oracle.com/java/) +[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.x-brightgreen?style=for-the-badge&logo=spring)](https://spring.io/projects/spring-boot) +[![MySQL](https://img.shields.io/badge/MySQL-8.0%2B-blue?style=for-the-badge&logo=mysql)](https://www.mysql.com/) +[![License](https://img.shields.io/badge/License-MIT-yellow.svg?style=for-the-badge)](LICENSE) + +[Features](#features) • [Installation](#installation) • [API Reference](#api-reference) • [Documentation](#documentation) • [Contributing](#contributing) + +
+ +A modern, scalable e-commerce backend API built with Spring Boot, featuring comprehensive order management, customer tracking, and inventory control. + +## 📊 System Architecture + +```mermaid +graph TD + A[Client Applications] -->|REST API| B[API Gateway] + B --> C[Spring Boot Application] + C --> D[Service Layer] + D --> E[Repository Layer] + E --> F[(MySQL Database)] + + style A fill:#f9a825,stroke:#f57f17,stroke-width:2px + style B fill:#29b6f6,stroke:#0288d1,stroke-width:2px + style C fill:#66bb6a,stroke:#43a047,stroke-width:2px + style D fill:#7e57c2,stroke:#5e35b1,stroke-width:2px + style E fill:#ec407a,stroke:#d81b60,stroke-width:2px + style F fill:#5c6bc0,stroke:#3949ab,stroke-width:2px +``` + +## 📈 Performance Metrics + +```mermaid +pie title API Response Time Distribution + "< 100ms" : 45 + "100-300ms" : 30 + "300-500ms" : 15 + "> 500ms" : 10 +``` + +## ✨ Features + +
+ +| Feature | Description | Status | +|---------|-------------|---------| +| 👥 **Customer Management** | Profile tracking & preferences | ✅ | +| 📦 **Inventory Control** | Real-time stock management | ✅ | +| 🛒 **Order Processing** | Complete order lifecycle | ✅ | +| 🔐 **Security** | JWT Authentication & Authorization | ✅ | +| 📊 **Analytics** | Sales & inventory insights | 🚧 | +| 💳 **Payment Gateway** | Secure payment processing | 🚧 | + +
+ +[Previous content remains the same until Tech Stack section] + +## 🛠️ Tech Stack + +
+ +```mermaid +graph LR + A[Java 17] --> B[Spring Boot 3.x] + B --> C[Spring Data JPA] + B --> D[Spring Security] + C --> E[Hibernate] + E --> F[MySQL] + B --> G[Maven] +``` + +
+ +[Previous installation & setup content remains the same] + +## 📊 API Performance + +```mermaid +gantt + title API Response Times + dateFormat X + axisFormat %s + + section Customer API + GET All :0, 150ms + POST New :0, 200ms + UPDATE :0, 180ms + + section Order API + Create Order :0, 300ms + Get Status :0, 100ms + + section Inventory API + Stock Check :0, 120ms + Update :0, 250ms +``` + +## 🔄 Business Flow + +```mermaid +sequenceDiagram + participant C as Client + participant A as API + participant S as Service + participant D as Database + + C->>A: Place Order + A->>S: Process Order + S->>D: Check Inventory + D-->>S: Inventory Status + S->>D: Update Stock + D-->>S: Confirmation + S-->>A: Order Status + A-->>C: Order Confirmation +``` + +[Previous API Endpoints content remains the same] + +## 📈 System Monitoring + +```mermaid +graph LR + A[API Gateway] -->|Metrics| B[Prometheus] + B -->|Visualization| C[Grafana] + A -->|Logs| D[ELK Stack] + A -->|Traces| E[Jaeger] +``` + +## 🌟 Feature Roadmap + +```mermaid +timeline + title Development Roadmap + 2024 Q1 : Basic E-commerce Features + : Customer Management + : Order Processing + 2024 Q2 : Advanced Features + : Payment Integration + : Analytics Dashboard + 2024 Q3 : Performance Optimization + : Caching Implementation + : Load Balancing + 2024 Q4 : Scale & Security + : Microservices Migration + : Enhanced Security +``` + +[Previous content remains the same until Authors section] + +## 👥 Authors + +
+ +[![GitHub](https://img.shields.io/badge/GitHub-Chamath_Dilshan-black?style=for-the-badge&logo=github)](https://github.com/ChamathDilshanC) +[![LinkedIn](https://img.shields.io/badge/LinkedIn-Chamath_Dilshan-blue?style=for-the-badge&logo=linkedin)](https://www.linkedin.com/in/chamathdilsahnc/) +[![Email](https://img.shields.io/badge/Email-dilshancolonne123%40gmail.com-red?style=for-the-badge&logo=gmail)](mailto:dilshancolonne123@gmail.com) + +
+ +## 📊 Project Statistics + +
+ +![Project Status](https://img.shields.io/badge/Status-Active-success?style=for-the-badge) +![Last Commit](https://img.shields.io/github/last-commit/ChamathDilshanC/spring-boot-ecommerce?style=for-the-badge) +![Issues](https://img.shields.io/github/issues/ChamathDilshanC/spring-boot-ecommerce?style=for-the-badge) +![Pull Requests](https://img.shields.io/github/issues-pr/ChamathDilshanC/spring-boot-ecommerce?style=for-the-badge) + +
+ +--- + +
+ +Made with ❤️ by [Chamath Dilshan](https://github.com/ChamathDilshanC) + +⭐ Star this repository if you find it helpful! + +
+ +## ✨ Features + +- **Customer Management**: Track and manage customer profiles and preferences +- **Inventory Control**: Real-time stock management and updates +- **Order Processing**: Complete order lifecycle management with transaction support +- **RESTful API**: Modern API design following REST principles +- **Security**: Robust authentication and authorization (customizable) +- **Database**: JPA/Hibernate with transaction management +- **Documentation**: Swagger/OpenAPI integration + +## 🚀 Tech Stack + +- **Java 17** +- **Spring Boot 3.x** +- **Spring Data JPA** +- **MySQL Database** +- **Maven** +- **Hibernate** + +## 📋 Prerequisites + +- JDK 17 or later +- Maven 3.6+ +- MySQL 8.0+ +- Your favorite IDE (IntelliJ IDEA recommended) + +## 🛠️ Installation & Setup + +1. **Clone the repository** + ```bash + git clone https://github.com/yourusername/spring-boot-ecommerce.git + cd spring-boot-ecommerce + ``` + +2. **Configure MySQL** + ```properties + # Update application.properties + spring.datasource.url=jdbc:mysql://localhost:3306/ecommerce_db + spring.datasource.username=your_username + spring.datasource.password=your_password + ``` + +3. **Build the project** + ```bash + mvn clean install + ``` + +4. **Run the application** + ```bash + mvn spring-boot:run + ``` + +## 🌐 API Endpoints + +### Customer Management +``` +GET /api/v1/customer - Get all customers +POST /api/v1/customer - Create new customer +PUT /api/v1/customer - Update customer +DELETE /api/v1/customer/{id} - Delete customer +``` + +### Inventory Management +``` +GET /api/v1/item - Get all items +POST /api/v1/item - Add new item +PUT /api/v1/item - Update item +DELETE /api/v1/item/{code} - Delete item +``` + +### Order Management +``` +POST /api/v1/order/save - Create new order +``` + +## 📦 Sample Request Objects + +### Create Order +```json +{ + "orderId": "ORD001", + "orderDate": "2024-02-15T14:30:00", + "customerId": "C001", + "orderDetails": [ + { + "itemCode": "ITM001", + "quantity": 2, + "unitPrice": 1500.00 + } + ], + "total": 3000.00 +} +``` + +## 🛡️ Security Configuration + +Basic configuration is included but should be customized for production: + +```java +@Configuration +@EnableWebSecurity +public class SecurityConfig { + // Add your security configuration here +} +``` + +## 📊 Database Schema + +### Core Tables +- `customer` - Customer information +- `item` - Product inventory +- `orders` - Order headers +- `order_detail` - Order line items + +## 🔧 Project Structure + +``` +src/ +├── main/ +│ ├── java/ +│ │ └── lk.ijse.spring_boot/ +│ │ ├── controller/ +│ │ ├── dto/ +│ │ ├── entity/ +│ │ ├── repo/ +│ │ ├── service/ +│ │ └── Application.java +│ └── resources/ +│ └── application.properties +└── test/ + └── java/ +``` + +## ⚙️ Configuration + +Key application properties: + +```properties +# Server Configuration +server.port=8080 +server.servlet.context-path=/api + +# Database Configuration +spring.jpa.hibernate.ddl-auto=update +spring.jpa.show-sql=true + +# Swagger/OpenAPI +springdoc.api-docs.path=/api-docs +``` + +## 🧪 Testing + +Run tests using Maven: + +```bash +mvn test +``` + +## 📈 Future Improvements + +- [ ] Add payment gateway integration +- [ ] Implement caching +- [ ] Add event-driven architecture +- [ ] Implement rate limiting +- [ ] Add metrics and monitoring +- [ ] Containerize with Docker + +## 🤝 Contributing + +1. Fork the project +2. Create your feature branch +3. Commit your changes +4. Push to the branch +5. Open a Pull Request + +## 📝 License + +This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details. + +## 👥 Authors + +- **Chamath Dilshan** - *Initial work* - [My Github ❤️](https://github.com/ChamathDilshanC) + +## 🙏 Acknowledgments + +- Spring Boot team for the amazing framework +- The open-source community + +## 📧 Contact + +- Email: dilshancolonne123@gmail.com.com +- LinkedIn: [My Linkedin ❤️](https://www.linkedin.com/in/chamathdilsahnc/) diff --git a/Spring.iml b/Spring.iml deleted file mode 100644 index 4ebfb83..0000000 --- a/Spring.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/Z16_Frontend/pom.xml b/Z16_Frontend/pom.xml new file mode 100644 index 0000000..f7a6076 --- /dev/null +++ b/Z16_Frontend/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + lk.ijse + Z16_Frontend + 1.0-SNAPSHOT + + + 22 + 22 + UTF-8 + + + \ No newline at end of file diff --git a/Z16_Frontend/src/main/java/lk/ijse/JQuery/jquery-3.7.1.min.js b/Z16_Frontend/src/main/java/lk/ijse/JQuery/jquery-3.7.1.min.js new file mode 100644 index 0000000..7f37b5d --- /dev/null +++ b/Z16_Frontend/src/main/java/lk/ijse/JQuery/jquery-3.7.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0').addClass('toast').addClass(type); + + const iconClass = type === 'success' ? 'fa-check-circle' : 'fa-exclamation-circle'; + const toastIcon = $('
').addClass('toast-icon').append( + $('').addClass('fas ' + iconClass) + ); + + const toastContent = $('
').addClass('toast-content'); + const toastTitle = $('
').addClass('toast-title').text( + type === 'success' ? 'Success' : 'Error' + ); + const toastMessage = $('
').addClass('toast-message').text(message); + toastContent.append(toastTitle, toastMessage); + + const closeBtn = $(' + +
+ +
+

+ Don't have an account? + Register +

+
+
+
+ + + + + + \ No newline at end of file diff --git a/Z16_Frontend/src/main/java/lk/ijse/register.html b/Z16_Frontend/src/main/java/lk/ijse/register.html new file mode 100644 index 0000000..8806dec --- /dev/null +++ b/Z16_Frontend/src/main/java/lk/ijse/register.html @@ -0,0 +1,118 @@ + + + + + + Modern Sign Up UI + + + + + +
+
+
+
+ + + +
+
+ +

Create Account

+

Enter your details to register

+ +
+
+
+ + + + +
+
+ +
+
+ + + + +
+
+ +
+
+ + + + +
+
+ +
+
+ + + + +
+
+ +
+
+ + +
+
+ + +
+
+ +
+

+ Already have an account? + Sign In +

+
+
+ + + + + + \ No newline at end of file diff --git a/Z16_Frontend/src/main/java/lk/ijse/tailwind.config.js b/Z16_Frontend/src/main/java/lk/ijse/tailwind.config.js new file mode 100644 index 0000000..e69de29 diff --git a/Z16_Frontend/target/classes/lk/ijse/JQuery/jquery-3.7.1.min.js b/Z16_Frontend/target/classes/lk/ijse/JQuery/jquery-3.7.1.min.js new file mode 100644 index 0000000..7f37b5d --- /dev/null +++ b/Z16_Frontend/target/classes/lk/ijse/JQuery/jquery-3.7.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0').addClass('toast').addClass(type); + + const iconClass = type === 'success' ? 'fa-check-circle' : 'fa-exclamation-circle'; + const toastIcon = $('
').addClass('toast-icon').append( + $('').addClass('fas ' + iconClass) + ); + + const toastContent = $('
').addClass('toast-content'); + const toastTitle = $('
').addClass('toast-title').text( + type === 'success' ? 'Success' : 'Error' + ); + const toastMessage = $('
').addClass('toast-message').text(message); + toastContent.append(toastTitle, toastMessage); + + const closeBtn = $(' + +
+ +
+

+ Don't have an account? + Register +

+
+
+
+ + + + + + \ No newline at end of file diff --git a/Z16_Frontend/target/classes/lk/ijse/register.html b/Z16_Frontend/target/classes/lk/ijse/register.html new file mode 100644 index 0000000..8806dec --- /dev/null +++ b/Z16_Frontend/target/classes/lk/ijse/register.html @@ -0,0 +1,118 @@ + + + + + + Modern Sign Up UI + + + + + +
+
+
+
+ + + +
+
+ +

Create Account

+

Enter your details to register

+ +
+
+
+ + + + +
+
+ +
+
+ + + + +
+
+ +
+
+ + + + +
+
+ +
+
+ + + + +
+
+ +
+
+ + +
+
+ + +
+
+ +
+

+ Already have an account? + Sign In +

+
+
+ + + + + + \ No newline at end of file diff --git a/Z16_Frontend/target/classes/lk/ijse/tailwind.config.js b/Z16_Frontend/target/classes/lk/ijse/tailwind.config.js new file mode 100644 index 0000000..e69de29 diff --git a/Z16_springwithjwt-master/.gitattributes b/Z16_springwithjwt-master/.gitattributes new file mode 100644 index 0000000..3b41682 --- /dev/null +++ b/Z16_springwithjwt-master/.gitattributes @@ -0,0 +1,2 @@ +/mvnw text eol=lf +*.cmd text eol=crlf diff --git a/Z16_springwithjwt-master/.gitignore b/Z16_springwithjwt-master/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/Z16_springwithjwt-master/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/Z16_springwithjwt-master/.mvn/wrapper/maven-wrapper.properties b/Z16_springwithjwt-master/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..d58dfb7 --- /dev/null +++ b/Z16_springwithjwt-master/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/Z16_springwithjwt-master/mvnw b/Z16_springwithjwt-master/mvnw new file mode 100644 index 0000000..19529dd --- /dev/null +++ b/Z16_springwithjwt-master/mvnw @@ -0,0 +1,259 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.2 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/Z16_springwithjwt-master/mvnw.cmd b/Z16_springwithjwt-master/mvnw.cmd new file mode 100644 index 0000000..249bdf3 --- /dev/null +++ b/Z16_springwithjwt-master/mvnw.cmd @@ -0,0 +1,149 @@ +<# : batch portion +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.2 +@REM +@REM Optional ENV vars +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output +@REM ---------------------------------------------------------------------------- + +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) +) +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' +$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" +if ($env:MAVEN_USER_HOME) { + $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" +} +$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/Z16_springwithjwt-master/pom.xml b/Z16_springwithjwt-master/pom.xml new file mode 100644 index 0000000..dc909d3 --- /dev/null +++ b/Z16_springwithjwt-master/pom.xml @@ -0,0 +1,116 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.3 + + + org.example + springwithjwt + 0.0.1-SNAPSHOT + springwithjwt + springwithjwt + + + + + + + + + + + + + + + 17 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + + com.mysql + mysql-connector-j + runtime + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + + + + org.modelmapper + modelmapper + 3.1.1 + + + org.projectlombok + lombok + true + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.3.0 + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt.zip b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt.zip new file mode 100644 index 0000000..cf584f0 Binary files /dev/null and b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt.zip differ diff --git a/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/SpringwithjwtApplication.java b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/SpringwithjwtApplication.java new file mode 100644 index 0000000..401f0a0 --- /dev/null +++ b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/SpringwithjwtApplication.java @@ -0,0 +1,19 @@ +package org.example.springwithjwt; + +import org.modelmapper.ModelMapper; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +@SpringBootApplication +public class SpringwithjwtApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringwithjwtApplication.class, args); + } + @Bean + public ModelMapper modelMapper() { + return new ModelMapper(); + } + +} diff --git a/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/config/JwtFilter.java b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/config/JwtFilter.java new file mode 100644 index 0000000..2ac6c3a --- /dev/null +++ b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/config/JwtFilter.java @@ -0,0 +1,77 @@ +package org.example.springwithjwt.config; + + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.example.springwithjwt.service.impl.UserServiceImpl; +import org.example.springwithjwt.util.JwtUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +/** + * @author udarasan + * @TimeStamp 2023-07-15 15:00 + * @ProjectDetails invoice_service + */ +@Component +public class JwtFilter extends OncePerRequestFilter { + @Autowired + private JwtUtil jwtUtil; + @Autowired + private UserServiceImpl userService; + @Value("${jwt.secret}") + private String secretKey; + + @Override + protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { + String authorization = httpServletRequest.getHeader("Authorization"); + String token = null; + String email = null; + + + if (null != authorization && authorization.startsWith("Bearer ")) { + + token = authorization.substring(7); + email = jwtUtil.getUsernameFromToken(token); + Claims claims=jwtUtil.getUserRoleCodeFromToken(token); + httpServletRequest.setAttribute("email", email); + httpServletRequest.setAttribute("role", claims.get("role")); + } + + if (null != email && SecurityContextHolder.getContext().getAuthentication() == null) { + UserDetails userDetails + = userService.loadUserByUsername(email); + + if (jwtUtil.validateToken(token, userDetails)) { + UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken + = new UsernamePasswordAuthenticationToken(userDetails, + null, userDetails.getAuthorities()); + + usernamePasswordAuthenticationToken.setDetails( + new WebAuthenticationDetailsSource().buildDetails(httpServletRequest) + ); + + SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); + } + + } + filterChain.doFilter(httpServletRequest, httpServletResponse); + } + + private Claims getClaimsFromJwtToken(String token) { + return Jwts.parser().setSigningKey(secretKey.getBytes()).parseClaimsJws(token).getBody(); + } + +} diff --git a/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/config/WebSecurityConfig.java b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/config/WebSecurityConfig.java new file mode 100644 index 0000000..ea8e888 --- /dev/null +++ b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/config/WebSecurityConfig.java @@ -0,0 +1,68 @@ +package org.example.springwithjwt.config; + +import org.example.springwithjwt.service.impl.UserServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + + +/** + * @author udarasan + * @TimeStamp 2023-07-15 15:00 + * @ProjectDetails invoice_service + */ + +@EnableWebSecurity +@Configuration +@EnableMethodSecurity(prePostEnabled = true) +public class WebSecurityConfig { + @Autowired + private UserServiceImpl userService; + @Autowired + private JwtFilter jwtFilter; + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userService).passwordEncoder(passwordEncoder()); + } + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) + throws Exception { + return authenticationConfiguration.getAuthenticationManager(); + } + @Bean + protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + return http + .csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests(auth -> auth + .requestMatchers( + "/api/v1/auth/authenticate", + "/api/v1/user/register", + "/api/v1/auth/refreshToken", + "/v3/api-docs/**", + "/swagger-ui/**", + "/swagger-ui.html").permitAll() + .anyRequest().authenticated() + ) + .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class) + .build(); + } + + +} diff --git a/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/controller/AdminController.java b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/controller/AdminController.java new file mode 100644 index 0000000..bd88b42 --- /dev/null +++ b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/controller/AdminController.java @@ -0,0 +1,28 @@ +package org.example.springwithjwt.controller; + +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("api/v1/admin") +public class AdminController { + @GetMapping("/test1") + @PreAuthorize("hasAuthority('ADMIN')") + public String check(){ + return "passed~!1"; + } + + @GetMapping("/test2") + @PreAuthorize("hasAuthority('USER')") + public String checks(){ + return "passed~!2"; + } + @GetMapping("/test3") + @PreAuthorize("hasAuthority('USER')") + public String checkss(){ + return "passed~!2"; + } + +} diff --git a/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/controller/AuthController.java b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/controller/AuthController.java new file mode 100644 index 0000000..c5d8e33 --- /dev/null +++ b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/controller/AuthController.java @@ -0,0 +1,65 @@ +package org.example.springwithjwt.controller; + + +import org.example.springwithjwt.dto.AuthDTO; +import org.example.springwithjwt.dto.ResponseDTO; +import org.example.springwithjwt.dto.UserDTO; +import org.example.springwithjwt.service.impl.UserServiceImpl; +import org.example.springwithjwt.util.JwtUtil; +import org.example.springwithjwt.util.VarList; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("api/v1/auth") +@CrossOrigin +public class AuthController { + + private final JwtUtil jwtUtil; + private final AuthenticationManager authenticationManager; + private final UserServiceImpl userService; + private final ResponseDTO responseDTO; + + //constructor injection + public AuthController(JwtUtil jwtUtil, AuthenticationManager authenticationManager, UserServiceImpl userService, ResponseDTO responseDTO) { + this.jwtUtil = jwtUtil; + this.authenticationManager = authenticationManager; + this.userService = userService; + this.responseDTO = responseDTO; + } + + @PostMapping("/authenticate") + public ResponseEntity authenticate(@RequestBody UserDTO userDTO) { + try { + authenticationManager.authenticate( + new UsernamePasswordAuthenticationToken(userDTO.getEmail(), userDTO.getPassword())); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body(new ResponseDTO(VarList.Unauthorized, "Invalid Credentials", e.getMessage())); + } + + UserDTO loadedUser = userService.loadUserDetailsByUsername(userDTO.getEmail()); + if (loadedUser == null) { + return ResponseEntity.status(HttpStatus.CONFLICT) + .body(new ResponseDTO(VarList.Conflict, "Authorization Failure! Please Try Again", null)); + } + + String token = jwtUtil.generateToken(loadedUser); + if (token == null || token.isEmpty()) { + return ResponseEntity.status(HttpStatus.CONFLICT) + .body(new ResponseDTO(VarList.Conflict, "Authorization Failure! Please Try Again", null)); + } + + AuthDTO authDTO = new AuthDTO(); + authDTO.setEmail(loadedUser.getEmail()); + authDTO.setToken(token); + + return ResponseEntity.status(HttpStatus.CREATED) + .body(new ResponseDTO(VarList.Created, "Success", authDTO)); + } + +} + diff --git a/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/controller/UserController.java b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/controller/UserController.java new file mode 100644 index 0000000..f94afb1 --- /dev/null +++ b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/controller/UserController.java @@ -0,0 +1,54 @@ +package org.example.springwithjwt.controller; + +import jakarta.validation.Valid; +import org.example.springwithjwt.dto.AuthDTO; +import org.example.springwithjwt.dto.ResponseDTO; +import org.example.springwithjwt.dto.UserDTO; +import org.example.springwithjwt.service.UserService; +import org.example.springwithjwt.util.JwtUtil; +import org.example.springwithjwt.util.VarList; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("api/v1/user") +@CrossOrigin +public class UserController { + private final UserService userService; + private final JwtUtil jwtUtil; + + //constructor injection + public UserController(UserService userService, JwtUtil jwtUtil) { + this.userService = userService; + this.jwtUtil = jwtUtil; + } + @PostMapping(value = "/register") + public ResponseEntity registerUser(@RequestBody @Valid UserDTO userDTO) { + try { + int res = userService.saveUser(userDTO); + switch (res) { + case VarList.Created -> { + String token = jwtUtil.generateToken(userDTO); + AuthDTO authDTO = new AuthDTO(); + authDTO.setEmail(userDTO.getEmail()); + authDTO.setToken(token); + return ResponseEntity.status(HttpStatus.CREATED) + .body(new ResponseDTO(VarList.Created, "Success", authDTO)); + } + case VarList.Not_Acceptable -> { + return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE) + .body(new ResponseDTO(VarList.Not_Acceptable, "Email Already Used", null)); + } + default -> { + return ResponseEntity.status(HttpStatus.BAD_GATEWAY) + .body(new ResponseDTO(VarList.Bad_Gateway, "Error", null)); + } + } + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(new ResponseDTO(VarList.Internal_Server_Error, e.getMessage(), null)); + } + } + +} diff --git a/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/dto/AuthDTO.java b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/dto/AuthDTO.java new file mode 100644 index 0000000..fa41445 --- /dev/null +++ b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/dto/AuthDTO.java @@ -0,0 +1,18 @@ +package org.example.springwithjwt.dto; + +import jakarta.validation.constraints.Email; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.stereotype.Component; + + +@AllArgsConstructor +@NoArgsConstructor +@Data +@Component +public class AuthDTO { + @Email + private String email; + private String token; +} \ No newline at end of file diff --git a/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/dto/ResponseDTO.java b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/dto/ResponseDTO.java new file mode 100644 index 0000000..972ad98 --- /dev/null +++ b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/dto/ResponseDTO.java @@ -0,0 +1,17 @@ +package org.example.springwithjwt.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.stereotype.Component; + + +@AllArgsConstructor +@NoArgsConstructor +@Data +@Component +public class ResponseDTO { + private int code; + private String message; + private Object data; +} diff --git a/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/dto/UserDTO.java b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/dto/UserDTO.java new file mode 100644 index 0000000..e8f1112 --- /dev/null +++ b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/dto/UserDTO.java @@ -0,0 +1,16 @@ +package org.example.springwithjwt.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@AllArgsConstructor +@NoArgsConstructor +@Data +public class UserDTO { + private String email; + private String password; + private String name; + private String role; +} diff --git a/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/entity/User.java b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/entity/User.java new file mode 100644 index 0000000..d9047b9 --- /dev/null +++ b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/entity/User.java @@ -0,0 +1,26 @@ +package org.example.springwithjwt.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.UUID; + + +@Entity +@Table(name = "systemuser") +@AllArgsConstructor +@NoArgsConstructor +@Data +public class User implements Serializable { + @Id + @GeneratedValue(strategy = GenerationType.UUID) + private UUID uid; + @Column(unique = true) + private String email; + private String password; + private String name; + private String role; +} \ No newline at end of file diff --git a/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/repo/UserRepository.java b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/repo/UserRepository.java new file mode 100644 index 0000000..a3131ad --- /dev/null +++ b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/repo/UserRepository.java @@ -0,0 +1,15 @@ +package org.example.springwithjwt.repo; + +import org.example.springwithjwt.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; + + +public interface UserRepository extends JpaRepository { + + User findByEmail(String userName); + + boolean existsByEmail(String userName); + + int deleteByEmail(String userName); + +} \ No newline at end of file diff --git a/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/service/UserService.java b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/service/UserService.java new file mode 100644 index 0000000..f0edeec --- /dev/null +++ b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/service/UserService.java @@ -0,0 +1,10 @@ +package org.example.springwithjwt.service; + + +import org.example.springwithjwt.dto.UserDTO; + + +public interface UserService { + int saveUser(UserDTO userDTO); + UserDTO searchUser(String username); +} \ No newline at end of file diff --git a/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/service/impl/UserServiceImpl.java b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..f5f7df7 --- /dev/null +++ b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/service/impl/UserServiceImpl.java @@ -0,0 +1,69 @@ +package org.example.springwithjwt.service.impl; + +import org.example.springwithjwt.dto.UserDTO; +import org.example.springwithjwt.entity.User; +import org.example.springwithjwt.repo.UserRepository; +import org.example.springwithjwt.service.UserService; +import org.example.springwithjwt.util.VarList; +import org.modelmapper.ModelMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.HashSet; +import java.util.Set; + + +@Service +@Transactional +public class UserServiceImpl implements UserDetailsService, UserService { + + @Autowired + private UserRepository userRepository; + + @Autowired + private ModelMapper modelMapper; + + @Override + public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { + User user = userRepository.findByEmail(email); + return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), getAuthority(user)); + } + + public UserDTO loadUserDetailsByUsername(String username) throws UsernameNotFoundException { + User user = userRepository.findByEmail(username); + return modelMapper.map(user,UserDTO.class); + } + + private Set getAuthority(User user) { + Set authorities = new HashSet<>(); + authorities.add(new SimpleGrantedAuthority(user.getRole())); + return authorities; + } + + @Override + public UserDTO searchUser(String username) { + if (userRepository.existsByEmail(username)) { + User user=userRepository.findByEmail(username); + return modelMapper.map(user,UserDTO.class); + } else { + return null; + } + } + + @Override + public int saveUser(UserDTO userDTO) { + if (userRepository.existsByEmail(userDTO.getEmail())) { + return VarList.Not_Acceptable; + } else { + BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + userDTO.setPassword(passwordEncoder.encode(userDTO.getPassword())); + userRepository.save(modelMapper.map(userDTO, User.class)); + return VarList.Created; + } + }} diff --git a/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/util/JwtUtil.java b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/util/JwtUtil.java new file mode 100644 index 0000000..346bb9d --- /dev/null +++ b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/util/JwtUtil.java @@ -0,0 +1,89 @@ +package org.example.springwithjwt.util; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.example.springwithjwt.dto.UserDTO; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.PropertySource; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + + +@Component +@PropertySource(ignoreResourceNotFound = true, value = "classpath:otherprops.properties") +public class JwtUtil implements Serializable { + + private static final long serialVersionUID = 234234523523L; + + public static final long JWT_TOKEN_VALIDITY = 24 * 60 * 60 * 12; + + @Value("${jwt.secret}") + private String secretKey; + + //retrieve username from jwt token + public String getUsernameFromToken(String token) { + return getClaimFromToken(token, Claims::getSubject); + } + + public Claims getUserRoleCodeFromToken(String token) { + return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody(); + } + + //retrieve expiration date from jwt token + public Date getExpirationDateFromToken(String token) { + return getClaimFromToken(token, Claims::getExpiration); + } + + + public T getClaimFromToken(String token, Function claimsResolver) { + final Claims claims = getAllClaimsFromToken(token); + return claimsResolver.apply(claims); + } + + + //for retrieving any information from token we will need the secret key + private Claims getAllClaimsFromToken(String token) { + return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody(); + } + + + //check if the token has expired + private Boolean isTokenExpired(String token) { + final Date expiration = getExpirationDateFromToken(token); + return expiration.before(new Date()); + } + + + //generate token for user + public String generateToken(UserDTO userDTO) { + Map claims = new HashMap<>(); + claims.put("role",userDTO.getRole()); + return doGenerateToken(claims, userDTO.getEmail()); + } + + //while creating the token - + //1. Define claims of the token, like Issuer, Expiration, Subject, and the ID + //2. Sign the JWT using the HS512 algorithm and secret key. + private String doGenerateToken(Map claims, String subject) { + return Jwts.builder() + .setClaims(claims) + .setSubject(subject) + .setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000)) + .signWith(SignatureAlgorithm.HS512, secretKey).compact(); + } + + + //validate token + public Boolean validateToken(String token, UserDetails userDetails) { + final String username = getUsernameFromToken(token); + return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); + } +} diff --git a/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/util/VarList.java b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/util/VarList.java new file mode 100644 index 0000000..8e5e4a1 --- /dev/null +++ b/Z16_springwithjwt-master/src/main/java/org/example/springwithjwt/util/VarList.java @@ -0,0 +1,58 @@ +package org.example.springwithjwt.util; + +public class VarList { + public static final int Continue = 100; + public static final int Switching_Protocols = 101; + public static final int Early_Hints = 103; + public static final int OK = 200; + public static final int Created = 201; + public static final int Accepted = 202; + public static final int Non_Authoritative_Information = 203; + public static final int No_Content = 204; + public static final int Reset_Content = 205; + public static final int Partial_Content = 206; + public static final int Multiple_Choices = 300; + public static final int Moved_Permanently = 301; + public static final int Found = 302; + public static final int See_Other = 303; + public static final int Not_Modified = 304; + public static final int Temporary_Redirect = 307; + public static final int Permanent_Redirect = 308; + public static final int Bad_Request = 400; + public static final int Unauthorized = 401; + public static final int Payment_Required = 402; + public static final int Forbidden = 403; + public static final int Not_Found = 404; + public static final int Method_Not_Allowed = 405; + public static final int Not_Acceptable = 406; + public static final int Proxy_Authentication_Required = 407; + public static final int Request_Timeout = 408; + public static final int Conflict = 409; + public static final int Gone = 410; + public static final int Length_Required = 411; + public static final int Precondition_Failed = 412; + public static final int Payload_Too_Large = 413; + public static final int URI_Too_Long = 414; + public static final int Unsupported_Media_Type = 415; + public static final int Range_Not_Satisfiable = 416; + public static final int Expectation_Failed = 417; + public static final int I_m_a_teapot = 418; + public static final int Unprocessable_Entity = 422; + public static final int Too_Early = 425; + public static final int Upgrade_Required = 426; + public static final int Precondition_Required = 428; + public static final int Too_Many_Requests = 429; + public static final int Request_Header_Fields_Too_Large = 431; + public static final int Unavailable_For_Legal_Reasons = 451; + public static final int Internal_Server_Error = 500; + public static final int Not_Implemented = 501; + public static final int Bad_Gateway = 502; + public static final int Service_Unavailable = 503; + public static final int Gateway_Timeout = 504; + public static final int HTTP_Version_Not_Supported = 505; + public static final int Variant_Also_Negotiates = 506; + public static final int Insufficient_Storage = 507; + public static final int Loop_Detected = 508; + public static final int Not_Extended = 510; + public static final int Network_Authentication_Required = 511; +} diff --git a/Z16_springwithjwt-master/src/main/resources/application.properties b/Z16_springwithjwt-master/src/main/resources/application.properties new file mode 100644 index 0000000..2d4aaad --- /dev/null +++ b/Z16_springwithjwt-master/src/main/resources/application.properties @@ -0,0 +1,12 @@ +spring.application.name=springwithjwt +spring.datasource.url = jdbc:mysql://localhost:3306/rapotortask?createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true&useSSL=false +spring.datasource.username=root +spring.datasource.password =Ijse@123 +spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL8Dialect +spring.jpa.hibernate.ddl-auto = update +spring.datasource.driver-class-name =com.mysql.cj.jdbc.Driver +spring.jpa.open-in-view=false +spring.jpa.show-sql= true +jwt.secret=2D4A614E645267556B58703273357638792F423F4428472B4B6250655368566DF423F4428472B4B6250655368566D +spring.main.allow-bean-definition-overriding=true +server.port=8080 \ No newline at end of file diff --git a/Z16_springwithjwt-master/src/test/java/org/example/springwithjwt/SpringwithjwtApplicationTests.java b/Z16_springwithjwt-master/src/test/java/org/example/springwithjwt/SpringwithjwtApplicationTests.java new file mode 100644 index 0000000..00011cd --- /dev/null +++ b/Z16_springwithjwt-master/src/test/java/org/example/springwithjwt/SpringwithjwtApplicationTests.java @@ -0,0 +1,13 @@ +package org.example.springwithjwt; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SpringwithjwtApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/Z17_Springboot_Bean_Validation/.gitattributes b/Z17_Springboot_Bean_Validation/.gitattributes new file mode 100644 index 0000000..3b41682 --- /dev/null +++ b/Z17_Springboot_Bean_Validation/.gitattributes @@ -0,0 +1,2 @@ +/mvnw text eol=lf +*.cmd text eol=crlf diff --git a/Z17_Springboot_Bean_Validation/.gitignore b/Z17_Springboot_Bean_Validation/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/Z17_Springboot_Bean_Validation/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/Z17_Springboot_Bean_Validation/.mvn/wrapper/maven-wrapper.properties b/Z17_Springboot_Bean_Validation/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..d58dfb7 --- /dev/null +++ b/Z17_Springboot_Bean_Validation/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/Z17_Springboot_Bean_Validation/mvnw b/Z17_Springboot_Bean_Validation/mvnw new file mode 100644 index 0000000..19529dd --- /dev/null +++ b/Z17_Springboot_Bean_Validation/mvnw @@ -0,0 +1,259 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.2 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/Z17_Springboot_Bean_Validation/mvnw.cmd b/Z17_Springboot_Bean_Validation/mvnw.cmd new file mode 100644 index 0000000..249bdf3 --- /dev/null +++ b/Z17_Springboot_Bean_Validation/mvnw.cmd @@ -0,0 +1,149 @@ +<# : batch portion +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.2 +@REM +@REM Optional ENV vars +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output +@REM ---------------------------------------------------------------------------- + +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) +) +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' +$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" +if ($env:MAVEN_USER_HOME) { + $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" +} +$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/Z17_Springboot_Bean_Validation/pom.xml b/Z17_Springboot_Bean_Validation/pom.xml new file mode 100644 index 0000000..108c4c2 --- /dev/null +++ b/Z17_Springboot_Bean_Validation/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.3 + + + lk.ijse + Z17_Springboot_Bean_Validation + 0.0.1-SNAPSHOT + Z17_Springboot_Bean_Validation + Z17_Springboot_Bean_Validation + + + + + + + + + + + + + + + 21 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-validation + 3.4.1 + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/Z17_Springboot_Bean_Validation/src/main/java/lk/ijse/z17_springboot_bean_validation/Advice/GlobalExceptionHandler.java b/Z17_Springboot_Bean_Validation/src/main/java/lk/ijse/z17_springboot_bean_validation/Advice/GlobalExceptionHandler.java new file mode 100644 index 0000000..3a3ea00 --- /dev/null +++ b/Z17_Springboot_Bean_Validation/src/main/java/lk/ijse/z17_springboot_bean_validation/Advice/GlobalExceptionHandler.java @@ -0,0 +1,24 @@ +package lk.ijse.z17_springboot_bean_validation.Advice; + +import lk.ijse.z17_springboot_bean_validation.DTO.ResponseDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.HashMap; +import java.util.Map; + +@RestControllerAdvice +public class GlobalExceptionHandler { + @ExceptionHandler(MethodArgumentNotValidException.class) + private ResponseEntity handleException(Exception e) { + Map errors = new HashMap<>(); + for (FieldError fieldError : ((MethodArgumentNotValidException) e).getBindingResult().getFieldErrors()) { + errors.put(fieldError.getField(), fieldError.getDefaultMessage()); + } + ResponseDTO responseDTO = new ResponseDTO(401, "Validation Error", errors); + return new ResponseEntity<>(responseDTO, org.springframework.http.HttpStatus.BAD_REQUEST); + } +} diff --git a/Z17_Springboot_Bean_Validation/src/main/java/lk/ijse/z17_springboot_bean_validation/Controller/CustomerController.java b/Z17_Springboot_Bean_Validation/src/main/java/lk/ijse/z17_springboot_bean_validation/Controller/CustomerController.java new file mode 100644 index 0000000..c8d461d --- /dev/null +++ b/Z17_Springboot_Bean_Validation/src/main/java/lk/ijse/z17_springboot_bean_validation/Controller/CustomerController.java @@ -0,0 +1,23 @@ +package lk.ijse.z17_springboot_bean_validation.Controller; + +import jakarta.validation.Valid; +import lk.ijse.z17_springboot_bean_validation.DTO.CustomerDTO; +import lk.ijse.z17_springboot_bean_validation.DTO.ResponseDTO; +import org.springframework.http.HttpStatus; +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.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("api/v1/customer/") +public class CustomerController { + + @PostMapping("save") + public ResponseEntity saveCustomer(@Valid @RequestBody CustomerDTO customerDTO) { + ResponseDTO responseDTO = new ResponseDTO(200, "Customer Saved Successfully", customerDTO); + return new ResponseEntity<>(responseDTO, HttpStatus.OK); + + } +} diff --git a/Z17_Springboot_Bean_Validation/src/main/java/lk/ijse/z17_springboot_bean_validation/DTO/CustomerDTO.java b/Z17_Springboot_Bean_Validation/src/main/java/lk/ijse/z17_springboot_bean_validation/DTO/CustomerDTO.java new file mode 100644 index 0000000..1834bc0 --- /dev/null +++ b/Z17_Springboot_Bean_Validation/src/main/java/lk/ijse/z17_springboot_bean_validation/DTO/CustomerDTO.java @@ -0,0 +1,53 @@ +package lk.ijse.z17_springboot_bean_validation.DTO; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import org.springframework.boot.context.properties.bind.Name; + +public class CustomerDTO { + @Name("name") + @Size(min = 3, max = 20, message = "Name should be between 3 and 20 characters") + @NotBlank(message = "Name is mandatory") + @Pattern(regexp = "^[a-zA-Z]*$", message = "Invalid Name") + private String name; + @Email(message = "Invalid Email") + @Pattern(regexp = "^[a-zA-Z0-9+_.-]+@[a-zA-Z0-9.-]+$", message = "Invalid Email") + private String email; + @Pattern(regexp = "^[0-9]*$", message = "Invalid Phone Number") + private String phone; + + public CustomerDTO(String email, String name, String phone) { + this.email = email; + this.name = name; + this.phone = phone; + } + + public CustomerDTO() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } +} diff --git a/Z17_Springboot_Bean_Validation/src/main/java/lk/ijse/z17_springboot_bean_validation/DTO/ResponseDTO.java b/Z17_Springboot_Bean_Validation/src/main/java/lk/ijse/z17_springboot_bean_validation/DTO/ResponseDTO.java new file mode 100644 index 0000000..9cdf1f3 --- /dev/null +++ b/Z17_Springboot_Bean_Validation/src/main/java/lk/ijse/z17_springboot_bean_validation/DTO/ResponseDTO.java @@ -0,0 +1,41 @@ +package lk.ijse.z17_springboot_bean_validation.DTO; + +public class ResponseDTO { + private int status; + private String message; + private Object data; + + + public ResponseDTO(int status, String message, Object data) { + this.status = status; + this.message = message; + this.data = data; + } + + public ResponseDTO() { + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/Z17_Springboot_Bean_Validation/src/main/java/lk/ijse/z17_springboot_bean_validation/Z17SpringbootBeanValidationApplication.java b/Z17_Springboot_Bean_Validation/src/main/java/lk/ijse/z17_springboot_bean_validation/Z17SpringbootBeanValidationApplication.java new file mode 100644 index 0000000..eea668a --- /dev/null +++ b/Z17_Springboot_Bean_Validation/src/main/java/lk/ijse/z17_springboot_bean_validation/Z17SpringbootBeanValidationApplication.java @@ -0,0 +1,13 @@ +package lk.ijse.z17_springboot_bean_validation; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Z17SpringbootBeanValidationApplication { + + public static void main(String[] args) { + SpringApplication.run(Z17SpringbootBeanValidationApplication.class, args); + } + +} diff --git a/Z17_Springboot_Bean_Validation/src/main/resources/application.properties b/Z17_Springboot_Bean_Validation/src/main/resources/application.properties new file mode 100644 index 0000000..8314ede --- /dev/null +++ b/Z17_Springboot_Bean_Validation/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.application.name=Z17_Springboot_Bean_Validation diff --git a/Z17_Springboot_Bean_Validation/src/test/java/lk/ijse/z17_springboot_bean_validation/Z17SpringbootBeanValidationApplicationTests.java b/Z17_Springboot_Bean_Validation/src/test/java/lk/ijse/z17_springboot_bean_validation/Z17SpringbootBeanValidationApplicationTests.java new file mode 100644 index 0000000..e6f0591 --- /dev/null +++ b/Z17_Springboot_Bean_Validation/src/test/java/lk/ijse/z17_springboot_bean_validation/Z17SpringbootBeanValidationApplicationTests.java @@ -0,0 +1,13 @@ +package lk.ijse.z17_springboot_bean_validation; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class Z17SpringbootBeanValidationApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/Z18_Springboot_Logins.log b/Z18_Springboot_Logins.log new file mode 100644 index 0000000..3753b31 --- /dev/null +++ b/Z18_Springboot_Logins.log @@ -0,0 +1,60 @@ +2025-03-07T11:32:27.580+05:30 INFO 8648 --- [Z18_Springboot_Logins] [main] l.i.z.Z18SpringbootLoginsApplication : Starting Z18SpringbootLoginsApplication using Java 21.0.2 with PID 8648 (C:\Users\dilsh\Desktop\Spring-Framework\Z18_Springboot_Logins\target\classes started by Chamath in C:\Users\dilsh\Desktop\Spring-Framework) +2025-03-07T11:32:27.584+05:30 INFO 8648 --- [Z18_Springboot_Logins] [main] l.i.z.Z18SpringbootLoginsApplication : No active profile set, falling back to 1 default profile: "default" +2025-03-07T11:32:28.928+05:30 INFO 8648 --- [Z18_Springboot_Logins] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) +2025-03-07T11:32:28.946+05:30 INFO 8648 --- [Z18_Springboot_Logins] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2025-03-07T11:32:28.947+05:30 INFO 8648 --- [Z18_Springboot_Logins] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.36] +2025-03-07T11:32:29.010+05:30 INFO 8648 --- [Z18_Springboot_Logins] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2025-03-07T11:32:29.011+05:30 INFO 8648 --- [Z18_Springboot_Logins] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1361 ms +2025-03-07T11:32:29.211+05:30 DEBUG 8648 --- [Z18_Springboot_Logins] [main] s.w.s.m.m.a.RequestMappingHandlerMapping : 3 mappings in 'requestMappingHandlerMapping' +2025-03-07T11:32:29.267+05:30 DEBUG 8648 --- [Z18_Springboot_Logins] [main] o.s.w.s.handler.SimpleUrlHandlerMapping : Patterns [/webjars/**, /**] in 'resourceHandlerMapping' +2025-03-07T11:32:29.295+05:30 DEBUG 8648 --- [Z18_Springboot_Logins] [main] s.w.s.m.m.a.RequestMappingHandlerAdapter : ControllerAdvice beans: 0 @ModelAttribute, 0 @InitBinder, 1 RequestBodyAdvice, 1 ResponseBodyAdvice +2025-03-07T11:32:29.338+05:30 DEBUG 8648 --- [Z18_Springboot_Logins] [main] .m.m.a.ExceptionHandlerExceptionResolver : ControllerAdvice beans: 0 @ExceptionHandler, 1 ResponseBodyAdvice +2025-03-07T11:32:29.435+05:30 INFO 8648 --- [Z18_Springboot_Logins] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' +2025-03-07T11:32:29.444+05:30 INFO 8648 --- [Z18_Springboot_Logins] [main] l.i.z.Z18SpringbootLoginsApplication : Started Z18SpringbootLoginsApplication in 2.503 seconds (process running for 3.33) +2025-03-07T11:33:04.990+05:30 INFO 8648 --- [Z18_Springboot_Logins] [SpringApplicationShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete +2025-03-07T11:33:04.995+05:30 INFO 8648 --- [Z18_Springboot_Logins] [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown : Graceful shutdown complete +2025-03-07T11:33:08.837+05:30 INFO 6712 --- [Z18_Springboot_Logins] [main] l.i.z.Z18SpringbootLoginsApplication : Starting Z18SpringbootLoginsApplication using Java 21.0.2 with PID 6712 (C:\Users\dilsh\Desktop\Spring-Framework\Z18_Springboot_Logins\target\classes started by Chamath in C:\Users\dilsh\Desktop\Spring-Framework) +2025-03-07T11:33:08.841+05:30 INFO 6712 --- [Z18_Springboot_Logins] [main] l.i.z.Z18SpringbootLoginsApplication : No active profile set, falling back to 1 default profile: "default" +2025-03-07T11:33:10.097+05:30 INFO 6712 --- [Z18_Springboot_Logins] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) +2025-03-07T11:33:10.114+05:30 INFO 6712 --- [Z18_Springboot_Logins] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2025-03-07T11:33:10.114+05:30 INFO 6712 --- [Z18_Springboot_Logins] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.36] +2025-03-07T11:33:10.169+05:30 INFO 6712 --- [Z18_Springboot_Logins] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2025-03-07T11:33:10.170+05:30 INFO 6712 --- [Z18_Springboot_Logins] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1261 ms +2025-03-07T11:33:10.331+05:30 DEBUG 6712 --- [Z18_Springboot_Logins] [main] s.w.s.m.m.a.RequestMappingHandlerMapping : 3 mappings in 'requestMappingHandlerMapping' +2025-03-07T11:33:10.387+05:30 DEBUG 6712 --- [Z18_Springboot_Logins] [main] o.s.w.s.handler.SimpleUrlHandlerMapping : Patterns [/webjars/**, /**] in 'resourceHandlerMapping' +2025-03-07T11:33:10.413+05:30 DEBUG 6712 --- [Z18_Springboot_Logins] [main] s.w.s.m.m.a.RequestMappingHandlerAdapter : ControllerAdvice beans: 0 @ModelAttribute, 0 @InitBinder, 1 RequestBodyAdvice, 1 ResponseBodyAdvice +2025-03-07T11:33:10.451+05:30 DEBUG 6712 --- [Z18_Springboot_Logins] [main] .m.m.a.ExceptionHandlerExceptionResolver : ControllerAdvice beans: 0 @ExceptionHandler, 1 ResponseBodyAdvice +2025-03-07T11:33:10.550+05:30 INFO 6712 --- [Z18_Springboot_Logins] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' +2025-03-07T11:33:10.558+05:30 INFO 6712 --- [Z18_Springboot_Logins] [main] l.i.z.Z18SpringbootLoginsApplication : Started Z18SpringbootLoginsApplication in 2.356 seconds (process running for 3.195) +2025-03-07T11:34:26.953+05:30 INFO 6712 --- [Z18_Springboot_Logins] [SpringApplicationShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete +2025-03-07T11:34:26.958+05:30 INFO 6712 --- [Z18_Springboot_Logins] [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown : Graceful shutdown complete +2025-03-07T11:34:30.045+05:30 INFO 16192 --- [Z18_Springboot_Logins] [main] l.i.z.Z18SpringbootLoginsApplication : Starting Z18SpringbootLoginsApplication using Java 21.0.2 with PID 16192 (C:\Users\dilsh\Desktop\Spring-Framework\Z18_Springboot_Logins\target\classes started by Chamath in C:\Users\dilsh\Desktop\Spring-Framework) +2025-03-07T11:34:30.048+05:30 INFO 16192 --- [Z18_Springboot_Logins] [main] l.i.z.Z18SpringbootLoginsApplication : No active profile set, falling back to 1 default profile: "default" +2025-03-07T11:34:31.310+05:30 INFO 16192 --- [Z18_Springboot_Logins] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) +2025-03-07T11:34:31.328+05:30 INFO 16192 --- [Z18_Springboot_Logins] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2025-03-07T11:34:31.329+05:30 INFO 16192 --- [Z18_Springboot_Logins] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.36] +2025-03-07T11:34:31.389+05:30 INFO 16192 --- [Z18_Springboot_Logins] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2025-03-07T11:34:31.390+05:30 INFO 16192 --- [Z18_Springboot_Logins] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1281 ms +2025-03-07T11:34:31.620+05:30 DEBUG 16192 --- [Z18_Springboot_Logins] [main] s.w.s.m.m.a.RequestMappingHandlerMapping : 3 mappings in 'requestMappingHandlerMapping' +2025-03-07T11:34:31.693+05:30 DEBUG 16192 --- [Z18_Springboot_Logins] [main] o.s.w.s.handler.SimpleUrlHandlerMapping : Patterns [/webjars/**, /**] in 'resourceHandlerMapping' +2025-03-07T11:34:31.718+05:30 DEBUG 16192 --- [Z18_Springboot_Logins] [main] s.w.s.m.m.a.RequestMappingHandlerAdapter : ControllerAdvice beans: 0 @ModelAttribute, 0 @InitBinder, 1 RequestBodyAdvice, 1 ResponseBodyAdvice +2025-03-07T11:34:31.756+05:30 DEBUG 16192 --- [Z18_Springboot_Logins] [main] .m.m.a.ExceptionHandlerExceptionResolver : ControllerAdvice beans: 0 @ExceptionHandler, 1 ResponseBodyAdvice +2025-03-07T11:34:31.857+05:30 INFO 16192 --- [Z18_Springboot_Logins] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' +2025-03-07T11:34:31.863+05:30 INFO 16192 --- [Z18_Springboot_Logins] [main] l.i.z.Z18SpringbootLoginsApplication : Started Z18SpringbootLoginsApplication in 2.465 seconds (process running for 3.365) +2025-03-07T11:35:51.624+05:30 INFO 16192 --- [Z18_Springboot_Logins] [SpringApplicationShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete +2025-03-07T11:35:51.635+05:30 INFO 16192 --- [Z18_Springboot_Logins] [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown : Graceful shutdown complete +2025-03-07T11:35:57.909+05:30 INFO 13432 --- [Z18_Springboot_Logins] [main] l.i.z.Z18SpringbootLoginsApplication : Starting Z18SpringbootLoginsApplication using Java 21.0.2 with PID 13432 (C:\Users\dilsh\Desktop\Spring-Framework\Z18_Springboot_Logins\target\classes started by Chamath in C:\Users\dilsh\Desktop\Spring-Framework) +2025-03-07T11:35:57.912+05:30 INFO 13432 --- [Z18_Springboot_Logins] [main] l.i.z.Z18SpringbootLoginsApplication : No active profile set, falling back to 1 default profile: "default" +2025-03-07T11:35:59.159+05:30 INFO 13432 --- [Z18_Springboot_Logins] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) +2025-03-07T11:35:59.179+05:30 INFO 13432 --- [Z18_Springboot_Logins] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2025-03-07T11:35:59.180+05:30 INFO 13432 --- [Z18_Springboot_Logins] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.36] +2025-03-07T11:35:59.246+05:30 INFO 13432 --- [Z18_Springboot_Logins] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2025-03-07T11:35:59.246+05:30 INFO 13432 --- [Z18_Springboot_Logins] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1270 ms +2025-03-07T11:35:59.514+05:30 DEBUG 13432 --- [Z18_Springboot_Logins] [main] s.w.s.m.m.a.RequestMappingHandlerMapping : 3 mappings in 'requestMappingHandlerMapping' +2025-03-07T11:35:59.584+05:30 DEBUG 13432 --- [Z18_Springboot_Logins] [main] o.s.w.s.handler.SimpleUrlHandlerMapping : Patterns [/webjars/**, /**] in 'resourceHandlerMapping' +2025-03-07T11:35:59.609+05:30 DEBUG 13432 --- [Z18_Springboot_Logins] [main] s.w.s.m.m.a.RequestMappingHandlerAdapter : ControllerAdvice beans: 0 @ModelAttribute, 0 @InitBinder, 1 RequestBodyAdvice, 1 ResponseBodyAdvice +2025-03-07T11:35:59.656+05:30 DEBUG 13432 --- [Z18_Springboot_Logins] [main] .m.m.a.ExceptionHandlerExceptionResolver : ControllerAdvice beans: 0 @ExceptionHandler, 1 ResponseBodyAdvice +2025-03-07T11:35:59.761+05:30 INFO 13432 --- [Z18_Springboot_Logins] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' +2025-03-07T11:35:59.768+05:30 INFO 13432 --- [Z18_Springboot_Logins] [main] l.i.z.Z18SpringbootLoginsApplication : Started Z18SpringbootLoginsApplication in 2.537 seconds (process running for 3.368) +2025-03-07T11:50:02.145+05:30 INFO 13432 --- [Z18_Springboot_Logins] [SpringApplicationShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete +2025-03-07T11:50:02.152+05:30 INFO 13432 --- [Z18_Springboot_Logins] [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown : Graceful shutdown complete diff --git a/Z18_Springboot_Logins/.gitattributes b/Z18_Springboot_Logins/.gitattributes new file mode 100644 index 0000000..3b41682 --- /dev/null +++ b/Z18_Springboot_Logins/.gitattributes @@ -0,0 +1,2 @@ +/mvnw text eol=lf +*.cmd text eol=crlf diff --git a/Z18_Springboot_Logins/.gitignore b/Z18_Springboot_Logins/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/Z18_Springboot_Logins/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/Z18_Springboot_Logins/.mvn/wrapper/maven-wrapper.properties b/Z18_Springboot_Logins/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..d58dfb7 --- /dev/null +++ b/Z18_Springboot_Logins/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/Z18_Springboot_Logins/mvnw b/Z18_Springboot_Logins/mvnw new file mode 100644 index 0000000..19529dd --- /dev/null +++ b/Z18_Springboot_Logins/mvnw @@ -0,0 +1,259 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.2 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/Z18_Springboot_Logins/mvnw.cmd b/Z18_Springboot_Logins/mvnw.cmd new file mode 100644 index 0000000..249bdf3 --- /dev/null +++ b/Z18_Springboot_Logins/mvnw.cmd @@ -0,0 +1,149 @@ +<# : batch portion +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.2 +@REM +@REM Optional ENV vars +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output +@REM ---------------------------------------------------------------------------- + +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) +) +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' +$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" +if ($env:MAVEN_USER_HOME) { + $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" +} +$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/Z18_Springboot_Logins/pom.xml b/Z18_Springboot_Logins/pom.xml new file mode 100644 index 0000000..e262bee --- /dev/null +++ b/Z18_Springboot_Logins/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.3 + + + lk.ijse + Z18_Springboot_Logins + 0.0.1-SNAPSHOT + Z18_Springboot_Logins + Z18_Springboot_Logins + + + + + + + + + + + + + + + 21 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-logging + 3.4.3 + + + + ch.qos.logback + logback-classic + runtime + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/Z18_Springboot_Logins/src/main/java/lk/ijse/z18_springboot_logins/Controller/DemoController.java b/Z18_Springboot_Logins/src/main/java/lk/ijse/z18_springboot_logins/Controller/DemoController.java new file mode 100644 index 0000000..ab6a3da --- /dev/null +++ b/Z18_Springboot_Logins/src/main/java/lk/ijse/z18_springboot_logins/Controller/DemoController.java @@ -0,0 +1,23 @@ +package lk.ijse.z18_springboot_logins.Controller; + +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/v1/demo") +public class DemoController { + + private static final org.slf4j.Logger log = LoggerFactory.getLogger(DemoController.class); + + @GetMapping + private void loadDemo(){ + log.trace("This is Trace Log"); + log.debug("This is Debug Log"); + log.info("This is Info Log"); + log.warn("This is Warn Log"); + log.error("This is Error Log"); + } + +} diff --git a/Z18_Springboot_Logins/src/main/java/lk/ijse/z18_springboot_logins/Z18SpringbootLoginsApplication.java b/Z18_Springboot_Logins/src/main/java/lk/ijse/z18_springboot_logins/Z18SpringbootLoginsApplication.java new file mode 100644 index 0000000..009cbc9 --- /dev/null +++ b/Z18_Springboot_Logins/src/main/java/lk/ijse/z18_springboot_logins/Z18SpringbootLoginsApplication.java @@ -0,0 +1,13 @@ +package lk.ijse.z18_springboot_logins; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Z18SpringbootLoginsApplication { + + public static void main(String[] args) { + SpringApplication.run(Z18SpringbootLoginsApplication.class, args); + } + +} diff --git a/Z18_Springboot_Logins/src/main/resources/application.properties b/Z18_Springboot_Logins/src/main/resources/application.properties new file mode 100644 index 0000000..8bceedf --- /dev/null +++ b/Z18_Springboot_Logins/src/main/resources/application.properties @@ -0,0 +1,8 @@ +spring.application.name=Z18_Springboot_Logins + +logging.level.root=INFO +logging.level.org.springframework.web=DEBUG +logging.level.org.hibernate=ERROR + +# Log file configuration +logging.file.name=Z18_Springboot_Logins.log diff --git a/Z18_Springboot_Logins/src/test/java/lk/ijse/z18_springboot_logins/Z18SpringbootLoginsApplicationTests.java b/Z18_Springboot_Logins/src/test/java/lk/ijse/z18_springboot_logins/Z18SpringbootLoginsApplicationTests.java new file mode 100644 index 0000000..2bf51ec --- /dev/null +++ b/Z18_Springboot_Logins/src/test/java/lk/ijse/z18_springboot_logins/Z18SpringbootLoginsApplicationTests.java @@ -0,0 +1,13 @@ +package lk.ijse.z18_springboot_logins; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class Z18SpringbootLoginsApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/desktop.ini b/desktop.ini deleted file mode 100644 index 631af8f..0000000 --- a/desktop.ini +++ /dev/null @@ -1,6 +0,0 @@ -[.ShellClassInfo] -IconResource=C:\WINDOWS\System32\SHELL32.dll,146 -[ViewState] -Mode= -Vid= -FolderType=Generic diff --git a/11_Frontend.iml b/out/Z15_Spring_Sequrity/Z15_Spring_Sequrity.iml similarity index 69% rename from 11_Frontend.iml rename to out/Z15_Spring_Sequrity/Z15_Spring_Sequrity.iml index b66f313..e45ed63 100644 --- a/11_Frontend.iml +++ b/out/Z15_Spring_Sequrity/Z15_Spring_Sequrity.iml @@ -1,8 +1,8 @@ - + - + \ No newline at end of file