Compare commits

...

41 Commits

Author SHA1 Message Date
6b22ec18a2 сейв 2023-12-12 14:26:41 +04:00
4e3dfdab49 я надеюсь это все и ничего не сломается 2023-05-13 13:29:35 +04:00
d1011d0537 так правильнее 2023-04-24 16:22:14 +04:00
63dcaa4d7a сделала кое-как как правильно делать не знаю 2023-04-18 18:44:02 +04:00
3aff5cb712 нет json-ignore 2023-04-17 18:24:00 +04:00
1f4f290522 вроде все 2023-04-17 15:52:23 +04:00
1544973e7b сохранение перед исправлениями 2023-04-17 14:12:12 +04:00
7a95e50ac3 удалить 2023-04-15 13:26:20 +04:00
a794ee636f надеюсь это все 2023-04-15 13:25:42 +04:00
0fafffd509 potom dodelaetsya 2023-04-14 14:21:30 +04:00
e2a29f4b65 vite ne nado 2023-04-10 15:40:13 +04:00
aeeeec6e21 Merge remote-tracking branch 'origin/LW04_fail' into LW04_fail 2023-04-10 15:37:32 +04:00
30655dc5a8 order add feature 2023-04-10 15:37:07 +04:00
af4b235a51 commit 2023-04-09 23:05:42 +04:00
5d8837809a bugfix 2023-04-09 19:54:51 +04:00
cf01392e65 exceptions 2023-04-09 18:46:22 +04:00
6f5a9771f0 delete db 2023-04-09 17:45:32 +04:00
91fc7f04ef delete db 2023-04-09 17:44:56 +04:00
74ccd6738b commit front 5 2023-04-09 15:34:56 +04:00
3922ca678d commit front 4 2023-04-09 15:33:44 +04:00
83f8e345fe commit front 3 2023-04-09 15:33:08 +04:00
1331a59414 commit front 2 2023-04-09 15:32:25 +04:00
c7af79da4b commit front 1 2023-04-09 15:32:06 +04:00
6abe4f67cb commit 2023-04-09 15:24:34 +04:00
3211024750 commit 2023-04-09 15:22:02 +04:00
076bd4e61b commit 2023-04-09 15:20:17 +04:00
9d40b79426 контроллеры 2023-04-07 15:28:42 +04:00
465dcc3fae приколы 2023-04-07 14:55:33 +04:00
cfe166c85a hz 2023-03-27 15:01:03 +04:00
77ce0752c1 Не знаю 2023-03-27 14:13:52 +04:00
82dcfd163c Ничего не работает 2023-03-27 03:46:21 +04:00
e6af154d0a Сохранение 2023-03-16 17:32:02 +04:00
a7c19cd750 Некоторые тесты всяких штук 2023-03-16 15:12:45 +04:00
0a40a6e2d1 Merge remote-tracking branch 'origin/LW03' into LW03 2023-03-16 00:57:52 +04:00
28263bf4f9 Убрали комментарий 2023-03-16 00:57:29 +04:00
63919836c4 Убрали комментарий 2023-03-15 23:57:08 +04:00
ba29a321f0 Ну вроде что-то работает 2023-03-15 23:52:50 +04:00
13226e0fa9 ниче не работает 2023-03-13 18:15:50 +04:00
cfcae77ad5 Merge remote-tracking branch 'origin/LW02' into LW02 2023-02-27 18:00:27 +04:00
5ff927f236 ЛР2 2023-02-27 17:59:04 +04:00
2138819860 ЛР2 2023-02-27 17:53:52 +04:00
58 changed files with 2436 additions and 976 deletions

4
.gitignore vendored
View File

@ -5,7 +5,7 @@ build/
!**/src/main/**/build/
!**/src/test/**/build/
node_modules
*.db
### STS ###
.apt_generated
.classpath
@ -36,3 +36,5 @@ out/
### VS Code ###
.vscode/
data.mv.db
data.trace.db

View File

@ -12,9 +12,25 @@ repositories {
mavenCentral()
}
jar {
enabled = false
}
dependencies {
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'com.h2database:h2:2.1.210'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.5'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'com.auth0:java-jwt:4.4.0'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.hibernate.validator:hibernate-validator'
implementation 'org.springdoc:springdoc-openapi-ui:1.6.5'
}
tasks.named('test') {

View File

@ -1,44 +0,0 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<link href="node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="node_modules/@fortawesome/fontawesome-free/css/all.min.css" rel="stylesheet" />
<title>Калькулятор</title>
</head>
<body>
<form class="mx-2 d-flex flex-column align-items-center text-center">
<div>
Первое число
<input id="first" class="form-control" type='number' value='0' />
</div>
<div>
Операция
<select class="form-select" id="operation">
<option value="1">+</option>
<option value="2">-</option>
<option value="3">*</option>
<option value="4">/</option>
</select>
</div>
<div>
Второе число
<input id="second" class="form-control" type='number' value='0' />
</div>
<div>
<button type="button" class="btn btn-primary" id="calculate">Тык</button>
</div>
<div>
Результат:
<p id="result"> </p>
</div>
</form>
</div>
<script src="script.js"></script>
</body>
</html>

817
front/package-lock.json generated
View File

@ -1,817 +0,0 @@
{
"name": "int-prog",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "int-prog",
"version": "1.0.0",
"dependencies": {
"@fortawesome/fontawesome-free": "6.2.0",
"bootstrap": "5.2.1"
},
"devDependencies": {
"http-server": "14.1.1"
}
},
"node_modules/@fortawesome/fontawesome-free": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.2.0.tgz",
"integrity": "sha512-CNR7qRIfCwWHNN7FnKUniva94edPdyQzil/zCwk3v6k4R6rR2Fr8i4s3PM7n/lyfPA6Zfko9z5WDzFxG9SW1uQ==",
"hasInstallScript": true,
"engines": {
"node": ">=6"
}
},
"node_modules/@popperjs/core": {
"version": "2.11.6",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==",
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/async": {
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
"dev": true,
"dependencies": {
"lodash": "^4.17.14"
}
},
"node_modules/basic-auth": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
"integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
"dev": true,
"dependencies": {
"safe-buffer": "5.1.2"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/bootstrap": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.1.tgz",
"integrity": "sha512-UQi3v2NpVPEi1n35dmRRzBJFlgvWHYwyem6yHhuT6afYF+sziEt46McRbT//kVXZ7b1YUYEVGdXEH74Nx3xzGA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/twbs"
},
{
"type": "opencollective",
"url": "https://opencollective.com/bootstrap"
}
],
"peerDependencies": {
"@popperjs/core": "^2.11.6"
}
},
"node_modules/call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/corser": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz",
"integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==",
"dev": true,
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"dependencies": {
"ms": "^2.1.1"
}
},
"node_modules/eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
"dev": true
},
"node_modules/follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"dev": true,
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"node_modules/get-intrinsic": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
"integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.3"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/has-symbols": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"dev": true,
"bin": {
"he": "bin/he"
}
},
"node_modules/html-encoding-sniffer": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
"integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
"dev": true,
"dependencies": {
"whatwg-encoding": "^2.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/http-proxy": {
"version": "1.18.1",
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
"integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
"dev": true,
"dependencies": {
"eventemitter3": "^4.0.0",
"follow-redirects": "^1.0.0",
"requires-port": "^1.0.0"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/http-server": {
"version": "14.1.1",
"resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz",
"integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==",
"dev": true,
"dependencies": {
"basic-auth": "^2.0.1",
"chalk": "^4.1.2",
"corser": "^2.0.1",
"he": "^1.2.0",
"html-encoding-sniffer": "^3.0.0",
"http-proxy": "^1.18.1",
"mime": "^1.6.0",
"minimist": "^1.2.6",
"opener": "^1.5.1",
"portfinder": "^1.0.28",
"secure-compare": "3.0.1",
"union": "~0.5.0",
"url-join": "^4.0.1"
},
"bin": {
"http-server": "bin/http-server"
},
"engines": {
"node": ">=12"
}
},
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dev": true,
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"dev": true,
"bin": {
"mime": "cli.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/minimist": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
"dev": true,
"dependencies": {
"minimist": "^1.2.6"
},
"bin": {
"mkdirp": "bin/cmd.js"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
},
"node_modules/object-inspect": {
"version": "1.12.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/opener": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
"integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
"dev": true,
"bin": {
"opener": "bin/opener-bin.js"
}
},
"node_modules/portfinder": {
"version": "1.0.32",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz",
"integrity": "sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==",
"dev": true,
"dependencies": {
"async": "^2.6.4",
"debug": "^3.2.7",
"mkdirp": "^0.5.6"
},
"engines": {
"node": ">= 0.12.0"
}
},
"node_modules/qs": {
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"dev": true,
"dependencies": {
"side-channel": "^1.0.4"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
"dev": true
},
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
},
"node_modules/secure-compare": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz",
"integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==",
"dev": true
},
"node_modules/side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.0",
"get-intrinsic": "^1.0.2",
"object-inspect": "^1.9.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/union": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz",
"integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==",
"dev": true,
"dependencies": {
"qs": "^6.4.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/url-join": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
"dev": true
},
"node_modules/whatwg-encoding": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
"integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
"dev": true,
"dependencies": {
"iconv-lite": "0.6.3"
},
"engines": {
"node": ">=12"
}
}
},
"dependencies": {
"@fortawesome/fontawesome-free": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.2.0.tgz",
"integrity": "sha512-CNR7qRIfCwWHNN7FnKUniva94edPdyQzil/zCwk3v6k4R6rR2Fr8i4s3PM7n/lyfPA6Zfko9z5WDzFxG9SW1uQ=="
},
"@popperjs/core": {
"version": "2.11.6",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==",
"peer": true
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"async": {
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
"dev": true,
"requires": {
"lodash": "^4.17.14"
}
},
"basic-auth": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
"integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
"dev": true,
"requires": {
"safe-buffer": "5.1.2"
}
},
"bootstrap": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.1.tgz",
"integrity": "sha512-UQi3v2NpVPEi1n35dmRRzBJFlgvWHYwyem6yHhuT6afYF+sziEt46McRbT//kVXZ7b1YUYEVGdXEH74Nx3xzGA==",
"requires": {}
},
"call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
"dev": true,
"requires": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
}
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"corser": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz",
"integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==",
"dev": true
},
"debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
},
"eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
"dev": true
},
"follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"dev": true
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"get-intrinsic": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
"integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
"dev": true,
"requires": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.3"
}
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"requires": {
"function-bind": "^1.1.1"
}
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"has-symbols": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
"dev": true
},
"he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"dev": true
},
"html-encoding-sniffer": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
"integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
"dev": true,
"requires": {
"whatwg-encoding": "^2.0.0"
}
},
"http-proxy": {
"version": "1.18.1",
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
"integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
"dev": true,
"requires": {
"eventemitter3": "^4.0.0",
"follow-redirects": "^1.0.0",
"requires-port": "^1.0.0"
}
},
"http-server": {
"version": "14.1.1",
"resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz",
"integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==",
"dev": true,
"requires": {
"basic-auth": "^2.0.1",
"chalk": "^4.1.2",
"corser": "^2.0.1",
"he": "^1.2.0",
"html-encoding-sniffer": "^3.0.0",
"http-proxy": "^1.18.1",
"mime": "^1.6.0",
"minimist": "^1.2.6",
"opener": "^1.5.1",
"portfinder": "^1.0.28",
"secure-compare": "3.0.1",
"union": "~0.5.0",
"url-join": "^4.0.1"
}
},
"iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dev": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
},
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"dev": true
},
"minimist": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true
},
"mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
"dev": true,
"requires": {
"minimist": "^1.2.6"
}
},
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
},
"object-inspect": {
"version": "1.12.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
"dev": true
},
"opener": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
"integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
"dev": true
},
"portfinder": {
"version": "1.0.32",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz",
"integrity": "sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==",
"dev": true,
"requires": {
"async": "^2.6.4",
"debug": "^3.2.7",
"mkdirp": "^0.5.6"
}
},
"qs": {
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"dev": true,
"requires": {
"side-channel": "^1.0.4"
}
},
"requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
"dev": true
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
},
"secure-compare": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz",
"integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==",
"dev": true
},
"side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
"dev": true,
"requires": {
"call-bind": "^1.0.0",
"get-intrinsic": "^1.0.2",
"object-inspect": "^1.9.0"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
},
"union": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz",
"integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==",
"dev": true,
"requires": {
"qs": "^6.4.0"
}
},
"url-join": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
"dev": true
},
"whatwg-encoding": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
"integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
"dev": true,
"requires": {
"iconv-lite": "0.6.3"
}
}
}
}

View File

@ -1,16 +0,0 @@
{
"name": "int-prog",
"version": "1.0.0",
"main": "index.html",
"scripts": {
"start": "http-server -p 3000 ./",
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"bootstrap": "5.2.1",
"@fortawesome/fontawesome-free": "6.2.0"
},
"devDependencies": {
"http-server": "14.1.1"
}
}

View File

@ -1,39 +0,0 @@
const calculateButton = document.getElementById("calculate");
const first = document.getElementById("first");
const second = document.getElementById("second");
const select = document.getElementById("operation");
const result = document.getElementById("result");
calculateButton.onclick = function() {
calculate();
};
function calculate() {
switch (parseInt(select.value)) {
case 1:
doSmth("plus")
break;
case 2:
doSmth("minus")
break;
case 3:
doSmth("mult")
break;
case 4:
doSmth("div")
break;
};
}
function checkNum(res) {
if (res.indexOf(".") != -1)
return parseInt(res)
else
return res
}
function doSmth(address) {
fetch(`http://localhost:8080/${address}?first=${first.value}&second=${second.value}`)
.then(response => response.text())
.then(res => result.innerHTML = checkNum(res));
}

View File

@ -1 +1,2 @@
rootProject.name = 'app'
include 'front'

View File

@ -2,8 +2,6 @@ package com.labwork1.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@ -12,32 +10,4 @@ public class AppApplication {
public static void main(String[] args) {
SpringApplication.run(AppApplication.class, args);
}
@GetMapping("/hello")
public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
return String.format("Hello %s!", name);
}
@GetMapping("/plus")
public String plus(@RequestParam(required = false, defaultValue = "0") double first,
@RequestParam(required = false, defaultValue = "0") double second) {
return Double.toString(first + second);
}
@GetMapping("/minus")
public String minus(@RequestParam(required = false, defaultValue = "0") double first,
@RequestParam(required = false, defaultValue = "0") double second) {
return Double.toString(first - second);
}
@GetMapping("/mult")
public String mult(@RequestParam(required = false, defaultValue = "1") double first,
@RequestParam(required = false, defaultValue = "1") double second) {
return Double.toString(first * second);
}
@GetMapping("/div")
public String div(@RequestParam(required = false, defaultValue = "1") double first,
@RequestParam(required = false, defaultValue = "1") double second) {
if(second == 0)
{
return null;
}
return Double.toString(first/second);
}
}

View File

@ -1,12 +0,0 @@
package com.labwork1.app;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("*");
}
}

View File

@ -0,0 +1,28 @@
package com.labwork1.app.configuration;
import com.labwork1.app.configuration.jwt.JwtFilter;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class OpenAPI30Configuration {
public static final String API_PREFIX = "/api/1.0";
@Bean
public OpenAPI customizeOpenAPI() {
final String securitySchemeName = JwtFilter.TOKEN_BEGIN_STR;
return new OpenAPI()
.addSecurityItem(new SecurityRequirement()
.addList(securitySchemeName))
.components(new Components()
.addSecuritySchemes(securitySchemeName, new SecurityScheme()
.name(securitySchemeName)
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")));
}
}

View File

@ -0,0 +1,14 @@
package com.labwork1.app.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class PasswordEncoderConfiguration {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

View File

@ -0,0 +1,87 @@
package com.labwork1.app.configuration;
import com.labwork1.app.configuration.jwt.JwtFilter;
import com.labwork1.app.student.controller.UserController;
import com.labwork1.app.student.model.UserRole;
import com.labwork1.app.student.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
public class SecurityConfiguration {
private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class);
public static final String SPA_URL_MASK = "/{path:[^\\.]*}";
private final UserService userService;
private final JwtFilter jwtFilter;
public SecurityConfiguration(UserService userService) {
this.userService = userService;
this.jwtFilter = new JwtFilter(userService);
createAdminOnStartup();
}
private void createAdminOnStartup() {
final String admin = "admin";
if (userService.findByLogin(admin) == null) {
log.info("Admin user successfully created");
userService.createUser(admin, admin, admin, UserRole.ADMIN);
}
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
log.info("Creating security configuration");
http.cors()
.and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeHttpRequests()
.requestMatchers("/", SPA_URL_MASK).permitAll()
.requestMatchers(HttpMethod.POST, UserController.URL_LOGIN).permitAll()
.requestMatchers(HttpMethod.POST, UserController.URL_SIGNUP).permitAll()
.requestMatchers(HttpMethod.POST, UserController.URL_GET_ROLE).permitAll()
.anyRequest()
.authenticated()
.and()
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
.anonymous();
return http.build();
}
@Bean
public AuthenticationManager authenticationManagerBean(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder = http
.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.userDetailsService(userService);
return authenticationManagerBuilder.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return web -> web.ignoring()
.requestMatchers(HttpMethod.OPTIONS, "/**")
.requestMatchers("/*.js")
.requestMatchers("/*.html")
.requestMatchers("/*.css")
.requestMatchers("/*.png")
.requestMatchers("/*.jpg")
.requestMatchers("/favicon.ico")
.requestMatchers("/swagger-ui/index.html")
.requestMatchers("/webjars/**")
.requestMatchers("/swagger-resources/**")
.requestMatchers("/v3/api-docs/**")
.requestMatchers("/h2-console/**");
}
}

View File

@ -0,0 +1,31 @@
package com.labwork1.app.configuration;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
class WebConfiguration implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController(SecurityConfiguration.SPA_URL_MASK).setViewName("forward:/");
registry.addViewController("/notFound").setViewName("forward:/");
}
@Bean
public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> containerCustomizer() {
return container -> container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notFound"));
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("*");
}
}

View File

@ -0,0 +1,11 @@
package com.labwork1.app.configuration.jwt;
public class JwtException extends RuntimeException {
public JwtException(Throwable throwable) {
super(throwable);
}
public JwtException(String message) {
super(message);
}
}

View File

@ -0,0 +1,71 @@
package com.labwork1.app.configuration.jwt;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.labwork1.app.student.service.UserService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;
import java.io.IOException;
public class JwtFilter extends GenericFilterBean {
private static final String AUTHORIZATION = "Authorization";
public static final String TOKEN_BEGIN_STR = "Bearer ";
private final UserService userService;
public JwtFilter(UserService userService) {
this.userService = userService;
}
private String getTokenFromRequest(HttpServletRequest request) {
String bearer = request.getHeader(AUTHORIZATION);
if (StringUtils.hasText(bearer) && bearer.startsWith(TOKEN_BEGIN_STR)) {
return bearer.substring(TOKEN_BEGIN_STR.length());
}
return null;
}
private void raiseException(ServletResponse response, int status, String message) throws IOException {
if (response instanceof final HttpServletResponse httpResponse) {
httpResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
httpResponse.setStatus(status);
final byte[] body = new ObjectMapper().writeValueAsBytes(message);
response.getOutputStream().write(body);
}
}
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (request instanceof final HttpServletRequest httpRequest) {
final String token = getTokenFromRequest(httpRequest);
if (StringUtils.hasText(token)) {
try {
final UserDetails user = userService.loadUserByToken(token);
final UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
} catch (JwtException e) {
raiseException(response, HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
return;
} catch (Exception e) {
e.printStackTrace();
raiseException(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
String.format("Internal error: %s", e.getMessage()));
return;
}
}
}
chain.doFilter(request, response);
}
}

View File

@ -0,0 +1,27 @@
package com.labwork1.app.configuration.jwt;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "jwt", ignoreInvalidFields = true)
public class JwtProperties {
private String devToken = "";
private Boolean isDev = true;
public String getDevToken() {
return devToken;
}
public void setDevToken(String devToken) {
this.devToken = devToken;
}
public Boolean isDev() {
return isDev;
}
public void setDev(Boolean dev) {
isDev = dev;
}
}

View File

@ -0,0 +1,107 @@
package com.labwork1.app.configuration.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.Optional;
import java.util.UUID;
@Component
public class JwtProvider {
private final static Logger LOG = LoggerFactory.getLogger(JwtProvider.class);
private final static byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
private final static String ISSUER = "auth0";
private final Algorithm algorithm;
private final JWTVerifier verifier;
public JwtProvider(JwtProperties jwtProperties) {
if (!jwtProperties.isDev()) {
LOG.info("Generate new JWT key for prod");
try {
final MessageDigest salt = MessageDigest.getInstance("SHA-256");
salt.update(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8));
LOG.info("Use generated JWT key for prod \n{}", bytesToHex(salt.digest()));
algorithm = Algorithm.HMAC256(bytesToHex(salt.digest()));
} catch (NoSuchAlgorithmException e) {
throw new JwtException(e);
}
} else {
LOG.info("Use default JWT key for dev \n{}", jwtProperties.getDevToken());
algorithm = Algorithm.HMAC256(jwtProperties.getDevToken());
}
verifier = JWT.require(algorithm)
.withIssuer(ISSUER)
.build();
}
private static String bytesToHex(byte[] bytes) {
byte[] hexChars = new byte[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars, StandardCharsets.UTF_8);
}
public String generateToken(String login) {
final Date issueDate = Date.from(LocalDate.now()
.atStartOfDay(ZoneId.systemDefault())
.toInstant());
final Date expireDate = Date.from(LocalDate.now()
.plusDays(15)
.atStartOfDay(ZoneId.systemDefault())
.toInstant());
return JWT.create()
.withIssuer(ISSUER)
.withIssuedAt(issueDate)
.withExpiresAt(expireDate)
.withSubject(login)
.sign(algorithm);
}
private DecodedJWT validateToken(String token) {
try {
return verifier.verify(token);
} catch (JWTVerificationException e) {
throw new JwtException(String.format("Token verification error: %s", e.getMessage()));
}
}
public boolean isTokenValid(String token) {
if (!StringUtils.hasText(token)) {
return false;
}
try {
validateToken(token);
return true;
} catch (JwtException e) {
LOG.error(e.getMessage());
return false;
}
}
public Optional<String> getLoginFromToken(String token) {
try {
return Optional.ofNullable(validateToken(token).getSubject());
} catch (JwtException e) {
LOG.error(e.getMessage());
return Optional.empty();
}
}
}

View File

@ -0,0 +1,57 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.student.model.UserRole;
import com.labwork1.app.student.service.CinemaService;
import jakarta.validation.Valid;
import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/cinema")
public class CinemaController {
private final CinemaService cinemaService;
public CinemaController(CinemaService cinemaService) {
this.cinemaService = cinemaService;
}
@GetMapping("/{id}")
public CinemaDto getCinema(@PathVariable Long id) {
return new CinemaDto(cinemaService.findCinema(id));
}
@GetMapping
public List<CinemaDto> getCinemas() {
return cinemaService.findAllCinemas().stream()
.map(CinemaDto::new)
.toList();
}
@GetMapping("/search")
public List<CinemaDto> getCinemas(@RequestParam("request") String request) {
return cinemaService.findAllCinemas(request).stream()
.map(CinemaDto::new)
.toList();
}
@PostMapping
@Secured({UserRole.AsString.ADMIN})
public CinemaDto createCinema(@RequestBody @Valid CinemaDto cinemaDto) {
return new CinemaDto(cinemaService.addCinema(cinemaDto));
}
@PutMapping("/{id}")
@Secured({UserRole.AsString.ADMIN})
public CinemaDto updateCinema(@RequestBody @Valid CinemaDto cinemaDto) {
return new CinemaDto(cinemaService.updateCinema(cinemaDto));
}
@DeleteMapping("/{id}")
@Secured({UserRole.AsString.ADMIN})
public CinemaDto deleteCinema(@PathVariable Long id) {
return new CinemaDto(cinemaService.deleteCinema(id));
}
}

View File

@ -0,0 +1,50 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.student.model.Cinema;
import jakarta.persistence.Column;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.nio.charset.StandardCharsets;
public class CinemaDto {
private long id;
@NotBlank
private String name;
private String image;
@NotBlank
private String description;
@NotNull
private Long year;
public CinemaDto() {
}
public CinemaDto(Cinema cinema) {
this.id = cinema.getId();
this.name = cinema.getName();
this.description = cinema.getDescription();
this.year = cinema.getYear();
this.image = new String(cinema.getImage(), StandardCharsets.UTF_8);
}
public String getDescription() {
return description;
}
public Long getYear() {
return year;
}
public String getImage() {
return image;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,50 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.student.service.OrderService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/order")
public class OrderController {
private final OrderService orderService;
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
@GetMapping("/{id}")
public OrderDto getOrder(@PathVariable Long id) {
return new OrderDto(orderService.findOrder(id));
}
@GetMapping
public List<OrderDto> getOrders() {
return orderService.findAllOrders().stream()
.map(OrderDto::new)
.toList();
}
@PostMapping("/{user}")
public OrderDto createOrder(@PathVariable String user) {
return new OrderDto(orderService.addOrder(user));
}
@PutMapping("/{id}")
public OrderDto updateOrder(@PathVariable Long id,
@RequestParam("session") Long session,
@RequestParam(value = "count", required = false) Integer count) {
if (count == null)
return new OrderDto(orderService.deleteSessionInOrder(id, session, Integer.MAX_VALUE));
if (count > 0)
return new OrderDto(orderService.addSession(id, session, count));
return new OrderDto(orderService.deleteSessionInOrder(id, session, -count));
}
@DeleteMapping("/{id}")
public OrderDto deleteOrder(@PathVariable Long id) {
return new OrderDto(orderService.deleteOrder(id));
}
}

View File

@ -0,0 +1,39 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.student.model.User;
import com.labwork1.app.student.model.Order;
import com.labwork1.app.student.model.OrderSession;
import java.sql.Date;
import java.util.List;
public class OrderDto {
private long id;
private String user;
private List<OrderSessionDto> sessions;
public OrderDto() {
}
public OrderDto(Order order) {
this.id = order.getId();
this.user = order.getUser().getLogin();
if (order.getSessions() != null && order.getSessions().size() > 0)
this.sessions = order.getSessions()
.stream()
.map(x -> new OrderSessionDto(new SessionDto(x.getSession()),
x.getId().getOrderId(), x.getCount())).toList();
}
public long getId() {
return id;
}
public String getUser() {
return user;
}
public List<OrderSessionDto> getSessions() {
return sessions;
}
}

View File

@ -0,0 +1,28 @@
package com.labwork1.app.student.controller;
public class OrderSessionDto {
private SessionDto session;
private Long orderId;
private Integer count;
public OrderSessionDto() {
}
public OrderSessionDto(SessionDto session, Long orderId, Integer count) {
this.session = session;
this.orderId = orderId;
this.count = count;
}
public SessionDto getSession() {
return session;
}
public Long getOrderId() {
return orderId;
}
public Integer getCount() {
return count;
}
}

View File

@ -0,0 +1,62 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.student.model.UserRole;
import com.labwork1.app.student.service.SessionService;
import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.*;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
@RestController
@RequestMapping("/session")
public class SessionController {
private final SessionService sessionService;
public SessionController(SessionService sessionService) {
this.sessionService = sessionService;
}
@GetMapping("/{id}")
public SessionDto getSession(@PathVariable Long id) {
return new SessionDto(sessionService.findSession(id));
}
@GetMapping
public List<SessionDto> getSessions() {
return sessionService.findAllSessions().stream()
.map(SessionDto::new)
.toList();
}
@PostMapping
@Secured({UserRole.AsString.ADMIN})
public SessionDto createSession(@RequestParam("price") String price,
@RequestParam("dateTime") String dateTime,
@RequestParam("cinemaid") Long cinemaId,
@RequestParam("capacity") Integer capacity) throws ParseException {
SimpleDateFormat format = new SimpleDateFormat();
format.applyPattern("yyyy-MM-dd-HH:ss");
Date docDate = format.parse(dateTime.replace('T', '-'));
return new SessionDto(sessionService.findSession(
sessionService.addSession(Double.parseDouble(price),
new Timestamp(docDate.getTime()), cinemaId, capacity).getId()));
}
@PutMapping("/{id}")
@Secured({UserRole.AsString.ADMIN})
public SessionDto updateSession(@PathVariable Long id,
@RequestParam("price") String price) {
return new SessionDto(sessionService.findSession(sessionService
.updateSession(id, Double.parseDouble(price)).getId()));
}
@DeleteMapping("/{id}")
@Secured({UserRole.AsString.ADMIN})
public SessionDto deleteSession(@PathVariable Long id) {
return new SessionDto(sessionService.deleteSession(id));
}
}

View File

@ -0,0 +1,64 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.student.model.Session;
import com.labwork1.app.student.model.SessionExtension;
import java.sql.Timestamp;
public class SessionDto {
private long id;
private Double price;
private Timestamp dateTime;
private CinemaDto cinema;
private Long capacity;
private int maxCount;
public SessionDto() {
}
public SessionDto(SessionExtension session) {
this.id = session.getId();
this.price = session.getPrice();
this.dateTime = session.getTimestamp();
this.capacity = session.getCapacity();
this.maxCount = session.getMaxCount();
if (session.getCinema() != null) {
this.cinema = new CinemaDto(session.getCinema());
} else this.cinema = null;
}
public SessionDto(Session session) {
this.id = session.getId();
this.price = session.getPrice();
this.dateTime = session.getTimestamp();
this.maxCount = session.getMaxCount();
if (session.getCinema() != null) {
this.cinema = new CinemaDto(session.getCinema());
} else this.cinema = null;
}
public int getMaxCount() {
return maxCount;
}
public long getId() {
return id;
}
public Double getPrice() {
return price;
}
public Timestamp getTimestamp() {
return dateTime;
}
public Long getCapacity() {
return capacity;
}
public CinemaDto getCinema() {
return cinema;
}
}

View File

@ -0,0 +1,88 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.configuration.OpenAPI30Configuration;
import com.labwork1.app.student.model.User;
import com.labwork1.app.student.model.UserRole;
import com.labwork1.app.student.service.UserService;
import com.labwork1.app.util.validation.ValidationException;
import jakarta.validation.Valid;
import org.springframework.data.domain.Page;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;
@RestController
public class UserController {
private final UserService userService;
public static final String URL_LOGIN = "/jwt/login";
public static final String URL_SIGNUP = "/signup";
public static final String URL_MAIN = "/user";
public static final String URL_GET_ROLE = "/get-role";
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping(URL_LOGIN)
public String login(@RequestBody @Valid UserDto userDto) {
return userService.loginAndGetToken(userDto);
}
@PostMapping(URL_SIGNUP)
public String signup(@RequestBody @Valid UserSignupDto userSignupDto){
try {
User user = userService.addUser(userSignupDto.getLogin(), userSignupDto.getPassword(), userSignupDto.getPasswordConfirm());
return user.getLogin() + " was created";
}
catch(ValidationException e){
return e.getMessage();
}
}
@GetMapping(URL_MAIN + "/{id}")
public UserDto getUser(@PathVariable Long id) {
return new UserDto(userService.findUser(id));
}
@GetMapping(URL_MAIN)
public UserDto getUserByLogin(@RequestParam("login") String login) {
return new UserDto(userService.findByLogin(login));
}
@GetMapping(URL_GET_ROLE)
public String getRole(@RequestParam("token") String token) {
UserDetails userDetails = userService.loadUserByToken(token);
User user = userService.findByLogin(userDetails.getUsername());
return user.getRole().toString();
}
@GetMapping(OpenAPI30Configuration.API_PREFIX + URL_MAIN)
@Secured({UserRole.AsString.ADMIN})
public Page<UserDto> getUsers(@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "5") int size) {
return userService.findAllPages(page, size)
.map(UserDto::new);
}
@PutMapping(URL_MAIN + "/{id}")
@Secured({UserRole.AsString.ADMIN})
public UserDto updateUser(@PathVariable Long id,
@RequestBody @Valid UserDto userDto) {
return new UserDto(userService.updateUser(id, userDto.getLogin(), userDto.getPassword()));
}
@PutMapping("/{id}")
public UserDto updateUserCart(@PathVariable Long id,
@RequestParam("session") Long session,
@RequestParam(value = "count", required = false) Integer count) {
if (count == null)
return new UserDto(userService.deleteSessionInCart(id, session, Integer.MAX_VALUE));
if (count > 0)
return new UserDto(userService.addSession(id, session, count));
return new UserDto(userService.deleteSessionInCart(id, session, -count));
}
@DeleteMapping(URL_MAIN + "/{id}")
public UserDto deleteUser(@PathVariable Long id) {
return new UserDto(userService.deleteUser(id));
}
}

View File

@ -0,0 +1,53 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.student.model.User;
import java.util.ArrayList;
import java.util.List;
public class UserDto {
private long id;
private String login;
private String password;
private List<OrderDto> orders;
private List<UserSessionDto> sessions;
public UserDto() {
}
public UserDto(User user) {
this.id = user.getId();
this.login = user.getLogin();
this.password = user.getPassword();
this.orders = new ArrayList<>();
if (user.getOrders() != null) {
orders = user.getOrders().stream()
.map(OrderDto::new).toList();
}
if (user.getSessions() != null && user.getSessions().size() > 0)
this.sessions = user.getSessions()
.stream()
.map(x -> new UserSessionDto(new SessionDto(x.getSession()),
x.getId().getUserId(), x.getCount())).toList();
}
public long getId() {
return id;
}
public String getLogin() {
return login;
}
public String getPassword() {
return password;
}
public List<OrderDto> getOrders() {
return orders;
}
public List<UserSessionDto> getSessions() {
return sessions;
}
}

View File

@ -0,0 +1,28 @@
package com.labwork1.app.student.controller;
public class UserSessionDto {
private SessionDto session;
private Long userId;
private Integer count;
public UserSessionDto() {
}
public UserSessionDto(SessionDto session, Long userId, Integer count) {
this.session = session;
this.userId = userId;
this.count = count;
}
public SessionDto getSession() {
return session;
}
public Long getUserId() {
return userId;
}
public Integer getCount() {
return count;
}
}

View File

@ -0,0 +1,31 @@
package com.labwork1.app.student.controller;
public class UserSignupDto {
private String login;
private String password;
private String passwordConfirm;
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPasswordConfirm() {
return passwordConfirm;
}
public void setPasswordConfirm(String passwordConfirm) {
this.passwordConfirm = passwordConfirm;
}
}

View File

@ -0,0 +1,90 @@
package com.labwork1.app.student.model;
import com.labwork1.app.student.controller.CinemaDto;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
@Entity
public class Cinema {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@NotBlank(message = "name can't be null or empty")
@Column
private String name;
@NotBlank(message = "description can't be null or empty")
@Column
private String description;
@NotNull(message = "year can't be null or empty")
@Column(name = "col_year")
private Long year;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "cinema", cascade = CascadeType.REMOVE)
private List<Session> sessions;
@Lob
private byte[] image;
public Cinema() {
}
public Cinema(CinemaDto cinemaDto) {
this.name = cinemaDto.getName();
this.description = cinemaDto.getDescription();
this.year = cinemaDto.getYear();
this.image = cinemaDto.getImage().getBytes();
this.sessions = new ArrayList<>();
}
public byte[] getImage() {
return image;
}
public void setImage(byte[] image) {
this.image = image;
}
public List<Session> getSessions() {
return sessions;
}
public void setSession(Session session) {
if (session.getCinema().equals(this)) {
this.sessions.add(session);
}
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Long getYear() {
return year;
}
public void setYear(Long year) {
this.year = year;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,86 @@
package com.labwork1.app.student.model;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import java.sql.Date;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Entity
@Table(name = "tab_order")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "user_fk")
private User user;
@OneToMany(mappedBy = "order", fetch = FetchType.EAGER, cascade =
{
CascadeType.REMOVE,
CascadeType.MERGE,
CascadeType.PERSIST
}, orphanRemoval = true)
private List<OrderSession> sessions;
public Order() {
}
public void addSession(OrderSession orderSession) {
if (sessions == null) {
sessions = new ArrayList<>();
}
if (!sessions.contains(orderSession))
this.sessions.add(orderSession);
}
public void removeSession(OrderSession orderSession){
if (sessions.contains(orderSession))
this.sessions.remove(orderSession);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Order order = (Order) o;
return Objects.equals(id, order.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
@Override
public String toString() {
return "Order {" +
"id=" + id +
", user='" + user.toString() + '\'';
}
public Long getId() {
return id;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
if (!user.getOrders().contains(this)) {
user.setOrder(this);
}
}
public List<OrderSession> getSessions() {
return sessions;
}
public void setSessions(List<OrderSession> sessions) {
this.sessions = sessions;
}
}

View File

@ -0,0 +1,62 @@
package com.labwork1.app.student.model;
import jakarta.persistence.*;
@Entity
@Table(name = "order_session")
public class OrderSession {
@EmbeddedId
private OrderSessionKey id;
@ManyToOne
@MapsId("sessionId")
@JoinColumn(name = "session_id")
private Session session;
@ManyToOne
@MapsId("orderId")
@JoinColumn(name = "order_id")
private Order order;
@Column(name = "count")
private Integer count;
public OrderSession() {
}
public OrderSession(Order order, Session session, Integer count) {
this.order = order;
this.session = session;
this.count = count;
this.id = new OrderSessionKey(session.getId(), order.getId());
}
public OrderSessionKey getId() {
return id;
}
public void setId(OrderSessionKey id) {
this.id = id;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
public Session getSession() {
return session;
}
public void setSession(Session session) {
this.session = session;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}

View File

@ -0,0 +1,48 @@
package com.labwork1.app.student.model;
import jakarta.persistence.Embeddable;
import java.io.Serializable;
import java.util.Objects;
@Embeddable
public class OrderSessionKey implements Serializable {
private Long sessionId;
private Long orderId;
public OrderSessionKey() {
}
public OrderSessionKey(Long sessionId, Long orderId) {
this.sessionId = sessionId;
this.orderId = orderId;
}
public Long getSessionId() {
return sessionId;
}
public void setSessionId(Long sessionId) {
this.sessionId = sessionId;
}
public Long getOrderId() {
return orderId;
}
public void setOrderId(Long orderId) {
this.orderId = orderId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof OrderSessionKey that)) return false;
return Objects.equals(getSessionId(), that.getSessionId()) && Objects.equals(getOrderId(), that.getOrderId());
}
@Override
public int hashCode() {
return Objects.hash(getSessionId(), getOrderId());
}
}

View File

@ -0,0 +1,160 @@
package com.labwork1.app.student.model;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Entity
public class Session {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
protected Long id;
@NotNull(message = "price can't be null or empty")
protected Double price;
@NotNull(message = "dateTime can't be null or empty")
@Column(name = "date_time")
@Temporal(TemporalType.TIMESTAMP)
protected Timestamp dateTime;
@OneToMany(mappedBy = "session", fetch = FetchType.EAGER)
private List<OrderSession> orders;
@OneToMany(mappedBy = "session", fetch = FetchType.EAGER)
private List<UserSession> users;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "cinema_fk")
protected Cinema cinema;
@NotNull(message = "maxCount can't be null or empty")
@Column(name = "max_count")
protected Integer maxCount;
public Session() {
}
public Integer getMaxCount() {
return maxCount;
}
public Session(Double price, Timestamp dateTime, Integer maxCount) {
this.price = price;
this.dateTime = dateTime;
this.maxCount = maxCount;
}
public Session(Session session) {
this.id = session.getId();
this.price = session.getPrice();
this.dateTime = session.getTimestamp();
this.orders = session.getOrders();
this.users = session.getUsers();
this.cinema = session.getCinema();
this.maxCount = session.getMaxCount();
}
public Cinema getCinema() {
return cinema;
}
public void setCinema(Cinema cinema) {
this.cinema = cinema;
if (!cinema.getSessions().contains(this)) {
cinema.setSession(this);
}
}
public void addOrder(OrderSession orderSession){
if (orders == null){
orders = new ArrayList<>();
}
if (!orders.contains(orderSession)) {
this.orders.add(orderSession);
}
}
public void removeOrder(OrderSession orderSession){
if (orders.contains(orderSession))
this.orders.remove(orderSession);
}
public void addUser(UserSession userSession){
if (users == null){
users = new ArrayList<>();
}
if (!users.contains(userSession)) {
this.users.add(userSession);
}
}
public void removeUser(UserSession userSession){
if (users.contains(userSession))
this.users.remove(userSession);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Session session = (Session) o;
return Objects.equals(id, session.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
@Override
public String toString() {
return "Session {" +
"id=" + id +
", price='" + price + '\'' +
", dateTime='" + dateTime.toString() + '\'' +
", maxCount='" + maxCount.toString() + '\'' +
", cinema='" + cinema.toString() + '\'' +
'}';
}
public Long getId() {
return id;
}
public Double getPrice() {
return price;
}
public void setId(Long id) {
this.id = id;
}
public void setOrders(List<OrderSession> orders) {
this.orders = orders;
}
public void setMaxCount(Integer maxCount) {
this.maxCount = maxCount;
}
public void setPrice(Double price) {
this.price = price;
}
public Timestamp getTimestamp() {
return dateTime;
}
public void setTimestamp(Timestamp dateTime) {
this.dateTime = dateTime;
}
public List<OrderSession> getOrders() {
return orders;
}
public void setUsers(List<UserSession> users) {
this.users = users;
}
public List<UserSession> getUsers() {
return users;
}
}

View File

@ -0,0 +1,17 @@
package com.labwork1.app.student.model;
public class SessionExtension extends Session {
private Long capacity;
public SessionExtension(Session session, Long capacity) {
super(session);
this.capacity = capacity;
}
public Long getCapacity() {
return capacity;
}
public void setCapacity(Long capacity) {
this.capacity = capacity;
}
}

View File

@ -0,0 +1,127 @@
package com.labwork1.app.student.model;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Entity
@Table(name = "tab_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false, unique = true, length = 64)
@NotBlank(message = "login can't be null or empty")
@Size(min = 3, max = 64)
private String login;
@Column(nullable = false, length = 64)
@NotBlank(message = "password can't be null or empty")
@Size(min = 6, max = 64)
private String password;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "user", cascade = {CascadeType.MERGE,CascadeType.REMOVE})
private List<Order> orders;
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade =
{
CascadeType.REMOVE,
CascadeType.MERGE,
CascadeType.PERSIST
}, orphanRemoval = true)
private List<UserSession> sessions;
private UserRole role;
public User() {
}
public User(String login, String password) {
this.login = login;
this.password = password;
this.orders = new ArrayList<>();
this.sessions = new ArrayList<>();
this.role = UserRole.USER;
}
public User(String login, String password, UserRole role) {
this.login = login;
this.password = password;
this.orders = new ArrayList<>();
this.sessions = new ArrayList<>();
this.role = role;
}
public void addSession(UserSession userSession) {
if (sessions == null) {
sessions = new ArrayList<>();
}
if (!sessions.contains(userSession))
this.sessions.add(userSession);
}
public void removeSession(UserSession userSession){
if (sessions.contains(userSession))
this.sessions.remove(userSession);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(id, user.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
@Override
public String toString() {
return "User {" +
"id=" + id +
", login='" + login + '\'' +
", password='" + password + '\'' +
'}';
}
public UserRole getRole() {
return role;
}
public Long getId() {
return id;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<Order> getOrders() {
return orders;
}
public void setOrder(Order order) {
if (order.getUser().equals(this)) {
this.orders.add(order);
}
}
public List<UserSession> getSessions() {
return sessions;
}
}

View File

@ -0,0 +1,20 @@
package com.labwork1.app.student.model;
import org.springframework.security.core.GrantedAuthority;
public enum UserRole implements GrantedAuthority {
ADMIN,
USER;
private static final String PREFIX = "ROLE_";
@Override
public String getAuthority() {
return PREFIX + this.name();
}
public static final class AsString {
public static final String ADMIN = PREFIX + "ADMIN";
public static final String USER = PREFIX + "USER";
}
}

View File

@ -0,0 +1,62 @@
package com.labwork1.app.student.model;
import jakarta.persistence.*;
@Entity
@Table(name = "user_session")
public class UserSession {
@EmbeddedId
private UserSessionKey id;
@ManyToOne
@MapsId("sessionId")
@JoinColumn(name = "session_id")
private Session session;
@ManyToOne
@MapsId("userId")
@JoinColumn(name = "user_id")
private User user;
@Column(name = "count")
private Integer count;
public UserSession() {
}
public UserSession(User user, Session session, Integer count) {
this.user = user;
this.session = session;
this.count = count;
this.id = new UserSessionKey(session.getId(), user.getId());
}
public UserSessionKey getId() {
return id;
}
public void setId(UserSessionKey id) {
this.id = id;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Session getSession() {
return session;
}
public void setSession(Session session) {
this.session = session;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}

View File

@ -0,0 +1,49 @@
package com.labwork1.app.student.model;
import jakarta.persistence.Embeddable;
import java.io.Serializable;
import java.util.Objects;
@Embeddable
public class UserSessionKey implements Serializable {
private Long sessionId;
private Long userId;
public UserSessionKey() {
}
public UserSessionKey(Long sessionId, Long userId) {
this.sessionId = sessionId;
this.userId = userId;
}
public Long getSessionId() {
return sessionId;
}
public void setSessionId(Long sessionId) {
this.sessionId = sessionId;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof UserSessionKey that)) return false;
return Objects.equals(getSessionId(), that.getSessionId()) && Objects.equals(getUserId(), that.getUserId());
}
@Override
public int hashCode() {
return Objects.hash(getSessionId(), getUserId());
}
}

View File

@ -0,0 +1,13 @@
package com.labwork1.app.student.repository;
import com.labwork1.app.student.model.Cinema;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface CinemaRepository extends JpaRepository<Cinema, Long> {
@Query("select p from Cinema p where p.name like CONCAT('%',:search,'%')")
List<Cinema> findAll(@Param("search") String search);
}

View File

@ -0,0 +1,12 @@
package com.labwork1.app.student.repository;
import com.labwork1.app.student.model.Order;
import com.labwork1.app.student.model.OrderSession;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface OrderRepository extends JpaRepository<Order, Long> {
@Query("Select os from OrderSession os where os.order.id = :orderId and os.session.id = :sessionId")
OrderSession getOrderSession(@Param("orderId") Long orderId, @Param("sessionId") Long sessionId);
}

View File

@ -0,0 +1,24 @@
package com.labwork1.app.student.repository;
import com.labwork1.app.student.model.Session;
import com.labwork1.app.student.model.SessionExtension;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
import java.util.Optional;
public interface SessionRepository extends JpaRepository<Session, Long> {
@Query("Select sum(os.count) from OrderSession os where os.session.id = :sessionId")
Optional<Integer> getCapacity(@Param("sessionId") Long sessionId);
@Query("Select new com.labwork1.app.student.model.SessionExtension(s, sum(os.count)) from Session s " +
"left join OrderSession os on s.id = os.session.id " +
"group by s")
List<SessionExtension> getSessionsWithCapacity();
@Query("Select new com.labwork1.app.student.model.SessionExtension(s, sum(os.count)) from Session s " +
"left join OrderSession os on s.id = os.session.id " +
"where s.id = :sessionId " +
"group by s")
Optional<SessionExtension> getSessionWithCapacity(@Param("sessionId") Long sessionId);
}

View File

@ -0,0 +1,14 @@
package com.labwork1.app.student.repository;
import com.labwork1.app.student.model.OrderSession;
import com.labwork1.app.student.model.User;
import com.labwork1.app.student.model.UserSession;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface UserRepository extends JpaRepository<User, Long> {
User findOneByLoginIgnoreCase(String login);
@Query("Select us from UserSession us where us.user.id = :userId and us.session.id = :sessionId")
UserSession getUserSession(@Param("userId") Long userId, @Param("sessionId") Long sessionId);
}

View File

@ -0,0 +1,7 @@
package com.labwork1.app.student.service;
public class CinemaNotFoundException extends RuntimeException {
public CinemaNotFoundException(Long id) {
super(String.format("Cinema with id [%s] is not found", id));
}
}

View File

@ -0,0 +1,66 @@
package com.labwork1.app.student.service;
import com.labwork1.app.student.controller.CinemaDto;
import com.labwork1.app.student.model.Cinema;
import com.labwork1.app.student.repository.CinemaRepository;
import com.labwork1.app.util.validation.ValidatorUtil;
import jakarta.transaction.Transactional;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class CinemaService {
private final CinemaRepository cinemaRepository;
private final ValidatorUtil validatorUtil;
public CinemaService(CinemaRepository cinemaRepository, ValidatorUtil validatorUtil) {
this.cinemaRepository = cinemaRepository;
this.validatorUtil = validatorUtil;
}
@Transactional
public Cinema addCinema(CinemaDto dto) {
final Cinema cinema = new Cinema(dto);
validatorUtil.validate(cinema);
return cinemaRepository.save(cinema);
}
@Transactional
public Cinema findCinema(Long id) {
final Optional<Cinema> cinema = cinemaRepository.findById(id);
return cinema.orElseThrow(() -> new CinemaNotFoundException(id));
}
@Transactional
public List<Cinema> findAllCinemas(String search) {
return cinemaRepository.findAll(search);
}
@Transactional
public List<Cinema> findAllCinemas() {
return cinemaRepository.findAll();
}
@Transactional
public Cinema updateCinema(CinemaDto cinema) {
final Cinema currentCinema = findCinema(cinema.getId());
currentCinema.setName(cinema.getName());
currentCinema.setImage(cinema.getImage().getBytes());
validatorUtil.validate(currentCinema);
return cinemaRepository.save(currentCinema);
}
@Transactional
public Cinema deleteCinema(Long id) {
final Cinema currentCinema = findCinema(id);
cinemaRepository.delete(currentCinema);
return currentCinema;
}
@Transactional
public void deleteAllCinemas() {
cinemaRepository.deleteAll();
}
}

View File

@ -0,0 +1,7 @@
package com.labwork1.app.student.service;
public class OrderNotFoundException extends RuntimeException {
public OrderNotFoundException(Long id) {
super(String.format("Order with id [%s] is not found", id));
}
}

View File

@ -0,0 +1,112 @@
package com.labwork1.app.student.service;
import com.labwork1.app.student.model.*;
import com.labwork1.app.student.repository.OrderRepository;
import com.labwork1.app.util.validation.ValidatorUtil;
import jakarta.persistence.EntityNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.sql.Date;
import java.util.List;
import java.util.Optional;
@Service
public class OrderService {
private final OrderRepository orderRepository;
private final UserService userService;
private final SessionService sessionService;
private final ValidatorUtil validatorUtil;
public OrderService(OrderRepository orderRepository, UserService userService, SessionService sessionService, ValidatorUtil validatorUtil) {
this.orderRepository = orderRepository;
this.userService = userService;
this.sessionService = sessionService;
this.validatorUtil = validatorUtil;
}
@Transactional
public Order addOrder(Long userId) {
final Order order = new Order();
final User user = userService.findUser(userId);
order.setUser(user);
validatorUtil.validate(order);
return orderRepository.save(order);
}
@Transactional
public Order addOrder(String userName) {
final Order order = new Order();
final User user = userService.findByLogin(userName);
order.setUser(user);
validatorUtil.validate(order);
return orderRepository.save(order);
}
@Transactional
public Order addSession(Long id, Long sessionId, Integer count) {
final Session currentSession = sessionService.findSession(sessionId);
final Order currentOrder = findOrder(id);
final OrderSession currentOrderSession = orderRepository.getOrderSession(id, sessionId);
final Integer currentSessionCapacity = currentSession.getMaxCount() - sessionService.getCapacity(sessionId);
if (currentSessionCapacity < count ||
(currentOrderSession != null && currentOrderSession.getCount() + count > currentSession.getMaxCount())) {
throw new IllegalArgumentException(String.format("No more tickets in session. Capacity: %1$s. Count: %2$s",
currentSessionCapacity, count));
}
if (currentOrderSession == null) {
currentOrder.addSession(new OrderSession(currentOrder, currentSession, count));
}
else if (currentOrderSession.getCount() + count <= currentSession.getMaxCount()) {
currentOrder.removeSession(currentOrderSession);
currentOrder.addSession(new OrderSession(currentOrder, currentSession,
currentOrderSession.getCount() + count));
}
return orderRepository.save(currentOrder);
}
@Transactional(readOnly = true)
public Order findOrder(Long id) {
final Optional<Order> order = orderRepository.findById(id);
return order.orElseThrow(() -> new OrderNotFoundException(id));
}
@Transactional(readOnly = true)
public List<Order> findAllOrders() {
return orderRepository.findAll();
}
@Transactional
public Order deleteOrder(Long id) {
final Order currentOrder = findOrder(id);
orderRepository.delete(currentOrder);
return currentOrder;
}
@Transactional
public Order deleteSessionInOrder(Long id, Long session, Integer count) {
final Order currentOrder = findOrder(id);
final Session currentSession = sessionService.findSession(session);
final OrderSession currentOrderSession = orderRepository.getOrderSession(id, session);
if (currentOrderSession == null)
throw new EntityNotFoundException();
if (count >= currentOrderSession.getCount()) {
currentOrder.removeSession(currentOrderSession);
}
else {
currentOrder.removeSession(currentOrderSession);
currentOrder.addSession(new OrderSession(currentOrder, currentSession,
currentOrderSession.getCount() - count));
}
return orderRepository.save(currentOrder);
}
@Transactional
public void deleteAllOrders() {
orderRepository.deleteAll();
}
}

View File

@ -0,0 +1,7 @@
package com.labwork1.app.student.service;
public class SessionNotFoundException extends RuntimeException {
public SessionNotFoundException(Long id) {
super(String.format("Session with id [%s] is not found", id));
}
}

View File

@ -0,0 +1,81 @@
package com.labwork1.app.student.service;
import com.labwork1.app.student.model.Cinema;
import com.labwork1.app.student.model.Session;
import com.labwork1.app.student.model.SessionExtension;
import com.labwork1.app.student.repository.SessionRepository;
import com.labwork1.app.util.validation.ValidatorUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.sql.Timestamp;
import java.util.List;
import java.util.Optional;
@Service
public class SessionService {
private final SessionRepository sessionRepository;
private final CinemaService cinemaService;
private final ValidatorUtil validatorUtil;
public SessionService(SessionRepository sessionRepository,
CinemaService cinemaService, ValidatorUtil validatorUtil) {
this.sessionRepository = sessionRepository;
this.cinemaService = cinemaService;
this.validatorUtil = validatorUtil;
}
@Transactional
public Session addSession(Double price, Timestamp date, Long cinemaId, Integer capacity) {
final Session session = new Session(price, date, capacity);
final Cinema cinema = cinemaService.findCinema(cinemaId);
session.setCinema(cinema);
validatorUtil.validate(session);
return sessionRepository.save(session);
}
@Transactional(readOnly = true)
public SessionExtension findSession(Long id) {
return sessionRepository.getSessionWithCapacity(id)
.orElseThrow(() -> new SessionNotFoundException(id));
}
@Transactional(readOnly = true)
public Session findBaseSession(Long id) {
final Optional<Session> session = sessionRepository.findById(id);
return session.orElseThrow(() -> new SessionNotFoundException(id));
}
@Transactional(readOnly = true)
public List<SessionExtension> findAllSessions() {
return sessionRepository.getSessionsWithCapacity();
}
@Transactional
public Session updateSession(Long id, Double price) {
final Session currentSession = findBaseSession(id);
currentSession.setPrice(price);
validatorUtil.validate(currentSession);
return sessionRepository.save(currentSession);
}
@Transactional
public Session deleteSession(Long id) {
final Session currentSession = findBaseSession(id);
// все равно сеанс не удалился бы, который участвует в заказах
// для отслеживания операции с ошибкой
if (currentSession.getOrders().size() > 0)
throw new IllegalArgumentException();
sessionRepository.delete(currentSession);
return currentSession;
}
@Transactional
public void deleteAllSessions() {
sessionRepository.deleteAll();
}
@Transactional
public Integer getCapacity(Long sessionId) {
return sessionRepository.getCapacity(sessionId).orElse(0);
}
}

View File

@ -0,0 +1,7 @@
package com.labwork1.app.student.service;
public class UserExistsException extends RuntimeException {
public UserExistsException(String login) {
super(String.format("User '%s' already exists", login));
}
}

View File

@ -0,0 +1,10 @@
package com.labwork1.app.student.service;
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(Long id) {
super(String.format("User with id [%s] is not found", id));
}
public UserNotFoundException(String login) {
super(String.format("User with login [%s] is not found", login));
}
}

View File

@ -0,0 +1,171 @@
package com.labwork1.app.student.service;
import com.labwork1.app.configuration.jwt.JwtProvider;
import com.labwork1.app.student.controller.UserDto;
import com.labwork1.app.student.model.*;
import com.labwork1.app.student.repository.UserRepository;
import com.labwork1.app.util.validation.ValidationException;
import com.labwork1.app.util.validation.ValidatorUtil;
import jakarta.persistence.EntityNotFoundException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
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.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.labwork1.app.configuration.jwt.JwtException;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@Service
public class UserService implements UserDetailsService {
private final UserRepository userRepository;
private final SessionService sessionService;
private final PasswordEncoder passwordEncoder;
private final ValidatorUtil validatorUtil;
private final JwtProvider jwtProvider;
public UserService(UserRepository userRepository, SessionService sessionService, PasswordEncoder passwordEncoder, ValidatorUtil validatorUtil, JwtProvider jwtProvider) {
this.userRepository = userRepository;
this.sessionService = sessionService;
this.passwordEncoder = passwordEncoder;
this.validatorUtil = validatorUtil;
this.jwtProvider = jwtProvider;
}
public Page<User> findAllPages(int page, int size) {
return userRepository.findAll(PageRequest.of(page - 1, size, Sort.by("id").ascending()));
}
public User findByLogin(String login) {
return userRepository.findOneByLoginIgnoreCase(login);
}
@Transactional
public User addUser(String login, String password, String passwordConfirm) {
return createUser(login, password, passwordConfirm, UserRole.USER);
}
public User createUser(String login, String password, String passwordConfirm, UserRole role) {
if (findByLogin(login) != null) {
throw new UserExistsException(login);
}
final User user = new User(login, passwordEncoder.encode(password), role);
validatorUtil.validate(user);
if (!Objects.equals(password, passwordConfirm)) {
throw new ValidationException("Passwords not equals");
}
return userRepository.save(user);
}
public String loginAndGetToken(UserDto userDto) {
final User user = findByLogin(userDto.getLogin());
if (user == null) {
throw new UserNotFoundException(userDto.getLogin());
}
if (!passwordEncoder.matches(userDto.getPassword(), user.getPassword())) {
throw new UserNotFoundException(user.getLogin());
}
return jwtProvider.generateToken(user.getLogin());
}
public UserDetails loadUserByToken(String token) throws UsernameNotFoundException {
if (!jwtProvider.isTokenValid(token)) {
throw new JwtException("Bad token");
}
final String userLogin = jwtProvider.getLoginFromToken(token)
.orElseThrow(() -> new JwtException("Token is not contain Login"));
return loadUserByUsername(userLogin);
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
final User userEntity = findByLogin(username);
if (userEntity == null) {
throw new UsernameNotFoundException(username);
}
return new org.springframework.security.core.userdetails.User(
userEntity.getLogin(), userEntity.getPassword(), Collections.singleton(userEntity.getRole()));
}
@Transactional(readOnly = true)
public User findUser(Long id) {
final Optional<User> user = userRepository.findById(id);
return user.orElseThrow(() -> new UserNotFoundException(id));
}
@Transactional(readOnly = true)
public List<User> findAllUsers() {
return userRepository.findAll();
}
@Transactional
public User updateUser(Long id, String login, String password) {
final User currentUser = findUser(id);
currentUser.setLogin(login);
currentUser.setPassword(passwordEncoder.encode(password));
validatorUtil.validate(currentUser);
return userRepository.save(currentUser);
}
@Transactional
public User addSession(Long id, Long sessionId, Integer count) {
final Session currentSession = sessionService.findSession(sessionId);
final User currentUser = findUser(id);
final UserSession currentUserSession = userRepository.getUserSession(id, sessionId);
final Integer currentSessionCapacity = currentSession.getMaxCount() - sessionService.getCapacity(sessionId);
if (currentSessionCapacity < count ||
(currentUserSession != null && currentUserSession.getCount() + count > currentSession.getMaxCount())) {
throw new IllegalArgumentException(String.format("No more tickets in session. Capacity: %1$s. Count: %2$s",
currentSessionCapacity, count));
}
if (currentUserSession == null) {
currentUser.addSession(new UserSession(currentUser, currentSession, count));
}
else if (currentUserSession.getCount() + count <= currentSession.getMaxCount()) {
currentUser.removeSession(currentUserSession);
currentUser.addSession(new UserSession(currentUser, currentSession,
currentUserSession.getCount() + count));
}
return userRepository.save(currentUser);
}
@Transactional
public User deleteSessionInCart(Long id, Long session, Integer count) {
final User currentUser = findUser(id);
final Session currentSession = sessionService.findSession(session);
final UserSession currentUserSession = userRepository.getUserSession(id, session);
if (currentUserSession == null)
throw new EntityNotFoundException();
if (count >= currentUserSession.getCount()) {
currentUser.removeSession(currentUserSession);
}
else {
currentUser.removeSession(currentUserSession);
currentUser.addSession(new UserSession(currentUser, currentSession,
currentUserSession.getCount() - count));
}
return userRepository.save(currentUser);
}
@Transactional
public User deleteUser(Long id) {
final User user = findUser(id);
userRepository.deleteById(id);
return user;
}
@Transactional
public void deleteAllUsers() {
userRepository.deleteAll();
}
}

View File

@ -0,0 +1,45 @@
package com.labwork1.app.util.error;
import com.labwork1.app.student.service.CinemaNotFoundException;
import com.labwork1.app.student.service.UserNotFoundException;
import com.labwork1.app.student.service.OrderNotFoundException;
import com.labwork1.app.student.service.SessionNotFoundException;
import com.labwork1.app.util.validation.ValidationException;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import java.util.stream.Collectors;
@ControllerAdvice
public class AdviceController {
@ExceptionHandler({
UserNotFoundException.class,
OrderNotFoundException.class,
SessionNotFoundException.class,
CinemaNotFoundException.class,
ValidationException.class,
IllegalArgumentException.class
})
public ResponseEntity<Object> handleException(Throwable e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Object> handleBindException(MethodArgumentNotValidException e) {
final ValidationException validationException = new ValidationException(
e.getBindingResult().getAllErrors().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.toSet()));
return handleException(validationException);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleUnknownException(Throwable e) {
e.printStackTrace();
return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}

View File

@ -0,0 +1,13 @@
package com.labwork1.app.util.validation;
import java.util.Set;
public class ValidationException extends RuntimeException {
public ValidationException(String message) {
super(message);
}
public ValidationException(Set<String> errors) {
super(String.join("\n", errors));
}
}

View File

@ -0,0 +1,30 @@
package com.labwork1.app.util.validation;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import org.springframework.stereotype.Component;
import java.util.Set;
import java.util.stream.Collectors;
@Component
public class ValidatorUtil {
private final Validator validator;
public ValidatorUtil() {
try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) {
this.validator = factory.getValidator();
}
}
public <T> void validate(T object) {
final Set<ConstraintViolation<T>> errors = validator.validate(object);
if (!errors.isEmpty()) {
throw new ValidationException(errors.stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.toSet()));
}
}
}

View File

@ -1 +1,12 @@
spring.main.banner-mode=off
spring.datasource.url=jdbc:h2:file:./data
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true
spring.h2.console.settings.trace=false
spring.h2.console.settings.web-allow-others=false
jwt.dev-token=my-secret-jwt
jwt.dev=true

View File

@ -1,13 +0,0 @@
package com.labwork1.app;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class AppApplicationTests {
@Test
void contextLoads() {
}
}

View File

@ -0,0 +1,129 @@
//package com.labwork1.app;
//
//import com.labwork1.app.student.model.*;
//import com.labwork1.app.student.service.*;
//import org.junit.jupiter.api.Assertions;
//import org.junit.jupiter.api.Test;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.boot.test.context.SpringBootTest;
//
//import java.sql.Timestamp;
//import java.util.List;
//
//@SpringBootTest
//public class JpaUserTests {
// private static final Logger log = LoggerFactory.getLogger(JpaUserTests.class);
// @Autowired
// private UserService userService;
// @Autowired
// private SessionService sessionService;
// @Autowired
// private OrderService orderService;
// @Autowired
// private CinemaService cinemaService;
//
// @Test
// void testOrder() {
// sessionService.deleteAllSessions();
// cinemaService.deleteAllCinemas();
// orderService.deleteAllOrders();
// userService.deleteAllUsers();
// // 2 кино
// final Cinema cinema1 = cinemaService.addCinema("Меню");
// final Cinema cinema2 = cinemaService.addCinema("Аватар");
//
// // 2 сеанса
// final Session session1 = sessionService.addSession(300.0,
// new Timestamp(System.currentTimeMillis()), cinema1.getId(), 10);
// final Session session2 = sessionService.addSession( 200.0,
// new Timestamp(System.currentTimeMillis()), cinema1.getId(), 10);
//
// // проверка 2 сеанса у 1 кино
// Assertions.assertEquals(cinemaService
// .findCinema(cinema1.getId()).getSessions().size(), 2);
// // 1 покупатель
// final User user1 = userService.addUser("Родион", "Иванов");
// userService.updateUser(user1.getId(), "Пчел", "Пчелов");
// Assertions.assertEquals(userService.findUser(user1.getId()).getLogin(), "Пчел");
// // 1 заказ, 1 копия заказа
// final Order order0 = orderService.addOrder(userService.findUser(user1.getId()).getId());
// final Order order1 = orderService.findOrder(order0.getId());
// Assertions.assertEquals(order0, order1);
//
// // у клиента точно есть заказ?
// Assertions.assertEquals(userService
// .findUser(user1.getId()).getOrders().size(), 1);
// // 0 заказов
// orderService.deleteAllOrders();
// Assertions.assertThrows(OrderNotFoundException.class, () -> orderService.findOrder(-1L));
// // 2 покупателя
// final User user2 = userService.addUser("Иннокентий", "Иванов");
//
// // 1 заказ
// final Order order2 = orderService
// .addOrder(userService.findUser(user2.getId()).getId());
// // у заказа 2 сеанса
// orderService.addSession(order2.getId(), session1.getId(), 2);
//
// List<SessionExtension> result = sessionService.findAllSessions();
//
// Assertions.assertEquals(sessionService.getCapacity(session1.getId()), 2);
//
// orderService.addSession(order2.getId(), session2.getId(), 5);
// Assertions.assertEquals(sessionService.getCapacity(session2.getId()), 5);
//
// Assertions.assertThrows(IllegalArgumentException.class, () ->
// orderService.addSession(order2.getId(), session2.getId(), 6));
//
// // у заказа 1 сеанс
// orderService.deleteSessionInOrder(order2.getId(), session2.getId(), 10);
// Assertions.assertEquals(sessionService.getCapacity(session2.getId()), 0);
// // заполнили всю 2 сессию
// orderService.addSession(order2.getId(), session2.getId(), 10);
//
// Assertions.assertEquals(sessionService.findAllSessions().size(), 2);
//
// orderService.deleteSessionInOrder(order2.getId(), session2.getId(), 4);
// Assertions.assertEquals(sessionService.getCapacity(session2.getId()), 6);
// orderService.deleteSessionInOrder(order2.getId(), session2.getId(), 6);
// Assertions.assertEquals(sessionService.getCapacity(session2.getId()), 0);
//
// Assertions.assertEquals(orderService.findOrder(order2.getId()).getSessions().size(), 1);
// Assertions.assertEquals(orderService.findOrder(order2.getId()).getSessions().get(0).getId().getSessionId(), session1.getId());
//
// // у заказа 1 сеанс
// // 3 сеанса всего
// final Session session3 = sessionService.addSession(300.0,
// new Timestamp(System.currentTimeMillis()), cinema2.getId(), 10);
// // удалили заказ2, у которого был сеанс1
// orderService.deleteOrder(order2.getId());
// Assertions.assertEquals(orderService.findAllOrders().size(), 0);
// Assertions.assertEquals(sessionService.findAllSessions().size(), 3);
//
// // создали 3 заказ у 2 покупателя
// final Order order3 = orderService
// .addOrder(userService.findUser(user2.getId()).getId());
// orderService.addSession(order3.getId(), session2.getId(), 2);
// orderService.addSession(order3.getId(), session3.getId(), 8);
// orderService.addSession(order3.getId(), session1.getId(), 8);
// // 2-ой покупатель удален
// // 0 заказов после его удаления
// Assertions.assertEquals(sessionService.getCapacity(session2.getId()), 2);
// userService.deleteUser(user2.getId());
//
// Assertions.assertThrows(UserNotFoundException.class, () -> userService.findUser(user2.getId()));
// Assertions.assertThrows(OrderNotFoundException.class, () -> orderService.findOrder(order3.getId()));
// Assertions.assertEquals(orderService.findAllOrders().size(), 0);
// Assertions.assertEquals(sessionService.getCapacity(session2.getId()), 0);
// Assertions.assertEquals(sessionService.getCapacity(session3.getId()), 0);
//
// Assertions.assertEquals(cinemaService.findAllCinemas().size(), 2);
// Assertions.assertEquals(sessionService.findAllSessions().size(), 3);
// // у синема1 1 и 2 сеанс, у синема2 3 сеанс. он удален
// cinemaService.deleteCinema(cinema2.getId());
// Assertions.assertEquals(cinemaService.findAllCinemas().size(), 1);
// Assertions.assertEquals(sessionService.findAllSessions().size(), 2);
// }
//}

View File

@ -0,0 +1,6 @@
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop