Compare commits
766 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0707b515ab | ||
|
|
78ae71fc46 | ||
|
|
3f62cd40e7 | ||
|
|
47657c0093 | ||
|
|
a5b0fde4b6 | ||
|
|
78cc0b34b1 | ||
|
|
e3017e986b | ||
|
|
e12cd876db | ||
|
|
5292e4b814 | ||
|
|
dbdd16ab89 | ||
|
|
ddc3c2e1b5 | ||
|
|
49184b287b | ||
|
|
f6139bda0d | ||
|
|
a6471b823b | ||
|
|
7c34003647 | ||
|
|
1aa21f9980 | ||
|
|
ce4ca50939 | ||
|
|
fb28260c4a | ||
|
|
626a904747 | ||
|
|
893cdafdc5 | ||
|
|
dbfb7d7d9c | ||
|
|
a66538a7db | ||
|
|
2f77d87d4f | ||
|
|
de85ba984c | ||
|
|
caac1a05ae | ||
|
|
eb5793b819 | ||
|
|
5ef3e1e2ce | ||
|
|
d8b459e5ee | ||
|
|
7b40d58aa1 | ||
|
|
809e9b838e | ||
|
|
23ae36ebd9 | ||
|
|
9c3f7d20f5 | ||
|
|
083298303c | ||
|
|
224970a07e | ||
|
|
86d039e5b0 | ||
|
|
6a8038aac9 | ||
|
|
e748f08a8e | ||
|
|
3580963e9f | ||
|
|
b008ce2ab8 | ||
|
|
ea0c2c7061 | ||
|
|
0926220933 | ||
|
|
ca975bbdd3 | ||
|
|
b16c5c5302 | ||
|
|
cad05fe5d9 | ||
|
|
a7cd466d9c | ||
|
|
4472a67ec0 | ||
|
|
c84a4029ec | ||
|
|
d7d9ab505e | ||
|
|
c582f5f5c7 | ||
|
|
4c30939339 | ||
|
|
cecd6a1d2b | ||
|
|
853dcbb364 | ||
|
|
ae327ed26d | ||
|
|
3e416aa255 | ||
|
|
61c2c3fc83 | ||
|
|
ca749aaf1e | ||
|
|
2a2cb3bd0c | ||
|
|
44e3d19844 | ||
|
|
1e25fffc70 | ||
|
|
44645ed23d | ||
|
|
fa557e5f76 | ||
|
|
7202fda38e | ||
|
|
d05afe41d6 | ||
|
|
bfc0b58728 | ||
|
|
22e8aaca81 | ||
|
|
5cb1247fb2 | ||
|
|
17a6d99703 | ||
|
|
3e7917f767 | ||
|
|
e9277d4dd9 | ||
|
|
058edd8af6 | ||
|
|
8ed7dcb9ff | ||
|
|
1f4827abc0 | ||
|
|
9715a0fcf7 | ||
|
|
9bf475c352 | ||
|
|
c2aeb4bca0 | ||
|
|
07b3020999 | ||
|
|
c2a7f39025 | ||
|
|
a92d422972 | ||
|
|
345eb65c3a | ||
|
|
a459973983 | ||
|
|
470dd4d78a | ||
|
|
e4cb183140 | ||
|
|
6455af96bf | ||
|
|
42afa87464 | ||
|
|
97466eeff2 | ||
|
|
bcbfd4ba9c | ||
|
|
cfa052fc31 | ||
|
|
3f71f6a8d8 | ||
|
|
b70e442ca3 | ||
|
|
1f60b2aadc | ||
|
|
3d2117ddaf | ||
|
|
bcff18ea58 | ||
|
|
2e9821402f | ||
|
|
8914c5cd51 | ||
|
|
0b240498f9 | ||
|
|
16f66364cf | ||
|
|
f2b0cec427 | ||
|
|
fac05ff5c0 | ||
|
|
1ac6dfd2a6 | ||
|
|
8bcac7344f | ||
|
|
300c986abb | ||
|
|
91a5f92df6 | ||
|
|
d60a09d48f | ||
|
|
b22bb7c7ad | ||
|
|
63cddc4ab0 | ||
|
|
790061d5c4 | ||
|
|
6e4e2795b6 | ||
|
|
d4e51b714d | ||
|
|
6a164dc60b | ||
|
|
ce602dcf66 | ||
|
|
2facb1ab46 | ||
|
|
3c7d575c85 | ||
|
|
9635c3c2c5 | ||
|
|
72427fc19d | ||
|
|
0bbd3c5491 | ||
|
|
871de4e75a | ||
|
|
bf984f280e | ||
|
|
2b8f3cf13a | ||
|
|
1630a5c9ec | ||
|
|
f17faa33f4 | ||
|
|
c245b848a0 | ||
|
|
0ead9112c6 | ||
|
|
44da393369 | ||
|
|
5ae1628b7c | ||
|
|
59511d9ddd | ||
|
|
82b0fba99a | ||
|
|
618107e515 | ||
|
|
35f931adf2 | ||
|
|
4a1e41cd54 | ||
|
|
888ec5cbbe | ||
|
|
f8f044d0cc | ||
|
|
36148c5539 | ||
|
|
030dde0d64 | ||
|
|
99faa951f9 | ||
|
|
7fb3a80ea3 | ||
|
|
f277048aa9 | ||
|
|
34e3b8e145 | ||
|
|
91e8526b8e | ||
|
|
926188ef64 | ||
|
|
1b5fc6729e | ||
|
|
3ac53ea144 | ||
|
|
4dc3b4f741 | ||
|
|
7c1e6bd45c | ||
|
|
00b3145e79 | ||
|
|
def9a7770f | ||
|
|
5ba0bd5771 | ||
|
|
adc2de07f7 | ||
|
|
e12f528635 | ||
|
|
c96ac53b91 | ||
|
|
8c15bd5534 | ||
|
|
90755d68b3 | ||
|
|
94dfe9a0bb | ||
|
|
9dbcf71856 | ||
|
|
728fc3593f | ||
|
|
1347585af2 | ||
|
|
920de489be | ||
|
|
19cb964543 | ||
|
|
eb03979ad8 | ||
|
|
ebe871b82a | ||
|
|
04a103fdc0 | ||
|
|
d0f80d4150 | ||
|
|
48c388dea7 | ||
|
|
d05f8b1f84 | ||
|
|
167d6e607e | ||
|
|
8755c6379a | ||
|
|
1e2bd0ea4b | ||
|
|
2cf93cf669 | ||
|
|
a18b81d52e | ||
|
|
604c98a031 | ||
|
|
940f48b816 | ||
|
|
f81545178d | ||
|
|
a87b599bdf | ||
|
|
2c45521fb4 | ||
|
|
0870387995 | ||
|
|
be281c78ff | ||
|
|
87c54335db | ||
|
|
12e6c1677b | ||
|
|
f69b789346 | ||
|
|
9f05295f18 | ||
|
|
bf14e4c8c0 | ||
|
|
bd4db09637 | ||
|
|
4b5dcb1c7e | ||
|
|
b7f1ac5e8f | ||
|
|
bcf3c3dc33 | ||
|
|
993c271fa8 | ||
|
|
b8b545a072 | ||
|
|
84b748a361 | ||
|
|
ef2b8cadc7 | ||
|
|
d8cfa2c397 | ||
|
|
d8c7d63f21 | ||
|
|
3d3aa23a65 | ||
|
|
6993fe5df8 | ||
|
|
48d80a8460 | ||
|
|
742c5b3489 | ||
|
|
3cd75c02ee | ||
|
|
854d5f0afe | ||
|
|
daabbfa759 | ||
|
|
42ca4f76bf | ||
|
|
6bf2801b1e | ||
|
|
3be3a28cc9 | ||
|
|
916e1640de | ||
|
|
ecb3b74581 | ||
|
|
2171c7fbe3 | ||
|
|
4a909e5c44 | ||
|
|
c44c239b35 | ||
|
|
6990046a8d | ||
|
|
0750b080f6 | ||
|
|
ca09d2ca66 | ||
|
|
ed3749eaf2 | ||
|
|
fa3c391ee9 | ||
|
|
c6d945b8c0 | ||
|
|
9dc20abbb4 | ||
|
|
94cd543e56 | ||
|
|
4f50939eb2 | ||
|
|
60f792b2ef | ||
|
|
383945b156 | ||
|
|
0e960715ee | ||
|
|
522fd2a9f5 | ||
|
|
9091b3d2a8 | ||
|
|
acc3d2f6d0 | ||
|
|
a9d7ab0193 | ||
|
|
cd720c34dd | ||
|
|
c3839b1e98 | ||
|
|
085eb2a9a0 | ||
|
|
f20c04d523 | ||
|
|
b7b7d6ad3e | ||
|
|
299444d767 | ||
|
|
0dbaa68fc0 | ||
|
|
80fd9e136a | ||
|
|
ba27db5f75 | ||
|
|
4629271fb2 | ||
|
|
91177af98b | ||
|
|
26281d1cbb | ||
|
|
a80c6e12ad | ||
|
|
8e208e8791 | ||
|
|
6e87c2d5cc | ||
|
|
3d96984735 | ||
|
|
4626fdf04a | ||
|
|
a2c013ec43 | ||
|
|
9262131936 | ||
|
|
02c5302653 | ||
|
|
fa73b61e3f | ||
|
|
96ade10289 | ||
|
|
acf16a6c28 | ||
|
|
dedf8fc2f7 | ||
|
|
7099652083 | ||
|
|
d0f9795e63 | ||
|
|
0ffc469ac8 | ||
|
|
b5ea3c63a1 | ||
|
|
5901531ddf | ||
|
|
814aa8d22b | ||
|
|
d3aa55f987 | ||
|
|
8b7fb7ef0f | ||
|
|
0fab57d19c | ||
|
|
0d8822c496 | ||
|
|
7235931f38 | ||
|
|
410f45c6c2 | ||
|
|
9a44d80be4 | ||
|
|
2f52ed64ba | ||
|
|
dd68dec05c | ||
|
|
a8bc9f90e1 | ||
|
|
8759216dd6 | ||
|
|
0851e0a222 | ||
|
|
40f1f1380e | ||
|
|
2a5ff7a911 | ||
|
|
0590f991d2 | ||
|
|
c6a96df3e9 | ||
|
|
0088c74b20 | ||
|
|
6af0d8b88e | ||
|
|
5204a71b00 | ||
|
|
8b2866b89b | ||
|
|
65f638f336 | ||
|
|
f92e95e01c | ||
|
|
2aeae70060 | ||
|
|
98b1cd9bc5 | ||
|
|
a02684f921 | ||
|
|
13ddc6309e | ||
|
|
2b2fd3ae28 | ||
|
|
2dd3dc1718 | ||
|
|
fe1b96d58c | ||
|
|
8dfee0fd12 | ||
|
|
275b60aa14 | ||
|
|
dd14b71e68 | ||
|
|
849171c4df | ||
|
|
2183c77606 | ||
|
|
bedf7bad34 | ||
|
|
802c7923d5 | ||
|
|
95c8cd19f8 | ||
|
|
e700a5f1c2 | ||
|
|
7fd7f7e29d | ||
|
|
902ddd0269 | ||
|
|
0a6424f8c0 | ||
|
|
3a36c624ba | ||
|
|
1329beb808 | ||
|
|
0e8ef0180f | ||
|
|
660f089035 | ||
|
|
04f90ae6a8 | ||
|
|
30b4a73fef | ||
|
|
b7158f3bf0 | ||
|
|
f46bbe9963 | ||
|
|
9f73068a9e | ||
|
|
779b18802b | ||
|
|
dce9acf47f | ||
|
|
c9a925f548 | ||
|
|
4eeec7887a | ||
|
|
156c781bd7 | ||
|
|
296cf92022 | ||
|
|
d5f0e57c3b | ||
|
|
86ba6200fc | ||
|
|
ac4ea07319 | ||
|
|
6d380de603 | ||
|
|
e789bc6925 | ||
|
|
f7481be91c | ||
|
|
a8151bcf0e | ||
|
|
0b6a6787bb | ||
|
|
7302982366 | ||
|
|
19b7dfc90a | ||
|
|
29825a6ad6 | ||
|
|
f6493f0496 | ||
|
|
c2d61eecc0 | ||
|
|
2a4354c52e | ||
|
|
e7dc4f67f5 | ||
|
|
8584d2cf9c | ||
|
|
92b9c6953c | ||
|
|
ac1c2ca7fe | ||
|
|
f05ca7f1f8 | ||
|
|
ecef1c8640 | ||
|
|
43d58a4b7e | ||
|
|
8293b376a2 | ||
|
|
c243cdd54c | ||
|
|
0383257356 | ||
|
|
73e8731bd4 | ||
|
|
b0e82889e0 | ||
|
|
8e28116371 | ||
|
|
ed717af91c | ||
|
|
7ae5a982e9 | ||
|
|
2e3f1e6763 | ||
|
|
4a2e02afc8 | ||
|
|
9c53850faa | ||
|
|
695b15faed | ||
|
|
33aeaf9825 | ||
|
|
dc3608524a | ||
|
|
6996814888 | ||
|
|
9bbaf49ade | ||
|
|
db737df712 | ||
|
|
bae1839c06 | ||
|
|
7e70f5108f | ||
|
|
c5c0a6900b | ||
|
|
50b88dd7a1 | ||
|
|
e44eb991f5 | ||
|
|
39d0d346ad | ||
|
|
142865f1ce | ||
|
|
2c18755a0f | ||
|
|
d3be77bf09 | ||
|
|
bcafd9e97e | ||
|
|
f581e55842 | ||
|
|
dfe4e4f1ab | ||
|
|
080e2a1667 | ||
|
|
01cbee00fd | ||
|
|
f0869c741f | ||
|
|
6dc690011d | ||
|
|
65891c7c11 | ||
|
|
d306152d38 | ||
|
|
b372f64e11 | ||
|
|
baff93bd96 | ||
|
|
abbe13b269 | ||
|
|
fb43932e0d | ||
|
|
c10aa73e5e | ||
|
|
be09f3e9dd | ||
|
|
d3f94337ae | ||
|
|
46a227453e | ||
|
|
8981d69844 | ||
|
|
09fbc37472 | ||
|
|
5cee1ea7cf | ||
|
|
cd9a673e62 | ||
|
|
dd9f754e85 | ||
|
|
7d22d1ddc4 | ||
|
|
d5f562b48f | ||
|
|
bb64ee4012 | ||
|
|
a60430b4b2 | ||
|
|
117a172bc2 | ||
|
|
b93b7f321e | ||
|
|
f34f3da587 | ||
|
|
8104f852d8 | ||
|
|
32e58e6280 | ||
|
|
c4dc81e4bc | ||
|
|
9fe0396abe | ||
|
|
ad2b58697a | ||
|
|
4845b02fc8 | ||
|
|
1ed53d5e4b | ||
|
|
00622126d7 | ||
|
|
b5cdd66248 | ||
|
|
78408427b8 | ||
|
|
baf9e8e833 | ||
|
|
bde00a26d5 | ||
|
|
6be6a2196e | ||
|
|
b8dab3d4a4 | ||
|
|
447c929386 | ||
|
|
9e37c01a83 | ||
|
|
3d39dc8ed8 | ||
|
|
08ace8b08d | ||
|
|
cbf95b1e04 | ||
|
|
fd8f93ee5f | ||
|
|
4f146f9427 | ||
|
|
19ace06c08 | ||
|
|
4bfe947ce1 | ||
|
|
4850b38e7f | ||
|
|
e5f19c5f20 | ||
|
|
8c4212678f | ||
|
|
573e80728c | ||
|
|
c88fa690f6 | ||
|
|
1feb89acf5 | ||
|
|
8be252e949 | ||
|
|
3aaf230a60 | ||
|
|
27126638be | ||
|
|
8c3a001930 | ||
|
|
2b2f181888 | ||
|
|
66557fa126 | ||
|
|
7c00951d74 | ||
|
|
1087ed56ce | ||
|
|
dd2cfd90b1 | ||
|
|
e45339f75c | ||
|
|
9c225ff7a0 | ||
|
|
6cdfba420f | ||
|
|
cc43d45c9c | ||
|
|
dba51f171d | ||
|
|
0bbf9f783f | ||
|
|
a52ac6a41b | ||
|
|
a542c91dc3 | ||
|
|
6bcbb0cc86 | ||
|
|
7a78d51c79 | ||
|
|
3c2715840e | ||
|
|
dfbd90aaf4 | ||
|
|
2b3a4ce8ce | ||
|
|
135292f2b4 | ||
|
|
499c697b0b | ||
|
|
fb74f01609 | ||
|
|
6ab2216742 | ||
|
|
7c97aa70a0 | ||
|
|
ff255e8293 | ||
|
|
57dc976a9f | ||
|
|
13361241e8 | ||
|
|
332af9a04a | ||
|
|
961c60f936 | ||
|
|
34483886be | ||
|
|
548989f9ae | ||
|
|
83a59aff37 | ||
|
|
60f28b16e7 | ||
|
|
9cb8bbd5b7 | ||
|
|
f7c95e9b36 | ||
|
|
cd37eedd15 | ||
|
|
7d11c4003f | ||
|
|
7d9b67a04d | ||
|
|
aba178a324 | ||
|
|
4ecdaf5225 | ||
|
|
c0bc9f7a14 | ||
|
|
094d96d880 | ||
|
|
a8fad6f160 | ||
|
|
6befd5ca76 | ||
|
|
046812ff27 | ||
|
|
db1778a749 | ||
|
|
f27fa1625c | ||
|
|
39a9d5f95b | ||
|
|
234d7163fc | ||
|
|
6f64cc9996 | ||
|
|
58e3b49bdf | ||
|
|
ca2dc1e1e0 | ||
|
|
c65dca4c58 | ||
|
|
82c2351b00 | ||
|
|
f31ca163e5 | ||
|
|
351db5de95 | ||
|
|
41164516f7 | ||
|
|
29a3c815fc | ||
|
|
1768063e57 | ||
|
|
35ce5603e5 | ||
|
|
19e38f9885 | ||
|
|
c55528b8a0 | ||
|
|
1c00f31312 | ||
|
|
8e66530544 | ||
|
|
7bdd3d902b | ||
|
|
abb44608fe | ||
|
|
0b1e3f4be8 | ||
|
|
156eb8ec27 | ||
|
|
472dcac590 | ||
|
|
b4d86f415c | ||
|
|
812e768f93 | ||
|
|
a08d4798e1 | ||
|
|
7bc08c9950 | ||
|
|
20107e3f05 | ||
|
|
ed678c36a5 | ||
|
|
f7574a9a60 | ||
|
|
e506b543e6 | ||
|
|
019a549b64 | ||
|
|
8dbc883a8c | ||
|
|
5fd918115c | ||
|
|
a11f8377fe | ||
|
|
7be19f8603 | ||
|
|
5407ebecb1 | ||
|
|
b75a1b4e6c | ||
|
|
1c28039aaf | ||
|
|
3a1836ef84 | ||
|
|
c747889f85 | ||
|
|
338a8426b2 | ||
|
|
4b1701d158 | ||
|
|
5d64a9a422 | ||
|
|
c2315db127 | ||
|
|
e40129f701 | ||
|
|
d198ad9a6b | ||
|
|
abffc5ab60 | ||
|
|
24ff9db32d | ||
|
|
07fa560344 | ||
|
|
28615d9038 | ||
|
|
d8f53e4b65 | ||
|
|
1f0cef4161 | ||
|
|
af5d72e0d0 | ||
|
|
1397e92709 | ||
|
|
a49121b1d9 | ||
|
|
ca65a6fb71 | ||
|
|
a54857c6bf | ||
|
|
2eadd05289 | ||
|
|
6eafa5e036 | ||
|
|
40f01ad100 | ||
|
|
161b36325e | ||
|
|
f9a6ddd513 | ||
|
|
e85110f8b6 | ||
|
|
76d3dba574 | ||
|
|
178b50a033 | ||
|
|
fb45aefde3 | ||
|
|
05bbc8a95b | ||
|
|
f123299dd6 | ||
|
|
7174413e2a | ||
|
|
d816f73598 | ||
|
|
b249ccdd6c | ||
|
|
4a007530a6 | ||
|
|
04ce448b23 | ||
|
|
ccd446f299 | ||
|
|
c49c8a5301 | ||
|
|
55cc2819d0 | ||
|
|
f8de7de0d6 | ||
|
|
2ea1bc2c20 | ||
|
|
90d095ea51 | ||
|
|
e1d12d0918 | ||
|
|
d9d0957040 | ||
|
|
9d73db3c51 | ||
|
|
c0f0786fd4 | ||
|
|
357eff116f | ||
|
|
32a047c522 | ||
|
|
8a237bb7ec | ||
|
|
f5b9072cc6 | ||
|
|
4e3eaa53ff | ||
|
|
4779d3f161 | ||
|
|
b0173fae94 | ||
|
|
c6ee8830a3 | ||
|
|
c2eeab5025 | ||
|
|
43fd40347f | ||
|
|
53139f9bb2 | ||
|
|
0b6033cc00 | ||
|
|
6f0115e5c5 | ||
|
|
2403adf537 | ||
|
|
f00ab897b5 | ||
|
|
093631bf6f | ||
|
|
5c2835ab76 | ||
|
|
03029981fd | ||
|
|
69b1838038 | ||
|
|
1c2f83026c | ||
|
|
d36f2c59e3 | ||
|
|
53ebec3f03 | ||
|
|
f2cbbaeb12 | ||
|
|
31c1202649 | ||
|
|
331499461a | ||
|
|
8c6dd5e343 | ||
|
|
01b1e8228d | ||
|
|
43979d6115 | ||
|
|
6a9860e202 | ||
|
|
39338e8028 | ||
|
|
d1d5351a01 | ||
|
|
c9385c7fdd | ||
|
|
afaae89af6 | ||
|
|
b9d799cd49 | ||
|
|
e47c541e08 | ||
|
|
51ff01d2cd | ||
|
|
618399cb09 | ||
|
|
b837a2e528 | ||
|
|
a1e8b8f9cc | ||
|
|
787c5da72a | ||
|
|
260703be8e | ||
|
|
053801b046 | ||
|
|
db9b1970c5 | ||
|
|
b153ef5ea5 | ||
|
|
b54809f399 | ||
|
|
f7f47c54ff | ||
|
|
92564ae527 | ||
|
|
52ada8574d | ||
|
|
013fb67943 | ||
|
|
d86298f502 | ||
|
|
5891b78be0 | ||
|
|
a9e3e44f2c | ||
|
|
0d1c7234e8 | ||
|
|
e3abe5f209 | ||
|
|
b453bfce5b | ||
|
|
147a1b03a7 | ||
|
|
3017db5f86 | ||
|
|
399d0d8058 | ||
|
|
b8c0d4ef67 | ||
|
|
918d086705 | ||
|
|
ac05acf96b | ||
|
|
e7449806c0 | ||
|
|
baab3213b5 | ||
|
|
d68e9e9589 | ||
|
|
be81f9727a | ||
|
|
04b7e7fd38 | ||
|
|
e6b50fafd2 | ||
|
|
d4896a7607 | ||
|
|
0b203709fa | ||
|
|
df5faba146 | ||
|
|
d8f8b63488 | ||
|
|
c100fc76ed | ||
|
|
c553d87600 | ||
|
|
b542bd54fb | ||
|
|
4ec11a47a1 | ||
|
|
175ce2be48 | ||
|
|
aad1655f2e | ||
|
|
85eb0b70e6 | ||
|
|
f54e12886a | ||
|
|
80ebe4c292 | ||
|
|
92b3bc3aea | ||
|
|
2cfb82c235 | ||
|
|
dd693323d7 | ||
|
|
5c8f03003e | ||
|
|
023fac2ea9 | ||
|
|
9086c26b5e | ||
|
|
0af8e99e61 | ||
|
|
4ca45dd32b | ||
|
|
127753ee86 | ||
|
|
30a9411cdd | ||
|
|
e801a4a77c | ||
|
|
d8c49995ce | ||
|
|
0c93663e51 | ||
|
|
605ac07594 | ||
|
|
9a7f2233a0 | ||
|
|
1339c427c4 | ||
|
|
8d79804872 | ||
|
|
3598bb6adb | ||
|
|
50b18a1a71 | ||
|
|
0ab585d4cc | ||
|
|
d32b9b879d | ||
|
|
594ad38454 | ||
|
|
ae8a885b4d | ||
|
|
975bbadaae | ||
|
|
42711bc92a | ||
|
|
f4538ffabd | ||
|
|
d60c3d3ea6 | ||
|
|
3cc32e48f4 | ||
|
|
0d4b7d8ee1 | ||
|
|
d8249c7163 | ||
|
|
60edb65b55 | ||
|
|
bc2bb3636b | ||
|
|
58c49c1240 | ||
|
|
2eb9a58aa6 | ||
|
|
b05ded67a9 | ||
|
|
76c9473704 | ||
|
|
3909223d2f | ||
|
|
ab720272da | ||
|
|
b702a663f4 | ||
|
|
1d8baaf423 | ||
|
|
0869c99090 | ||
|
|
48b2bab5d6 | ||
|
|
0bfa036603 | ||
|
|
a02bcf94d7 | ||
|
|
9e0b45deac | ||
|
|
1b04faad9c | ||
|
|
17f5cf6a1d | ||
|
|
bf7cffdf8f | ||
|
|
a3ba527765 | ||
|
|
a085b2d87d | ||
|
|
06f1ce5884 | ||
|
|
c77f9bce51 | ||
|
|
cf11c203ce | ||
|
|
4550d33b92 | ||
|
|
503127eb03 | ||
|
|
dbb139dfad | ||
|
|
e1a5a871ae | ||
|
|
0714ec6432 | ||
|
|
36339a04e1 | ||
|
|
8af9868d2f | ||
|
|
99d5372f25 | ||
|
|
bd6defe205 | ||
|
|
f5276031c0 | ||
|
|
50ebdf547a | ||
|
|
ba248758cb | ||
|
|
4bde8181b7 | ||
|
|
d0d733b7d2 | ||
|
|
e377f6c8d0 | ||
|
|
2fafe1101c | ||
|
|
56a315524a | ||
|
|
244a164891 | ||
|
|
2ec0c1d465 | ||
|
|
239ca73a64 | ||
|
|
b03460d6bb | ||
|
|
d2686949c5 | ||
|
|
971242b015 | ||
|
|
bd3b821226 | ||
|
|
6ffa856795 | ||
|
|
6895d2060d | ||
|
|
d413a06b87 | ||
|
|
263000f0ae | ||
|
|
578f6ab62a | ||
|
|
469b625989 | ||
|
|
95a630b600 | ||
|
|
5f576a2792 | ||
|
|
f5af92da93 | ||
|
|
4ccfcd6be7 | ||
|
|
917d093bcf | ||
|
|
c916771815 | ||
|
|
d4517ac986 | ||
|
|
040cc6adf9 | ||
|
|
ec740089fe | ||
|
|
e29e14bc3e | ||
|
|
592baa4c6e | ||
|
|
5e5c9c96b4 | ||
|
|
487f64e459 | ||
|
|
d67aeaa333 | ||
|
|
fb5cdfce29 | ||
|
|
6e5cfde2cf | ||
|
|
7122f4ac0d | ||
|
|
2fb24b8b65 | ||
|
|
6540d96d4d | ||
|
|
62e196b97d | ||
|
|
4975861710 | ||
|
|
8d74799099 | ||
|
|
c58b4552b2 | ||
|
|
8c6920afab | ||
|
|
b77fd2c1c7 | ||
|
|
2035d6f6e2 | ||
|
|
e58454ef5d | ||
|
|
915eb1722d | ||
|
|
4f706d3e93 | ||
|
|
d80f0dcb8f | ||
|
|
2ae334d06d | ||
|
|
4388df71f3 | ||
|
|
c972f9c8a2 | ||
|
|
90fa6ad5fc | ||
|
|
a1b2b40abe | ||
|
|
00fd499805 | ||
|
|
8f3f71772b | ||
|
|
08104eef2a | ||
|
|
8d989ee81c | ||
|
|
2247b1b1db | ||
|
|
249ad938f6 | ||
|
|
c9d60910e5 | ||
|
|
03b89786ec | ||
|
|
8815009b04 | ||
|
|
bb4a8f7f83 | ||
|
|
c7730d1775 | ||
|
|
b7a3ef0fa7 | ||
|
|
d525e2195c | ||
|
|
cb73be0e43 | ||
|
|
a06bdbff88 | ||
|
|
0de6ab7547 | ||
|
|
5b54b8113e | ||
|
|
4d804803a8 | ||
|
|
2434245c84 | ||
|
|
d00e6e252d | ||
|
|
e006c158fc | ||
|
|
75d610200b | ||
|
|
f696030ac2 |
13
.env
13
.env
@@ -1,2 +1,13 @@
|
|||||||
LC_ALL=en_US.UTF-8
|
LC_ALL=en_US.UTF-8
|
||||||
LANG=en_US.UTF-8
|
LANG=en_US.UTF-8
|
||||||
|
MailConfig__EmailServer=""
|
||||||
|
MailConfig__EmailFrom=""
|
||||||
|
MailConfig__UseSSL="false"
|
||||||
|
MailConfig__Port=587
|
||||||
|
MailConfig__Username=""
|
||||||
|
MailConfig__Password=""
|
||||||
|
LOGGING__LOGLEVEL__DEFAULT=Error
|
||||||
|
|
||||||
|
# * Uncoment this line if you use postgresSQL as database backend.
|
||||||
|
# * Check the docker-compose.postgresql.yml file
|
||||||
|
#POSTGRES_CONNECTION="Host=postgres;Username=lubelogger;Password=lubepass;Database=lubelogger;"
|
||||||
|
|||||||
14
.github/FUNDING.yml
vendored
Normal file
14
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: lubelogger
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||||
|
polar: # Replace with a single Polar username
|
||||||
|
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
|
||||||
|
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||||
30
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
30
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Report a bug
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Checklist**
|
||||||
|
Please make sure you have performed the following steps before opening a new bug ticket, change `[ ]` to `[x]` to mark it as done
|
||||||
|
|
||||||
|
- [ ] I have read and tried the steps outlined in the [Troubleshooting Guide](https://docs.lubelogger.com/Troubleshooting)
|
||||||
|
- [ ] I have searched through existing issues.
|
||||||
|
|
||||||
|
**Description**
|
||||||
|
<!-- Describe the bug below this line -->
|
||||||
|
|
||||||
|
**Platform**
|
||||||
|
- [ ] Docker Image
|
||||||
|
- [ ] Windows Standalone Executable
|
||||||
|
|
||||||
|
**Browser Console Errors(F12)**
|
||||||
|
<!-- Attach a screenshot or codeblock containing the browser console error -->
|
||||||
|
|
||||||
|
**App/Container Console Error**
|
||||||
|
<!-- Attach a screenshot or codeblock containing the app/container console error -->
|
||||||
|
|
||||||
|
**Screenshots(optional)**
|
||||||
|
<!-- Attach a screenshot describing the bug -->
|
||||||
51
.github/workflows/build-and-push-image.yml
vendored
Normal file
51
.github/workflows/build-and-push-image.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
name: Build and Push Image to Dockerhub and GHCR
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
release:
|
||||||
|
types: ["published"]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: "${{ secrets.DH_USER }}"
|
||||||
|
password: "${{ secrets.DH_PASS }}"
|
||||||
|
|
||||||
|
- name: Login to GitHub Container Registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: "hargata"
|
||||||
|
password: "${{ secrets.GHCR_PAT }}"
|
||||||
|
|
||||||
|
- name: Docker Metadata
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v5
|
||||||
|
with:
|
||||||
|
context: workflow
|
||||||
|
images: |
|
||||||
|
hargata/lubelogger
|
||||||
|
ghcr.io/hargata/lubelogger
|
||||||
|
tags: |
|
||||||
|
type=edge,branch=main
|
||||||
|
type=ref,event=tag
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
31
.github/workflows/docker-image.yml
vendored
31
.github/workflows/docker-image.yml
vendored
@@ -1,31 +0,0 @@
|
|||||||
name: Docker Image CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "main" ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
build:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: "hargata"
|
|
||||||
password: "${{ secrets.GHCR_PAT }}"
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64
|
|
||||||
push: true
|
|
||||||
tags: |
|
|
||||||
ghcr.io/hargata/lubelogger:latest
|
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -7,3 +7,8 @@ data/cartracker.db
|
|||||||
wwwroot/documents/
|
wwwroot/documents/
|
||||||
wwwroot/temp/
|
wwwroot/temp/
|
||||||
wwwroot/imports/
|
wwwroot/imports/
|
||||||
|
wwwroot/translations/
|
||||||
|
config/userConfig.json
|
||||||
|
CarCareTracker.csproj.user
|
||||||
|
Properties/launchSettings.json
|
||||||
|
data/cartracker-log.db
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
||||||
<PackageReference Include="LiteDB" Version="5.0.17" />
|
<PackageReference Include="LiteDB" Version="5.0.17" />
|
||||||
|
<PackageReference Include="MailKit" Version="4.5.0" />
|
||||||
|
<PackageReference Include="Npgsql" Version="8.0.2" />
|
||||||
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.3.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<View_SelectedScaffolderID>RazorViewEmptyScaffolder</View_SelectedScaffolderID>
|
|
||||||
<View_SelectedScaffolderCategoryPath>root/Common/MVC/View</View_SelectedScaffolderCategoryPath>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
using CarCareTracker.External.Interfaces;
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Filter;
|
||||||
using CarCareTracker.Helper;
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Logic;
|
||||||
using CarCareTracker.Models;
|
using CarCareTracker.Models;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
namespace CarCareTracker.Controllers
|
namespace CarCareTracker.Controllers
|
||||||
{
|
{
|
||||||
@@ -17,8 +20,17 @@ namespace CarCareTracker.Controllers
|
|||||||
private readonly ITaxRecordDataAccess _taxRecordDataAccess;
|
private readonly ITaxRecordDataAccess _taxRecordDataAccess;
|
||||||
private readonly IReminderRecordDataAccess _reminderRecordDataAccess;
|
private readonly IReminderRecordDataAccess _reminderRecordDataAccess;
|
||||||
private readonly IUpgradeRecordDataAccess _upgradeRecordDataAccess;
|
private readonly IUpgradeRecordDataAccess _upgradeRecordDataAccess;
|
||||||
|
private readonly IOdometerRecordDataAccess _odometerRecordDataAccess;
|
||||||
|
private readonly IUserAccessDataAccess _userAccessDataAccess;
|
||||||
|
private readonly IUserRecordDataAccess _userRecordDataAccess;
|
||||||
private readonly IReminderHelper _reminderHelper;
|
private readonly IReminderHelper _reminderHelper;
|
||||||
private readonly IGasHelper _gasHelper;
|
private readonly IGasHelper _gasHelper;
|
||||||
|
private readonly IUserLogic _userLogic;
|
||||||
|
private readonly IVehicleLogic _vehicleLogic;
|
||||||
|
private readonly IOdometerLogic _odometerLogic;
|
||||||
|
private readonly IFileHelper _fileHelper;
|
||||||
|
private readonly IMailHelper _mailHelper;
|
||||||
|
private readonly IConfigHelper _config;
|
||||||
public APIController(IVehicleDataAccess dataAccess,
|
public APIController(IVehicleDataAccess dataAccess,
|
||||||
IGasHelper gasHelper,
|
IGasHelper gasHelper,
|
||||||
IReminderHelper reminderHelper,
|
IReminderHelper reminderHelper,
|
||||||
@@ -28,7 +40,16 @@ namespace CarCareTracker.Controllers
|
|||||||
ICollisionRecordDataAccess collisionRecordDataAccess,
|
ICollisionRecordDataAccess collisionRecordDataAccess,
|
||||||
ITaxRecordDataAccess taxRecordDataAccess,
|
ITaxRecordDataAccess taxRecordDataAccess,
|
||||||
IReminderRecordDataAccess reminderRecordDataAccess,
|
IReminderRecordDataAccess reminderRecordDataAccess,
|
||||||
IUpgradeRecordDataAccess upgradeRecordDataAccess)
|
IUpgradeRecordDataAccess upgradeRecordDataAccess,
|
||||||
|
IOdometerRecordDataAccess odometerRecordDataAccess,
|
||||||
|
IUserAccessDataAccess userAccessDataAccess,
|
||||||
|
IUserRecordDataAccess userRecordDataAccess,
|
||||||
|
IMailHelper mailHelper,
|
||||||
|
IFileHelper fileHelper,
|
||||||
|
IConfigHelper config,
|
||||||
|
IUserLogic userLogic,
|
||||||
|
IVehicleLogic vehicleLogic,
|
||||||
|
IOdometerLogic odometerLogic)
|
||||||
{
|
{
|
||||||
_dataAccess = dataAccess;
|
_dataAccess = dataAccess;
|
||||||
_noteDataAccess = noteDataAccess;
|
_noteDataAccess = noteDataAccess;
|
||||||
@@ -38,21 +59,38 @@ namespace CarCareTracker.Controllers
|
|||||||
_taxRecordDataAccess = taxRecordDataAccess;
|
_taxRecordDataAccess = taxRecordDataAccess;
|
||||||
_reminderRecordDataAccess = reminderRecordDataAccess;
|
_reminderRecordDataAccess = reminderRecordDataAccess;
|
||||||
_upgradeRecordDataAccess = upgradeRecordDataAccess;
|
_upgradeRecordDataAccess = upgradeRecordDataAccess;
|
||||||
|
_odometerRecordDataAccess = odometerRecordDataAccess;
|
||||||
|
_userAccessDataAccess = userAccessDataAccess;
|
||||||
|
_userRecordDataAccess = userRecordDataAccess;
|
||||||
|
_mailHelper = mailHelper;
|
||||||
_gasHelper = gasHelper;
|
_gasHelper = gasHelper;
|
||||||
_reminderHelper = reminderHelper;
|
_reminderHelper = reminderHelper;
|
||||||
|
_userLogic = userLogic;
|
||||||
|
_odometerLogic = odometerLogic;
|
||||||
|
_vehicleLogic = vehicleLogic;
|
||||||
|
_fileHelper = fileHelper;
|
||||||
|
_config = config;
|
||||||
}
|
}
|
||||||
public IActionResult Index()
|
public IActionResult Index()
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
private int GetUserID()
|
||||||
|
{
|
||||||
|
return int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier));
|
||||||
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("/api/vehicles")]
|
[Route("/api/vehicles")]
|
||||||
public IActionResult Vehicles()
|
public IActionResult Vehicles()
|
||||||
{
|
{
|
||||||
var result = _dataAccess.GetVehicles();
|
var result = _dataAccess.GetVehicles();
|
||||||
|
if (!User.IsInRole(nameof(UserData.IsRootUser)))
|
||||||
|
{
|
||||||
|
result = _userLogic.FilterUserVehicles(result, GetUserID());
|
||||||
|
}
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("/api/vehicle/servicerecords")]
|
[Route("/api/vehicle/servicerecords")]
|
||||||
public IActionResult ServiceRecords(int vehicleId)
|
public IActionResult ServiceRecords(int vehicleId)
|
||||||
@@ -61,6 +99,66 @@ namespace CarCareTracker.Controllers
|
|||||||
var result = vehicleRecords.Select(x => new ServiceRecordExportModel { Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString(), Notes = x.Notes, Odometer = x.Mileage.ToString() });
|
var result = vehicleRecords.Select(x => new ServiceRecordExportModel { Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString(), Notes = x.Notes, Odometer = x.Mileage.ToString() });
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
|
[HttpPost]
|
||||||
|
[Route("/api/vehicle/servicerecords/add")]
|
||||||
|
public IActionResult AddServiceRecord(int vehicleId, ServiceRecordExportModel input)
|
||||||
|
{
|
||||||
|
var response = new OperationResponse();
|
||||||
|
if (vehicleId == default)
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = "Must provide a valid vehicle id";
|
||||||
|
Response.StatusCode = 400;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(input.Date) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.Description) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.Odometer) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.Cost))
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = "Input object invalid, Date, Description, Odometer, and Cost cannot be empty.";
|
||||||
|
Response.StatusCode = 400;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var serviceRecord = new ServiceRecord()
|
||||||
|
{
|
||||||
|
VehicleId = vehicleId,
|
||||||
|
Date = DateTime.Parse(input.Date),
|
||||||
|
Mileage = int.Parse(input.Odometer),
|
||||||
|
Description = input.Description,
|
||||||
|
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
|
||||||
|
Cost = decimal.Parse(input.Cost)
|
||||||
|
};
|
||||||
|
_serviceRecordDataAccess.SaveServiceRecordToVehicle(serviceRecord);
|
||||||
|
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||||
|
{
|
||||||
|
var odometerRecord = new OdometerRecord()
|
||||||
|
{
|
||||||
|
VehicleId = vehicleId,
|
||||||
|
Date = DateTime.Parse(input.Date),
|
||||||
|
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
|
||||||
|
Mileage = int.Parse(input.Odometer)
|
||||||
|
};
|
||||||
|
_odometerLogic.AutoInsertOdometerRecord(odometerRecord);
|
||||||
|
}
|
||||||
|
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), vehicleId, User.Identity.Name, $"Added Service Record via API - Description: {serviceRecord.Description}");
|
||||||
|
response.Success = true;
|
||||||
|
response.Message = "Service Record Added";
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = ex.Message;
|
||||||
|
Response.StatusCode = 500;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("/api/vehicle/repairrecords")]
|
[Route("/api/vehicle/repairrecords")]
|
||||||
public IActionResult RepairRecords(int vehicleId)
|
public IActionResult RepairRecords(int vehicleId)
|
||||||
@@ -69,6 +167,66 @@ namespace CarCareTracker.Controllers
|
|||||||
var result = vehicleRecords.Select(x => new ServiceRecordExportModel { Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString(), Notes = x.Notes, Odometer = x.Mileage.ToString() });
|
var result = vehicleRecords.Select(x => new ServiceRecordExportModel { Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString(), Notes = x.Notes, Odometer = x.Mileage.ToString() });
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
|
[HttpPost]
|
||||||
|
[Route("/api/vehicle/repairrecords/add")]
|
||||||
|
public IActionResult AddRepairRecord(int vehicleId, ServiceRecordExportModel input)
|
||||||
|
{
|
||||||
|
var response = new OperationResponse();
|
||||||
|
if (vehicleId == default)
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = "Must provide a valid vehicle id";
|
||||||
|
Response.StatusCode = 400;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(input.Date) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.Description) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.Odometer) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.Cost))
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = "Input object invalid, Date, Description, Odometer, and Cost cannot be empty.";
|
||||||
|
Response.StatusCode = 400;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var repairRecord = new CollisionRecord()
|
||||||
|
{
|
||||||
|
VehicleId = vehicleId,
|
||||||
|
Date = DateTime.Parse(input.Date),
|
||||||
|
Mileage = int.Parse(input.Odometer),
|
||||||
|
Description = input.Description,
|
||||||
|
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
|
||||||
|
Cost = decimal.Parse(input.Cost)
|
||||||
|
};
|
||||||
|
_collisionRecordDataAccess.SaveCollisionRecordToVehicle(repairRecord);
|
||||||
|
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||||
|
{
|
||||||
|
var odometerRecord = new OdometerRecord()
|
||||||
|
{
|
||||||
|
VehicleId = vehicleId,
|
||||||
|
Date = DateTime.Parse(input.Date),
|
||||||
|
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
|
||||||
|
Mileage = int.Parse(input.Odometer)
|
||||||
|
};
|
||||||
|
_odometerLogic.AutoInsertOdometerRecord(odometerRecord);
|
||||||
|
}
|
||||||
|
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), vehicleId, User.Identity.Name, $"Added Repair Record via API - Description: {repairRecord.Description}");
|
||||||
|
response.Success = true;
|
||||||
|
response.Message = "Repair Record Added";
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = ex.Message;
|
||||||
|
Response.StatusCode = 500;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("/api/vehicle/upgraderecords")]
|
[Route("/api/vehicle/upgraderecords")]
|
||||||
public IActionResult UpgradeRecords(int vehicleId)
|
public IActionResult UpgradeRecords(int vehicleId)
|
||||||
@@ -77,6 +235,66 @@ namespace CarCareTracker.Controllers
|
|||||||
var result = vehicleRecords.Select(x => new ServiceRecordExportModel { Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString(), Notes = x.Notes, Odometer = x.Mileage.ToString() });
|
var result = vehicleRecords.Select(x => new ServiceRecordExportModel { Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString(), Notes = x.Notes, Odometer = x.Mileage.ToString() });
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
|
[HttpPost]
|
||||||
|
[Route("/api/vehicle/upgraderecords/add")]
|
||||||
|
public IActionResult AddUpgradeRecord(int vehicleId, ServiceRecordExportModel input)
|
||||||
|
{
|
||||||
|
var response = new OperationResponse();
|
||||||
|
if (vehicleId == default)
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = "Must provide a valid vehicle id";
|
||||||
|
Response.StatusCode = 400;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(input.Date) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.Description) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.Odometer) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.Cost))
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = "Input object invalid, Date, Description, Odometer, and Cost cannot be empty.";
|
||||||
|
Response.StatusCode = 400;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var upgradeRecord = new UpgradeRecord()
|
||||||
|
{
|
||||||
|
VehicleId = vehicleId,
|
||||||
|
Date = DateTime.Parse(input.Date),
|
||||||
|
Mileage = int.Parse(input.Odometer),
|
||||||
|
Description = input.Description,
|
||||||
|
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
|
||||||
|
Cost = decimal.Parse(input.Cost)
|
||||||
|
};
|
||||||
|
_upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(upgradeRecord);
|
||||||
|
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||||
|
{
|
||||||
|
var odometerRecord = new OdometerRecord()
|
||||||
|
{
|
||||||
|
VehicleId = vehicleId,
|
||||||
|
Date = DateTime.Parse(input.Date),
|
||||||
|
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
|
||||||
|
Mileage = int.Parse(input.Odometer)
|
||||||
|
};
|
||||||
|
_odometerLogic.AutoInsertOdometerRecord(odometerRecord);
|
||||||
|
}
|
||||||
|
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), vehicleId, User.Identity.Name, $"Added Upgrade Record via API - Description: {upgradeRecord.Description}");
|
||||||
|
response.Success = true;
|
||||||
|
response.Message = "Upgrade Record Added";
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = ex.Message;
|
||||||
|
Response.StatusCode = 500;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("/api/vehicle/taxrecords")]
|
[Route("/api/vehicle/taxrecords")]
|
||||||
public IActionResult TaxRecords(int vehicleId)
|
public IActionResult TaxRecords(int vehicleId)
|
||||||
@@ -84,47 +302,271 @@ namespace CarCareTracker.Controllers
|
|||||||
var result = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId);
|
var result = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId);
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
|
[HttpPost]
|
||||||
|
[Route("/api/vehicle/taxrecords/add")]
|
||||||
|
public IActionResult AddTaxRecord(int vehicleId, TaxRecordExportModel input)
|
||||||
|
{
|
||||||
|
var response = new OperationResponse();
|
||||||
|
if (vehicleId == default)
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = "Must provide a valid vehicle id";
|
||||||
|
Response.StatusCode = 400;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(input.Date) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.Description) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.Cost))
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = "Input object invalid, Date, Description, and Cost cannot be empty.";
|
||||||
|
Response.StatusCode = 400;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var taxRecord = new TaxRecord()
|
||||||
|
{
|
||||||
|
VehicleId = vehicleId,
|
||||||
|
Date = DateTime.Parse(input.Date),
|
||||||
|
Description = input.Description,
|
||||||
|
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
|
||||||
|
Cost = decimal.Parse(input.Cost)
|
||||||
|
};
|
||||||
|
_taxRecordDataAccess.SaveTaxRecordToVehicle(taxRecord);
|
||||||
|
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), vehicleId, User.Identity.Name, $"Added Tax Record via API - Description: {taxRecord.Description}");
|
||||||
|
response.Success = true;
|
||||||
|
response.Message = "Tax Record Added";
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = ex.Message;
|
||||||
|
Response.StatusCode = 500;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
|
[HttpGet]
|
||||||
|
[Route("/api/vehicle/odometerrecords/latest")]
|
||||||
|
public IActionResult LastOdometer(int vehicleId)
|
||||||
|
{
|
||||||
|
var result = _vehicleLogic.GetMaxMileage(vehicleId);
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
|
[HttpGet]
|
||||||
|
[Route("/api/vehicle/odometerrecords")]
|
||||||
|
public IActionResult OdometerRecords(int vehicleId)
|
||||||
|
{
|
||||||
|
var vehicleRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
|
||||||
|
//determine if conversion is needed.
|
||||||
|
if (vehicleRecords.All(x => x.InitialMileage == default))
|
||||||
|
{
|
||||||
|
vehicleRecords = _odometerLogic.AutoConvertOdometerRecord(vehicleRecords);
|
||||||
|
}
|
||||||
|
var result = vehicleRecords.Select(x => new OdometerRecordExportModel { Date = x.Date.ToShortDateString(), InitialOdometer = x.InitialMileage.ToString(), Odometer = x.Mileage.ToString(), Notes = x.Notes });
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
|
[HttpPost]
|
||||||
|
[Route("/api/vehicle/odometerrecords/add")]
|
||||||
|
public IActionResult AddOdometerRecord(int vehicleId, OdometerRecordExportModel input)
|
||||||
|
{
|
||||||
|
var response = new OperationResponse();
|
||||||
|
if (vehicleId == default)
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = "Must provide a valid vehicle id";
|
||||||
|
Response.StatusCode = 400;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(input.Date) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.Odometer))
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = "Input object invalid, Date and Odometer cannot be empty.";
|
||||||
|
Response.StatusCode = 400;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var odometerRecord = new OdometerRecord()
|
||||||
|
{
|
||||||
|
VehicleId = vehicleId,
|
||||||
|
Date = DateTime.Parse(input.Date),
|
||||||
|
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
|
||||||
|
InitialMileage = (string.IsNullOrWhiteSpace(input.InitialOdometer) || int.Parse(input.InitialOdometer) == default) ? _odometerLogic.GetLastOdometerRecordMileage(vehicleId, new List<OdometerRecord>()) : int.Parse(input.InitialOdometer),
|
||||||
|
Mileage = int.Parse(input.Odometer)
|
||||||
|
};
|
||||||
|
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(odometerRecord);
|
||||||
|
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), vehicleId, User.Identity.Name, $"Added Odometer Record via API - Mileage: {odometerRecord.Mileage.ToString()}");
|
||||||
|
response.Success = true;
|
||||||
|
response.Message = "Odometer Record Added";
|
||||||
|
return Json(response);
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = ex.Message;
|
||||||
|
Response.StatusCode = 500;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("/api/vehicle/gasrecords")]
|
[Route("/api/vehicle/gasrecords")]
|
||||||
public IActionResult GasRecords(int vehicleId, bool useMPG, bool useUKMPG)
|
public IActionResult GasRecords(int vehicleId, bool useMPG, bool useUKMPG)
|
||||||
{
|
{
|
||||||
var vehicleRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
var vehicleRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
||||||
var result = _gasHelper.GetGasRecordViewModels(vehicleRecords, useMPG, useUKMPG).Select(x => new GasRecordExportModel { Date = x.Date, Odometer = x.Mileage.ToString(), Cost = x.Cost.ToString(), FuelConsumed = x.Gallons.ToString(), FuelEconomy = x.MilesPerGallon.ToString()});
|
var result = _gasHelper.GetGasRecordViewModels(vehicleRecords, useMPG, useUKMPG)
|
||||||
|
.Select(x => new GasRecordExportModel {
|
||||||
|
Date = x.Date,
|
||||||
|
Odometer = x.Mileage.ToString(),
|
||||||
|
Cost = x.Cost.ToString(),
|
||||||
|
FuelConsumed = x.Gallons.ToString(),
|
||||||
|
FuelEconomy = x.MilesPerGallon.ToString(),
|
||||||
|
IsFillToFull = x.IsFillToFull.ToString(),
|
||||||
|
MissedFuelUp = x.MissedFuelUp.ToString(),
|
||||||
|
Notes = x.Notes
|
||||||
|
});
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
|
[HttpPost]
|
||||||
|
[Route("/api/vehicle/gasrecords/add")]
|
||||||
|
public IActionResult AddGasRecord(int vehicleId, GasRecordExportModel input)
|
||||||
|
{
|
||||||
|
var response = new OperationResponse();
|
||||||
|
if (vehicleId == default)
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = "Must provide a valid vehicle id";
|
||||||
|
Response.StatusCode = 400;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(input.Date) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.Odometer) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.FuelConsumed) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.Cost) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.IsFillToFull) ||
|
||||||
|
string.IsNullOrWhiteSpace(input.MissedFuelUp)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = "Input object invalid, Date, Odometer, FuelConsumed, IsFillToFull, MissedFuelUp, and Cost cannot be empty.";
|
||||||
|
Response.StatusCode = 400;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var gasRecord = new GasRecord()
|
||||||
|
{
|
||||||
|
VehicleId = vehicleId,
|
||||||
|
Date = DateTime.Parse(input.Date),
|
||||||
|
Mileage = int.Parse(input.Odometer),
|
||||||
|
Gallons = decimal.Parse(input.FuelConsumed),
|
||||||
|
IsFillToFull = bool.Parse(input.IsFillToFull),
|
||||||
|
MissedFuelUp = bool.Parse(input.MissedFuelUp),
|
||||||
|
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
|
||||||
|
Cost = decimal.Parse(input.Cost)
|
||||||
|
};
|
||||||
|
_gasRecordDataAccess.SaveGasRecordToVehicle(gasRecord);
|
||||||
|
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||||
|
{
|
||||||
|
var odometerRecord = new OdometerRecord()
|
||||||
|
{
|
||||||
|
VehicleId = vehicleId,
|
||||||
|
Date = DateTime.Parse(input.Date),
|
||||||
|
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
|
||||||
|
Mileage = int.Parse(input.Odometer)
|
||||||
|
};
|
||||||
|
_odometerLogic.AutoInsertOdometerRecord(odometerRecord);
|
||||||
|
}
|
||||||
|
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), vehicleId, User.Identity.Name, $"Added Gas record via API - Mileage: {gasRecord.Mileage.ToString()}");
|
||||||
|
response.Success = true;
|
||||||
|
response.Message = "Gas Record Added";
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
response.Success = false;
|
||||||
|
response.Message = ex.Message;
|
||||||
|
Response.StatusCode = 500;
|
||||||
|
return Json(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("/api/vehicle/reminders")]
|
[Route("/api/vehicle/reminders")]
|
||||||
public IActionResult Reminders(int vehicleId)
|
public IActionResult Reminders(int vehicleId)
|
||||||
{
|
{
|
||||||
var currentMileage = GetMaxMileage(vehicleId);
|
var currentMileage = _vehicleLogic.GetMaxMileage(vehicleId);
|
||||||
var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId);
|
var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId);
|
||||||
var results = _reminderHelper.GetReminderRecordViewModels(reminders, currentMileage, DateTime.Now).Select(x=> new ReminderExportModel { Description = x.Description, Urgency = x.Urgency.ToString(), Metric = x.Metric.ToString(), Notes = x.Notes});
|
var results = _reminderHelper.GetReminderRecordViewModels(reminders, currentMileage, DateTime.Now).Select(x=> new ReminderExportModel { Description = x.Description, Urgency = x.Urgency.ToString(), Metric = x.Metric.ToString(), Notes = x.Notes});
|
||||||
return Json(results);
|
return Json(results);
|
||||||
}
|
}
|
||||||
private int GetMaxMileage(int vehicleId)
|
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||||
|
[HttpGet]
|
||||||
|
[Route("/api/vehicle/reminders/send")]
|
||||||
|
public IActionResult SendReminders(List<ReminderUrgency> urgencies)
|
||||||
{
|
{
|
||||||
var numbersArray = new List<int>();
|
var vehicles = _dataAccess.GetVehicles();
|
||||||
var serviceRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId);
|
List<OperationResponse> operationResponses = new List<OperationResponse>();
|
||||||
if (serviceRecords.Any())
|
foreach(Vehicle vehicle in vehicles)
|
||||||
{
|
{
|
||||||
numbersArray.Add(serviceRecords.Max(x => x.Mileage));
|
var vehicleId = vehicle.Id;
|
||||||
|
//get reminders
|
||||||
|
var currentMileage = _vehicleLogic.GetMaxMileage(vehicleId);
|
||||||
|
var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId);
|
||||||
|
var results = _reminderHelper.GetReminderRecordViewModels(reminders, currentMileage, DateTime.Now).OrderByDescending(x => x.Urgency).ToList();
|
||||||
|
results.RemoveAll(x => !urgencies.Contains(x.Urgency));
|
||||||
|
if (!results.Any())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//get list of recipients.
|
||||||
|
var userIds = _userAccessDataAccess.GetUserAccessByVehicleId(vehicleId).Select(x => x.Id.UserId);
|
||||||
|
List<string> emailRecipients = new List<string>();
|
||||||
|
foreach (int userId in userIds)
|
||||||
|
{
|
||||||
|
var userData = _userRecordDataAccess.GetUserRecordById(userId);
|
||||||
|
emailRecipients.Add(userData.EmailAddress);
|
||||||
|
};
|
||||||
|
if (!emailRecipients.Any())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var result = _mailHelper.NotifyUserForReminders(vehicle, emailRecipients, results);
|
||||||
|
operationResponses.Add(result);
|
||||||
}
|
}
|
||||||
var repairRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId);
|
if (operationResponses.All(x => x.Success))
|
||||||
if (repairRecords.Any())
|
|
||||||
{
|
{
|
||||||
numbersArray.Add(repairRecords.Max(x => x.Mileage));
|
return Json(new OperationResponse { Success = true, Message = "Emails sent" });
|
||||||
}
|
} else if (operationResponses.All(x => !x.Success))
|
||||||
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
|
||||||
if (gasRecords.Any())
|
|
||||||
{
|
{
|
||||||
numbersArray.Add(gasRecords.Max(x => x.Mileage));
|
return Json(new OperationResponse { Success = false, Message = "All emails failed, check SMTP settings" });
|
||||||
}
|
} else
|
||||||
var upgradeRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
|
|
||||||
if (upgradeRecords.Any())
|
|
||||||
{
|
{
|
||||||
numbersArray.Add(upgradeRecords.Max(x => x.Mileage));
|
return Json(new OperationResponse { Success = true, Message = "Some emails sent, some failed, check recipient settings" });
|
||||||
}
|
}
|
||||||
return numbersArray.Any() ? numbersArray.Max() : 0;
|
}
|
||||||
|
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||||
|
[HttpGet]
|
||||||
|
[Route("/api/makebackup")]
|
||||||
|
public IActionResult MakeBackup()
|
||||||
|
{
|
||||||
|
var result = _fileHelper.MakeBackup();
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||||
|
[HttpGet]
|
||||||
|
[Route("/api/demo/restore")]
|
||||||
|
public IActionResult RestoreDemo()
|
||||||
|
{
|
||||||
|
var result = _fileHelper.RestoreBackup("/defaults/demo_default.zip", true);
|
||||||
|
return Json(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
54
Controllers/AdminController.cs
Normal file
54
Controllers/AdminController.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Logic;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Controllers
|
||||||
|
{
|
||||||
|
[Authorize(Roles = nameof(UserData.IsAdmin))]
|
||||||
|
public class AdminController : Controller
|
||||||
|
{
|
||||||
|
private ILoginLogic _loginLogic;
|
||||||
|
private IUserLogic _userLogic;
|
||||||
|
private IConfigHelper _configHelper;
|
||||||
|
public AdminController(ILoginLogic loginLogic, IUserLogic userLogic, IConfigHelper configHelper)
|
||||||
|
{
|
||||||
|
_loginLogic = loginLogic;
|
||||||
|
_userLogic = userLogic;
|
||||||
|
_configHelper = configHelper;
|
||||||
|
}
|
||||||
|
public IActionResult Index()
|
||||||
|
{
|
||||||
|
var viewModel = new AdminViewModel
|
||||||
|
{
|
||||||
|
Users = _loginLogic.GetAllUsers(),
|
||||||
|
Tokens = _loginLogic.GetAllTokens()
|
||||||
|
};
|
||||||
|
return View(viewModel);
|
||||||
|
}
|
||||||
|
public IActionResult GenerateNewToken(string emailAddress, bool autoNotify)
|
||||||
|
{
|
||||||
|
var result = _loginLogic.GenerateUserToken(emailAddress, autoNotify);
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult DeleteToken(int tokenId)
|
||||||
|
{
|
||||||
|
var result = _loginLogic.DeleteUserToken(tokenId);
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult DeleteUser(int userId)
|
||||||
|
{
|
||||||
|
var result =_userLogic.DeleteAllAccessToUser(userId) && _configHelper.DeleteUserConfig(userId) && _loginLogic.DeleteUser(userId);
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult UpdateUserAdminStatus(int userId, bool isAdmin)
|
||||||
|
{
|
||||||
|
var result = _loginLogic.MakeUserAdmin(userId, isAdmin);
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
Controllers/ErrorController.cs
Normal file
17
Controllers/ErrorController.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Controllers
|
||||||
|
{
|
||||||
|
public class ErrorController : Controller
|
||||||
|
{
|
||||||
|
public IActionResult Unauthorized()
|
||||||
|
{
|
||||||
|
if (!User.IsInRole("CookieAuth"))
|
||||||
|
{
|
||||||
|
Response.StatusCode = 403;
|
||||||
|
return new EmptyResult();
|
||||||
|
}
|
||||||
|
return View("401");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,5 @@
|
|||||||
using CarCareTracker.External.Interfaces;
|
|
||||||
using CarCareTracker.Models;
|
using CarCareTracker.Models;
|
||||||
using LiteDB;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using System.Diagnostics;
|
|
||||||
using static System.Net.Mime.MediaTypeNames;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using CarCareTracker.Helper;
|
using CarCareTracker.Helper;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
@@ -33,6 +26,26 @@ namespace CarCareTracker.Controllers
|
|||||||
return Json(fileName);
|
return Json(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult HandleTranslationFileUpload(IFormFile file)
|
||||||
|
{
|
||||||
|
var originalFileName = Path.GetFileNameWithoutExtension(file.FileName);
|
||||||
|
if (originalFileName == "en_US")
|
||||||
|
{
|
||||||
|
return Json(new OperationResponse { Success = false, Message = "The translation file name en_US is reserved." });
|
||||||
|
}
|
||||||
|
var fileName = UploadFile(file);
|
||||||
|
//move file from temp to translation folder.
|
||||||
|
var uploadedFilePath = _fileHelper.MoveFileFromTemp(fileName, "translations/");
|
||||||
|
//rename uploaded file so that it preserves original name.
|
||||||
|
if (!string.IsNullOrWhiteSpace(uploadedFilePath))
|
||||||
|
{
|
||||||
|
var result = _fileHelper.RenameFile(uploadedFilePath, originalFileName);
|
||||||
|
return Json(new OperationResponse { Success = result, Message = string.Empty });
|
||||||
|
}
|
||||||
|
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage });
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult HandleMultipleFileUpload(List<IFormFile> file)
|
public IActionResult HandleMultipleFileUpload(List<IFormFile> file)
|
||||||
{
|
{
|
||||||
@@ -44,14 +57,27 @@ namespace CarCareTracker.Controllers
|
|||||||
}
|
}
|
||||||
return Json(uploadedFiles);
|
return Json(uploadedFiles);
|
||||||
}
|
}
|
||||||
|
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public ActionResult DeleteFiles(string fileLocation)
|
public IActionResult DeleteFiles(string fileLocation)
|
||||||
{
|
{
|
||||||
var result = _fileHelper.DeleteFile(fileLocation);
|
var result = _fileHelper.DeleteFile(fileLocation);
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
|
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult MakeBackup()
|
||||||
|
{
|
||||||
|
var result = _fileHelper.MakeBackup();
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult RestoreBackup(string fileName)
|
||||||
|
{
|
||||||
|
var result = _fileHelper.RestoreBackup(fileName);
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
private string UploadFile(IFormFile fileToUpload)
|
private string UploadFile(IFormFile fileToUpload)
|
||||||
{
|
{
|
||||||
string uploadDirectory = "temp/";
|
string uploadDirectory = "temp/";
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
using CarCareTracker.External.Interfaces;
|
using CarCareTracker.External.Interfaces;
|
||||||
using CarCareTracker.Models;
|
using CarCareTracker.Models;
|
||||||
using LiteDB;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using static System.Net.Mime.MediaTypeNames;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using CarCareTracker.Helper;
|
using CarCareTracker.Helper;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using CarCareTracker.Logic;
|
||||||
|
|
||||||
namespace CarCareTracker.Controllers
|
namespace CarCareTracker.Controllers
|
||||||
{
|
{
|
||||||
@@ -17,17 +14,40 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
private readonly ILogger<HomeController> _logger;
|
private readonly ILogger<HomeController> _logger;
|
||||||
private readonly IVehicleDataAccess _dataAccess;
|
private readonly IVehicleDataAccess _dataAccess;
|
||||||
|
private readonly IUserLogic _userLogic;
|
||||||
|
private readonly ILoginLogic _loginLogic;
|
||||||
|
private readonly IVehicleLogic _vehicleLogic;
|
||||||
private readonly IFileHelper _fileHelper;
|
private readonly IFileHelper _fileHelper;
|
||||||
private readonly IConfiguration _config;
|
private readonly IConfigHelper _config;
|
||||||
|
private readonly IExtraFieldDataAccess _extraFieldDataAccess;
|
||||||
public HomeController(ILogger<HomeController> logger, IVehicleDataAccess dataAccess, IFileHelper fileHelper, IConfiguration configuration)
|
private readonly IReminderRecordDataAccess _reminderRecordDataAccess;
|
||||||
|
private readonly IReminderHelper _reminderHelper;
|
||||||
|
public HomeController(ILogger<HomeController> logger,
|
||||||
|
IVehicleDataAccess dataAccess,
|
||||||
|
IUserLogic userLogic,
|
||||||
|
ILoginLogic loginLogic,
|
||||||
|
IVehicleLogic vehicleLogic,
|
||||||
|
IConfigHelper configuration,
|
||||||
|
IFileHelper fileHelper,
|
||||||
|
IExtraFieldDataAccess extraFieldDataAccess,
|
||||||
|
IReminderRecordDataAccess reminderRecordDataAccess,
|
||||||
|
IReminderHelper reminderHelper)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_dataAccess = dataAccess;
|
_dataAccess = dataAccess;
|
||||||
_fileHelper = fileHelper;
|
|
||||||
_config = configuration;
|
_config = configuration;
|
||||||
|
_userLogic = userLogic;
|
||||||
|
_fileHelper = fileHelper;
|
||||||
|
_extraFieldDataAccess = extraFieldDataAccess;
|
||||||
|
_reminderRecordDataAccess = reminderRecordDataAccess;
|
||||||
|
_reminderHelper = reminderHelper;
|
||||||
|
_loginLogic = loginLogic;
|
||||||
|
_vehicleLogic = vehicleLogic;
|
||||||
|
}
|
||||||
|
private int GetUserID()
|
||||||
|
{
|
||||||
|
return int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier));
|
||||||
}
|
}
|
||||||
|
|
||||||
public IActionResult Index(string tab = "garage")
|
public IActionResult Index(string tab = "garage")
|
||||||
{
|
{
|
||||||
return View(model: tab);
|
return View(model: tab);
|
||||||
@@ -35,59 +55,170 @@ namespace CarCareTracker.Controllers
|
|||||||
public IActionResult Garage()
|
public IActionResult Garage()
|
||||||
{
|
{
|
||||||
var vehiclesStored = _dataAccess.GetVehicles();
|
var vehiclesStored = _dataAccess.GetVehicles();
|
||||||
return PartialView("_GarageDisplay", vehiclesStored);
|
if (!User.IsInRole(nameof(UserData.IsRootUser)))
|
||||||
}
|
|
||||||
public IActionResult Settings()
|
|
||||||
{
|
|
||||||
var userConfig = new UserConfig
|
|
||||||
{
|
{
|
||||||
EnableCsvImports = bool.Parse(_config[nameof(UserConfig.EnableCsvImports)]),
|
vehiclesStored = _userLogic.FilterUserVehicles(vehiclesStored, GetUserID());
|
||||||
UseDarkMode = bool.Parse(_config[nameof(UserConfig.UseDarkMode)]),
|
}
|
||||||
UseMPG = bool.Parse(_config[nameof(UserConfig.UseMPG)]),
|
var vehicleViewModels = vehiclesStored.Select(x => new VehicleViewModel
|
||||||
UseDescending = bool.Parse(_config[nameof(UserConfig.UseDescending)]),
|
{
|
||||||
EnableAuth = bool.Parse(_config[nameof(UserConfig.EnableAuth)]),
|
Id = x.Id,
|
||||||
HideZero = bool.Parse(_config[nameof(UserConfig.HideZero)]),
|
ImageLocation = x.ImageLocation,
|
||||||
UseUKMPG = bool.Parse(_config[nameof(UserConfig.UseUKMPG)])
|
Year = x.Year,
|
||||||
|
Make = x.Make,
|
||||||
|
Model = x.Model,
|
||||||
|
LicensePlate = x.LicensePlate,
|
||||||
|
SoldDate = x.SoldDate,
|
||||||
|
IsElectric = x.IsElectric,
|
||||||
|
UseHours = x.UseHours,
|
||||||
|
ExtraFields = x.ExtraFields,
|
||||||
|
Tags = x.Tags,
|
||||||
|
LastReportedMileage = _vehicleLogic.GetMaxMileage(x.Id),
|
||||||
|
HasReminders = _vehicleLogic.GetVehicleHasUrgentOrPastDueReminders(x.Id)
|
||||||
|
}).ToList();
|
||||||
|
return PartialView("_GarageDisplay", vehicleViewModels);
|
||||||
|
}
|
||||||
|
public IActionResult Calendar()
|
||||||
|
{
|
||||||
|
var vehiclesStored = _dataAccess.GetVehicles();
|
||||||
|
if (!User.IsInRole(nameof(UserData.IsRootUser)))
|
||||||
|
{
|
||||||
|
vehiclesStored = _userLogic.FilterUserVehicles(vehiclesStored, GetUserID());
|
||||||
|
}
|
||||||
|
List<ReminderRecordViewModel> reminders = new List<ReminderRecordViewModel>();
|
||||||
|
foreach (Vehicle vehicle in vehiclesStored)
|
||||||
|
{
|
||||||
|
var vehicleReminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicle.Id);
|
||||||
|
vehicleReminders.RemoveAll(x => x.Metric == ReminderMetric.Odometer);
|
||||||
|
//we don't care about mileages so we can basically fake the current vehicle mileage.
|
||||||
|
if (vehicleReminders.Any())
|
||||||
|
{
|
||||||
|
var reminderUrgency = _reminderHelper.GetReminderRecordViewModels(vehicleReminders, 0, DateTime.Now);
|
||||||
|
reminderUrgency = reminderUrgency.Select(x => new ReminderRecordViewModel { Id = x.Id, Date = x.Date, Urgency = x.Urgency, Description = $"{vehicle.Year} {vehicle.Make} {vehicle.Model} #{vehicle.LicensePlate} - {x.Description}" }).ToList();
|
||||||
|
reminders.AddRange(reminderUrgency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PartialView("_Calendar", reminders);
|
||||||
|
}
|
||||||
|
public IActionResult ViewCalendarReminder(int reminderId)
|
||||||
|
{
|
||||||
|
var reminder = _reminderRecordDataAccess.GetReminderRecordById(reminderId);
|
||||||
|
var reminderUrgency = _reminderHelper.GetReminderRecordViewModels(new List<ReminderRecord> { reminder }, 0, DateTime.Now).FirstOrDefault();
|
||||||
|
return PartialView("_ReminderRecordCalendarModal", reminderUrgency);
|
||||||
|
}
|
||||||
|
public async Task<IActionResult> Settings()
|
||||||
|
{
|
||||||
|
var userConfig = _config.GetUserConfig(User);
|
||||||
|
var languages = _fileHelper.GetLanguages();
|
||||||
|
var viewModel = new SettingsViewModel
|
||||||
|
{
|
||||||
|
UserConfig = userConfig,
|
||||||
|
UILanguages = languages
|
||||||
};
|
};
|
||||||
return PartialView("_Settings", userConfig);
|
try
|
||||||
|
{
|
||||||
|
var httpClient = new HttpClient();
|
||||||
|
var sponsorsData = await httpClient.GetFromJsonAsync<Sponsors>(StaticHelper.SponsorsPath) ?? new Sponsors();
|
||||||
|
viewModel.Sponsors = sponsorsData;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError($"Unable to retrieve sponsors: {ex.Message}");
|
||||||
|
}
|
||||||
|
return PartialView("_Settings", viewModel);
|
||||||
}
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult WriteToSettings(UserConfig userConfig)
|
public IActionResult WriteToSettings(UserConfig userConfig)
|
||||||
{
|
{
|
||||||
try
|
//retrieve existing userConfig.
|
||||||
{
|
var existingConfig = _config.GetUserConfig(User);
|
||||||
if (!System.IO.File.Exists(StaticHelper.UserConfigPath))
|
//copy over stuff that persists
|
||||||
{
|
userConfig.UserColumnPreferences = existingConfig.UserColumnPreferences;
|
||||||
//if file doesn't exist it might be because it's running on a mounted volume in docker.
|
userConfig.ReminderUrgencyConfig = existingConfig.ReminderUrgencyConfig;
|
||||||
System.IO.File.WriteAllText(StaticHelper.UserConfigPath, System.Text.Json.JsonSerializer.Serialize(new UserConfig()));
|
var result = _config.SaveUserConfig(User, userConfig);
|
||||||
}
|
return Json(result);
|
||||||
var configFileContents = System.IO.File.ReadAllText(StaticHelper.UserConfigPath);
|
}
|
||||||
var existingUserConfig = System.Text.Json.JsonSerializer.Deserialize<UserConfig>(configFileContents);
|
[HttpPost]
|
||||||
if (existingUserConfig is not null)
|
public IActionResult SaveReminderUrgencyThreshold(ReminderUrgencyConfig reminderUrgencyConfig)
|
||||||
{
|
{
|
||||||
//copy over settings that are off limits on the settings page.
|
//retrieve existing userConfig.
|
||||||
userConfig.EnableAuth = existingUserConfig.EnableAuth;
|
var existingConfig = _config.GetUserConfig(User);
|
||||||
userConfig.UserNameHash = existingUserConfig.UserNameHash;
|
existingConfig.ReminderUrgencyConfig = reminderUrgencyConfig;
|
||||||
userConfig.UserPasswordHash = existingUserConfig.UserPasswordHash;
|
var result = _config.SaveUserConfig(User, existingConfig);
|
||||||
} else
|
return Json(result);
|
||||||
{
|
|
||||||
userConfig.EnableAuth = false;
|
|
||||||
userConfig.UserNameHash = string.Empty;
|
|
||||||
userConfig.UserPasswordHash = string.Empty;
|
|
||||||
}
|
|
||||||
System.IO.File.WriteAllText(StaticHelper.UserConfigPath, System.Text.Json.JsonSerializer.Serialize(userConfig));
|
|
||||||
return Json(true);
|
|
||||||
} catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error on saving config file.");
|
|
||||||
}
|
|
||||||
return Json(false);
|
|
||||||
}
|
}
|
||||||
public IActionResult Privacy()
|
public IActionResult Privacy()
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||||
|
public IActionResult GetExtraFieldsModal(int importMode = 0)
|
||||||
|
{
|
||||||
|
var recordExtraFields = _extraFieldDataAccess.GetExtraFieldsById(importMode);
|
||||||
|
if (recordExtraFields.Id != importMode)
|
||||||
|
{
|
||||||
|
recordExtraFields.Id = importMode;
|
||||||
|
}
|
||||||
|
return PartialView("_ExtraFields", recordExtraFields);
|
||||||
|
}
|
||||||
|
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||||
|
public IActionResult UpdateExtraFields(RecordExtraField record)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = _extraFieldDataAccess.SaveExtraFields(record);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
var recordExtraFields = _extraFieldDataAccess.GetExtraFieldsById(record.Id);
|
||||||
|
return PartialView("_ExtraFields", recordExtraFields);
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult GenerateTokenForUser()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//get current user email address.
|
||||||
|
var emailAddress = User.FindFirstValue(ClaimTypes.Email);
|
||||||
|
if (!string.IsNullOrWhiteSpace(emailAddress))
|
||||||
|
{
|
||||||
|
var result = _loginLogic.GenerateTokenForEmailAddress(emailAddress, false);
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
return Json(false);
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return Json(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult UpdateUserAccount(LoginModel userAccount)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var userId = GetUserID();
|
||||||
|
if (userId > 0)
|
||||||
|
{
|
||||||
|
var result = _loginLogic.UpdateUserDetails(userId, userAccount);
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetUserAccountInformationModal()
|
||||||
|
{
|
||||||
|
var emailAddress = User.FindFirstValue(ClaimTypes.Email);
|
||||||
|
var userName = User.Identity.Name;
|
||||||
|
return PartialView("_AccountModal", new UserData() { EmailAddress = emailAddress, UserName = userName });
|
||||||
|
}
|
||||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||||
public IActionResult Error()
|
public IActionResult Error()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
using CarCareTracker.Helper;
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Logic;
|
||||||
using CarCareTracker.Models;
|
using CarCareTracker.Models;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.DataProtection;
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using System.Net;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace CarCareTracker.Controllers
|
namespace CarCareTracker.Controllers
|
||||||
@@ -13,22 +12,143 @@ namespace CarCareTracker.Controllers
|
|||||||
public class LoginController : Controller
|
public class LoginController : Controller
|
||||||
{
|
{
|
||||||
private IDataProtector _dataProtector;
|
private IDataProtector _dataProtector;
|
||||||
private ILoginHelper _loginHelper;
|
private ILoginLogic _loginLogic;
|
||||||
|
private IConfigHelper _config;
|
||||||
private readonly ILogger<LoginController> _logger;
|
private readonly ILogger<LoginController> _logger;
|
||||||
public LoginController(
|
public LoginController(
|
||||||
ILogger<LoginController> logger,
|
ILogger<LoginController> logger,
|
||||||
IDataProtectionProvider securityProvider,
|
IDataProtectionProvider securityProvider,
|
||||||
ILoginHelper loginHelper
|
ILoginLogic loginLogic,
|
||||||
)
|
IConfigHelper config
|
||||||
|
)
|
||||||
{
|
{
|
||||||
_dataProtector = securityProvider.CreateProtector("login");
|
_dataProtector = securityProvider.CreateProtector("login");
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_loginHelper = loginHelper;
|
_loginLogic = loginLogic;
|
||||||
|
_config = config;
|
||||||
}
|
}
|
||||||
public IActionResult Index()
|
public IActionResult Index(string redirectURL = "")
|
||||||
|
{
|
||||||
|
var remoteAuthConfig = _config.GetOpenIDConfig();
|
||||||
|
if (remoteAuthConfig.DisableRegularLogin && !string.IsNullOrWhiteSpace(remoteAuthConfig.LogOutURL))
|
||||||
|
{
|
||||||
|
var generatedState = Guid.NewGuid().ToString().Substring(0, 8);
|
||||||
|
remoteAuthConfig.State = generatedState;
|
||||||
|
if (remoteAuthConfig.ValidateState)
|
||||||
|
{
|
||||||
|
Response.Cookies.Append("OIDC_STATE", remoteAuthConfig.State, new CookieOptions { Expires = new DateTimeOffset(DateTime.Now.AddMinutes(5)) });
|
||||||
|
}
|
||||||
|
var remoteAuthURL = remoteAuthConfig.RemoteAuthURL;
|
||||||
|
return Redirect(remoteAuthURL);
|
||||||
|
}
|
||||||
|
return View(model: redirectURL);
|
||||||
|
}
|
||||||
|
public IActionResult Registration()
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
public IActionResult ForgotPassword()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
public IActionResult ResetPassword()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
public IActionResult GetRemoteLoginLink()
|
||||||
|
{
|
||||||
|
var remoteAuthConfig = _config.GetOpenIDConfig();
|
||||||
|
var generatedState = Guid.NewGuid().ToString().Substring(0, 8);
|
||||||
|
remoteAuthConfig.State = generatedState;
|
||||||
|
if (remoteAuthConfig.ValidateState)
|
||||||
|
{
|
||||||
|
Response.Cookies.Append("OIDC_STATE", remoteAuthConfig.State, new CookieOptions { Expires = new DateTimeOffset(DateTime.Now.AddMinutes(5)) });
|
||||||
|
}
|
||||||
|
var remoteAuthURL = remoteAuthConfig.RemoteAuthURL;
|
||||||
|
return Json(remoteAuthURL);
|
||||||
|
}
|
||||||
|
public async Task<IActionResult> RemoteAuth(string code, string state = "")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(code))
|
||||||
|
{
|
||||||
|
//received code from OIDC provider
|
||||||
|
//create http client to retrieve user token from OIDC
|
||||||
|
var httpClient = new HttpClient();
|
||||||
|
var openIdConfig = _config.GetOpenIDConfig();
|
||||||
|
//check if validate state is enabled.
|
||||||
|
if (openIdConfig.ValidateState)
|
||||||
|
{
|
||||||
|
var storedStateValue = Request.Cookies["OIDC_STATE"];
|
||||||
|
if (!string.IsNullOrWhiteSpace(storedStateValue))
|
||||||
|
{
|
||||||
|
Response.Cookies.Delete("OIDC_STATE");
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(storedStateValue) || string.IsNullOrWhiteSpace(state) || storedStateValue != state)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Failed OIDC State Validation - Try disabling state validation if you are confident this is not a malicious attempt.");
|
||||||
|
return new RedirectResult("/Login");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var httpParams = new List<KeyValuePair<string, string>>
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, string>("code", code),
|
||||||
|
new KeyValuePair<string, string>("grant_type", "authorization_code"),
|
||||||
|
new KeyValuePair<string, string>("client_id", openIdConfig.ClientId),
|
||||||
|
new KeyValuePair<string, string>("client_secret", openIdConfig.ClientSecret),
|
||||||
|
new KeyValuePair<string, string>("redirect_uri", openIdConfig.RedirectURL)
|
||||||
|
};
|
||||||
|
var httpRequest = new HttpRequestMessage(HttpMethod.Post, openIdConfig.TokenURL)
|
||||||
|
{
|
||||||
|
Content = new FormUrlEncodedContent(httpParams)
|
||||||
|
};
|
||||||
|
var tokenResult = await httpClient.SendAsync(httpRequest).Result.Content.ReadAsStringAsync();
|
||||||
|
var userJwt = JsonSerializer.Deserialize<OpenIDResult>(tokenResult)?.id_token ?? string.Empty;
|
||||||
|
if (!string.IsNullOrWhiteSpace(userJwt))
|
||||||
|
{
|
||||||
|
//validate JWT token
|
||||||
|
var tokenParser = new JwtSecurityTokenHandler();
|
||||||
|
var parsedToken = tokenParser.ReadJwtToken(userJwt);
|
||||||
|
var userEmailAddress = parsedToken.Claims.First(x => x.Type == "email").Value;
|
||||||
|
if (!string.IsNullOrWhiteSpace(userEmailAddress))
|
||||||
|
{
|
||||||
|
var userData = _loginLogic.ValidateOpenIDUser(new LoginModel() { EmailAddress = userEmailAddress });
|
||||||
|
if (userData.Id != default)
|
||||||
|
{
|
||||||
|
AuthCookie authCookie = new AuthCookie
|
||||||
|
{
|
||||||
|
UserData = userData,
|
||||||
|
ExpiresOn = DateTime.Now.AddDays(1)
|
||||||
|
};
|
||||||
|
var serializedCookie = JsonSerializer.Serialize(authCookie);
|
||||||
|
var encryptedCookie = _dataProtector.Protect(serializedCookie);
|
||||||
|
Response.Cookies.Append("ACCESS_TOKEN", encryptedCookie, new CookieOptions { Expires = new DateTimeOffset(authCookie.ExpiresOn) });
|
||||||
|
return new RedirectResult("/Home");
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"User {userEmailAddress} tried to login via OpenID but is not a registered user in LubeLogger.");
|
||||||
|
return View("OpenIDRegistration", model: userEmailAddress);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
_logger.LogInformation("OpenID Provider did not provide a valid email address for the user");
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
_logger.LogInformation("OpenID Provider did not provide a valid id_token");
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
_logger.LogInformation("OpenID Provider did not provide a code.");
|
||||||
|
}
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new RedirectResult("/Login");
|
||||||
|
}
|
||||||
|
return new RedirectResult("/Login");
|
||||||
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult Login(LoginModel credentials)
|
public IActionResult Login(LoginModel credentials)
|
||||||
{
|
{
|
||||||
@@ -40,13 +160,12 @@ namespace CarCareTracker.Controllers
|
|||||||
//compare it against hashed credentials
|
//compare it against hashed credentials
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var loginIsValid = _loginHelper.ValidateUserCredentials(credentials);
|
var userData = _loginLogic.ValidateUserCredentials(credentials);
|
||||||
if (loginIsValid)
|
if (userData.Id != default)
|
||||||
{
|
{
|
||||||
AuthCookie authCookie = new AuthCookie
|
AuthCookie authCookie = new AuthCookie
|
||||||
{
|
{
|
||||||
Id = 1, //this is hardcoded for now
|
UserData = userData,
|
||||||
UserName = credentials.UserName,
|
|
||||||
ExpiresOn = DateTime.Now.AddDays(credentials.IsPersistent ? 30 : 1)
|
ExpiresOn = DateTime.Now.AddDays(credentials.IsPersistent ? 30 : 1)
|
||||||
};
|
};
|
||||||
var serializedCookie = JsonSerializer.Serialize(authCookie);
|
var serializedCookie = JsonSerializer.Serialize(authCookie);
|
||||||
@@ -61,26 +180,54 @@ namespace CarCareTracker.Controllers
|
|||||||
}
|
}
|
||||||
return Json(false);
|
return Json(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult Register(LoginModel credentials)
|
||||||
|
{
|
||||||
|
var result = _loginLogic.RegisterNewUser(credentials);
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult RegisterOpenIdUser(LoginModel credentials)
|
||||||
|
{
|
||||||
|
var result = _loginLogic.RegisterOpenIdUser(credentials);
|
||||||
|
if (result.Success)
|
||||||
|
{
|
||||||
|
var userData = _loginLogic.ValidateOpenIDUser(new LoginModel() { EmailAddress = credentials.EmailAddress });
|
||||||
|
if (userData.Id != default)
|
||||||
|
{
|
||||||
|
AuthCookie authCookie = new AuthCookie
|
||||||
|
{
|
||||||
|
UserData = userData,
|
||||||
|
ExpiresOn = DateTime.Now.AddDays(1)
|
||||||
|
};
|
||||||
|
var serializedCookie = JsonSerializer.Serialize(authCookie);
|
||||||
|
var encryptedCookie = _dataProtector.Protect(serializedCookie);
|
||||||
|
Response.Cookies.Append("ACCESS_TOKEN", encryptedCookie, new CookieOptions { Expires = new DateTimeOffset(authCookie.ExpiresOn) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult RequestResetPassword(LoginModel credentials)
|
||||||
|
{
|
||||||
|
var result = _loginLogic.RequestResetPassword(credentials);
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult PerformPasswordReset(LoginModel credentials)
|
||||||
|
{
|
||||||
|
var result = _loginLogic.ResetPasswordByUser(credentials);
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
[Authorize] //User must already be logged in to do this.
|
[Authorize] //User must already be logged in to do this.
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult CreateLoginCreds(LoginModel credentials)
|
public IActionResult CreateLoginCreds(LoginModel credentials)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var configFileContents = System.IO.File.ReadAllText(StaticHelper.UserConfigPath);
|
var result = _loginLogic.CreateRootUserCredentials(credentials);
|
||||||
var existingUserConfig = JsonSerializer.Deserialize<UserConfig>(configFileContents);
|
return Json(result);
|
||||||
if (existingUserConfig is not null)
|
|
||||||
{
|
|
||||||
//create hashes of the login credentials.
|
|
||||||
var hashedUserName = Sha256_hash(credentials.UserName);
|
|
||||||
var hashedPassword = Sha256_hash(credentials.Password);
|
|
||||||
//copy over settings that are off limits on the settings page.
|
|
||||||
existingUserConfig.EnableAuth = true;
|
|
||||||
existingUserConfig.UserNameHash = hashedUserName;
|
|
||||||
existingUserConfig.UserPasswordHash = hashedPassword;
|
|
||||||
}
|
|
||||||
System.IO.File.WriteAllText(StaticHelper.UserConfigPath, JsonSerializer.Serialize(existingUserConfig));
|
|
||||||
return Json(true);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -94,19 +241,13 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var configFileContents = System.IO.File.ReadAllText(StaticHelper.UserConfigPath);
|
var result = _loginLogic.DeleteRootUserCredentials();
|
||||||
var existingUserConfig = JsonSerializer.Deserialize<UserConfig>(configFileContents);
|
|
||||||
if (existingUserConfig is not null)
|
|
||||||
{
|
|
||||||
//copy over settings that are off limits on the settings page.
|
|
||||||
existingUserConfig.EnableAuth = false;
|
|
||||||
existingUserConfig.UserNameHash = string.Empty;
|
|
||||||
existingUserConfig.UserPasswordHash = string.Empty;
|
|
||||||
}
|
|
||||||
System.IO.File.WriteAllText(StaticHelper.UserConfigPath, JsonSerializer.Serialize(existingUserConfig));
|
|
||||||
//destroy any login cookies.
|
//destroy any login cookies.
|
||||||
Response.Cookies.Delete("ACCESS_TOKEN");
|
if (result)
|
||||||
return Json(true);
|
{
|
||||||
|
Response.Cookies.Delete("ACCESS_TOKEN");
|
||||||
|
}
|
||||||
|
return Json(result);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -119,22 +260,12 @@ namespace CarCareTracker.Controllers
|
|||||||
public IActionResult LogOut()
|
public IActionResult LogOut()
|
||||||
{
|
{
|
||||||
Response.Cookies.Delete("ACCESS_TOKEN");
|
Response.Cookies.Delete("ACCESS_TOKEN");
|
||||||
return Json(true);
|
var remoteAuthConfig = _config.GetOpenIDConfig();
|
||||||
}
|
if (remoteAuthConfig.DisableRegularLogin && !string.IsNullOrWhiteSpace(remoteAuthConfig.LogOutURL))
|
||||||
private static string Sha256_hash(string value)
|
|
||||||
{
|
|
||||||
StringBuilder Sb = new StringBuilder();
|
|
||||||
|
|
||||||
using (var hash = SHA256.Create())
|
|
||||||
{
|
{
|
||||||
Encoding enc = Encoding.UTF8;
|
return Json(remoteAuthConfig.LogOutURL);
|
||||||
byte[] result = hash.ComputeHash(enc.GetBytes(value));
|
|
||||||
|
|
||||||
foreach (byte b in result)
|
|
||||||
Sb.Append(b.ToString("x2"));
|
|
||||||
}
|
}
|
||||||
|
return Json("/Login");
|
||||||
return Sb.ToString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
754
Controllers/MigrationController.cs
Normal file
754
Controllers/MigrationController.cs
Normal file
@@ -0,0 +1,754 @@
|
|||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using LiteDB;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Npgsql;
|
||||||
|
using System.IO.Compression;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Controllers
|
||||||
|
{
|
||||||
|
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||||
|
public class MigrationController : Controller
|
||||||
|
{
|
||||||
|
private IConfigHelper _configHelper;
|
||||||
|
private IFileHelper _fileHelper;
|
||||||
|
private readonly ILogger<MigrationController> _logger;
|
||||||
|
public MigrationController(IConfigHelper configHelper, IFileHelper fileHelper, IConfiguration serverConfig, ILogger<MigrationController> logger)
|
||||||
|
{
|
||||||
|
_configHelper = configHelper;
|
||||||
|
_fileHelper = fileHelper;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
public IActionResult Index()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(_configHelper.GetServerPostgresConnection()))
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return new RedirectResult("/Error/Unauthorized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void InitializeTables(NpgsqlDataSource conn)
|
||||||
|
{
|
||||||
|
var cmds = new List<string>
|
||||||
|
{
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.vehicles (id INT GENERATED BY DEFAULT AS IDENTITY primary key, data jsonb not null)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.collisionrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.upgraderecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.servicerecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.gasrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.notes (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.odometerrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.reminderrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.planrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.planrecordtemplates (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.supplyrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.taxrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.userrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, username TEXT not null, emailaddress TEXT not null, password TEXT not null, isadmin BOOLEAN)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.tokenrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, body TEXT not null, emailaddress TEXT not null)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.userconfigrecords (id INT primary key, data jsonb not null)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.useraccessrecords (userId INT, vehicleId INT, PRIMARY KEY(userId, vehicleId))",
|
||||||
|
"CREATE TABLE IF NOT EXISTS app.extrafields (id INT primary key, data jsonb not null)"
|
||||||
|
};
|
||||||
|
foreach(string cmd in cmds)
|
||||||
|
{
|
||||||
|
using (var ctext = conn.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public IActionResult Export()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(_configHelper.GetServerPostgresConnection()))
|
||||||
|
{
|
||||||
|
return Json(new OperationResponse { Success = false, Message = "Postgres connection not set up" });
|
||||||
|
}
|
||||||
|
var tempFolder = $"temp/{Guid.NewGuid()}";
|
||||||
|
var tempPath = $"{tempFolder}/cartracker.db";
|
||||||
|
var fullFolderPath = _fileHelper.GetFullFilePath(tempFolder, false);
|
||||||
|
Directory.CreateDirectory(fullFolderPath);
|
||||||
|
var fullFileName = _fileHelper.GetFullFilePath(tempPath, false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pgDataSource = NpgsqlDataSource.Create(_configHelper.GetServerPostgresConnection());
|
||||||
|
InitializeTables(pgDataSource);
|
||||||
|
//pull records
|
||||||
|
var vehicles = new List<Vehicle>();
|
||||||
|
var repairrecords = new List<CollisionRecord>();
|
||||||
|
var upgraderecords = new List<UpgradeRecord>();
|
||||||
|
var servicerecords = new List<ServiceRecord>();
|
||||||
|
|
||||||
|
var gasrecords = new List<GasRecord>();
|
||||||
|
var noterecords = new List<Note>();
|
||||||
|
var odometerrecords = new List<OdometerRecord>();
|
||||||
|
var reminderrecords = new List<ReminderRecord>();
|
||||||
|
|
||||||
|
var planrecords = new List<PlanRecord>();
|
||||||
|
var planrecordtemplates = new List<PlanRecordInput>();
|
||||||
|
var supplyrecords = new List<SupplyRecord>();
|
||||||
|
var taxrecords = new List<TaxRecord>();
|
||||||
|
|
||||||
|
var userrecords = new List<UserData>();
|
||||||
|
var tokenrecords = new List<Token>();
|
||||||
|
var userconfigrecords = new List<UserConfigData>();
|
||||||
|
var useraccessrecords = new List<UserAccess>();
|
||||||
|
|
||||||
|
var extrafields = new List<RecordExtraField>();
|
||||||
|
#region "Part1"
|
||||||
|
string cmd = $"SELECT data FROM app.vehicles";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
Vehicle vehicle = System.Text.Json.JsonSerializer.Deserialize<Vehicle>(reader["data"] as string);
|
||||||
|
vehicles.Add(vehicle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var vehicle in vehicles)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<Vehicle>("vehicles");
|
||||||
|
table.Upsert(vehicle);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
cmd = $"SELECT data FROM app.collisionrecords";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
repairrecords.Add(System.Text.Json.JsonSerializer.Deserialize<CollisionRecord>(reader["data"] as string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var record in repairrecords)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<CollisionRecord>("collisionrecords");
|
||||||
|
table.Upsert(record);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
cmd = $"SELECT data FROM app.upgraderecords";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
upgraderecords.Add(System.Text.Json.JsonSerializer.Deserialize<UpgradeRecord>(reader["data"] as string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var record in upgraderecords)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<UpgradeRecord>("upgraderecords");
|
||||||
|
table.Upsert(record);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
cmd = $"SELECT data FROM app.servicerecords";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
servicerecords.Add(System.Text.Json.JsonSerializer.Deserialize<ServiceRecord>(reader["data"] as string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var record in servicerecords)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<ServiceRecord>("servicerecords");
|
||||||
|
table.Upsert(record);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region "Part2"
|
||||||
|
cmd = $"SELECT data FROM app.gasrecords";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
gasrecords.Add(System.Text.Json.JsonSerializer.Deserialize<GasRecord>(reader["data"] as string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var record in gasrecords)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<GasRecord>("gasrecords");
|
||||||
|
table.Upsert(record);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
cmd = $"SELECT data FROM app.notes";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
noterecords.Add(System.Text.Json.JsonSerializer.Deserialize<Note>(reader["data"] as string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var record in noterecords)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<Note>("notes");
|
||||||
|
table.Upsert(record);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
cmd = $"SELECT data FROM app.odometerrecords";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
odometerrecords.Add(System.Text.Json.JsonSerializer.Deserialize<OdometerRecord>(reader["data"] as string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var record in odometerrecords)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<OdometerRecord>("odometerrecords");
|
||||||
|
table.Upsert(record);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
cmd = $"SELECT data FROM app.reminderrecords";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
reminderrecords.Add(System.Text.Json.JsonSerializer.Deserialize<ReminderRecord>(reader["data"] as string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var record in reminderrecords)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<ReminderRecord>("reminderrecords");
|
||||||
|
table.Upsert(record);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region "Part3"
|
||||||
|
cmd = $"SELECT data FROM app.planrecords";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
planrecords.Add(System.Text.Json.JsonSerializer.Deserialize<PlanRecord>(reader["data"] as string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var record in planrecords)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<PlanRecord>("planrecords");
|
||||||
|
table.Upsert(record);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
cmd = $"SELECT data FROM app.planrecordtemplates";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
planrecordtemplates.Add(System.Text.Json.JsonSerializer.Deserialize<PlanRecordInput>(reader["data"] as string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var record in planrecordtemplates)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<PlanRecordInput>("planrecordtemplates");
|
||||||
|
table.Upsert(record);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
cmd = $"SELECT data FROM app.supplyrecords";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
supplyrecords.Add(System.Text.Json.JsonSerializer.Deserialize<SupplyRecord>(reader["data"] as string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var record in supplyrecords)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<SupplyRecord>("supplyrecords");
|
||||||
|
table.Upsert(record);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
cmd = $"SELECT data FROM app.taxrecords";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
taxrecords.Add(System.Text.Json.JsonSerializer.Deserialize<TaxRecord>(reader["data"] as string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var record in taxrecords)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<TaxRecord>("taxrecords");
|
||||||
|
table.Upsert(record);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region "Part4"
|
||||||
|
cmd = $"SELECT id, username, emailaddress, password, isadmin FROM app.userrecords";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
UserData result = new UserData();
|
||||||
|
result.Id = int.Parse(reader["id"].ToString());
|
||||||
|
result.UserName = reader["username"].ToString();
|
||||||
|
result.EmailAddress = reader["emailaddress"].ToString();
|
||||||
|
result.Password = reader["password"].ToString();
|
||||||
|
result.IsAdmin = bool.Parse(reader["isadmin"].ToString());
|
||||||
|
userrecords.Add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var record in userrecords)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<UserData>("userrecords");
|
||||||
|
table.Upsert(record);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
cmd = $"SELECT id, emailaddress, body FROM app.tokenrecords";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
Token result = new Token();
|
||||||
|
result.Id = int.Parse(reader["id"].ToString());
|
||||||
|
result.EmailAddress = reader["emailaddress"].ToString();
|
||||||
|
result.Body = reader["body"].ToString();
|
||||||
|
tokenrecords.Add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var record in tokenrecords)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<Token>("tokenrecords");
|
||||||
|
table.Upsert(record);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
cmd = $"SELECT data FROM app.userconfigrecords";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
userconfigrecords.Add(System.Text.Json.JsonSerializer.Deserialize<UserConfigData>(reader["data"] as string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var record in userconfigrecords)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<UserConfigData>("userconfigrecords");
|
||||||
|
table.Upsert(record);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
cmd = $"SELECT userId, vehicleId FROM app.useraccessrecords";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
UserAccess result = new UserAccess()
|
||||||
|
{
|
||||||
|
Id = new UserVehicle
|
||||||
|
{
|
||||||
|
UserId = int.Parse(reader["userId"].ToString()),
|
||||||
|
VehicleId = int.Parse(reader["vehicleId"].ToString())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
useraccessrecords.Add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var record in useraccessrecords)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<UserAccess>("useraccessrecords");
|
||||||
|
table.Upsert(record);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region "Part5"
|
||||||
|
cmd = $"SELECT data FROM app.extrafields";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
extrafields.Add(System.Text.Json.JsonSerializer.Deserialize<RecordExtraField>(reader["data"] as string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var record in extrafields)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<RecordExtraField>("extrafields");
|
||||||
|
table.Upsert(record);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
var destFilePath = $"{fullFolderPath}.zip";
|
||||||
|
ZipFile.CreateFromDirectory(fullFolderPath, destFilePath);
|
||||||
|
return Json(new OperationResponse { Success = true, Message = $"/{tempFolder}.zip" });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public IActionResult Import(string fileName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(_configHelper.GetServerPostgresConnection()))
|
||||||
|
{
|
||||||
|
return Json(new OperationResponse { Success = false, Message = "Postgres connection not set up" });
|
||||||
|
}
|
||||||
|
var fullFileName = _fileHelper.GetFullFilePath(fileName);
|
||||||
|
if (string.IsNullOrWhiteSpace(fullFileName))
|
||||||
|
{
|
||||||
|
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage });
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pgDataSource = NpgsqlDataSource.Create(_configHelper.GetServerPostgresConnection());
|
||||||
|
InitializeTables(pgDataSource);
|
||||||
|
//pull records
|
||||||
|
var vehicles = new List<Vehicle>();
|
||||||
|
var repairrecords = new List<CollisionRecord>();
|
||||||
|
var upgraderecords = new List<UpgradeRecord>();
|
||||||
|
var servicerecords = new List<ServiceRecord>();
|
||||||
|
|
||||||
|
var gasrecords = new List<GasRecord>();
|
||||||
|
var noterecords = new List<Note>();
|
||||||
|
var odometerrecords = new List<OdometerRecord>();
|
||||||
|
var reminderrecords = new List<ReminderRecord>();
|
||||||
|
|
||||||
|
var planrecords = new List<PlanRecord>();
|
||||||
|
var planrecordtemplates = new List<PlanRecordInput>();
|
||||||
|
var supplyrecords = new List<SupplyRecord>();
|
||||||
|
var taxrecords = new List<TaxRecord>();
|
||||||
|
|
||||||
|
var userrecords = new List<UserData>();
|
||||||
|
var tokenrecords = new List<Token>();
|
||||||
|
var userconfigrecords = new List<UserConfigData>();
|
||||||
|
var useraccessrecords = new List<UserAccess>();
|
||||||
|
|
||||||
|
var extrafields = new List<RecordExtraField>();
|
||||||
|
#region "Part1"
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<Vehicle>("vehicles");
|
||||||
|
vehicles = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach(var vehicle in vehicles)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.vehicles (id, data) VALUES(@id, CAST(@data AS jsonb)); SELECT setval('app.vehicles_id_seq', (SELECT MAX(id) from app.vehicles));";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicle.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(vehicle));
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<CollisionRecord>("collisionrecords");
|
||||||
|
repairrecords = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach (var record in repairrecords)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.collisionrecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.collisionrecords_id_seq', (SELECT MAX(id) from app.collisionrecords));";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<ServiceRecord>("servicerecords");
|
||||||
|
servicerecords = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach (var record in servicerecords)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.servicerecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.servicerecords_id_seq', (SELECT MAX(id) from app.servicerecords));";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<UpgradeRecord>("upgraderecords");
|
||||||
|
upgraderecords = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach (var record in upgraderecords)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.upgraderecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.upgraderecords_id_seq', (SELECT MAX(id) from app.upgraderecords));";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region "Part2"
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<GasRecord>("gasrecords");
|
||||||
|
gasrecords = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach (var record in gasrecords)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.gasrecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.gasrecords_id_seq', (SELECT MAX(id) from app.gasrecords));";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<Note>("notes");
|
||||||
|
noterecords = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach (var record in noterecords)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.notes (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.notes_id_seq', (SELECT MAX(id) from app.notes));";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<OdometerRecord>("odometerrecords");
|
||||||
|
odometerrecords = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach (var record in odometerrecords)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.odometerrecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.odometerrecords_id_seq', (SELECT MAX(id) from app.odometerrecords));";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<ReminderRecord>("reminderrecords");
|
||||||
|
reminderrecords = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach (var record in reminderrecords)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.reminderrecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.reminderrecords_id_seq', (SELECT MAX(id) from app.reminderrecords));";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region "Part3"
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<PlanRecord>("planrecords");
|
||||||
|
planrecords = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach (var record in planrecords)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.planrecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.planrecords_id_seq', (SELECT MAX(id) from app.planrecords));";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<PlanRecordInput>("planrecordtemplates");
|
||||||
|
planrecordtemplates = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach (var record in planrecordtemplates)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.planrecordtemplates (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.planrecordtemplates_id_seq', (SELECT MAX(id) from app.planrecordtemplates));";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<SupplyRecord>("supplyrecords");
|
||||||
|
supplyrecords = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach (var record in supplyrecords)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.supplyrecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.supplyrecords_id_seq', (SELECT MAX(id) from app.supplyrecords));";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<TaxRecord>("taxrecords");
|
||||||
|
taxrecords = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach (var record in taxrecords)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.taxrecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.taxrecords_id_seq', (SELECT MAX(id) from app.taxrecords));";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region "Part4"
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<UserData>("userrecords");
|
||||||
|
userrecords = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach (var record in userrecords)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.userrecords (id, username, emailaddress, password, isadmin) VALUES(@id, @username, @emailaddress, @password, @isadmin); SELECT setval('app.userrecords_id_seq', (SELECT MAX(id) from app.userrecords));";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("username", record.UserName);
|
||||||
|
ctext.Parameters.AddWithValue("emailaddress", record.EmailAddress);
|
||||||
|
ctext.Parameters.AddWithValue("password", record.Password);
|
||||||
|
ctext.Parameters.AddWithValue("isadmin", record.IsAdmin);
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<Token>("tokenrecords");
|
||||||
|
tokenrecords = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach (var record in tokenrecords)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.tokenrecords (id, emailaddress, body) VALUES(@id, @emailaddress, @body); SELECT setval('app.tokenrecords_id_seq', (SELECT MAX(id) from app.tokenrecords));";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("emailaddress", record.EmailAddress);
|
||||||
|
ctext.Parameters.AddWithValue("body", record.Body);
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<UserConfigData>("userconfigrecords");
|
||||||
|
userconfigrecords = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach (var record in userconfigrecords)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.userconfigrecords (id, data) VALUES(@id, CAST(@data AS jsonb))";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<UserAccess>("useraccessrecords");
|
||||||
|
useraccessrecords = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach (var record in useraccessrecords)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.useraccessrecords (userId, vehicleId) VALUES(@userId, @vehicleId)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("userId", record.Id.UserId);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", record.Id.VehicleId);
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region "Part5"
|
||||||
|
using (var db = new LiteDatabase(fullFileName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<RecordExtraField>("extrafields");
|
||||||
|
extrafields = table.FindAll().ToList();
|
||||||
|
};
|
||||||
|
foreach (var record in extrafields)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.extrafields (id, data) VALUES(@id, CAST(@data AS jsonb))";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
return Json(new OperationResponse { Success = true, Message = "Data Imported Successfully" });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,13 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
|
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
|
||||||
WORKDIR /App
|
WORKDIR /App
|
||||||
|
|
||||||
COPY . ./
|
COPY . ./
|
||||||
RUN dotnet restore
|
ARG TARGETARCH
|
||||||
RUN dotnet publish -c Release -o out
|
RUN dotnet restore -a $TARGETARCH
|
||||||
|
RUN dotnet publish -a $TARGETARCH -c Release -o out
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||||
WORKDIR /App
|
WORKDIR /App
|
||||||
COPY --from=build-env /App/out .
|
COPY --from=build-env /App/out .
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
CMD ["./CarCareTracker"]
|
CMD ["./CarCareTracker"]
|
||||||
|
|||||||
@@ -6,6 +6,13 @@
|
|||||||
RepairRecord = 1,
|
RepairRecord = 1,
|
||||||
GasRecord = 2,
|
GasRecord = 2,
|
||||||
TaxRecord = 3,
|
TaxRecord = 3,
|
||||||
UpgradeRecord = 4
|
UpgradeRecord = 4,
|
||||||
|
ReminderRecord = 5,
|
||||||
|
NoteRecord = 6,
|
||||||
|
SupplyRecord = 7,
|
||||||
|
Dashboard = 8,
|
||||||
|
PlanRecord = 9,
|
||||||
|
OdometerRecord = 10,
|
||||||
|
VehicleRecord = 11
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
9
Enum/PlanPriority.cs
Normal file
9
Enum/PlanPriority.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public enum PlanPriority
|
||||||
|
{
|
||||||
|
Critical = 0,
|
||||||
|
Normal = 1,
|
||||||
|
Low = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
10
Enum/PlanProgress.cs
Normal file
10
Enum/PlanProgress.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public enum PlanProgress
|
||||||
|
{
|
||||||
|
Backlog = 0,
|
||||||
|
InProgress = 1,
|
||||||
|
Testing = 2,
|
||||||
|
Done = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
24
Enum/ReminderMileageInterval.cs
Normal file
24
Enum/ReminderMileageInterval.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public enum ReminderMileageInterval
|
||||||
|
{
|
||||||
|
Other = 0,
|
||||||
|
FiftyMiles = 50,
|
||||||
|
OneHundredMiles = 100,
|
||||||
|
FiveHundredMiles = 500,
|
||||||
|
OneThousandMiles = 1000,
|
||||||
|
ThreeThousandMiles = 3000,
|
||||||
|
FourThousandMiles = 4000,
|
||||||
|
FiveThousandMiles = 5000,
|
||||||
|
SevenThousandFiveHundredMiles = 7500,
|
||||||
|
TenThousandMiles = 10000,
|
||||||
|
FifteenThousandMiles = 15000,
|
||||||
|
TwentyThousandMiles = 20000,
|
||||||
|
ThirtyThousandMiles = 30000,
|
||||||
|
FortyThousandMiles = 40000,
|
||||||
|
FiftyThousandMiles = 50000,
|
||||||
|
SixtyThousandMiles = 60000,
|
||||||
|
OneHundredThousandMiles = 100000,
|
||||||
|
OneHundredFiftyThousandMiles = 150000
|
||||||
|
}
|
||||||
|
}
|
||||||
14
Enum/ReminderMonthInterval.cs
Normal file
14
Enum/ReminderMonthInterval.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public enum ReminderMonthInterval
|
||||||
|
{
|
||||||
|
Other = 0,
|
||||||
|
OneMonth = 1,
|
||||||
|
ThreeMonths = 3,
|
||||||
|
SixMonths = 6,
|
||||||
|
OneYear = 12,
|
||||||
|
TwoYears = 24,
|
||||||
|
ThreeYears = 36,
|
||||||
|
FiveYears = 60
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
using CarCareTracker.External.Interfaces;
|
|
||||||
using CarCareTracker.Helper;
|
|
||||||
using CarCareTracker.Models;
|
|
||||||
using LiteDB;
|
|
||||||
|
|
||||||
namespace CarCareTracker.External.Implementations
|
|
||||||
{
|
|
||||||
public class CollisionRecordDataAccess : ICollisionRecordDataAccess
|
|
||||||
{
|
|
||||||
private static string dbName = StaticHelper.DbName;
|
|
||||||
private static string tableName = "collisionrecords";
|
|
||||||
public List<CollisionRecord> GetCollisionRecordsByVehicleId(int vehicleId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<CollisionRecord>(tableName);
|
|
||||||
var collisionRecords = table.Find(Query.EQ(nameof(CollisionRecord.VehicleId), vehicleId));
|
|
||||||
return collisionRecords.ToList() ?? new List<CollisionRecord>();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public CollisionRecord GetCollisionRecordById(int collisionRecordId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<CollisionRecord>(tableName);
|
|
||||||
return table.FindById(collisionRecordId);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool DeleteCollisionRecordById(int collisionRecordId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<CollisionRecord>(tableName);
|
|
||||||
table.Delete(collisionRecordId);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool SaveCollisionRecordToVehicle(CollisionRecord collisionRecord)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<CollisionRecord>(tableName);
|
|
||||||
table.Upsert(collisionRecord);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool DeleteAllCollisionRecordsByVehicleId(int vehicleId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<CollisionRecord>(tableName);
|
|
||||||
var collisionRecords = table.DeleteMany(Query.EQ(nameof(CollisionRecord.VehicleId), vehicleId));
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
57
External/Implementations/GasRecordDataAccess.cs
vendored
57
External/Implementations/GasRecordDataAccess.cs
vendored
@@ -1,57 +0,0 @@
|
|||||||
using CarCareTracker.External.Interfaces;
|
|
||||||
using CarCareTracker.Helper;
|
|
||||||
using CarCareTracker.Models;
|
|
||||||
using LiteDB;
|
|
||||||
|
|
||||||
namespace CarCareTracker.External.Implementations
|
|
||||||
{
|
|
||||||
public class GasRecordDataAccess: IGasRecordDataAccess
|
|
||||||
{
|
|
||||||
private static string dbName = StaticHelper.DbName;
|
|
||||||
private static string tableName = "gasrecords";
|
|
||||||
public List<GasRecord> GetGasRecordsByVehicleId(int vehicleId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<GasRecord>(tableName);
|
|
||||||
var gasRecords = table.Find(Query.EQ(nameof(GasRecord.VehicleId), vehicleId));
|
|
||||||
return gasRecords.ToList() ?? new List<GasRecord>();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public GasRecord GetGasRecordById(int gasRecordId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<GasRecord>(tableName);
|
|
||||||
return table.FindById(gasRecordId);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool DeleteGasRecordById(int gasRecordId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<GasRecord>(tableName);
|
|
||||||
table.Delete(gasRecordId);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool SaveGasRecordToVehicle(GasRecord gasRecord)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<GasRecord>(tableName);
|
|
||||||
table.Upsert(gasRecord);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool DeleteAllGasRecordsByVehicleId(int vehicleId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<GasRecord>(tableName);
|
|
||||||
var gasRecords = table.DeleteMany(Query.EQ(nameof(GasRecord.VehicleId), vehicleId));
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
54
External/Implementations/Litedb/CollisionRecordDataAccess.cs
vendored
Normal file
54
External/Implementations/Litedb/CollisionRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class CollisionRecordDataAccess : ICollisionRecordDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
private static string tableName = "collisionrecords";
|
||||||
|
public CollisionRecordDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
public List<CollisionRecord> GetCollisionRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<CollisionRecord>(tableName);
|
||||||
|
var collisionRecords = table.Find(Query.EQ(nameof(CollisionRecord.VehicleId), vehicleId));
|
||||||
|
return collisionRecords.ToList() ?? new List<CollisionRecord>();
|
||||||
|
}
|
||||||
|
public CollisionRecord GetCollisionRecordById(int collisionRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<CollisionRecord>(tableName);
|
||||||
|
return table.FindById(collisionRecordId);
|
||||||
|
}
|
||||||
|
public bool DeleteCollisionRecordById(int collisionRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<CollisionRecord>(tableName);
|
||||||
|
table.Delete(collisionRecordId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool SaveCollisionRecordToVehicle(CollisionRecord collisionRecord)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<CollisionRecord>(tableName);
|
||||||
|
table.Upsert(collisionRecord);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteAllCollisionRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<CollisionRecord>(tableName);
|
||||||
|
var collisionRecords = table.DeleteMany(Query.EQ(nameof(CollisionRecord.VehicleId), vehicleId));
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
30
External/Implementations/Litedb/ExtraFieldDataAccess.cs
vendored
Normal file
30
External/Implementations/Litedb/ExtraFieldDataAccess.cs
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class ExtraFieldDataAccess : IExtraFieldDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
private static string tableName = "extrafields";
|
||||||
|
public ExtraFieldDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
public RecordExtraField GetExtraFieldsById(int importMode)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<RecordExtraField>(tableName);
|
||||||
|
return table.FindById(importMode) ?? new RecordExtraField();
|
||||||
|
}
|
||||||
|
public bool SaveExtraFields(RecordExtraField record)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<RecordExtraField>(tableName);
|
||||||
|
table.Upsert(record);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
External/Implementations/Litedb/GasRecordDataAccess.cs
vendored
Normal file
54
External/Implementations/Litedb/GasRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class GasRecordDataAccess : IGasRecordDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
private static string tableName = "gasrecords";
|
||||||
|
public GasRecordDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
public List<GasRecord> GetGasRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<GasRecord>(tableName);
|
||||||
|
var gasRecords = table.Find(Query.EQ(nameof(GasRecord.VehicleId), vehicleId));
|
||||||
|
return gasRecords.ToList() ?? new List<GasRecord>();
|
||||||
|
}
|
||||||
|
public GasRecord GetGasRecordById(int gasRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<GasRecord>(tableName);
|
||||||
|
return table.FindById(gasRecordId);
|
||||||
|
}
|
||||||
|
public bool DeleteGasRecordById(int gasRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<GasRecord>(tableName);
|
||||||
|
table.Delete(gasRecordId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool SaveGasRecordToVehicle(GasRecord gasRecord)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<GasRecord>(tableName);
|
||||||
|
table.Upsert(gasRecord);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteAllGasRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<GasRecord>(tableName);
|
||||||
|
var gasRecords = table.DeleteMany(Query.EQ(nameof(GasRecord.VehicleId), vehicleId));
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
External/Implementations/Litedb/NoteDataAccess.cs
vendored
Normal file
54
External/Implementations/Litedb/NoteDataAccess.cs
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class NoteDataAccess : INoteDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
private static string tableName = "notes";
|
||||||
|
public NoteDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
public List<Note> GetNotesByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<Note>(tableName);
|
||||||
|
var noteToReturn = table.Find(Query.EQ(nameof(Note.VehicleId), vehicleId));
|
||||||
|
return noteToReturn.ToList() ?? new List<Note>();
|
||||||
|
}
|
||||||
|
public Note GetNoteById(int noteId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<Note>(tableName);
|
||||||
|
return table.FindById(noteId);
|
||||||
|
}
|
||||||
|
public bool SaveNoteToVehicle(Note note)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<Note>(tableName);
|
||||||
|
table.Upsert(note);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteNoteById(int noteId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<Note>(tableName);
|
||||||
|
table.Delete(noteId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteAllNotesByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<Note>(tableName);
|
||||||
|
var notes = table.DeleteMany(Query.EQ(nameof(Note.VehicleId), vehicleId));
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
External/Implementations/Litedb/OdometerRecordDataAccess.cs
vendored
Normal file
54
External/Implementations/Litedb/OdometerRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class OdometerRecordDataAccess : IOdometerRecordDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
private static string tableName = "odometerrecords";
|
||||||
|
public OdometerRecordDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
public List<OdometerRecord> GetOdometerRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<OdometerRecord>(tableName);
|
||||||
|
var odometerRecords = table.Find(Query.EQ(nameof(OdometerRecord.VehicleId), vehicleId));
|
||||||
|
return odometerRecords.ToList() ?? new List<OdometerRecord>();
|
||||||
|
}
|
||||||
|
public OdometerRecord GetOdometerRecordById(int odometerRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<OdometerRecord>(tableName);
|
||||||
|
return table.FindById(odometerRecordId);
|
||||||
|
}
|
||||||
|
public bool DeleteOdometerRecordById(int odometerRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<OdometerRecord>(tableName);
|
||||||
|
table.Delete(odometerRecordId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool SaveOdometerRecordToVehicle(OdometerRecord odometerRecord)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<OdometerRecord>(tableName);
|
||||||
|
table.Upsert(odometerRecord);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteAllOdometerRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<OdometerRecord>(tableName);
|
||||||
|
var odometerRecords = table.DeleteMany(Query.EQ(nameof(OdometerRecord.VehicleId), vehicleId));
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
External/Implementations/Litedb/PlanRecordDataAccess.cs
vendored
Normal file
54
External/Implementations/Litedb/PlanRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PlanRecordDataAccess : IPlanRecordDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
private static string tableName = "planrecords";
|
||||||
|
public PlanRecordDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
public List<PlanRecord> GetPlanRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<PlanRecord>(tableName);
|
||||||
|
var planRecords = table.Find(Query.EQ(nameof(PlanRecord.VehicleId), vehicleId));
|
||||||
|
return planRecords.ToList() ?? new List<PlanRecord>();
|
||||||
|
}
|
||||||
|
public PlanRecord GetPlanRecordById(int planRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<PlanRecord>(tableName);
|
||||||
|
return table.FindById(planRecordId);
|
||||||
|
}
|
||||||
|
public bool DeletePlanRecordById(int planRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<PlanRecord>(tableName);
|
||||||
|
table.Delete(planRecordId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool SavePlanRecordToVehicle(PlanRecord planRecord)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<PlanRecord>(tableName);
|
||||||
|
table.Upsert(planRecord);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteAllPlanRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<PlanRecord>(tableName);
|
||||||
|
var planRecords = table.DeleteMany(Query.EQ(nameof(PlanRecord.VehicleId), vehicleId));
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
External/Implementations/Litedb/PlanRecordTemplateDataAccess.cs
vendored
Normal file
54
External/Implementations/Litedb/PlanRecordTemplateDataAccess.cs
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PlanRecordTemplateDataAccess : IPlanRecordTemplateDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
private static string tableName = "planrecordtemplates";
|
||||||
|
public PlanRecordTemplateDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
public List<PlanRecordInput> GetPlanRecordTemplatesByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<PlanRecordInput>(tableName);
|
||||||
|
var planRecords = table.Find(Query.EQ(nameof(PlanRecordInput.VehicleId), vehicleId));
|
||||||
|
return planRecords.ToList() ?? new List<PlanRecordInput>();
|
||||||
|
}
|
||||||
|
public PlanRecordInput GetPlanRecordTemplateById(int planRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<PlanRecordInput>(tableName);
|
||||||
|
return table.FindById(planRecordId);
|
||||||
|
}
|
||||||
|
public bool DeletePlanRecordTemplateById(int planRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<PlanRecordInput>(tableName);
|
||||||
|
table.Delete(planRecordId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool SavePlanRecordTemplateToVehicle(PlanRecordInput planRecord)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<PlanRecordInput>(tableName);
|
||||||
|
table.Upsert(planRecord);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteAllPlanRecordTemplatesByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<PlanRecord>(tableName);
|
||||||
|
var planRecords = table.DeleteMany(Query.EQ(nameof(PlanRecordInput.VehicleId), vehicleId));
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
External/Implementations/Litedb/ReminderRecordDataAccess.cs
vendored
Normal file
54
External/Implementations/Litedb/ReminderRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class ReminderRecordDataAccess : IReminderRecordDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
private static string tableName = "reminderrecords";
|
||||||
|
public ReminderRecordDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
public List<ReminderRecord> GetReminderRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<ReminderRecord>(tableName);
|
||||||
|
var reminderRecords = table.Find(Query.EQ(nameof(ReminderRecord.VehicleId), vehicleId));
|
||||||
|
return reminderRecords.ToList() ?? new List<ReminderRecord>();
|
||||||
|
}
|
||||||
|
public ReminderRecord GetReminderRecordById(int reminderRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<ReminderRecord>(tableName);
|
||||||
|
return table.FindById(reminderRecordId);
|
||||||
|
}
|
||||||
|
public bool DeleteReminderRecordById(int reminderRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<ReminderRecord>(tableName);
|
||||||
|
table.Delete(reminderRecordId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool SaveReminderRecordToVehicle(ReminderRecord reminderRecord)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<ReminderRecord>(tableName);
|
||||||
|
table.Upsert(reminderRecord);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteAllReminderRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<ReminderRecord>(tableName);
|
||||||
|
var reminderRecords = table.DeleteMany(Query.EQ(nameof(ReminderRecord.VehicleId), vehicleId));
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
External/Implementations/Litedb/ServiceRecordDataAccess.cs
vendored
Normal file
54
External/Implementations/Litedb/ServiceRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class ServiceRecordDataAccess : IServiceRecordDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
private static string tableName = "servicerecords";
|
||||||
|
public ServiceRecordDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
public List<ServiceRecord> GetServiceRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<ServiceRecord>(tableName);
|
||||||
|
var serviceRecords = table.Find(Query.EQ(nameof(ServiceRecord.VehicleId), vehicleId));
|
||||||
|
return serviceRecords.ToList() ?? new List<ServiceRecord>();
|
||||||
|
}
|
||||||
|
public ServiceRecord GetServiceRecordById(int serviceRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<ServiceRecord>(tableName);
|
||||||
|
return table.FindById(serviceRecordId);
|
||||||
|
}
|
||||||
|
public bool DeleteServiceRecordById(int serviceRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<ServiceRecord>(tableName);
|
||||||
|
table.Delete(serviceRecordId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool SaveServiceRecordToVehicle(ServiceRecord serviceRecord)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<ServiceRecord>(tableName);
|
||||||
|
table.Upsert(serviceRecord);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteAllServiceRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<ServiceRecord>(tableName);
|
||||||
|
var serviceRecords = table.DeleteMany(Query.EQ(nameof(ServiceRecord.VehicleId), vehicleId));
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
External/Implementations/Litedb/SupplyRecordDataAccess.cs
vendored
Normal file
54
External/Implementations/Litedb/SupplyRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class SupplyRecordDataAccess : ISupplyRecordDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
private static string tableName = "supplyrecords";
|
||||||
|
public SupplyRecordDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
public List<SupplyRecord> GetSupplyRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<SupplyRecord>(tableName);
|
||||||
|
var supplyRecords = table.Find(Query.EQ(nameof(SupplyRecord.VehicleId), vehicleId));
|
||||||
|
return supplyRecords.ToList() ?? new List<SupplyRecord>();
|
||||||
|
}
|
||||||
|
public SupplyRecord GetSupplyRecordById(int supplyRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<SupplyRecord>(tableName);
|
||||||
|
return table.FindById(supplyRecordId);
|
||||||
|
}
|
||||||
|
public bool DeleteSupplyRecordById(int supplyRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<SupplyRecord>(tableName);
|
||||||
|
table.Delete(supplyRecordId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool SaveSupplyRecordToVehicle(SupplyRecord supplyRecord)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<SupplyRecord>(tableName);
|
||||||
|
table.Upsert(supplyRecord);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteAllSupplyRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<SupplyRecord>(tableName);
|
||||||
|
var supplyRecords = table.DeleteMany(Query.EQ(nameof(SupplyRecord.VehicleId), vehicleId));
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
External/Implementations/Litedb/TaxRecordDataAccess.cs
vendored
Normal file
54
External/Implementations/Litedb/TaxRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class TaxRecordDataAccess : ITaxRecordDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
private static string tableName = "taxrecords";
|
||||||
|
public TaxRecordDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
public List<TaxRecord> GetTaxRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<TaxRecord>(tableName);
|
||||||
|
var taxRecords = table.Find(Query.EQ(nameof(TaxRecord.VehicleId), vehicleId));
|
||||||
|
return taxRecords.ToList() ?? new List<TaxRecord>();
|
||||||
|
}
|
||||||
|
public TaxRecord GetTaxRecordById(int taxRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<TaxRecord>(tableName);
|
||||||
|
return table.FindById(taxRecordId);
|
||||||
|
}
|
||||||
|
public bool DeleteTaxRecordById(int taxRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<TaxRecord>(tableName);
|
||||||
|
table.Delete(taxRecordId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool SaveTaxRecordToVehicle(TaxRecord taxRecord)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<TaxRecord>(tableName);
|
||||||
|
table.Upsert(taxRecord);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteAllTaxRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<TaxRecord>(tableName);
|
||||||
|
var taxRecords = table.DeleteMany(Query.EQ(nameof(TaxRecord.VehicleId), vehicleId));
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
53
External/Implementations/Litedb/TokenRecordDataAccess.cs
vendored
Normal file
53
External/Implementations/Litedb/TokenRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class TokenRecordDataAccess : ITokenRecordDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
private static string tableName = "tokenrecords";
|
||||||
|
public TokenRecordDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
public List<Token> GetTokens()
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<Token>(tableName);
|
||||||
|
return table.FindAll().ToList();
|
||||||
|
}
|
||||||
|
public Token GetTokenRecordByBody(string tokenBody)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<Token>(tableName);
|
||||||
|
var tokenRecord = table.FindOne(Query.EQ(nameof(Token.Body), tokenBody));
|
||||||
|
return tokenRecord ?? new Token();
|
||||||
|
}
|
||||||
|
public Token GetTokenRecordByEmailAddress(string emailAddress)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<Token>(tableName);
|
||||||
|
var tokenRecord = table.FindOne(Query.EQ(nameof(Token.EmailAddress), emailAddress));
|
||||||
|
return tokenRecord ?? new Token();
|
||||||
|
}
|
||||||
|
public bool CreateNewToken(Token token)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<Token>(tableName);
|
||||||
|
table.Insert(token);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteToken(int tokenId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<Token>(tableName);
|
||||||
|
table.Delete(tokenId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
External/Implementations/Litedb/UpgradeRecordDataAccess.cs
vendored
Normal file
54
External/Implementations/Litedb/UpgradeRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class UpgradeRecordDataAccess : IUpgradeRecordDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
public UpgradeRecordDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
private static string tableName = "upgraderecords";
|
||||||
|
public List<UpgradeRecord> GetUpgradeRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UpgradeRecord>(tableName);
|
||||||
|
var upgradeRecords = table.Find(Query.EQ(nameof(UpgradeRecord.VehicleId), vehicleId));
|
||||||
|
return upgradeRecords.ToList() ?? new List<UpgradeRecord>();
|
||||||
|
}
|
||||||
|
public UpgradeRecord GetUpgradeRecordById(int upgradeRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UpgradeRecord>(tableName);
|
||||||
|
return table.FindById(upgradeRecordId);
|
||||||
|
}
|
||||||
|
public bool DeleteUpgradeRecordById(int upgradeRecordId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UpgradeRecord>(tableName);
|
||||||
|
table.Delete(upgradeRecordId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool SaveUpgradeRecordToVehicle(UpgradeRecord upgradeRecord)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UpgradeRecord>(tableName);
|
||||||
|
table.Upsert(upgradeRecord);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteAllUpgradeRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UpgradeRecord>(tableName);
|
||||||
|
var upgradeRecords = table.DeleteMany(Query.EQ(nameof(UpgradeRecord.VehicleId), vehicleId));
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
82
External/Implementations/Litedb/UserAccessDataAcces.cs
vendored
Normal file
82
External/Implementations/Litedb/UserAccessDataAcces.cs
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class UserAccessDataAccess : IUserAccessDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
private static string tableName = "useraccessrecords";
|
||||||
|
public UserAccessDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of vehicles user have access to.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public List<UserAccess> GetUserAccessByUserId(int userId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UserAccess>(tableName);
|
||||||
|
return table.Find(x => x.Id.UserId == userId).ToList();
|
||||||
|
}
|
||||||
|
public UserAccess GetUserAccessByVehicleAndUserId(int userId, int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UserAccess>(tableName);
|
||||||
|
return table.Find(x => x.Id.UserId == userId && x.Id.VehicleId == vehicleId).FirstOrDefault();
|
||||||
|
}
|
||||||
|
public List<UserAccess> GetUserAccessByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UserAccess>(tableName);
|
||||||
|
return table.Find(x => x.Id.VehicleId == vehicleId).ToList();
|
||||||
|
}
|
||||||
|
public bool SaveUserAccess(UserAccess userAccess)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UserAccess>(tableName);
|
||||||
|
table.Upsert(userAccess);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteUserAccess(int userId, int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UserAccess>(tableName);
|
||||||
|
table.DeleteMany(x => x.Id.UserId == userId && x.Id.VehicleId == vehicleId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Delete all access records when a vehicle is deleted.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vehicleId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool DeleteAllAccessRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UserAccess>(tableName);
|
||||||
|
table.DeleteMany(x => x.Id.VehicleId == vehicleId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Delee all access records when a user is deleted.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool DeleteAllAccessRecordsByUserId(int userId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UserAccess>(tableName);
|
||||||
|
table.DeleteMany(x => x.Id.UserId == userId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
External/Implementations/Litedb/UserConfigDataAccess.cs
vendored
Normal file
38
External/Implementations/Litedb/UserConfigDataAccess.cs
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class UserConfigDataAccess : IUserConfigDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
private static string tableName = "userconfigrecords";
|
||||||
|
public UserConfigDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
public UserConfigData GetUserConfig(int userId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UserConfigData>(tableName);
|
||||||
|
return table.FindById(userId);
|
||||||
|
}
|
||||||
|
public bool SaveUserConfig(UserConfigData userConfigData)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UserConfigData>(tableName);
|
||||||
|
table.Upsert(userConfigData);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteUserConfig(int userId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UserConfigData>(tableName);
|
||||||
|
table.Delete(userId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
60
External/Implementations/Litedb/UserRecordDataAccess.cs
vendored
Normal file
60
External/Implementations/Litedb/UserRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using LiteDB;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class UserRecordDataAccess : IUserRecordDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
private static string tableName = "userrecords";
|
||||||
|
public UserRecordDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
public List<UserData> GetUsers()
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UserData>(tableName);
|
||||||
|
return table.FindAll().ToList();
|
||||||
|
}
|
||||||
|
public UserData GetUserRecordByUserName(string userName)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UserData>(tableName);
|
||||||
|
var userRecord = table.FindOne(Query.EQ(nameof(UserData.UserName), userName));
|
||||||
|
return userRecord ?? new UserData();
|
||||||
|
}
|
||||||
|
public UserData GetUserRecordByEmailAddress(string emailAddress)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UserData>(tableName);
|
||||||
|
var userRecord = table.FindOne(Query.EQ(nameof(UserData.EmailAddress), emailAddress));
|
||||||
|
return userRecord ?? new UserData();
|
||||||
|
}
|
||||||
|
public UserData GetUserRecordById(int userId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UserData>(tableName);
|
||||||
|
var userRecord = table.FindById(userId);
|
||||||
|
return userRecord ?? new UserData();
|
||||||
|
}
|
||||||
|
public bool SaveUserRecord(UserData userRecord)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UserData>(tableName);
|
||||||
|
table.Upsert(userRecord);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteUserRecord(int userId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<UserData>(tableName);
|
||||||
|
table.Delete(userId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
45
External/Implementations/Litedb/VehicleDataAccess.cs
vendored
Normal file
45
External/Implementations/Litedb/VehicleDataAccess.cs
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class VehicleDataAccess : IVehicleDataAccess
|
||||||
|
{
|
||||||
|
private ILiteDBHelper _liteDB { get; set; }
|
||||||
|
private static string tableName = "vehicles";
|
||||||
|
public VehicleDataAccess(ILiteDBHelper liteDB)
|
||||||
|
{
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
public bool SaveVehicle(Vehicle vehicle)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<Vehicle>(tableName);
|
||||||
|
var result = table.Upsert(vehicle);
|
||||||
|
db.Checkpoint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteVehicle(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<Vehicle>(tableName);
|
||||||
|
var result = table.Delete(vehicleId);
|
||||||
|
db.Checkpoint();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public List<Vehicle> GetVehicles()
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<Vehicle>(tableName);
|
||||||
|
return table.FindAll().ToList();
|
||||||
|
}
|
||||||
|
public Vehicle GetVehicleById(int vehicleId)
|
||||||
|
{
|
||||||
|
var db = _liteDB.GetLiteDB();
|
||||||
|
var table = db.GetCollection<Vehicle>(tableName);
|
||||||
|
return table.FindById(vehicleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
External/Implementations/NoteDataAccess.cs
vendored
57
External/Implementations/NoteDataAccess.cs
vendored
@@ -1,57 +0,0 @@
|
|||||||
using CarCareTracker.External.Interfaces;
|
|
||||||
using CarCareTracker.Helper;
|
|
||||||
using CarCareTracker.Models;
|
|
||||||
using LiteDB;
|
|
||||||
|
|
||||||
namespace CarCareTracker.External.Implementations
|
|
||||||
{
|
|
||||||
public class NoteDataAccess: INoteDataAccess
|
|
||||||
{
|
|
||||||
private static string dbName = StaticHelper.DbName;
|
|
||||||
private static string tableName = "notes";
|
|
||||||
public List<Note> GetNotesByVehicleId(int vehicleId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<Note>(tableName);
|
|
||||||
var noteToReturn = table.Find(Query.EQ(nameof(Note.VehicleId), vehicleId));
|
|
||||||
return noteToReturn.ToList() ?? new List<Note>();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public Note GetNoteById(int noteId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<Note>(tableName);
|
|
||||||
return table.FindById(noteId);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool SaveNoteToVehicle(Note note)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<Note>(tableName);
|
|
||||||
table.Upsert(note);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool DeleteNoteById(int noteId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<Note>(tableName);
|
|
||||||
table.Delete(noteId);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool DeleteAllNotesByVehicleId(int vehicleId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<Note>(tableName);
|
|
||||||
var notes = table.DeleteMany(Query.EQ(nameof(Note.VehicleId), vehicleId));
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
160
External/Implementations/Postgres/CollisionRecordDataAccess.cs
vendored
Normal file
160
External/Implementations/Postgres/CollisionRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGCollisionRecordDataAccess : ICollisionRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGCollisionRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "collisionrecords";
|
||||||
|
public PGCollisionRecordDataAccess(IConfiguration config, ILogger<PGCollisionRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<CollisionRecord> GetCollisionRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<CollisionRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
CollisionRecord collisionRecord = JsonSerializer.Deserialize<CollisionRecord>(reader["data"] as string);
|
||||||
|
results.Add(collisionRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<CollisionRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public CollisionRecord GetCollisionRecordById(int collisionRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new CollisionRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", collisionRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
CollisionRecord collisionRecord = JsonSerializer.Deserialize<CollisionRecord>(reader["data"] as string);
|
||||||
|
result = collisionRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new CollisionRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteCollisionRecordById(int collisionRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", collisionRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveCollisionRecordToVehicle(CollisionRecord collisionRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (collisionRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", collisionRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
collisionRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (collisionRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(collisionRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", collisionRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collisionRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(collisionRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", collisionRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllCollisionRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
76
External/Implementations/Postgres/ExtraFieldDataAccess.cs
vendored
Normal file
76
External/Implementations/Postgres/ExtraFieldDataAccess.cs
vendored
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGExtraFieldDataAccess : IExtraFieldDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGExtraFieldDataAccess> _logger;
|
||||||
|
private static string tableName = "extrafields";
|
||||||
|
public PGExtraFieldDataAccess(IConfiguration config, ILogger<PGExtraFieldDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT primary key, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public RecordExtraField GetExtraFieldsById(int importMode)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var results = new RecordExtraField();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", importMode);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
RecordExtraField result = JsonSerializer.Deserialize<RecordExtraField>(reader["data"] as string);
|
||||||
|
results = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new RecordExtraField();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveExtraFields(RecordExtraField record)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var existingRecord = GetExtraFieldsById(record.Id);
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (id, data) VALUES(@id, CAST(@data AS jsonb)) ON CONFLICT(id) DO UPDATE SET data = CAST(@data AS jsonb)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", JsonSerializer.Serialize(record));
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/GasRecordDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/GasRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGGasRecordDataAccess: IGasRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGGasRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "gasrecords";
|
||||||
|
public PGGasRecordDataAccess(IConfiguration config, ILogger<PGGasRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<GasRecord> GetGasRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<GasRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
GasRecord gasRecord = JsonSerializer.Deserialize<GasRecord>(reader["data"] as string);
|
||||||
|
results.Add(gasRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<GasRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public GasRecord GetGasRecordById(int gasRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new GasRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", gasRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
GasRecord gasRecord = JsonSerializer.Deserialize<GasRecord>(reader["data"] as string);
|
||||||
|
result = gasRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new GasRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteGasRecordById(int gasRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", gasRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveGasRecordToVehicle(GasRecord gasRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (gasRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", gasRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
gasRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (gasRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(gasRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", gasRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gasRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(gasRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", gasRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllGasRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
153
External/Implementations/Postgres/NoteDataAccess.cs
vendored
Normal file
153
External/Implementations/Postgres/NoteDataAccess.cs
vendored
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGNoteDataAccess: INoteDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGNoteDataAccess> _logger;
|
||||||
|
private static string tableName = "notes";
|
||||||
|
public PGNoteDataAccess(IConfiguration config, ILogger<PGNoteDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<Note> GetNotesByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<Note>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
Note note = JsonSerializer.Deserialize<Note>(reader["data"] as string);
|
||||||
|
results.Add(note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<Note>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Note GetNoteById(int noteId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new Note();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", noteId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
Note note = JsonSerializer.Deserialize<Note>(reader["data"] as string);
|
||||||
|
result = note;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new Note();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveNoteToVehicle(Note note)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (note.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", note.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
note.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (note.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(note);
|
||||||
|
ctextU.Parameters.AddWithValue("id", note.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return note.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(note);
|
||||||
|
ctext.Parameters.AddWithValue("id", note.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteNoteById(int noteId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", noteId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllNotesByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/OdometerRecordDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/OdometerRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGOdometerRecordDataAccess : IOdometerRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGOdometerRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "odometerrecords";
|
||||||
|
public PGOdometerRecordDataAccess(IConfiguration config, ILogger<PGOdometerRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<OdometerRecord> GetOdometerRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<OdometerRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
OdometerRecord odometerRecord = JsonSerializer.Deserialize<OdometerRecord>(reader["data"] as string);
|
||||||
|
results.Add(odometerRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<OdometerRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public OdometerRecord GetOdometerRecordById(int odometerRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new OdometerRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", odometerRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
OdometerRecord odometerRecord = JsonSerializer.Deserialize<OdometerRecord>(reader["data"] as string);
|
||||||
|
result = odometerRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new OdometerRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteOdometerRecordById(int odometerRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", odometerRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveOdometerRecordToVehicle(OdometerRecord odometerRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (odometerRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", odometerRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
odometerRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (odometerRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(odometerRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", odometerRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return odometerRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(odometerRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", odometerRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllOdometerRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/PlanRecordDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/PlanRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGPlanRecordDataAccess : IPlanRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGPlanRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "planrecords";
|
||||||
|
public PGPlanRecordDataAccess(IConfiguration config, ILogger<PGPlanRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<PlanRecord> GetPlanRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<PlanRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
PlanRecord planRecord = JsonSerializer.Deserialize<PlanRecord>(reader["data"] as string);
|
||||||
|
results.Add(planRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<PlanRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public PlanRecord GetPlanRecordById(int planRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new PlanRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", planRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
PlanRecord planRecord = JsonSerializer.Deserialize<PlanRecord>(reader["data"] as string);
|
||||||
|
result = planRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new PlanRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeletePlanRecordById(int planRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", planRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SavePlanRecordToVehicle(PlanRecord planRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (planRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", planRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
planRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (planRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(planRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", planRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return planRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(planRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", planRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllPlanRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/PlanRecordTemplateDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/PlanRecordTemplateDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGPlanRecordTemplateDataAccess : IPlanRecordTemplateDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGPlanRecordTemplateDataAccess> _logger;
|
||||||
|
private static string tableName = "planrecordtemplates";
|
||||||
|
public PGPlanRecordTemplateDataAccess(IConfiguration config, ILogger<PGPlanRecordTemplateDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<PlanRecordInput> GetPlanRecordTemplatesByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<PlanRecordInput>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
PlanRecordInput planRecord = JsonSerializer.Deserialize<PlanRecordInput>(reader["data"] as string);
|
||||||
|
results.Add(planRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<PlanRecordInput>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public PlanRecordInput GetPlanRecordTemplateById(int planRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new PlanRecordInput();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", planRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
PlanRecordInput planRecord = JsonSerializer.Deserialize<PlanRecordInput>(reader["data"] as string);
|
||||||
|
result = planRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new PlanRecordInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeletePlanRecordTemplateById(int planRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", planRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SavePlanRecordTemplateToVehicle(PlanRecordInput planRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (planRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", planRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
planRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (planRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(planRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", planRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return planRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(planRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", planRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllPlanRecordTemplatesByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/ReminderRecordDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/ReminderRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGReminderRecordDataAccess : IReminderRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGReminderRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "reminderrecords";
|
||||||
|
public PGReminderRecordDataAccess(IConfiguration config, ILogger<PGReminderRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<ReminderRecord> GetReminderRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<ReminderRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
ReminderRecord reminderRecord = JsonSerializer.Deserialize<ReminderRecord>(reader["data"] as string);
|
||||||
|
results.Add(reminderRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<ReminderRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public ReminderRecord GetReminderRecordById(int reminderRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new ReminderRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", reminderRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
ReminderRecord reminderRecord = JsonSerializer.Deserialize<ReminderRecord>(reader["data"] as string);
|
||||||
|
result = reminderRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new ReminderRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteReminderRecordById(int reminderRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", reminderRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveReminderRecordToVehicle(ReminderRecord reminderRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (reminderRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", reminderRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
reminderRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (reminderRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(reminderRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", reminderRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reminderRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(reminderRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", reminderRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllReminderRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/ServiceRecordDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/ServiceRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGServiceRecordDataAccess: IServiceRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGServiceRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "servicerecords";
|
||||||
|
public PGServiceRecordDataAccess(IConfiguration config, ILogger<PGServiceRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<ServiceRecord> GetServiceRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<ServiceRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
ServiceRecord serviceRecord = JsonSerializer.Deserialize<ServiceRecord>(reader["data"] as string);
|
||||||
|
results.Add(serviceRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<ServiceRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public ServiceRecord GetServiceRecordById(int serviceRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new ServiceRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", serviceRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
ServiceRecord serviceRecord = JsonSerializer.Deserialize<ServiceRecord>(reader["data"] as string);
|
||||||
|
result = serviceRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new ServiceRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteServiceRecordById(int serviceRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", serviceRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveServiceRecordToVehicle(ServiceRecord serviceRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (serviceRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", serviceRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
serviceRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (serviceRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(serviceRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", serviceRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return serviceRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(serviceRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", serviceRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllServiceRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/SupplyRecordDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/SupplyRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGSupplyRecordDataAccess : ISupplyRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGSupplyRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "supplyrecords";
|
||||||
|
public PGSupplyRecordDataAccess(IConfiguration config, ILogger<PGSupplyRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<SupplyRecord> GetSupplyRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<SupplyRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
SupplyRecord supplyRecord = JsonSerializer.Deserialize<SupplyRecord>(reader["data"] as string);
|
||||||
|
results.Add(supplyRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<SupplyRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public SupplyRecord GetSupplyRecordById(int supplyRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new SupplyRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", supplyRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
SupplyRecord supplyRecord = JsonSerializer.Deserialize<SupplyRecord>(reader["data"] as string);
|
||||||
|
result = supplyRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new SupplyRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteSupplyRecordById(int supplyRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", supplyRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveSupplyRecordToVehicle(SupplyRecord supplyRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (supplyRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", supplyRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
supplyRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (supplyRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(supplyRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", supplyRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return supplyRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(supplyRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", supplyRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllSupplyRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/TaxRecordDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/TaxRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGTaxRecordDataAccess : ITaxRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGTaxRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "taxrecords";
|
||||||
|
public PGTaxRecordDataAccess(IConfiguration config, ILogger<PGTaxRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<TaxRecord> GetTaxRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<TaxRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
TaxRecord taxRecord = JsonSerializer.Deserialize<TaxRecord>(reader["data"] as string);
|
||||||
|
results.Add(taxRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<TaxRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public TaxRecord GetTaxRecordById(int taxRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new TaxRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", taxRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
TaxRecord taxRecord = JsonSerializer.Deserialize<TaxRecord>(reader["data"] as string);
|
||||||
|
result = taxRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new TaxRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteTaxRecordById(int taxRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", taxRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveTaxRecordToVehicle(TaxRecord taxRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (taxRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", taxRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
taxRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (taxRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(taxRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", taxRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return taxRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(taxRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", taxRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllTaxRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
143
External/Implementations/Postgres/TokenRecordDataAccess.cs
vendored
Normal file
143
External/Implementations/Postgres/TokenRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGTokenRecordDataAccess : ITokenRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGTokenRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "tokenrecords";
|
||||||
|
public PGTokenRecordDataAccess(IConfiguration config, ILogger<PGTokenRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, body TEXT not null, emailaddress TEXT not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<Token> GetTokens()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, emailaddress, body FROM app.{tableName}";
|
||||||
|
var results = new List<Token>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
Token result = new Token();
|
||||||
|
result.Id = int.Parse(reader["id"].ToString());
|
||||||
|
result.EmailAddress = reader["emailaddress"].ToString();
|
||||||
|
result.Body = reader["body"].ToString();
|
||||||
|
results.Add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<Token>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Token GetTokenRecordByBody(string tokenBody)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, emailaddress, body FROM app.{tableName} WHERE body = @body";
|
||||||
|
var result = new Token();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("body", tokenBody);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
result.Id = int.Parse(reader["id"].ToString());
|
||||||
|
result.EmailAddress = reader["emailaddress"].ToString();
|
||||||
|
result.Body = reader["body"].ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new Token();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Token GetTokenRecordByEmailAddress(string emailAddress)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, emailaddress, body FROM app.{tableName} WHERE emailaddress = @emailaddress";
|
||||||
|
var result = new Token();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("emailaddress", emailAddress);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
result.Id = int.Parse(reader["id"].ToString());
|
||||||
|
result.EmailAddress = reader["emailaddress"].ToString();
|
||||||
|
result.Body = reader["body"].ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new Token();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool CreateNewToken(Token token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (emailaddress, body) VALUES(@emailaddress, @body) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("emailaddress", token.EmailAddress);
|
||||||
|
ctext.Parameters.AddWithValue("body", token.Body);
|
||||||
|
token.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
return token.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteToken(int tokenId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", tokenId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/UpgradeRecordDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/UpgradeRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGUpgradeRecordDataAccess : IUpgradeRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGUpgradeRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "upgraderecords";
|
||||||
|
public PGUpgradeRecordDataAccess(IConfiguration config, ILogger<PGUpgradeRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<UpgradeRecord> GetUpgradeRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<UpgradeRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
UpgradeRecord upgradeRecord = JsonSerializer.Deserialize<UpgradeRecord>(reader["data"] as string);
|
||||||
|
results.Add(upgradeRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<UpgradeRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public UpgradeRecord GetUpgradeRecordById(int upgradeRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new UpgradeRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", upgradeRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
UpgradeRecord upgradeRecord = JsonSerializer.Deserialize<UpgradeRecord>(reader["data"] as string);
|
||||||
|
result = upgradeRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new UpgradeRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteUpgradeRecordById(int upgradeRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", upgradeRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveUpgradeRecordToVehicle(UpgradeRecord upgradeRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (upgradeRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", upgradeRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
upgradeRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (upgradeRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(upgradeRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", upgradeRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return upgradeRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(upgradeRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", upgradeRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllUpgradeRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
211
External/Implementations/Postgres/UserAccessDataAcces.cs
vendored
Normal file
211
External/Implementations/Postgres/UserAccessDataAcces.cs
vendored
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Net.Mail;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGUserAccessDataAccess : IUserAccessDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGUserAccessDataAccess> _logger;
|
||||||
|
private static string tableName = "useraccessrecords";
|
||||||
|
public PGUserAccessDataAccess(IConfiguration config, ILogger<PGUserAccessDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (userId INT, vehicleId INT, PRIMARY KEY(userId, vehicleId))";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of vehicles user have access to.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public List<UserAccess> GetUserAccessByUserId(int userId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT userId, vehicleId FROM app.{tableName} WHERE userId = @userId";
|
||||||
|
var results = new List<UserAccess>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("userId", userId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
UserAccess result = new UserAccess()
|
||||||
|
{
|
||||||
|
Id = new UserVehicle
|
||||||
|
{
|
||||||
|
UserId = int.Parse(reader["userId"].ToString()),
|
||||||
|
VehicleId = int.Parse(reader["vehicleId"].ToString())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
results.Add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<UserAccess>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public UserAccess GetUserAccessByVehicleAndUserId(int userId, int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT userId, vehicleId FROM app.{tableName} WHERE userId = @userId AND vehicleId = @vehicleId";
|
||||||
|
UserAccess result = null;
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("userId", userId);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
result = new UserAccess()
|
||||||
|
{
|
||||||
|
Id = new UserVehicle
|
||||||
|
{
|
||||||
|
UserId = int.Parse(reader["userId"].ToString()),
|
||||||
|
VehicleId = int.Parse(reader["vehicleId"].ToString())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new UserAccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<UserAccess> GetUserAccessByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT userId, vehicleId FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<UserAccess>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
UserAccess result = new UserAccess()
|
||||||
|
{
|
||||||
|
Id = new UserVehicle
|
||||||
|
{
|
||||||
|
UserId = int.Parse(reader["userId"].ToString()),
|
||||||
|
VehicleId = int.Parse(reader["vehicleId"].ToString())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
results.Add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<UserAccess>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveUserAccess(UserAccess userAccess)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (userId, vehicleId) VALUES(@userId, @vehicleId)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("userId", userAccess.Id.UserId);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", userAccess.Id.VehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteUserAccess(int userId, int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE userId = @userId AND vehicleId = @vehicleId";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("userId", userId);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Delete all access records when a vehicle is deleted.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vehicleId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool DeleteAllAccessRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Delee all access records when a user is deleted.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool DeleteAllAccessRecordsByUserId(int userId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE userId = @userId";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("userId", userId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
107
External/Implementations/Postgres/UserConfigDataAccess.cs
vendored
Normal file
107
External/Implementations/Postgres/UserConfigDataAccess.cs
vendored
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGUserConfigDataAccess: IUserConfigDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGUserConfigDataAccess> _logger;
|
||||||
|
private static string tableName = "userconfigrecords";
|
||||||
|
public PGUserConfigDataAccess(IConfiguration config, ILogger<PGUserConfigDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT primary key, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public UserConfigData GetUserConfig(int userId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
UserConfigData result = null;
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", userId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
UserConfigData userConfig = JsonSerializer.Deserialize<UserConfigData>(reader["data"] as string);
|
||||||
|
result = userConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new UserConfigData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveUserConfig(UserConfigData userConfigData)
|
||||||
|
{
|
||||||
|
var existingRecord = GetUserConfig(userConfigData.Id);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (existingRecord == null)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (id, data) VALUES(@id, CAST(@data AS jsonb))";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(userConfigData);
|
||||||
|
ctext.Parameters.AddWithValue("id", userConfigData.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(userConfigData);
|
||||||
|
ctext.Parameters.AddWithValue("id", userConfigData.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteUserConfig(int userId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", userId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
194
External/Implementations/Postgres/UserRecordDataAccess.cs
vendored
Normal file
194
External/Implementations/Postgres/UserRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGUserRecordDataAccess : IUserRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGUserRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "userrecords";
|
||||||
|
public PGUserRecordDataAccess(IConfiguration config, ILogger<PGUserRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, username TEXT not null, emailaddress TEXT not null, password TEXT not null, isadmin BOOLEAN)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<UserData> GetUsers()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, username, emailaddress, password, isadmin FROM app.{tableName}";
|
||||||
|
var results = new List<UserData>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
UserData result = new UserData();
|
||||||
|
result.Id = int.Parse(reader["id"].ToString());
|
||||||
|
result.UserName = reader["username"].ToString();
|
||||||
|
result.EmailAddress = reader["emailaddress"].ToString();
|
||||||
|
result.Password = reader["password"].ToString();
|
||||||
|
result.IsAdmin = bool.Parse(reader["isadmin"].ToString());
|
||||||
|
results.Add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<UserData>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public UserData GetUserRecordByUserName(string userName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, username, emailaddress, password, isadmin FROM app.{tableName} WHERE username = @username";
|
||||||
|
var result = new UserData();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("username", userName);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
result.Id = int.Parse(reader["id"].ToString());
|
||||||
|
result.UserName = reader["username"].ToString();
|
||||||
|
result.EmailAddress = reader["emailaddress"].ToString();
|
||||||
|
result.Password = reader["password"].ToString();
|
||||||
|
result.IsAdmin = bool.Parse(reader["isadmin"].ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new UserData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public UserData GetUserRecordByEmailAddress(string emailAddress)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, username, emailaddress, password, isadmin FROM app.{tableName} WHERE emailaddress = @emailaddress";
|
||||||
|
var result = new UserData();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("emailaddress", emailAddress);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
result.Id = int.Parse(reader["id"].ToString());
|
||||||
|
result.UserName = reader["username"].ToString();
|
||||||
|
result.EmailAddress = reader["emailaddress"].ToString();
|
||||||
|
result.Password = reader["password"].ToString();
|
||||||
|
result.IsAdmin = bool.Parse(reader["isadmin"].ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new UserData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public UserData GetUserRecordById(int userId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, username, emailaddress, password, isadmin FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new UserData();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", userId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
result.Id = int.Parse(reader["id"].ToString());
|
||||||
|
result.UserName = reader["username"].ToString();
|
||||||
|
result.EmailAddress = reader["emailaddress"].ToString();
|
||||||
|
result.Password = reader["password"].ToString();
|
||||||
|
result.IsAdmin = bool.Parse(reader["isadmin"].ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new UserData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveUserRecord(UserData userRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (userRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (username, emailaddress, password, isadmin) VALUES(@username, @emailaddress, @password, @isadmin) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("username", userRecord.UserName);
|
||||||
|
ctext.Parameters.AddWithValue("emailaddress", userRecord.EmailAddress);
|
||||||
|
ctext.Parameters.AddWithValue("password", userRecord.Password);
|
||||||
|
ctext.Parameters.AddWithValue("isadmin", userRecord.IsAdmin);
|
||||||
|
userRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
return userRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET username = @username, emailaddress = @emailaddress, password = @password, isadmin = @isadmin WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", userRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("username", userRecord.UserName);
|
||||||
|
ctext.Parameters.AddWithValue("emailaddress", userRecord.EmailAddress);
|
||||||
|
ctext.Parameters.AddWithValue("password", userRecord.Password);
|
||||||
|
ctext.Parameters.AddWithValue("isadmin", userRecord.IsAdmin);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteUserRecord(int userId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", userId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
138
External/Implementations/Postgres/VehicleDataAccess.cs
vendored
Normal file
138
External/Implementations/Postgres/VehicleDataAccess.cs
vendored
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGVehicleDataAccess: IVehicleDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGVehicleDataAccess> _logger;
|
||||||
|
private static string tableName = "vehicles";
|
||||||
|
public PGVehicleDataAccess(IConfiguration config, ILogger<PGVehicleDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveVehicle(Vehicle vehicle)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(vehicle.ImageLocation))
|
||||||
|
{
|
||||||
|
vehicle.ImageLocation = "/defaults/noimage.png";
|
||||||
|
}
|
||||||
|
if (vehicle.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (data) VALUES(CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
vehicle.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (vehicle.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(vehicle);
|
||||||
|
ctextU.Parameters.AddWithValue("id", vehicle.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vehicle.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(vehicle);
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicle.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public bool DeleteVehicle(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<Vehicle> GetVehicles()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, data FROM app.{tableName} ORDER BY id ASC";
|
||||||
|
var results = new List<Vehicle>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
Vehicle vehicle = JsonSerializer.Deserialize<Vehicle>(reader["data"] as string);
|
||||||
|
results.Add(vehicle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<Vehicle>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Vehicle GetVehicleById(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, data FROM app.{tableName} WHERE id = @id";
|
||||||
|
Vehicle vehicle = new Vehicle();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
vehicle = JsonSerializer.Deserialize<Vehicle>(reader["data"] as string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vehicle;
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new Vehicle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
using CarCareTracker.External.Interfaces;
|
|
||||||
using CarCareTracker.Helper;
|
|
||||||
using CarCareTracker.Models;
|
|
||||||
using LiteDB;
|
|
||||||
|
|
||||||
namespace CarCareTracker.External.Implementations
|
|
||||||
{
|
|
||||||
public class ReminderRecordDataAccess : IReminderRecordDataAccess
|
|
||||||
{
|
|
||||||
private static string dbName = StaticHelper.DbName;
|
|
||||||
private static string tableName = "reminderrecords";
|
|
||||||
public List<ReminderRecord> GetReminderRecordsByVehicleId(int vehicleId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<ReminderRecord>(tableName);
|
|
||||||
var reminderRecords = table.Find(Query.EQ(nameof(ReminderRecord.VehicleId), vehicleId));
|
|
||||||
return reminderRecords.ToList() ?? new List<ReminderRecord>();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public ReminderRecord GetReminderRecordById(int reminderRecordId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<ReminderRecord>(tableName);
|
|
||||||
return table.FindById(reminderRecordId);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool DeleteReminderRecordById(int reminderRecordId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<ReminderRecord>(tableName);
|
|
||||||
table.Delete(reminderRecordId);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool SaveReminderRecordToVehicle(ReminderRecord reminderRecord)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<ReminderRecord>(tableName);
|
|
||||||
table.Upsert(reminderRecord);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool DeleteAllReminderRecordsByVehicleId(int vehicleId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<ReminderRecord>(tableName);
|
|
||||||
var reminderRecords = table.DeleteMany(Query.EQ(nameof(ReminderRecord.VehicleId), vehicleId));
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
using CarCareTracker.External.Interfaces;
|
|
||||||
using CarCareTracker.Helper;
|
|
||||||
using CarCareTracker.Models;
|
|
||||||
using LiteDB;
|
|
||||||
|
|
||||||
namespace CarCareTracker.External.Implementations
|
|
||||||
{
|
|
||||||
public class ServiceRecordDataAccess: IServiceRecordDataAccess
|
|
||||||
{
|
|
||||||
private static string dbName = StaticHelper.DbName;
|
|
||||||
private static string tableName = "servicerecords";
|
|
||||||
public List<ServiceRecord> GetServiceRecordsByVehicleId(int vehicleId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<ServiceRecord>(tableName);
|
|
||||||
var serviceRecords = table.Find(Query.EQ(nameof(ServiceRecord.VehicleId), vehicleId));
|
|
||||||
return serviceRecords.ToList() ?? new List<ServiceRecord>();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public ServiceRecord GetServiceRecordById(int serviceRecordId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<ServiceRecord>(tableName);
|
|
||||||
return table.FindById(serviceRecordId);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool DeleteServiceRecordById(int serviceRecordId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<ServiceRecord>(tableName);
|
|
||||||
table.Delete(serviceRecordId);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool SaveServiceRecordToVehicle(ServiceRecord serviceRecord)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<ServiceRecord>(tableName);
|
|
||||||
table.Upsert(serviceRecord);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool DeleteAllServiceRecordsByVehicleId(int vehicleId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<ServiceRecord>(tableName);
|
|
||||||
var serviceRecords = table.DeleteMany(Query.EQ(nameof(ServiceRecord.VehicleId), vehicleId));
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
57
External/Implementations/TaxRecordDataAccess.cs
vendored
57
External/Implementations/TaxRecordDataAccess.cs
vendored
@@ -1,57 +0,0 @@
|
|||||||
using CarCareTracker.External.Interfaces;
|
|
||||||
using CarCareTracker.Helper;
|
|
||||||
using CarCareTracker.Models;
|
|
||||||
using LiteDB;
|
|
||||||
|
|
||||||
namespace CarCareTracker.External.Implementations
|
|
||||||
{
|
|
||||||
public class TaxRecordDataAccess : ITaxRecordDataAccess
|
|
||||||
{
|
|
||||||
private static string dbName = StaticHelper.DbName;
|
|
||||||
private static string tableName = "taxrecords";
|
|
||||||
public List<TaxRecord> GetTaxRecordsByVehicleId(int vehicleId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<TaxRecord>(tableName);
|
|
||||||
var taxRecords = table.Find(Query.EQ(nameof(TaxRecord.VehicleId), vehicleId));
|
|
||||||
return taxRecords.ToList() ?? new List<TaxRecord>();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public TaxRecord GetTaxRecordById(int taxRecordId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<TaxRecord>(tableName);
|
|
||||||
return table.FindById(taxRecordId);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool DeleteTaxRecordById(int taxRecordId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<TaxRecord>(tableName);
|
|
||||||
table.Delete(taxRecordId);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool SaveTaxRecordToVehicle(TaxRecord taxRecord)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<TaxRecord>(tableName);
|
|
||||||
table.Upsert(taxRecord);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool DeleteAllTaxRecordsByVehicleId(int vehicleId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<TaxRecord>(tableName);
|
|
||||||
var taxRecords = table.DeleteMany(Query.EQ(nameof(TaxRecord.VehicleId), vehicleId));
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
using CarCareTracker.External.Interfaces;
|
|
||||||
using CarCareTracker.Helper;
|
|
||||||
using CarCareTracker.Models;
|
|
||||||
using LiteDB;
|
|
||||||
|
|
||||||
namespace CarCareTracker.External.Implementations
|
|
||||||
{
|
|
||||||
public class UpgradeRecordDataAccess : IUpgradeRecordDataAccess
|
|
||||||
{
|
|
||||||
private static string dbName = StaticHelper.DbName;
|
|
||||||
private static string tableName = "upgraderecords";
|
|
||||||
public List<UpgradeRecord> GetUpgradeRecordsByVehicleId(int vehicleId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<UpgradeRecord>(tableName);
|
|
||||||
var upgradeRecords = table.Find(Query.EQ(nameof(UpgradeRecord.VehicleId), vehicleId));
|
|
||||||
return upgradeRecords.ToList() ?? new List<UpgradeRecord>();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public UpgradeRecord GetUpgradeRecordById(int upgradeRecordId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<UpgradeRecord>(tableName);
|
|
||||||
return table.FindById(upgradeRecordId);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool DeleteUpgradeRecordById(int upgradeRecordId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<UpgradeRecord>(tableName);
|
|
||||||
table.Delete(upgradeRecordId);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool SaveUpgradeRecordToVehicle(UpgradeRecord upgradeRecord)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<UpgradeRecord>(tableName);
|
|
||||||
table.Upsert(upgradeRecord);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool DeleteAllUpgradeRecordsByVehicleId(int vehicleId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<UpgradeRecord>(tableName);
|
|
||||||
var upgradeRecords = table.DeleteMany(Query.EQ(nameof(UpgradeRecord.VehicleId), vehicleId));
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
46
External/Implementations/VehicleDataAccess.cs
vendored
46
External/Implementations/VehicleDataAccess.cs
vendored
@@ -1,46 +0,0 @@
|
|||||||
using CarCareTracker.External.Interfaces;
|
|
||||||
using CarCareTracker.Helper;
|
|
||||||
using CarCareTracker.Models;
|
|
||||||
using LiteDB;
|
|
||||||
|
|
||||||
namespace CarCareTracker.External.Implementations
|
|
||||||
{
|
|
||||||
public class VehicleDataAccess: IVehicleDataAccess
|
|
||||||
{
|
|
||||||
private static string dbName = StaticHelper.DbName;
|
|
||||||
private static string tableName = "vehicles";
|
|
||||||
public bool SaveVehicle(Vehicle vehicle)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<Vehicle>(tableName);
|
|
||||||
table.Upsert(vehicle);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public bool DeleteVehicle(int vehicleId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<Vehicle>(tableName);
|
|
||||||
return table.Delete(vehicleId);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public List<Vehicle> GetVehicles()
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<Vehicle>(tableName);
|
|
||||||
return table.FindAll().ToList();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public Vehicle GetVehicleById(int vehicleId)
|
|
||||||
{
|
|
||||||
using (var db = new LiteDatabase(dbName))
|
|
||||||
{
|
|
||||||
var table = db.GetCollection<Vehicle>(tableName);
|
|
||||||
return table.FindById(vehicleId);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
10
External/Interfaces/IExtraFieldDataAccess.cs
vendored
Normal file
10
External/Interfaces/IExtraFieldDataAccess.cs
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using CarCareTracker.Models;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Interfaces
|
||||||
|
{
|
||||||
|
public interface IExtraFieldDataAccess
|
||||||
|
{
|
||||||
|
public RecordExtraField GetExtraFieldsById(int importMode);
|
||||||
|
public bool SaveExtraFields(RecordExtraField record);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
External/Interfaces/IOdometerRecordDataAccess.cs
vendored
Normal file
13
External/Interfaces/IOdometerRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using CarCareTracker.Models;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Interfaces
|
||||||
|
{
|
||||||
|
public interface IOdometerRecordDataAccess
|
||||||
|
{
|
||||||
|
public List<OdometerRecord> GetOdometerRecordsByVehicleId(int vehicleId);
|
||||||
|
public OdometerRecord GetOdometerRecordById(int odometerRecordId);
|
||||||
|
public bool DeleteOdometerRecordById(int odometerRecordId);
|
||||||
|
public bool SaveOdometerRecordToVehicle(OdometerRecord odometerRecord);
|
||||||
|
public bool DeleteAllOdometerRecordsByVehicleId(int vehicleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
External/Interfaces/IPlanRecordDataAccess.cs
vendored
Normal file
13
External/Interfaces/IPlanRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using CarCareTracker.Models;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Interfaces
|
||||||
|
{
|
||||||
|
public interface IPlanRecordDataAccess
|
||||||
|
{
|
||||||
|
public List<PlanRecord> GetPlanRecordsByVehicleId(int vehicleId);
|
||||||
|
public PlanRecord GetPlanRecordById(int planRecordId);
|
||||||
|
public bool DeletePlanRecordById(int planRecordId);
|
||||||
|
public bool SavePlanRecordToVehicle(PlanRecord planRecord);
|
||||||
|
public bool DeleteAllPlanRecordsByVehicleId(int vehicleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
External/Interfaces/IPlanRecordTemplateDataAccess.cs
vendored
Normal file
13
External/Interfaces/IPlanRecordTemplateDataAccess.cs
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using CarCareTracker.Models;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Interfaces
|
||||||
|
{
|
||||||
|
public interface IPlanRecordTemplateDataAccess
|
||||||
|
{
|
||||||
|
public List<PlanRecordInput> GetPlanRecordTemplatesByVehicleId(int vehicleId);
|
||||||
|
public PlanRecordInput GetPlanRecordTemplateById(int planRecordId);
|
||||||
|
public bool DeletePlanRecordTemplateById(int planRecordId);
|
||||||
|
public bool SavePlanRecordTemplateToVehicle(PlanRecordInput planRecord);
|
||||||
|
public bool DeleteAllPlanRecordTemplatesByVehicleId(int vehicleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
External/Interfaces/ISupplyRecordDataAccess.cs
vendored
Normal file
13
External/Interfaces/ISupplyRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using CarCareTracker.Models;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Interfaces
|
||||||
|
{
|
||||||
|
public interface ISupplyRecordDataAccess
|
||||||
|
{
|
||||||
|
public List<SupplyRecord> GetSupplyRecordsByVehicleId(int vehicleId);
|
||||||
|
public SupplyRecord GetSupplyRecordById(int supplyRecordId);
|
||||||
|
public bool DeleteSupplyRecordById(int supplyRecordId);
|
||||||
|
public bool SaveSupplyRecordToVehicle(SupplyRecord supplyRecord);
|
||||||
|
public bool DeleteAllSupplyRecordsByVehicleId(int vehicleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
External/Interfaces/ITokenRecordDataAccess.cs
vendored
Normal file
13
External/Interfaces/ITokenRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using CarCareTracker.Models;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Interfaces
|
||||||
|
{
|
||||||
|
public interface ITokenRecordDataAccess
|
||||||
|
{
|
||||||
|
public List<Token> GetTokens();
|
||||||
|
public Token GetTokenRecordByBody(string tokenBody);
|
||||||
|
public Token GetTokenRecordByEmailAddress(string emailAddress);
|
||||||
|
public bool CreateNewToken(Token token);
|
||||||
|
public bool DeleteToken(int tokenId);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
External/Interfaces/IUserAccessDataAccess.cs
vendored
Normal file
15
External/Interfaces/IUserAccessDataAccess.cs
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using CarCareTracker.Models;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Interfaces
|
||||||
|
{
|
||||||
|
public interface IUserAccessDataAccess
|
||||||
|
{
|
||||||
|
List<UserAccess> GetUserAccessByUserId(int userId);
|
||||||
|
UserAccess GetUserAccessByVehicleAndUserId(int userId, int vehicleId);
|
||||||
|
List<UserAccess> GetUserAccessByVehicleId(int vehicleId);
|
||||||
|
bool SaveUserAccess(UserAccess userAccess);
|
||||||
|
bool DeleteUserAccess(int userId, int vehicleId);
|
||||||
|
bool DeleteAllAccessRecordsByVehicleId(int vehicleId);
|
||||||
|
bool DeleteAllAccessRecordsByUserId(int userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
External/Interfaces/IUserConfigDataAccess.cs
vendored
Normal file
11
External/Interfaces/IUserConfigDataAccess.cs
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using CarCareTracker.Models;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Interfaces
|
||||||
|
{
|
||||||
|
public interface IUserConfigDataAccess
|
||||||
|
{
|
||||||
|
public UserConfigData GetUserConfig(int userId);
|
||||||
|
public bool SaveUserConfig(UserConfigData userConfigData);
|
||||||
|
public bool DeleteUserConfig(int userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
14
External/Interfaces/IUserRecordDataAccess.cs
vendored
Normal file
14
External/Interfaces/IUserRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using CarCareTracker.Models;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Interfaces
|
||||||
|
{
|
||||||
|
public interface IUserRecordDataAccess
|
||||||
|
{
|
||||||
|
public List<UserData> GetUsers();
|
||||||
|
public UserData GetUserRecordByUserName(string userName);
|
||||||
|
public UserData GetUserRecordByEmailAddress(string emailAddress);
|
||||||
|
public UserData GetUserRecordById(int userId);
|
||||||
|
public bool SaveUserRecord(UserData userRecord);
|
||||||
|
public bool DeleteUserRecord(int userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
47
Filter/CollaboratorFilter.cs
Normal file
47
Filter/CollaboratorFilter.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Logic;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Filter
|
||||||
|
{
|
||||||
|
public class CollaboratorFilter: ActionFilterAttribute
|
||||||
|
{
|
||||||
|
private readonly IUserLogic _userLogic;
|
||||||
|
private readonly IConfigHelper _config;
|
||||||
|
public CollaboratorFilter(IUserLogic userLogic, IConfigHelper config) {
|
||||||
|
_userLogic = userLogic;
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
public override void OnActionExecuting(ActionExecutingContext filterContext)
|
||||||
|
{
|
||||||
|
if (!filterContext.HttpContext.User.IsInRole(nameof(UserData.IsRootUser)))
|
||||||
|
{
|
||||||
|
var vehicleId = int.Parse(filterContext.ActionArguments["vehicleId"].ToString());
|
||||||
|
if (vehicleId != default)
|
||||||
|
{
|
||||||
|
var userId = int.Parse(filterContext.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier));
|
||||||
|
if (!_userLogic.UserCanEditVehicle(userId, vehicleId))
|
||||||
|
{
|
||||||
|
filterContext.Result = new RedirectResult("/Error/Unauthorized");
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
var shopSupplyEndpoints = new List<string> { "ImportToVehicleIdFromCsv", "GetSupplyRecordsByVehicleId", "ExportFromVehicleToCsv" };
|
||||||
|
if (shopSupplyEndpoints.Contains(filterContext.RouteData.Values["action"].ToString()) && !_config.GetServerEnableShopSupplies())
|
||||||
|
{
|
||||||
|
//user trying to access shop supplies but shop supplies is not enabled by root user.
|
||||||
|
filterContext.Result = new RedirectResult("/Error/Unauthorized");
|
||||||
|
}
|
||||||
|
else if (!shopSupplyEndpoints.Contains(filterContext.RouteData.Values["action"].ToString()))
|
||||||
|
{
|
||||||
|
//user trying to access any other endpoints using 0 as vehicle id.
|
||||||
|
filterContext.Result = new RedirectResult("/Error/Unauthorized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
224
Helper/ConfigHelper.cs
Normal file
224
Helper/ConfigHelper.cs
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Helper
|
||||||
|
{
|
||||||
|
public interface IConfigHelper
|
||||||
|
{
|
||||||
|
OpenIDConfig GetOpenIDConfig();
|
||||||
|
ReminderUrgencyConfig GetReminderUrgencyConfig();
|
||||||
|
UserConfig GetUserConfig(ClaimsPrincipal user);
|
||||||
|
bool SaveUserConfig(ClaimsPrincipal user, UserConfig configData);
|
||||||
|
bool AuthenticateRootUser(string username, string password);
|
||||||
|
string GetWebHookUrl();
|
||||||
|
string GetMOTD();
|
||||||
|
string GetLogoUrl();
|
||||||
|
string GetServerLanguage();
|
||||||
|
bool GetServerEnableShopSupplies();
|
||||||
|
string GetServerPostgresConnection();
|
||||||
|
string GetAllowedFileUploadExtensions();
|
||||||
|
public bool DeleteUserConfig(int userId);
|
||||||
|
}
|
||||||
|
public class ConfigHelper : IConfigHelper
|
||||||
|
{
|
||||||
|
private readonly IConfiguration _config;
|
||||||
|
private readonly IUserConfigDataAccess _userConfig;
|
||||||
|
private IMemoryCache _cache;
|
||||||
|
public ConfigHelper(IConfiguration serverConfig,
|
||||||
|
IUserConfigDataAccess userConfig,
|
||||||
|
IMemoryCache memoryCache)
|
||||||
|
{
|
||||||
|
_config = serverConfig;
|
||||||
|
_userConfig = userConfig;
|
||||||
|
_cache = memoryCache;
|
||||||
|
}
|
||||||
|
public string GetWebHookUrl()
|
||||||
|
{
|
||||||
|
var webhook = _config["LUBELOGGER_WEBHOOK"];
|
||||||
|
if (string.IsNullOrWhiteSpace(webhook))
|
||||||
|
{
|
||||||
|
webhook = "";
|
||||||
|
}
|
||||||
|
return webhook;
|
||||||
|
}
|
||||||
|
public string GetMOTD()
|
||||||
|
{
|
||||||
|
var motd = _config["LUBELOGGER_MOTD"];
|
||||||
|
if (string.IsNullOrWhiteSpace(motd))
|
||||||
|
{
|
||||||
|
motd = "";
|
||||||
|
}
|
||||||
|
return motd;
|
||||||
|
}
|
||||||
|
public OpenIDConfig GetOpenIDConfig()
|
||||||
|
{
|
||||||
|
OpenIDConfig openIdConfig = _config.GetSection("OpenIDConfig").Get<OpenIDConfig>() ?? new OpenIDConfig();
|
||||||
|
return openIdConfig;
|
||||||
|
}
|
||||||
|
public ReminderUrgencyConfig GetReminderUrgencyConfig()
|
||||||
|
{
|
||||||
|
ReminderUrgencyConfig reminderUrgencyConfig = _config.GetSection("ReminderUrgencyConfig").Get<ReminderUrgencyConfig>() ?? new ReminderUrgencyConfig();
|
||||||
|
return reminderUrgencyConfig;
|
||||||
|
}
|
||||||
|
public string GetLogoUrl()
|
||||||
|
{
|
||||||
|
var logoUrl = _config["LUBELOGGER_LOGO_URL"];
|
||||||
|
if (string.IsNullOrWhiteSpace(logoUrl))
|
||||||
|
{
|
||||||
|
logoUrl = "/defaults/lubelogger_logo.png";
|
||||||
|
}
|
||||||
|
return logoUrl;
|
||||||
|
}
|
||||||
|
public string GetAllowedFileUploadExtensions()
|
||||||
|
{
|
||||||
|
var allowedFileExtensions = _config["LUBELOGGER_ALLOWED_FILE_EXTENSIONS"];
|
||||||
|
if (string.IsNullOrWhiteSpace(allowedFileExtensions)){
|
||||||
|
return StaticHelper.DefaultAllowedFileExtensions;
|
||||||
|
}
|
||||||
|
return allowedFileExtensions;
|
||||||
|
}
|
||||||
|
public bool AuthenticateRootUser(string username, string password)
|
||||||
|
{
|
||||||
|
var rootUsername = _config[nameof(UserConfig.UserNameHash)] ?? string.Empty;
|
||||||
|
var rootPassword = _config[nameof(UserConfig.UserPasswordHash)] ?? string.Empty;
|
||||||
|
if (string.IsNullOrWhiteSpace(rootUsername) || string.IsNullOrWhiteSpace(rootPassword))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return username == rootUsername && password == rootPassword;
|
||||||
|
}
|
||||||
|
public string GetServerLanguage()
|
||||||
|
{
|
||||||
|
var serverLanguage = _config[nameof(UserConfig.UserLanguage)] ?? "en_US";
|
||||||
|
return serverLanguage;
|
||||||
|
}
|
||||||
|
public string GetServerPostgresConnection()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(_config["POSTGRES_CONNECTION"]))
|
||||||
|
{
|
||||||
|
return _config["POSTGRES_CONNECTION"];
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool GetServerEnableShopSupplies()
|
||||||
|
{
|
||||||
|
return bool.Parse(_config[nameof(UserConfig.EnableShopSupplies)] ?? "false");
|
||||||
|
}
|
||||||
|
public bool SaveUserConfig(ClaimsPrincipal user, UserConfig configData)
|
||||||
|
{
|
||||||
|
var storedUserId = user.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||||
|
int userId = 0;
|
||||||
|
if (storedUserId != null)
|
||||||
|
{
|
||||||
|
userId = int.Parse(storedUserId);
|
||||||
|
}
|
||||||
|
bool isRootUser = user.IsInRole(nameof(UserData.IsRootUser)) || userId == -1;
|
||||||
|
if (isRootUser)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!File.Exists(StaticHelper.UserConfigPath))
|
||||||
|
{
|
||||||
|
//if file doesn't exist it might be because it's running on a mounted volume in docker.
|
||||||
|
File.WriteAllText(StaticHelper.UserConfigPath, System.Text.Json.JsonSerializer.Serialize(new UserConfig()));
|
||||||
|
}
|
||||||
|
var configFileContents = File.ReadAllText(StaticHelper.UserConfigPath);
|
||||||
|
configData.EnableAuth = bool.Parse(_config[nameof(UserConfig.EnableAuth)] ?? "false");
|
||||||
|
configData.UserNameHash = _config[nameof(UserConfig.UserNameHash)] ?? string.Empty;
|
||||||
|
configData.UserPasswordHash = _config[nameof(UserConfig.UserPasswordHash)] ?? string.Empty;
|
||||||
|
File.WriteAllText(StaticHelper.UserConfigPath, System.Text.Json.JsonSerializer.Serialize(configData));
|
||||||
|
_cache.Set<UserConfig>($"userConfig_{userId}", configData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
var userConfig = new UserConfigData()
|
||||||
|
{
|
||||||
|
Id = userId,
|
||||||
|
UserConfig = configData
|
||||||
|
};
|
||||||
|
var result = _userConfig.SaveUserConfig(userConfig);
|
||||||
|
_cache.Set<UserConfig>($"userConfig_{userId}", configData);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteUserConfig(int userId)
|
||||||
|
{
|
||||||
|
_cache.Remove($"userConfig_{userId}");
|
||||||
|
var result = _userConfig.DeleteUserConfig(userId);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public UserConfig GetUserConfig(ClaimsPrincipal user)
|
||||||
|
{
|
||||||
|
var serverConfig = new UserConfig
|
||||||
|
{
|
||||||
|
EnableCsvImports = bool.Parse(_config[nameof(UserConfig.EnableCsvImports)]),
|
||||||
|
UseDarkMode = bool.Parse(_config[nameof(UserConfig.UseDarkMode)]),
|
||||||
|
UseMPG = bool.Parse(_config[nameof(UserConfig.UseMPG)]),
|
||||||
|
UseDescending = bool.Parse(_config[nameof(UserConfig.UseDescending)]),
|
||||||
|
EnableAuth = bool.Parse(_config[nameof(UserConfig.EnableAuth)]),
|
||||||
|
HideZero = bool.Parse(_config[nameof(UserConfig.HideZero)]),
|
||||||
|
UseUKMPG = bool.Parse(_config[nameof(UserConfig.UseUKMPG)]),
|
||||||
|
UseMarkDownOnSavedNotes = bool.Parse(_config[nameof(UserConfig.UseMarkDownOnSavedNotes)]),
|
||||||
|
UseThreeDecimalGasCost = bool.Parse(_config[nameof(UserConfig.UseThreeDecimalGasCost)]),
|
||||||
|
EnableAutoReminderRefresh = bool.Parse(_config[nameof(UserConfig.EnableAutoReminderRefresh)]),
|
||||||
|
EnableAutoOdometerInsert = bool.Parse(_config[nameof(UserConfig.EnableAutoOdometerInsert)]),
|
||||||
|
PreferredGasMileageUnit = _config[nameof(UserConfig.PreferredGasMileageUnit)],
|
||||||
|
PreferredGasUnit = _config[nameof(UserConfig.PreferredGasUnit)],
|
||||||
|
UserLanguage = _config[nameof(UserConfig.UserLanguage)],
|
||||||
|
HideSoldVehicles = bool.Parse(_config[nameof(UserConfig.HideSoldVehicles)]),
|
||||||
|
EnableShopSupplies = bool.Parse(_config[nameof(UserConfig.EnableShopSupplies)]),
|
||||||
|
EnableExtraFieldColumns = bool.Parse(_config[nameof(UserConfig.EnableExtraFieldColumns)]),
|
||||||
|
VisibleTabs = _config.GetSection(nameof(UserConfig.VisibleTabs)).Get<List<ImportMode>>(),
|
||||||
|
UserColumnPreferences = _config.GetSection(nameof(UserConfig.UserColumnPreferences)).Get<List<UserColumnPreference>>() ?? new List<UserColumnPreference>(),
|
||||||
|
ReminderUrgencyConfig = _config.GetSection(nameof(UserConfig.ReminderUrgencyConfig)).Get<ReminderUrgencyConfig>() ?? new ReminderUrgencyConfig(),
|
||||||
|
DefaultTab = (ImportMode)int.Parse(_config[nameof(UserConfig.DefaultTab)])
|
||||||
|
};
|
||||||
|
int userId = 0;
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
var storedUserId = user.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||||
|
if (storedUserId != null)
|
||||||
|
{
|
||||||
|
userId = int.Parse(storedUserId);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return serverConfig;
|
||||||
|
}
|
||||||
|
return _cache.GetOrCreate<UserConfig>($"userConfig_{userId}", entry =>
|
||||||
|
{
|
||||||
|
entry.SlidingExpiration = TimeSpan.FromHours(1);
|
||||||
|
if (!user.Identity.IsAuthenticated)
|
||||||
|
{
|
||||||
|
return serverConfig;
|
||||||
|
}
|
||||||
|
bool isRootUser = user.IsInRole(nameof(UserData.IsRootUser)) || userId == -1;
|
||||||
|
if (isRootUser)
|
||||||
|
{
|
||||||
|
return serverConfig;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var result = _userConfig.GetUserConfig(userId);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return serverConfig;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return result.UserConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,63 @@
|
|||||||
namespace CarCareTracker.Helper
|
using CarCareTracker.Models;
|
||||||
|
using System.IO.Compression;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Helper
|
||||||
{
|
{
|
||||||
public interface IFileHelper
|
public interface IFileHelper
|
||||||
{
|
{
|
||||||
string GetFullFilePath(string currentFilePath, bool mustExist = true);
|
string GetFullFilePath(string currentFilePath, bool mustExist = true);
|
||||||
string MoveFileFromTemp(string currentFilePath, string newFolder);
|
string MoveFileFromTemp(string currentFilePath, string newFolder);
|
||||||
|
bool RenameFile(string currentFilePath, string newName);
|
||||||
bool DeleteFile(string currentFilePath);
|
bool DeleteFile(string currentFilePath);
|
||||||
|
string MakeBackup();
|
||||||
|
bool RestoreBackup(string fileName, bool clearExisting = false);
|
||||||
|
string MakeAttachmentsExport(List<GenericReportModel> exportData);
|
||||||
|
List<string> GetLanguages();
|
||||||
}
|
}
|
||||||
public class FileHelper: IFileHelper
|
public class FileHelper : IFileHelper
|
||||||
{
|
{
|
||||||
private readonly IWebHostEnvironment _webEnv;
|
private readonly IWebHostEnvironment _webEnv;
|
||||||
public FileHelper(IWebHostEnvironment webEnv)
|
private readonly ILogger<IFileHelper> _logger;
|
||||||
|
private ILiteDBHelper _liteDB;
|
||||||
|
public FileHelper(IWebHostEnvironment webEnv, ILogger<IFileHelper> logger, ILiteDBHelper liteDB)
|
||||||
{
|
{
|
||||||
_webEnv = webEnv;
|
_webEnv = webEnv;
|
||||||
|
_logger = logger;
|
||||||
|
_liteDB = liteDB;
|
||||||
|
}
|
||||||
|
public List<string> GetLanguages()
|
||||||
|
{
|
||||||
|
var languagePath = Path.Combine(_webEnv.WebRootPath, "translations");
|
||||||
|
var defaultList = new List<string>() { "en_US" };
|
||||||
|
if (Directory.Exists(languagePath))
|
||||||
|
{
|
||||||
|
var listOfLanguages = Directory.GetFiles(languagePath);
|
||||||
|
if (listOfLanguages.Any())
|
||||||
|
{
|
||||||
|
defaultList.AddRange(listOfLanguages.Select(x => Path.GetFileNameWithoutExtension(x)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultList;
|
||||||
|
}
|
||||||
|
public bool RenameFile(string currentFilePath, string newName)
|
||||||
|
{
|
||||||
|
var fullFilePath = GetFullFilePath(currentFilePath);
|
||||||
|
if (!string.IsNullOrWhiteSpace(fullFilePath))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var originalFileName = Path.GetFileNameWithoutExtension(fullFilePath);
|
||||||
|
var newFilePath = fullFilePath.Replace(originalFileName, newName);
|
||||||
|
File.Move(fullFilePath, newFilePath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
public string GetFullFilePath(string currentFilePath, bool mustExist = true)
|
public string GetFullFilePath(string currentFilePath, bool mustExist = true)
|
||||||
{
|
{
|
||||||
@@ -23,7 +69,8 @@
|
|||||||
if (File.Exists(oldFilePath))
|
if (File.Exists(oldFilePath))
|
||||||
{
|
{
|
||||||
return oldFilePath;
|
return oldFilePath;
|
||||||
} else if (!mustExist)
|
}
|
||||||
|
else if (!mustExist)
|
||||||
{
|
{
|
||||||
return oldFilePath;
|
return oldFilePath;
|
||||||
}
|
}
|
||||||
@@ -31,6 +78,199 @@
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public bool RestoreBackup(string fileName, bool clearExisting = false)
|
||||||
|
{
|
||||||
|
var fullFilePath = GetFullFilePath(fileName);
|
||||||
|
if (string.IsNullOrWhiteSpace(fullFilePath))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var tempPath = Path.Combine(_webEnv.WebRootPath, $"temp/{Guid.NewGuid()}");
|
||||||
|
if (!Directory.Exists(tempPath))
|
||||||
|
Directory.CreateDirectory(tempPath);
|
||||||
|
//extract zip file
|
||||||
|
ZipFile.ExtractToDirectory(fullFilePath, tempPath);
|
||||||
|
//copy over images and documents.
|
||||||
|
var imagePath = Path.Combine(tempPath, "images");
|
||||||
|
var documentPath = Path.Combine(tempPath, "documents");
|
||||||
|
var translationPath = Path.Combine(tempPath, "translations");
|
||||||
|
var dataPath = Path.Combine(tempPath, StaticHelper.DbName);
|
||||||
|
var configPath = Path.Combine(tempPath, StaticHelper.UserConfigPath);
|
||||||
|
if (Directory.Exists(imagePath))
|
||||||
|
{
|
||||||
|
var existingPath = Path.Combine(_webEnv.WebRootPath, "images");
|
||||||
|
if (!Directory.Exists(existingPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(existingPath);
|
||||||
|
}
|
||||||
|
else if (clearExisting)
|
||||||
|
{
|
||||||
|
var filesToDelete = Directory.GetFiles(existingPath);
|
||||||
|
foreach (string file in filesToDelete)
|
||||||
|
{
|
||||||
|
File.Delete(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//copy each files from temp folder to newPath
|
||||||
|
var filesToUpload = Directory.GetFiles(imagePath);
|
||||||
|
foreach (string file in filesToUpload)
|
||||||
|
{
|
||||||
|
File.Copy(file, $"{existingPath}/{Path.GetFileName(file)}", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Directory.Exists(documentPath))
|
||||||
|
{
|
||||||
|
var existingPath = Path.Combine(_webEnv.WebRootPath, "documents");
|
||||||
|
if (!Directory.Exists(existingPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(existingPath);
|
||||||
|
}
|
||||||
|
else if (clearExisting)
|
||||||
|
{
|
||||||
|
var filesToDelete = Directory.GetFiles(existingPath);
|
||||||
|
foreach (string file in filesToDelete)
|
||||||
|
{
|
||||||
|
File.Delete(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//copy each files from temp folder to newPath
|
||||||
|
var filesToUpload = Directory.GetFiles(documentPath);
|
||||||
|
foreach (string file in filesToUpload)
|
||||||
|
{
|
||||||
|
File.Copy(file, $"{existingPath}/{Path.GetFileName(file)}", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Directory.Exists(translationPath))
|
||||||
|
{
|
||||||
|
var existingPath = Path.Combine(_webEnv.WebRootPath, "translations");
|
||||||
|
if (!Directory.Exists(existingPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(existingPath);
|
||||||
|
}
|
||||||
|
else if (clearExisting)
|
||||||
|
{
|
||||||
|
var filesToDelete = Directory.GetFiles(existingPath);
|
||||||
|
foreach (string file in filesToDelete)
|
||||||
|
{
|
||||||
|
File.Delete(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//copy each files from temp folder to newPath
|
||||||
|
var filesToUpload = Directory.GetFiles(translationPath);
|
||||||
|
foreach (string file in filesToUpload)
|
||||||
|
{
|
||||||
|
File.Copy(file, $"{existingPath}/{Path.GetFileName(file)}", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (File.Exists(dataPath))
|
||||||
|
{
|
||||||
|
//Relinquish current DB file lock
|
||||||
|
_liteDB.DisposeLiteDB();
|
||||||
|
//data path will always exist as it is created on startup if not.
|
||||||
|
File.Move(dataPath, StaticHelper.DbName, true);
|
||||||
|
}
|
||||||
|
if (File.Exists(configPath))
|
||||||
|
{
|
||||||
|
//check if config folder exists.
|
||||||
|
if (!Directory.Exists("config/"))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory("config/");
|
||||||
|
}
|
||||||
|
File.Move(configPath, StaticHelper.UserConfigPath, true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"Error Restoring Database Backup: {ex.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string MakeAttachmentsExport(List<GenericReportModel> exportData)
|
||||||
|
{
|
||||||
|
var folderName = Guid.NewGuid();
|
||||||
|
var tempPath = Path.Combine(_webEnv.WebRootPath, $"temp/{folderName}");
|
||||||
|
if (!Directory.Exists(tempPath))
|
||||||
|
Directory.CreateDirectory(tempPath);
|
||||||
|
int fileIndex = 0;
|
||||||
|
foreach (GenericReportModel reportModel in exportData)
|
||||||
|
{
|
||||||
|
foreach (UploadedFiles file in reportModel.Files)
|
||||||
|
{
|
||||||
|
var fileToCopy = GetFullFilePath(file.Location);
|
||||||
|
var destFileName = $"{tempPath}/{fileIndex}_{reportModel.DataType}_{reportModel.Date.ToString("yyyy-MM-dd")}_{file.Name}{Path.GetExtension(file.Location)}";
|
||||||
|
File.Copy(fileToCopy, destFileName);
|
||||||
|
fileIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var destFilePath = $"{tempPath}.zip";
|
||||||
|
ZipFile.CreateFromDirectory(tempPath, destFilePath);
|
||||||
|
//delete temp directory
|
||||||
|
Directory.Delete(tempPath, true);
|
||||||
|
var zipFileName = $"/temp/{folderName}.zip";
|
||||||
|
return zipFileName;
|
||||||
|
}
|
||||||
|
public string MakeBackup()
|
||||||
|
{
|
||||||
|
var folderName = $"db_backup_{DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss")}";
|
||||||
|
var tempPath = Path.Combine(_webEnv.WebRootPath, $"temp/{folderName}");
|
||||||
|
var imagePath = Path.Combine(_webEnv.WebRootPath, "images");
|
||||||
|
var documentPath = Path.Combine(_webEnv.WebRootPath, "documents");
|
||||||
|
var translationPath = Path.Combine(_webEnv.WebRootPath, "translations");
|
||||||
|
var dataPath = StaticHelper.DbName;
|
||||||
|
var configPath = StaticHelper.UserConfigPath;
|
||||||
|
if (!Directory.Exists(tempPath))
|
||||||
|
Directory.CreateDirectory(tempPath);
|
||||||
|
if (Directory.Exists(imagePath))
|
||||||
|
{
|
||||||
|
var files = Directory.GetFiles(imagePath);
|
||||||
|
foreach (var file in files)
|
||||||
|
{
|
||||||
|
var newPath = Path.Combine(tempPath, "images");
|
||||||
|
Directory.CreateDirectory(newPath);
|
||||||
|
File.Copy(file, $"{newPath}/{Path.GetFileName(file)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Directory.Exists(documentPath))
|
||||||
|
{
|
||||||
|
var files = Directory.GetFiles(documentPath);
|
||||||
|
foreach (var file in files)
|
||||||
|
{
|
||||||
|
var newPath = Path.Combine(tempPath, "documents");
|
||||||
|
Directory.CreateDirectory(newPath);
|
||||||
|
File.Copy(file, $"{newPath}/{Path.GetFileName(file)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Directory.Exists(translationPath))
|
||||||
|
{
|
||||||
|
var files = Directory.GetFiles(translationPath);
|
||||||
|
foreach(var file in files)
|
||||||
|
{
|
||||||
|
var newPath = Path.Combine(tempPath, "translations");
|
||||||
|
Directory.CreateDirectory(newPath);
|
||||||
|
File.Copy(file, $"{newPath}/{Path.GetFileName(file)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (File.Exists(dataPath))
|
||||||
|
{
|
||||||
|
var newPath = Path.Combine(tempPath, "data");
|
||||||
|
Directory.CreateDirectory(newPath);
|
||||||
|
File.Copy(dataPath, $"{newPath}/{Path.GetFileName(dataPath)}");
|
||||||
|
}
|
||||||
|
if (File.Exists(configPath))
|
||||||
|
{
|
||||||
|
var newPath = Path.Combine(tempPath, "config");
|
||||||
|
Directory.CreateDirectory(newPath);
|
||||||
|
File.Copy(configPath, $"{newPath}/{Path.GetFileName(configPath)}");
|
||||||
|
}
|
||||||
|
var destFilePath = $"{tempPath}.zip";
|
||||||
|
ZipFile.CreateFromDirectory(tempPath, destFilePath);
|
||||||
|
//delete temp directory
|
||||||
|
Directory.Delete(tempPath, true);
|
||||||
|
return $"/temp/{folderName}.zip";
|
||||||
|
}
|
||||||
public string MoveFileFromTemp(string currentFilePath, string newFolder)
|
public string MoveFileFromTemp(string currentFilePath, string newFolder)
|
||||||
{
|
{
|
||||||
string tempPath = "temp/";
|
string tempPath = "temp/";
|
||||||
@@ -38,7 +278,8 @@
|
|||||||
{
|
{
|
||||||
return currentFilePath;
|
return currentFilePath;
|
||||||
}
|
}
|
||||||
if (currentFilePath.StartsWith("/")) {
|
if (currentFilePath.StartsWith("/"))
|
||||||
|
{
|
||||||
currentFilePath = currentFilePath.Substring(1);
|
currentFilePath = currentFilePath.Substring(1);
|
||||||
}
|
}
|
||||||
string uploadPath = Path.Combine(_webEnv.WebRootPath, newFolder);
|
string uploadPath = Path.Combine(_webEnv.WebRootPath, newFolder);
|
||||||
@@ -67,7 +308,8 @@
|
|||||||
if (!File.Exists(filePath)) //verify file no longer exists.
|
if (!File.Exists(filePath)) //verify file no longer exists.
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,36 @@ namespace CarCareTracker.Helper
|
|||||||
public interface IGasHelper
|
public interface IGasHelper
|
||||||
{
|
{
|
||||||
List<GasRecordViewModel> GetGasRecordViewModels(List<GasRecord> result, bool useMPG, bool useUKMPG);
|
List<GasRecordViewModel> GetGasRecordViewModels(List<GasRecord> result, bool useMPG, bool useUKMPG);
|
||||||
|
string GetAverageGasMileage(List<GasRecordViewModel> results, bool useMPG);
|
||||||
}
|
}
|
||||||
public class GasHelper : IGasHelper
|
public class GasHelper : IGasHelper
|
||||||
{
|
{
|
||||||
|
public string GetAverageGasMileage(List<GasRecordViewModel> results, bool useMPG)
|
||||||
|
{
|
||||||
|
var recordsToCalculate = results.Where(x => x.IncludeInAverage);
|
||||||
|
if (recordsToCalculate.Any())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var totalMileage = recordsToCalculate.Sum(x => x.DeltaMileage);
|
||||||
|
var totalGallons = recordsToCalculate.Sum(x => x.Gallons);
|
||||||
|
var averageGasMileage = totalMileage / totalGallons;
|
||||||
|
if (!useMPG && averageGasMileage > 0)
|
||||||
|
{
|
||||||
|
averageGasMileage = 100 / averageGasMileage;
|
||||||
|
}
|
||||||
|
return averageGasMileage.ToString("F");
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
public List<GasRecordViewModel> GetGasRecordViewModels(List<GasRecord> result, bool useMPG, bool useUKMPG)
|
public List<GasRecordViewModel> GetGasRecordViewModels(List<GasRecord> result, bool useMPG, bool useUKMPG)
|
||||||
{
|
{
|
||||||
|
//need to order by to get correct results
|
||||||
|
result = result.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList();
|
||||||
var computedResults = new List<GasRecordViewModel>();
|
var computedResults = new List<GasRecordViewModel>();
|
||||||
int previousMileage = 0;
|
int previousMileage = 0;
|
||||||
decimal unFactoredConsumption = 0.00M;
|
decimal unFactoredConsumption = 0.00M;
|
||||||
@@ -36,12 +61,18 @@ namespace CarCareTracker.Helper
|
|||||||
{
|
{
|
||||||
Id = currentObject.Id,
|
Id = currentObject.Id,
|
||||||
VehicleId = currentObject.VehicleId,
|
VehicleId = currentObject.VehicleId,
|
||||||
|
MonthId = currentObject.Date.Month,
|
||||||
Date = currentObject.Date.ToShortDateString(),
|
Date = currentObject.Date.ToShortDateString(),
|
||||||
Mileage = currentObject.Mileage,
|
Mileage = currentObject.Mileage,
|
||||||
Gallons = convertedConsumption,
|
Gallons = convertedConsumption,
|
||||||
Cost = currentObject.Cost,
|
Cost = currentObject.Cost,
|
||||||
DeltaMileage = deltaMileage,
|
DeltaMileage = deltaMileage,
|
||||||
CostPerGallon = currentObject.Cost / convertedConsumption
|
CostPerGallon = convertedConsumption > 0.00M ? currentObject.Cost / convertedConsumption : 0,
|
||||||
|
IsFillToFull = currentObject.IsFillToFull,
|
||||||
|
MissedFuelUp = currentObject.MissedFuelUp,
|
||||||
|
Notes = currentObject.Notes,
|
||||||
|
Tags = currentObject.Tags,
|
||||||
|
ExtraFields = currentObject.ExtraFields
|
||||||
};
|
};
|
||||||
if (currentObject.MissedFuelUp)
|
if (currentObject.MissedFuelUp)
|
||||||
{
|
{
|
||||||
@@ -54,7 +85,17 @@ namespace CarCareTracker.Helper
|
|||||||
else if (currentObject.IsFillToFull)
|
else if (currentObject.IsFillToFull)
|
||||||
{
|
{
|
||||||
//if user filled to full.
|
//if user filled to full.
|
||||||
gasRecordViewModel.MilesPerGallon = useMPG ? (unFactoredMileage + deltaMileage) / (unFactoredConsumption + convertedConsumption) : 100 / ((unFactoredMileage + deltaMileage) / (unFactoredConsumption + convertedConsumption));
|
if (convertedConsumption > 0.00M && deltaMileage > 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
gasRecordViewModel.MilesPerGallon = useMPG ? (unFactoredMileage + deltaMileage) / (unFactoredConsumption + convertedConsumption) : 100 / ((unFactoredMileage + deltaMileage) / (unFactoredConsumption + convertedConsumption));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
gasRecordViewModel.MilesPerGallon = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
//reset unFactored vars
|
//reset unFactored vars
|
||||||
unFactoredConsumption = 0;
|
unFactoredConsumption = 0;
|
||||||
unFactoredMileage = 0;
|
unFactoredMileage = 0;
|
||||||
@@ -73,13 +114,19 @@ namespace CarCareTracker.Helper
|
|||||||
{
|
{
|
||||||
Id = currentObject.Id,
|
Id = currentObject.Id,
|
||||||
VehicleId = currentObject.VehicleId,
|
VehicleId = currentObject.VehicleId,
|
||||||
|
MonthId = currentObject.Date.Month,
|
||||||
Date = currentObject.Date.ToShortDateString(),
|
Date = currentObject.Date.ToShortDateString(),
|
||||||
Mileage = currentObject.Mileage,
|
Mileage = currentObject.Mileage,
|
||||||
Gallons = convertedConsumption,
|
Gallons = convertedConsumption,
|
||||||
Cost = currentObject.Cost,
|
Cost = currentObject.Cost,
|
||||||
DeltaMileage = 0,
|
DeltaMileage = 0,
|
||||||
MilesPerGallon = 0,
|
MilesPerGallon = 0,
|
||||||
CostPerGallon = currentObject.Cost / convertedConsumption
|
CostPerGallon = convertedConsumption > 0.00M ? currentObject.Cost / convertedConsumption : 0,
|
||||||
|
IsFillToFull = currentObject.IsFillToFull,
|
||||||
|
MissedFuelUp = currentObject.MissedFuelUp,
|
||||||
|
Notes = currentObject.Notes,
|
||||||
|
Tags = currentObject.Tags,
|
||||||
|
ExtraFields = currentObject.ExtraFields
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
previousMileage = currentObject.Mileage;
|
previousMileage = currentObject.Mileage;
|
||||||
|
|||||||
36
Helper/LiteDBHelper.cs
Normal file
36
Helper/LiteDBHelper.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Helper;
|
||||||
|
|
||||||
|
public interface ILiteDBHelper
|
||||||
|
{
|
||||||
|
LiteDatabase GetLiteDB();
|
||||||
|
void DisposeLiteDB();
|
||||||
|
}
|
||||||
|
public class LiteDBHelper: ILiteDBHelper
|
||||||
|
{
|
||||||
|
public LiteDatabase db { get; set; }
|
||||||
|
public LiteDBHelper()
|
||||||
|
{
|
||||||
|
if (db == null)
|
||||||
|
{
|
||||||
|
db = new LiteDatabase(StaticHelper.DbName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public LiteDatabase GetLiteDB()
|
||||||
|
{
|
||||||
|
if (db == null)
|
||||||
|
{
|
||||||
|
db = new LiteDatabase(StaticHelper.DbName);
|
||||||
|
}
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
public void DisposeLiteDB()
|
||||||
|
{
|
||||||
|
if (db != null)
|
||||||
|
{
|
||||||
|
db.Dispose();
|
||||||
|
db = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
using CarCareTracker.Models;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace CarCareTracker.Helper
|
|
||||||
{
|
|
||||||
public interface ILoginHelper
|
|
||||||
{
|
|
||||||
bool ValidateUserCredentials(LoginModel credentials);
|
|
||||||
}
|
|
||||||
public class LoginHelper: ILoginHelper
|
|
||||||
{
|
|
||||||
public bool ValidateUserCredentials(LoginModel credentials)
|
|
||||||
{
|
|
||||||
var configFileContents = System.IO.File.ReadAllText(StaticHelper.UserConfigPath);
|
|
||||||
var existingUserConfig = System.Text.Json.JsonSerializer.Deserialize<UserConfig>(configFileContents);
|
|
||||||
if (existingUserConfig is not null)
|
|
||||||
{
|
|
||||||
//create hashes of the login credentials.
|
|
||||||
var hashedUserName = Sha256_hash(credentials.UserName);
|
|
||||||
var hashedPassword = Sha256_hash(credentials.Password);
|
|
||||||
//compare against stored hash.
|
|
||||||
if (hashedUserName == existingUserConfig.UserNameHash &&
|
|
||||||
hashedPassword == existingUserConfig.UserPasswordHash)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
private static string Sha256_hash(string value)
|
|
||||||
{
|
|
||||||
StringBuilder Sb = new StringBuilder();
|
|
||||||
|
|
||||||
using (var hash = SHA256.Create())
|
|
||||||
{
|
|
||||||
Encoding enc = Encoding.UTF8;
|
|
||||||
byte[] result = hash.ComputeHash(enc.GetBytes(value));
|
|
||||||
|
|
||||||
foreach (byte b in result)
|
|
||||||
Sb.Append(b.ToString("x2"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Sb.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
163
Helper/MailHelper.cs
Normal file
163
Helper/MailHelper.cs
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
using CarCareTracker.Models;
|
||||||
|
using MimeKit;
|
||||||
|
using MailKit.Net.Smtp;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Helper
|
||||||
|
{
|
||||||
|
public interface IMailHelper
|
||||||
|
{
|
||||||
|
OperationResponse NotifyUserForRegistration(string emailAddress, string token);
|
||||||
|
OperationResponse NotifyUserForPasswordReset(string emailAddress, string token);
|
||||||
|
OperationResponse NotifyUserForAccountUpdate(string emailAddress, string token);
|
||||||
|
OperationResponse NotifyUserForReminders(Vehicle vehicle, List<string> emailAddresses, List<ReminderRecordViewModel> reminders);
|
||||||
|
}
|
||||||
|
public class MailHelper : IMailHelper
|
||||||
|
{
|
||||||
|
private readonly MailConfig mailConfig;
|
||||||
|
private readonly IFileHelper _fileHelper;
|
||||||
|
private readonly ILogger<MailHelper> _logger;
|
||||||
|
public MailHelper(
|
||||||
|
IConfiguration config,
|
||||||
|
IFileHelper fileHelper,
|
||||||
|
ILogger<MailHelper> logger
|
||||||
|
) {
|
||||||
|
//load mailConfig from Configuration
|
||||||
|
mailConfig = config.GetSection("MailConfig").Get<MailConfig>() ?? new MailConfig();
|
||||||
|
_fileHelper = fileHelper;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
public OperationResponse NotifyUserForRegistration(string emailAddress, string token)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(mailConfig.EmailServer))
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "SMTP Server Not Setup" };
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(emailAddress) || string.IsNullOrWhiteSpace(token)) {
|
||||||
|
return new OperationResponse { Success = false, Message = "Email Address or Token is invalid" };
|
||||||
|
}
|
||||||
|
string emailSubject = "Your Registration Token for LubeLogger";
|
||||||
|
string emailBody = $"A token has been generated on your behalf, please complete your registration for LubeLogger using the token: {token}";
|
||||||
|
var result = SendEmail(new List<string> { emailAddress }, emailSubject, emailBody);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = true, Message = "Email Sent!" };
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public OperationResponse NotifyUserForPasswordReset(string emailAddress, string token)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(mailConfig.EmailServer))
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "SMTP Server Not Setup" };
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(emailAddress) || string.IsNullOrWhiteSpace(token))
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Email Address or Token is invalid" };
|
||||||
|
}
|
||||||
|
string emailSubject = "Your Password Reset Token for LubeLogger";
|
||||||
|
string emailBody = $"A token has been generated on your behalf, please reset your password for LubeLogger using the token: {token}";
|
||||||
|
var result = SendEmail(new List<string> { emailAddress }, emailSubject, emailBody);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = true, Message = "Email Sent!" };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public OperationResponse NotifyUserForAccountUpdate(string emailAddress, string token)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(mailConfig.EmailServer))
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "SMTP Server Not Setup" };
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(emailAddress) || string.IsNullOrWhiteSpace(token))
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Email Address or Token is invalid" };
|
||||||
|
}
|
||||||
|
string emailSubject = "Your User Account Update Token for LubeLogger";
|
||||||
|
string emailBody = $"A token has been generated on your behalf, please update your account for LubeLogger using the token: {token}";
|
||||||
|
var result = SendEmail(new List<string> { emailAddress}, emailSubject, emailBody);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = true, Message = "Email Sent!" };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public OperationResponse NotifyUserForReminders(Vehicle vehicle, List<string> emailAddresses, List<ReminderRecordViewModel> reminders)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(mailConfig.EmailServer))
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "SMTP Server Not Setup" };
|
||||||
|
}
|
||||||
|
if (!emailAddresses.Any())
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "No recipients could be found" };
|
||||||
|
}
|
||||||
|
if (!reminders.Any())
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "No reminders could be found" };
|
||||||
|
}
|
||||||
|
//get email template, this file has to exist since it's a static file.
|
||||||
|
var emailTemplatePath = _fileHelper.GetFullFilePath(StaticHelper.ReminderEmailTemplate);
|
||||||
|
string emailSubject = $"Vehicle Reminders From LubeLogger - {DateTime.Now.ToShortDateString()}";
|
||||||
|
//construct html table.
|
||||||
|
string emailBody = File.ReadAllText(emailTemplatePath);
|
||||||
|
emailBody = emailBody.Replace("{VehicleInformation}", $"{vehicle.Year} {vehicle.Make} {vehicle.Model} #{vehicle.LicensePlate}");
|
||||||
|
string tableBody = "";
|
||||||
|
foreach(ReminderRecordViewModel reminder in reminders)
|
||||||
|
{
|
||||||
|
var dueOn = reminder.Metric == ReminderMetric.Both ? $"{reminder.Date} or {reminder.Mileage}" : reminder.Metric == ReminderMetric.Date ? $"{reminder.Date.ToShortDateString()}" : $"{reminder.Mileage}";
|
||||||
|
tableBody += $"<tr class='{reminder.Urgency}'><td>{StaticHelper.GetTitleCaseReminderUrgency(reminder.Urgency)}</td><td>{reminder.Description}</td><td>{dueOn}</td></tr>";
|
||||||
|
}
|
||||||
|
emailBody = emailBody.Replace("{TableBody}", tableBody);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SendEmail(emailAddresses, emailSubject, emailBody);
|
||||||
|
return new OperationResponse { Success = true, Message = "Email Sent!" };
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = ex.Message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private bool SendEmail(List<string> emailTo, string emailSubject, string emailBody) {
|
||||||
|
string from = mailConfig.EmailFrom;
|
||||||
|
var server = mailConfig.EmailServer;
|
||||||
|
var message = new MimeMessage();
|
||||||
|
message.From.Add(new MailboxAddress(from, from));
|
||||||
|
foreach(string emailRecipient in emailTo)
|
||||||
|
{
|
||||||
|
message.To.Add(new MailboxAddress(emailRecipient, emailRecipient));
|
||||||
|
}
|
||||||
|
message.Subject = emailSubject;
|
||||||
|
|
||||||
|
var builder = new BodyBuilder();
|
||||||
|
|
||||||
|
builder.HtmlBody = emailBody;
|
||||||
|
|
||||||
|
message.Body = builder.ToMessageBody();
|
||||||
|
|
||||||
|
using (var client = new SmtpClient())
|
||||||
|
{
|
||||||
|
client.Connect(server, mailConfig.Port, MailKit.Security.SecureSocketOptions.Auto);
|
||||||
|
client.Authenticate(mailConfig.Username, mailConfig.Password);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
client.Send(message);
|
||||||
|
client.Disconnect(true);
|
||||||
|
return true;
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,13 +4,66 @@ namespace CarCareTracker.Helper
|
|||||||
{
|
{
|
||||||
public interface IReminderHelper
|
public interface IReminderHelper
|
||||||
{
|
{
|
||||||
|
ReminderRecord GetUpdatedRecurringReminderRecord(ReminderRecord existingReminder, DateTime? currentDate, int? currentMileage);
|
||||||
List<ReminderRecordViewModel> GetReminderRecordViewModels(List<ReminderRecord> reminders, int currentMileage, DateTime dateCompare);
|
List<ReminderRecordViewModel> GetReminderRecordViewModels(List<ReminderRecord> reminders, int currentMileage, DateTime dateCompare);
|
||||||
}
|
}
|
||||||
public class ReminderHelper: IReminderHelper
|
public class ReminderHelper: IReminderHelper
|
||||||
{
|
{
|
||||||
|
private readonly IConfigHelper _config;
|
||||||
|
public ReminderHelper(IConfigHelper config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
public ReminderRecord GetUpdatedRecurringReminderRecord(ReminderRecord existingReminder, DateTime? currentDate, int? currentMileage)
|
||||||
|
{
|
||||||
|
var newDate = currentDate ?? existingReminder.Date;
|
||||||
|
var newMileage = currentMileage ?? existingReminder.Mileage;
|
||||||
|
if (existingReminder.Metric == ReminderMetric.Both)
|
||||||
|
{
|
||||||
|
if (existingReminder.ReminderMonthInterval != ReminderMonthInterval.Other)
|
||||||
|
{
|
||||||
|
existingReminder.Date = newDate.AddMonths((int)existingReminder.ReminderMonthInterval);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
existingReminder.Date = newDate.Date.AddMonths(existingReminder.CustomMonthInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingReminder.ReminderMileageInterval != ReminderMileageInterval.Other)
|
||||||
|
{
|
||||||
|
existingReminder.Mileage = newMileage + (int)existingReminder.ReminderMileageInterval;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
existingReminder.Mileage = newMileage + existingReminder.CustomMileageInterval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (existingReminder.Metric == ReminderMetric.Odometer)
|
||||||
|
{
|
||||||
|
if (existingReminder.ReminderMileageInterval != ReminderMileageInterval.Other)
|
||||||
|
{
|
||||||
|
existingReminder.Mileage = newMileage + (int)existingReminder.ReminderMileageInterval;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
existingReminder.Mileage = newMileage + existingReminder.CustomMileageInterval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (existingReminder.Metric == ReminderMetric.Date)
|
||||||
|
{
|
||||||
|
if (existingReminder.ReminderMonthInterval != ReminderMonthInterval.Other)
|
||||||
|
{
|
||||||
|
existingReminder.Date = newDate.AddMonths((int)existingReminder.ReminderMonthInterval);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
existingReminder.Date = newDate.AddMonths(existingReminder.CustomMonthInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return existingReminder;
|
||||||
|
}
|
||||||
public List<ReminderRecordViewModel> GetReminderRecordViewModels(List<ReminderRecord> reminders, int currentMileage, DateTime dateCompare)
|
public List<ReminderRecordViewModel> GetReminderRecordViewModels(List<ReminderRecord> reminders, int currentMileage, DateTime dateCompare)
|
||||||
{
|
{
|
||||||
List<ReminderRecordViewModel> reminderViewModels = new List<ReminderRecordViewModel>();
|
List<ReminderRecordViewModel> reminderViewModels = new List<ReminderRecordViewModel>();
|
||||||
|
var reminderUrgencyConfig = _config.GetReminderUrgencyConfig();
|
||||||
foreach (var reminder in reminders)
|
foreach (var reminder in reminders)
|
||||||
{
|
{
|
||||||
var reminderViewModel = new ReminderRecordViewModel()
|
var reminderViewModel = new ReminderRecordViewModel()
|
||||||
@@ -21,7 +74,9 @@ namespace CarCareTracker.Helper
|
|||||||
Mileage = reminder.Mileage,
|
Mileage = reminder.Mileage,
|
||||||
Description = reminder.Description,
|
Description = reminder.Description,
|
||||||
Notes = reminder.Notes,
|
Notes = reminder.Notes,
|
||||||
Metric = reminder.Metric
|
Metric = reminder.Metric,
|
||||||
|
IsRecurring = reminder.IsRecurring,
|
||||||
|
Tags = reminder.Tags
|
||||||
};
|
};
|
||||||
if (reminder.Metric == ReminderMetric.Both)
|
if (reminder.Metric == ReminderMetric.Both)
|
||||||
{
|
{
|
||||||
@@ -35,24 +90,24 @@ namespace CarCareTracker.Helper
|
|||||||
reminderViewModel.Urgency = ReminderUrgency.PastDue;
|
reminderViewModel.Urgency = ReminderUrgency.PastDue;
|
||||||
reminderViewModel.Metric = ReminderMetric.Odometer;
|
reminderViewModel.Metric = ReminderMetric.Odometer;
|
||||||
}
|
}
|
||||||
else if (reminder.Date < dateCompare.AddDays(7))
|
else if (reminder.Date < dateCompare.AddDays(reminderUrgencyConfig.VeryUrgentDays))
|
||||||
{
|
{
|
||||||
//if less than a week from today or less than 50 miles from current mileage then very urgent.
|
//if less than a week from today or less than 50 miles from current mileage then very urgent.
|
||||||
reminderViewModel.Urgency = ReminderUrgency.VeryUrgent;
|
reminderViewModel.Urgency = ReminderUrgency.VeryUrgent;
|
||||||
//have to specify by which metric this reminder is urgent.
|
//have to specify by which metric this reminder is urgent.
|
||||||
reminderViewModel.Metric = ReminderMetric.Date;
|
reminderViewModel.Metric = ReminderMetric.Date;
|
||||||
}
|
}
|
||||||
else if (reminder.Mileage < currentMileage + 50)
|
else if (reminder.Mileage < currentMileage + reminderUrgencyConfig.VeryUrgentDistance)
|
||||||
{
|
{
|
||||||
reminderViewModel.Urgency = ReminderUrgency.VeryUrgent;
|
reminderViewModel.Urgency = ReminderUrgency.VeryUrgent;
|
||||||
reminderViewModel.Metric = ReminderMetric.Odometer;
|
reminderViewModel.Metric = ReminderMetric.Odometer;
|
||||||
}
|
}
|
||||||
else if (reminder.Date < dateCompare.AddDays(30))
|
else if (reminder.Date < dateCompare.AddDays(reminderUrgencyConfig.UrgentDays))
|
||||||
{
|
{
|
||||||
reminderViewModel.Urgency = ReminderUrgency.Urgent;
|
reminderViewModel.Urgency = ReminderUrgency.Urgent;
|
||||||
reminderViewModel.Metric = ReminderMetric.Date;
|
reminderViewModel.Metric = ReminderMetric.Date;
|
||||||
}
|
}
|
||||||
else if (reminder.Mileage < currentMileage + 100)
|
else if (reminder.Mileage < currentMileage + reminderUrgencyConfig.UrgentDistance)
|
||||||
{
|
{
|
||||||
reminderViewModel.Urgency = ReminderUrgency.Urgent;
|
reminderViewModel.Urgency = ReminderUrgency.Urgent;
|
||||||
reminderViewModel.Metric = ReminderMetric.Odometer;
|
reminderViewModel.Metric = ReminderMetric.Odometer;
|
||||||
@@ -64,11 +119,11 @@ namespace CarCareTracker.Helper
|
|||||||
{
|
{
|
||||||
reminderViewModel.Urgency = ReminderUrgency.PastDue;
|
reminderViewModel.Urgency = ReminderUrgency.PastDue;
|
||||||
}
|
}
|
||||||
else if (reminder.Date < dateCompare.AddDays(7))
|
else if (reminder.Date < dateCompare.AddDays(reminderUrgencyConfig.VeryUrgentDays))
|
||||||
{
|
{
|
||||||
reminderViewModel.Urgency = ReminderUrgency.VeryUrgent;
|
reminderViewModel.Urgency = ReminderUrgency.VeryUrgent;
|
||||||
}
|
}
|
||||||
else if (reminder.Date < dateCompare.AddDays(30))
|
else if (reminder.Date < dateCompare.AddDays(reminderUrgencyConfig.UrgentDays))
|
||||||
{
|
{
|
||||||
reminderViewModel.Urgency = ReminderUrgency.Urgent;
|
reminderViewModel.Urgency = ReminderUrgency.Urgent;
|
||||||
}
|
}
|
||||||
@@ -80,11 +135,11 @@ namespace CarCareTracker.Helper
|
|||||||
reminderViewModel.Urgency = ReminderUrgency.PastDue;
|
reminderViewModel.Urgency = ReminderUrgency.PastDue;
|
||||||
reminderViewModel.Metric = ReminderMetric.Odometer;
|
reminderViewModel.Metric = ReminderMetric.Odometer;
|
||||||
}
|
}
|
||||||
else if (reminder.Mileage < currentMileage + 50)
|
else if (reminder.Mileage < currentMileage + reminderUrgencyConfig.VeryUrgentDistance)
|
||||||
{
|
{
|
||||||
reminderViewModel.Urgency = ReminderUrgency.VeryUrgent;
|
reminderViewModel.Urgency = ReminderUrgency.VeryUrgent;
|
||||||
}
|
}
|
||||||
else if (reminder.Mileage < currentMileage + 100)
|
else if (reminder.Mileage < currentMileage + reminderUrgencyConfig.UrgentDistance)
|
||||||
{
|
{
|
||||||
reminderViewModel.Urgency = ReminderUrgency.Urgent;
|
reminderViewModel.Urgency = ReminderUrgency.Urgent;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace CarCareTracker.Helper
|
|||||||
{
|
{
|
||||||
public interface IReportHelper
|
public interface IReportHelper
|
||||||
{
|
{
|
||||||
|
IEnumerable<CostForVehicleByMonth> GetOdometerRecordSum(List<OdometerRecord> odometerRecords, int year = 0);
|
||||||
IEnumerable<CostForVehicleByMonth> GetServiceRecordSum(List<ServiceRecord> serviceRecords, int year = 0);
|
IEnumerable<CostForVehicleByMonth> GetServiceRecordSum(List<ServiceRecord> serviceRecords, int year = 0);
|
||||||
IEnumerable<CostForVehicleByMonth> GetRepairRecordSum(List<CollisionRecord> repairRecords, int year = 0);
|
IEnumerable<CostForVehicleByMonth> GetRepairRecordSum(List<CollisionRecord> repairRecords, int year = 0);
|
||||||
IEnumerable<CostForVehicleByMonth> GetUpgradeRecordSum(List<UpgradeRecord> upgradeRecords, int year = 0);
|
IEnumerable<CostForVehicleByMonth> GetUpgradeRecordSum(List<UpgradeRecord> upgradeRecords, int year = 0);
|
||||||
@@ -13,6 +14,20 @@ namespace CarCareTracker.Helper
|
|||||||
}
|
}
|
||||||
public class ReportHelper: IReportHelper
|
public class ReportHelper: IReportHelper
|
||||||
{
|
{
|
||||||
|
public IEnumerable<CostForVehicleByMonth> GetOdometerRecordSum(List<OdometerRecord> odometerRecords, int year = 0)
|
||||||
|
{
|
||||||
|
if (year != default)
|
||||||
|
{
|
||||||
|
odometerRecords.RemoveAll(x => x.Date.Year != year);
|
||||||
|
}
|
||||||
|
return odometerRecords.GroupBy(x => x.Date.Month).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
||||||
|
{
|
||||||
|
MonthId = x.Key,
|
||||||
|
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
||||||
|
Cost = 0,
|
||||||
|
DistanceTraveled = x.Sum(y=>y.DistanceTraveled)
|
||||||
|
});
|
||||||
|
}
|
||||||
public IEnumerable<CostForVehicleByMonth> GetServiceRecordSum(List<ServiceRecord> serviceRecords, int year = 0)
|
public IEnumerable<CostForVehicleByMonth> GetServiceRecordSum(List<ServiceRecord> serviceRecords, int year = 0)
|
||||||
{
|
{
|
||||||
if (year != default)
|
if (year != default)
|
||||||
@@ -21,6 +36,7 @@ namespace CarCareTracker.Helper
|
|||||||
}
|
}
|
||||||
return serviceRecords.GroupBy(x => x.Date.Month).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
return serviceRecords.GroupBy(x => x.Date.Month).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
||||||
{
|
{
|
||||||
|
MonthId = x.Key,
|
||||||
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
||||||
Cost = x.Sum(y => y.Cost)
|
Cost = x.Sum(y => y.Cost)
|
||||||
});
|
});
|
||||||
@@ -33,6 +49,7 @@ namespace CarCareTracker.Helper
|
|||||||
}
|
}
|
||||||
return repairRecords.GroupBy(x => x.Date.Month).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
return repairRecords.GroupBy(x => x.Date.Month).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
||||||
{
|
{
|
||||||
|
MonthId = x.Key,
|
||||||
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
||||||
Cost = x.Sum(y => y.Cost)
|
Cost = x.Sum(y => y.Cost)
|
||||||
});
|
});
|
||||||
@@ -45,6 +62,7 @@ namespace CarCareTracker.Helper
|
|||||||
}
|
}
|
||||||
return upgradeRecords.GroupBy(x => x.Date.Month).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
return upgradeRecords.GroupBy(x => x.Date.Month).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
||||||
{
|
{
|
||||||
|
MonthId = x.Key,
|
||||||
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
||||||
Cost = x.Sum(y => y.Cost)
|
Cost = x.Sum(y => y.Cost)
|
||||||
});
|
});
|
||||||
@@ -57,6 +75,7 @@ namespace CarCareTracker.Helper
|
|||||||
}
|
}
|
||||||
return gasRecords.GroupBy(x => x.Date.Month).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
return gasRecords.GroupBy(x => x.Date.Month).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
||||||
{
|
{
|
||||||
|
MonthId = x.Key,
|
||||||
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
||||||
Cost = x.Sum(y => y.Cost)
|
Cost = x.Sum(y => y.Cost)
|
||||||
});
|
});
|
||||||
@@ -69,6 +88,7 @@ namespace CarCareTracker.Helper
|
|||||||
}
|
}
|
||||||
return taxRecords.GroupBy(x => x.Date.Month).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
return taxRecords.GroupBy(x => x.Date.Month).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
||||||
{
|
{
|
||||||
|
MonthId = x.Key,
|
||||||
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
||||||
Cost = x.Sum(y => y.Cost)
|
Cost = x.Sum(y => y.Cost)
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,12 +1,34 @@
|
|||||||
namespace CarCareTracker.Helper
|
using CarCareTracker.Models;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Helper
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// helper method for static vars
|
/// helper method for static vars
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class StaticHelper
|
public static class StaticHelper
|
||||||
{
|
{
|
||||||
|
public static string VersionNumber = "1.3.3";
|
||||||
public static string DbName = "data/cartracker.db";
|
public static string DbName = "data/cartracker.db";
|
||||||
public static string UserConfigPath = "config/userConfig.json";
|
public static string UserConfigPath = "config/userConfig.json";
|
||||||
|
public static string GenericErrorMessage = "An error occurred, please try again later";
|
||||||
|
public static string ReminderEmailTemplate = "defaults/reminderemailtemplate.txt";
|
||||||
|
public static string DefaultAllowedFileExtensions = ".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx";
|
||||||
|
public static string SponsorsPath = "https://hargata.github.io/hargata/sponsors.json";
|
||||||
|
public static string GetTitleCaseReminderUrgency(ReminderUrgency input)
|
||||||
|
{
|
||||||
|
switch (input)
|
||||||
|
{
|
||||||
|
case ReminderUrgency.NotUrgent:
|
||||||
|
return "Not Urgent";
|
||||||
|
case ReminderUrgency.VeryUrgent:
|
||||||
|
return "Very Urgent";
|
||||||
|
case ReminderUrgency.PastDue:
|
||||||
|
return "Past Due";
|
||||||
|
default:
|
||||||
|
return input.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static string TruncateStrings(string input, int maxLength = 25)
|
public static string TruncateStrings(string input, int maxLength = 25)
|
||||||
{
|
{
|
||||||
@@ -17,10 +39,253 @@
|
|||||||
if (input.Length > maxLength)
|
if (input.Length > maxLength)
|
||||||
{
|
{
|
||||||
return (input.Substring(0, maxLength) + "...");
|
return (input.Substring(0, maxLength) + "...");
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public static string DefaultActiveTab(UserConfig userConfig, ImportMode tab)
|
||||||
|
{
|
||||||
|
var defaultTab = userConfig.DefaultTab;
|
||||||
|
var visibleTabs = userConfig.VisibleTabs;
|
||||||
|
if (visibleTabs.Contains(tab) && tab == defaultTab)
|
||||||
|
{
|
||||||
|
return "active";
|
||||||
|
}
|
||||||
|
else if (!visibleTabs.Contains(tab))
|
||||||
|
{
|
||||||
|
return "d-none";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
public static string DefaultActiveTabContent(UserConfig userConfig, ImportMode tab)
|
||||||
|
{
|
||||||
|
var defaultTab = userConfig.DefaultTab;
|
||||||
|
if (tab == defaultTab)
|
||||||
|
{
|
||||||
|
return "show active";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
public static string DefaultTabSelected(UserConfig userConfig, ImportMode tab)
|
||||||
|
{
|
||||||
|
var defaultTab = userConfig.DefaultTab;
|
||||||
|
var visibleTabs = userConfig.VisibleTabs;
|
||||||
|
if (!visibleTabs.Contains(tab))
|
||||||
|
{
|
||||||
|
return "disabled";
|
||||||
|
}
|
||||||
|
else if (tab == defaultTab)
|
||||||
|
{
|
||||||
|
return "selected";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
public static List<CostForVehicleByMonth> GetBaseLineCosts()
|
||||||
|
{
|
||||||
|
return new List<CostForVehicleByMonth>()
|
||||||
|
{
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(1), MonthId = 1, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(2), MonthId = 2, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(3), MonthId = 3, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(4), MonthId = 4, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(5), MonthId = 5, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(6), MonthId = 6, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(7), MonthId = 7, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(8), MonthId = 8, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(9), MonthId = 9, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(10), MonthId = 10, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(11), MonthId = 11, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(12), MonthId = 12, Cost = 0M}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static List<CostForVehicleByMonth> GetBaseLineCostsNoMonthName()
|
||||||
|
{
|
||||||
|
return new List<CostForVehicleByMonth>()
|
||||||
|
{
|
||||||
|
new CostForVehicleByMonth { MonthId = 1, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthId = 2, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthId = 3, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthId = 4, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthId = 5, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthId = 6, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthId = 7, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthId = 8, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthId = 9, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth { MonthId = 10, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth { MonthId = 11, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth { MonthId = 12, Cost = 0M}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServiceRecord GenericToServiceRecord(GenericRecord input)
|
||||||
|
{
|
||||||
|
return new ServiceRecord
|
||||||
|
{
|
||||||
|
VehicleId = input.VehicleId,
|
||||||
|
Date = input.Date,
|
||||||
|
Description = input.Description,
|
||||||
|
Cost = input.Cost,
|
||||||
|
Mileage = input.Mileage,
|
||||||
|
Files = input.Files,
|
||||||
|
Notes = input.Notes,
|
||||||
|
Tags = input.Tags,
|
||||||
|
ExtraFields = input.ExtraFields,
|
||||||
|
RequisitionHistory = input.RequisitionHistory
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static CollisionRecord GenericToRepairRecord(GenericRecord input)
|
||||||
|
{
|
||||||
|
return new CollisionRecord
|
||||||
|
{
|
||||||
|
VehicleId = input.VehicleId,
|
||||||
|
Date = input.Date,
|
||||||
|
Description = input.Description,
|
||||||
|
Cost = input.Cost,
|
||||||
|
Mileage = input.Mileage,
|
||||||
|
Files = input.Files,
|
||||||
|
Notes = input.Notes,
|
||||||
|
Tags = input.Tags,
|
||||||
|
ExtraFields = input.ExtraFields,
|
||||||
|
RequisitionHistory = input.RequisitionHistory
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static UpgradeRecord GenericToUpgradeRecord(GenericRecord input)
|
||||||
|
{
|
||||||
|
return new UpgradeRecord
|
||||||
|
{
|
||||||
|
VehicleId = input.VehicleId,
|
||||||
|
Date = input.Date,
|
||||||
|
Description = input.Description,
|
||||||
|
Cost = input.Cost,
|
||||||
|
Mileage = input.Mileage,
|
||||||
|
Files = input.Files,
|
||||||
|
Notes = input.Notes,
|
||||||
|
Tags = input.Tags,
|
||||||
|
ExtraFields = input.ExtraFields,
|
||||||
|
RequisitionHistory = input.RequisitionHistory
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<ExtraField> AddExtraFields(List<ExtraField> recordExtraFields, List<ExtraField> templateExtraFields)
|
||||||
|
{
|
||||||
|
if (!templateExtraFields.Any()) {
|
||||||
|
return new List<ExtraField>();
|
||||||
|
}
|
||||||
|
if (!recordExtraFields.Any())
|
||||||
|
{
|
||||||
|
return templateExtraFields;
|
||||||
|
}
|
||||||
|
var fieldNames = templateExtraFields.Select(x => x.Name);
|
||||||
|
//remove fields that are no longer present in template.
|
||||||
|
recordExtraFields.RemoveAll(x => !fieldNames.Contains(x.Name));
|
||||||
|
if (!recordExtraFields.Any())
|
||||||
|
{
|
||||||
|
return templateExtraFields;
|
||||||
|
}
|
||||||
|
var recordFieldNames = recordExtraFields.Select(x => x.Name);
|
||||||
|
//update isrequired setting
|
||||||
|
foreach (ExtraField extraField in recordExtraFields)
|
||||||
|
{
|
||||||
|
extraField.IsRequired = templateExtraFields.Where(x => x.Name == extraField.Name).First().IsRequired;
|
||||||
|
}
|
||||||
|
//append extra fields
|
||||||
|
foreach(ExtraField extraField in templateExtraFields)
|
||||||
|
{
|
||||||
|
if (!recordFieldNames.Contains(extraField.Name))
|
||||||
|
{
|
||||||
|
recordExtraFields.Add(extraField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return recordExtraFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetFuelEconomyUnit(bool useKwh, bool useHours, bool useMPG, bool useUKMPG)
|
||||||
|
{
|
||||||
|
string fuelEconomyUnit;
|
||||||
|
if (useKwh)
|
||||||
|
{
|
||||||
|
var distanceUnit = useHours ? "h" : (useMPG ? "mi." : "km");
|
||||||
|
fuelEconomyUnit = useMPG ? $"{distanceUnit}/kWh" : $"kWh/100{distanceUnit}";
|
||||||
|
}
|
||||||
|
else if (useMPG && useUKMPG)
|
||||||
|
{
|
||||||
|
fuelEconomyUnit = useHours ? "h/g" : "mpg";
|
||||||
|
}
|
||||||
|
else if (useUKMPG)
|
||||||
|
{
|
||||||
|
fuelEconomyUnit = useHours ? "l/100h" : "l/100mi.";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fuelEconomyUnit = useHours ? (useMPG ? "h/g" : "l/100h") : (useMPG ? "mpg" : "l/100km");
|
||||||
|
}
|
||||||
|
return fuelEconomyUnit;
|
||||||
|
}
|
||||||
|
public static long GetEpochFromDateTime(DateTime date)
|
||||||
|
{
|
||||||
|
return new DateTimeOffset(date).ToUnixTimeMilliseconds();
|
||||||
|
}
|
||||||
|
public static void InitMessage(IConfiguration config)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"LubeLogger {VersionNumber}");
|
||||||
|
Console.WriteLine("Website: https://lubelogger.com");
|
||||||
|
Console.WriteLine("Documentation: https://docs.lubelogger.com");
|
||||||
|
Console.WriteLine("GitHub: https://github.com/hargata/lubelog");
|
||||||
|
var mailConfig = config.GetSection("MailConfig").Get<MailConfig>();
|
||||||
|
if (mailConfig != null && !string.IsNullOrWhiteSpace(mailConfig.EmailServer))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"SMTP Configured for {mailConfig.EmailServer}");
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
Console.WriteLine("SMTP Not Configured");
|
||||||
|
}
|
||||||
|
var motd = config["LUBELOGGER_MOTD"] ?? "Not Configured";
|
||||||
|
Console.WriteLine($"Message Of The Day: {motd}");
|
||||||
|
}
|
||||||
|
public static async void NotifyAsync(string webhookURL, int vehicleId, string username, string action)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(webhookURL))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var httpClient = new HttpClient();
|
||||||
|
var httpParams = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "vehicleId", vehicleId.ToString() },
|
||||||
|
{ "username", username },
|
||||||
|
{ "action", action },
|
||||||
|
};
|
||||||
|
httpClient.PostAsJsonAsync(webhookURL, httpParams);
|
||||||
|
}
|
||||||
|
public static string GetImportModeIcon(ImportMode importMode)
|
||||||
|
{
|
||||||
|
switch (importMode)
|
||||||
|
{
|
||||||
|
case ImportMode.ServiceRecord:
|
||||||
|
return "bi-card-checklist";
|
||||||
|
case ImportMode.RepairRecord:
|
||||||
|
return "bi-exclamation-octagon";
|
||||||
|
case ImportMode.UpgradeRecord:
|
||||||
|
return "bi-wrench-adjustable";
|
||||||
|
case ImportMode.TaxRecord:
|
||||||
|
return "bi-currency-dollar";
|
||||||
|
case ImportMode.SupplyRecord:
|
||||||
|
return "bi-shop";
|
||||||
|
case ImportMode.PlanRecord:
|
||||||
|
return "bi-bar-chart-steps";
|
||||||
|
case ImportMode.OdometerRecord:
|
||||||
|
return "bi-speedometer";
|
||||||
|
case ImportMode.GasRecord:
|
||||||
|
return "bi-fuel-pump";
|
||||||
|
case ImportMode.NoteRecord:
|
||||||
|
return "bi-journal-bookmark";
|
||||||
|
case ImportMode.ReminderRecord:
|
||||||
|
return "bi-bell";
|
||||||
|
default:
|
||||||
|
return "bi-file-bar-graph";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
61
Helper/TranslationHelper.cs
Normal file
61
Helper/TranslationHelper.cs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Helper
|
||||||
|
{
|
||||||
|
public interface ITranslationHelper
|
||||||
|
{
|
||||||
|
string Translate(string userLanguage, string text);
|
||||||
|
}
|
||||||
|
public class TranslationHelper : ITranslationHelper
|
||||||
|
{
|
||||||
|
private readonly IFileHelper _fileHelper;
|
||||||
|
private readonly IConfiguration _config;
|
||||||
|
private IMemoryCache _cache;
|
||||||
|
public TranslationHelper(IFileHelper fileHelper, IConfiguration config, IMemoryCache memoryCache)
|
||||||
|
{
|
||||||
|
_fileHelper = fileHelper;
|
||||||
|
_config = config;
|
||||||
|
_cache = memoryCache;
|
||||||
|
}
|
||||||
|
public string Translate(string userLanguage, string text)
|
||||||
|
{
|
||||||
|
bool create = bool.Parse(_config["LUBELOGGER_TRANSLATOR"] ?? "false");
|
||||||
|
//transform input text into key.
|
||||||
|
string translationKey = text.Replace(" ", "_");
|
||||||
|
var translationFilePath = userLanguage == "en_US" ? _fileHelper.GetFullFilePath($"/defaults/en_US.json") : _fileHelper.GetFullFilePath($"/translations/{userLanguage}.json", false);
|
||||||
|
var dictionary = _cache.GetOrCreate<Dictionary<string, string>>($"lang_{userLanguage}", entry =>
|
||||||
|
{
|
||||||
|
entry.SlidingExpiration = TimeSpan.FromHours(1);
|
||||||
|
if (File.Exists(translationFilePath))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var translationFile = File.ReadAllText(translationFilePath);
|
||||||
|
var translationDictionary = JsonSerializer.Deserialize<Dictionary<string, string>>(translationFile);
|
||||||
|
return translationDictionary ?? new Dictionary<string, string>();
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
return new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (dictionary != null && dictionary.ContainsKey(translationKey))
|
||||||
|
{
|
||||||
|
return dictionary[translationKey];
|
||||||
|
}
|
||||||
|
else if (create && File.Exists(translationFilePath))
|
||||||
|
{
|
||||||
|
//create entry
|
||||||
|
dictionary.Add(translationKey, text);
|
||||||
|
File.WriteAllText(translationFilePath, JsonSerializer.Serialize(dictionary));
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2023 Hargata Softworks
|
Copyright (c) 2024 Hargata Softworks
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
468
Logic/LoginLogic.cs
Normal file
468
Logic/LoginLogic.cs
Normal file
@@ -0,0 +1,468 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Logic
|
||||||
|
{
|
||||||
|
public interface ILoginLogic
|
||||||
|
{
|
||||||
|
bool MakeUserAdmin(int userId, bool isAdmin);
|
||||||
|
OperationResponse GenerateUserToken(string emailAddress, bool autoNotify);
|
||||||
|
bool DeleteUserToken(int tokenId);
|
||||||
|
bool DeleteUser(int userId);
|
||||||
|
OperationResponse RegisterOpenIdUser(LoginModel credentials);
|
||||||
|
OperationResponse UpdateUserDetails(int userId, LoginModel credentials);
|
||||||
|
OperationResponse RegisterNewUser(LoginModel credentials);
|
||||||
|
OperationResponse RequestResetPassword(LoginModel credentials);
|
||||||
|
OperationResponse ResetPasswordByUser(LoginModel credentials);
|
||||||
|
OperationResponse ResetUserPassword(LoginModel credentials);
|
||||||
|
UserData ValidateUserCredentials(LoginModel credentials);
|
||||||
|
UserData ValidateOpenIDUser(LoginModel credentials);
|
||||||
|
bool CheckIfUserIsValid(int userId);
|
||||||
|
bool CreateRootUserCredentials(LoginModel credentials);
|
||||||
|
bool DeleteRootUserCredentials();
|
||||||
|
bool GenerateTokenForEmailAddress(string emailAddress, bool isPasswordReset);
|
||||||
|
List<UserData> GetAllUsers();
|
||||||
|
List<Token> GetAllTokens();
|
||||||
|
|
||||||
|
}
|
||||||
|
public class LoginLogic : ILoginLogic
|
||||||
|
{
|
||||||
|
private readonly IUserRecordDataAccess _userData;
|
||||||
|
private readonly ITokenRecordDataAccess _tokenData;
|
||||||
|
private readonly IMailHelper _mailHelper;
|
||||||
|
private readonly IConfigHelper _configHelper;
|
||||||
|
private IMemoryCache _cache;
|
||||||
|
public LoginLogic(IUserRecordDataAccess userData,
|
||||||
|
ITokenRecordDataAccess tokenData,
|
||||||
|
IMailHelper mailHelper,
|
||||||
|
IConfigHelper configHelper,
|
||||||
|
IMemoryCache memoryCache)
|
||||||
|
{
|
||||||
|
_userData = userData;
|
||||||
|
_tokenData = tokenData;
|
||||||
|
_mailHelper = mailHelper;
|
||||||
|
_configHelper = configHelper;
|
||||||
|
_cache = memoryCache;
|
||||||
|
}
|
||||||
|
public bool CheckIfUserIsValid(int userId)
|
||||||
|
{
|
||||||
|
if (userId == -1)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var result = _userData.GetUserRecordById(userId);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return result.Id != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public OperationResponse UpdateUserDetails(int userId, LoginModel credentials)
|
||||||
|
{
|
||||||
|
//get current user details
|
||||||
|
var existingUser = _userData.GetUserRecordById(userId);
|
||||||
|
if (existingUser.Id == default)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Invalid user" };
|
||||||
|
}
|
||||||
|
//validate user token
|
||||||
|
var existingToken = _tokenData.GetTokenRecordByBody(credentials.Token);
|
||||||
|
if (existingToken.Id == default || existingToken.EmailAddress != existingUser.EmailAddress)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Invalid Token" };
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrWhiteSpace(credentials.UserName) && existingUser.UserName != credentials.UserName)
|
||||||
|
{
|
||||||
|
//check if new username is already taken.
|
||||||
|
var existingUserWithUserName = _userData.GetUserRecordByUserName(credentials.UserName);
|
||||||
|
if (existingUserWithUserName.Id != default)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Username already taken" };
|
||||||
|
}
|
||||||
|
existingUser.UserName = credentials.UserName;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrWhiteSpace(credentials.EmailAddress) && existingUser.EmailAddress != credentials.EmailAddress)
|
||||||
|
{
|
||||||
|
//check if email address already exists
|
||||||
|
var existingUserWithEmailAddress = _userData.GetUserRecordByEmailAddress(credentials.EmailAddress);
|
||||||
|
if (existingUserWithEmailAddress.Id != default)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "A user with that email already exists" };
|
||||||
|
}
|
||||||
|
existingUser.EmailAddress = credentials.EmailAddress;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrWhiteSpace(credentials.Password))
|
||||||
|
{
|
||||||
|
//update password
|
||||||
|
existingUser.Password = GetHash(credentials.Password);
|
||||||
|
}
|
||||||
|
//delete token
|
||||||
|
_tokenData.DeleteToken(existingToken.Id);
|
||||||
|
var result = _userData.SaveUserRecord(existingUser);
|
||||||
|
return new OperationResponse { Success = result, Message = result ? "User Updated" : StaticHelper.GenericErrorMessage };
|
||||||
|
}
|
||||||
|
public OperationResponse RegisterOpenIdUser(LoginModel credentials)
|
||||||
|
{
|
||||||
|
//validate their token.
|
||||||
|
var existingToken = _tokenData.GetTokenRecordByBody(credentials.Token);
|
||||||
|
if (existingToken.Id == default || existingToken.EmailAddress != credentials.EmailAddress)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Invalid Token" };
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(credentials.EmailAddress) || string.IsNullOrWhiteSpace(credentials.UserName))
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Username cannot be blank" };
|
||||||
|
}
|
||||||
|
var existingUser = _userData.GetUserRecordByUserName(credentials.UserName);
|
||||||
|
if (existingUser.Id != default)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Username already taken" };
|
||||||
|
}
|
||||||
|
var existingUserWithEmail = _userData.GetUserRecordByEmailAddress(credentials.EmailAddress);
|
||||||
|
if (existingUserWithEmail.Id != default)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "A user with that email already exists" };
|
||||||
|
}
|
||||||
|
_tokenData.DeleteToken(existingToken.Id);
|
||||||
|
var newUser = new UserData()
|
||||||
|
{
|
||||||
|
UserName = credentials.UserName,
|
||||||
|
Password = GetHash(NewToken()), //generate a password for OpenID User
|
||||||
|
EmailAddress = credentials.EmailAddress
|
||||||
|
};
|
||||||
|
var result = _userData.SaveUserRecord(newUser);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = true, Message = "You will be logged in briefly." };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Something went wrong, please try again later." };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//handles user registration
|
||||||
|
public OperationResponse RegisterNewUser(LoginModel credentials)
|
||||||
|
{
|
||||||
|
//validate their token.
|
||||||
|
var existingToken = _tokenData.GetTokenRecordByBody(credentials.Token);
|
||||||
|
if (existingToken.Id == default || existingToken.EmailAddress != credentials.EmailAddress)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Invalid Token" };
|
||||||
|
}
|
||||||
|
//token is valid, check if username and password is acceptable and that username is unique.
|
||||||
|
if (string.IsNullOrWhiteSpace(credentials.EmailAddress) || string.IsNullOrWhiteSpace(credentials.UserName) || string.IsNullOrWhiteSpace(credentials.Password))
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Neither username nor password can be blank" };
|
||||||
|
}
|
||||||
|
var existingUser = _userData.GetUserRecordByUserName(credentials.UserName);
|
||||||
|
if (existingUser.Id != default)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Username already taken" };
|
||||||
|
}
|
||||||
|
var existingUserWithEmail = _userData.GetUserRecordByEmailAddress(credentials.EmailAddress);
|
||||||
|
if (existingUserWithEmail.Id != default)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "A user with that email already exists" };
|
||||||
|
}
|
||||||
|
//username is unique then we delete the token and create the user.
|
||||||
|
_tokenData.DeleteToken(existingToken.Id);
|
||||||
|
var newUser = new UserData()
|
||||||
|
{
|
||||||
|
UserName = credentials.UserName,
|
||||||
|
Password = GetHash(credentials.Password),
|
||||||
|
EmailAddress = credentials.EmailAddress
|
||||||
|
};
|
||||||
|
var result = _userData.SaveUserRecord(newUser);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = true, Message = "You will be redirected to the login page briefly." };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Something went wrong, please try again later." };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a token and notifies user via email so they can reset their password.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="credentials"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public OperationResponse RequestResetPassword(LoginModel credentials)
|
||||||
|
{
|
||||||
|
var existingUser = _userData.GetUserRecordByUserName(credentials.UserName);
|
||||||
|
if (existingUser.Id != default)
|
||||||
|
{
|
||||||
|
//user exists, generate a token and send email.
|
||||||
|
GenerateTokenForEmailAddress(existingUser.EmailAddress, true);
|
||||||
|
}
|
||||||
|
//for security purposes we want to always return true for this method.
|
||||||
|
//otherwise someone can spam the reset password method to sniff out users.
|
||||||
|
return new OperationResponse { Success = true, Message = "If your user exists in the system you should receive an email shortly with instructions on how to proceed." };
|
||||||
|
}
|
||||||
|
public OperationResponse ResetPasswordByUser(LoginModel credentials)
|
||||||
|
{
|
||||||
|
var existingToken = _tokenData.GetTokenRecordByBody(credentials.Token);
|
||||||
|
if (existingToken.Id == default || existingToken.EmailAddress != credentials.EmailAddress)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Invalid Token" };
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(credentials.Password))
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "New Password cannot be blank" };
|
||||||
|
}
|
||||||
|
//if token is valid.
|
||||||
|
var existingUser = _userData.GetUserRecordByEmailAddress(credentials.EmailAddress);
|
||||||
|
if (existingUser.Id == default)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Unable to locate user" };
|
||||||
|
}
|
||||||
|
existingUser.Password = GetHash(credentials.Password);
|
||||||
|
var result = _userData.SaveUserRecord(existingUser);
|
||||||
|
//delete token
|
||||||
|
_tokenData.DeleteToken(existingToken.Id);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = true, Message = "Password resetted, you will be redirected to login page shortly." };
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an empty user if can't auth against neither root nor db user.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="credentials">credentials from login page</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public UserData ValidateUserCredentials(LoginModel credentials)
|
||||||
|
{
|
||||||
|
if (UserIsRoot(credentials))
|
||||||
|
{
|
||||||
|
return new UserData()
|
||||||
|
{
|
||||||
|
Id = -1,
|
||||||
|
UserName = credentials.UserName,
|
||||||
|
IsAdmin = true,
|
||||||
|
IsRootUser = true,
|
||||||
|
EmailAddress = string.Empty
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//authenticate via DB.
|
||||||
|
var result = _userData.GetUserRecordByUserName(credentials.UserName);
|
||||||
|
if (GetHash(credentials.Password) == result.Password)
|
||||||
|
{
|
||||||
|
result.Password = string.Empty;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new UserData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public UserData ValidateOpenIDUser(LoginModel credentials)
|
||||||
|
{
|
||||||
|
var result = _userData.GetUserRecordByEmailAddress(credentials.EmailAddress);
|
||||||
|
if (result.Id != default)
|
||||||
|
{
|
||||||
|
result.Password = string.Empty;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new UserData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#region "Admin Functions"
|
||||||
|
public bool MakeUserAdmin(int userId, bool isAdmin)
|
||||||
|
{
|
||||||
|
var user = _userData.GetUserRecordById(userId);
|
||||||
|
if (user == default)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
user.IsAdmin = isAdmin;
|
||||||
|
var result = _userData.SaveUserRecord(user);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public List<UserData> GetAllUsers()
|
||||||
|
{
|
||||||
|
var result = _userData.GetUsers();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public List<Token> GetAllTokens()
|
||||||
|
{
|
||||||
|
var result = _tokenData.GetTokens();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public OperationResponse GenerateUserToken(string emailAddress, bool autoNotify)
|
||||||
|
{
|
||||||
|
//check if email address already has a token attached to it.
|
||||||
|
var existingToken = _tokenData.GetTokenRecordByEmailAddress(emailAddress);
|
||||||
|
if (existingToken.Id != default)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "There is an existing token tied to this email address" };
|
||||||
|
}
|
||||||
|
var token = new Token()
|
||||||
|
{
|
||||||
|
Body = NewToken(),
|
||||||
|
EmailAddress = emailAddress
|
||||||
|
};
|
||||||
|
var result = _tokenData.CreateNewToken(token);
|
||||||
|
if (result && autoNotify)
|
||||||
|
{
|
||||||
|
result = _mailHelper.NotifyUserForRegistration(emailAddress, token.Body).Success;
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Token Generated, but Email failed to send, please check your SMTP settings." };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = true, Message = "Token Generated!" };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteUserToken(int tokenId)
|
||||||
|
{
|
||||||
|
var result = _tokenData.DeleteToken(tokenId);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public bool DeleteUser(int userId)
|
||||||
|
{
|
||||||
|
var result = _userData.DeleteUserRecord(userId);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public OperationResponse ResetUserPassword(LoginModel credentials)
|
||||||
|
{
|
||||||
|
//user might have forgotten their password.
|
||||||
|
var existingUser = _userData.GetUserRecordByUserName(credentials.UserName);
|
||||||
|
if (existingUser.Id == default)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Unable to find user" };
|
||||||
|
}
|
||||||
|
var newPassword = Guid.NewGuid().ToString().Substring(0, 8);
|
||||||
|
existingUser.Password = GetHash(newPassword);
|
||||||
|
var result = _userData.SaveUserRecord(existingUser);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = true, Message = newPassword };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "Something went wrong, please try again later." };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region "Root User"
|
||||||
|
public bool CreateRootUserCredentials(LoginModel credentials)
|
||||||
|
{
|
||||||
|
//check if file exists
|
||||||
|
if (File.Exists(StaticHelper.UserConfigPath))
|
||||||
|
{
|
||||||
|
var configFileContents = File.ReadAllText(StaticHelper.UserConfigPath);
|
||||||
|
var existingUserConfig = JsonSerializer.Deserialize<UserConfig>(configFileContents);
|
||||||
|
if (existingUserConfig is not null)
|
||||||
|
{
|
||||||
|
//create hashes of the login credentials.
|
||||||
|
var hashedUserName = GetHash(credentials.UserName);
|
||||||
|
var hashedPassword = GetHash(credentials.Password);
|
||||||
|
//copy over settings that are off limits on the settings page.
|
||||||
|
existingUserConfig.EnableAuth = true;
|
||||||
|
existingUserConfig.UserNameHash = hashedUserName;
|
||||||
|
existingUserConfig.UserPasswordHash = hashedPassword;
|
||||||
|
}
|
||||||
|
File.WriteAllText(StaticHelper.UserConfigPath, JsonSerializer.Serialize(existingUserConfig));
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
var newUserConfig = new UserConfig()
|
||||||
|
{
|
||||||
|
EnableAuth = true,
|
||||||
|
UserNameHash = GetHash(credentials.UserName),
|
||||||
|
UserPasswordHash = GetHash(credentials.Password)
|
||||||
|
};
|
||||||
|
File.WriteAllText(StaticHelper.UserConfigPath, JsonSerializer.Serialize(newUserConfig));
|
||||||
|
}
|
||||||
|
_cache.Remove("userConfig_-1");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool DeleteRootUserCredentials()
|
||||||
|
{
|
||||||
|
var configFileContents = File.ReadAllText(StaticHelper.UserConfigPath);
|
||||||
|
var existingUserConfig = JsonSerializer.Deserialize<UserConfig>(configFileContents);
|
||||||
|
if (existingUserConfig is not null)
|
||||||
|
{
|
||||||
|
//copy over settings that are off limits on the settings page.
|
||||||
|
existingUserConfig.EnableAuth = false;
|
||||||
|
existingUserConfig.UserNameHash = string.Empty;
|
||||||
|
existingUserConfig.UserPasswordHash = string.Empty;
|
||||||
|
}
|
||||||
|
//clear out the cached config for the root user.
|
||||||
|
_cache.Remove("userConfig_-1");
|
||||||
|
File.WriteAllText(StaticHelper.UserConfigPath, JsonSerializer.Serialize(existingUserConfig));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
private bool UserIsRoot(LoginModel credentials)
|
||||||
|
{
|
||||||
|
var hashedUserName = GetHash(credentials.UserName);
|
||||||
|
var hashedPassword = GetHash(credentials.Password);
|
||||||
|
return _configHelper.AuthenticateRootUser(hashedUserName, hashedPassword);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
private static string GetHash(string value)
|
||||||
|
{
|
||||||
|
StringBuilder Sb = new StringBuilder();
|
||||||
|
|
||||||
|
using (var hash = SHA256.Create())
|
||||||
|
{
|
||||||
|
Encoding enc = Encoding.UTF8;
|
||||||
|
byte[] result = hash.ComputeHash(enc.GetBytes(value));
|
||||||
|
|
||||||
|
foreach (byte b in result)
|
||||||
|
Sb.Append(b.ToString("x2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Sb.ToString();
|
||||||
|
}
|
||||||
|
private string NewToken()
|
||||||
|
{
|
||||||
|
return Guid.NewGuid().ToString().Substring(0, 8);
|
||||||
|
}
|
||||||
|
public bool GenerateTokenForEmailAddress(string emailAddress, bool isPasswordReset)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
//check if there is already a token tied to this email address.
|
||||||
|
var existingToken = _tokenData.GetTokenRecordByEmailAddress(emailAddress);
|
||||||
|
if (existingToken.Id == default)
|
||||||
|
{
|
||||||
|
//no token, generate one and send.
|
||||||
|
var token = new Token()
|
||||||
|
{
|
||||||
|
Body = NewToken(),
|
||||||
|
EmailAddress = emailAddress
|
||||||
|
};
|
||||||
|
result = _tokenData.CreateNewToken(token);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
result = isPasswordReset ? _mailHelper.NotifyUserForPasswordReset(emailAddress, token.Body).Success : _mailHelper.NotifyUserForAccountUpdate(emailAddress, token.Body).Success;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
//token exists, send it again.
|
||||||
|
result = isPasswordReset ? _mailHelper.NotifyUserForPasswordReset(emailAddress, existingToken.Body).Success : _mailHelper.NotifyUserForAccountUpdate(emailAddress, existingToken.Body).Success;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
67
Logic/OdometerLogic.cs
Normal file
67
Logic/OdometerLogic.cs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Logic
|
||||||
|
{
|
||||||
|
public interface IOdometerLogic
|
||||||
|
{
|
||||||
|
int GetLastOdometerRecordMileage(int vehicleId, List<OdometerRecord> odometerRecords);
|
||||||
|
bool AutoInsertOdometerRecord(OdometerRecord odometer);
|
||||||
|
List<OdometerRecord> AutoConvertOdometerRecord(List<OdometerRecord> odometerRecords);
|
||||||
|
}
|
||||||
|
public class OdometerLogic: IOdometerLogic
|
||||||
|
{
|
||||||
|
private readonly IOdometerRecordDataAccess _odometerRecordDataAccess;
|
||||||
|
private readonly ILogger<IOdometerLogic> _logger;
|
||||||
|
public OdometerLogic(IOdometerRecordDataAccess odometerRecordDataAccess, ILogger<IOdometerLogic> logger)
|
||||||
|
{
|
||||||
|
_odometerRecordDataAccess = odometerRecordDataAccess;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
public int GetLastOdometerRecordMileage(int vehicleId, List<OdometerRecord> odometerRecords)
|
||||||
|
{
|
||||||
|
if (!odometerRecords.Any())
|
||||||
|
{
|
||||||
|
odometerRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
|
||||||
|
}
|
||||||
|
if (!odometerRecords.Any())
|
||||||
|
{
|
||||||
|
//no existing odometer records for this vehicle.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return odometerRecords.Max(x => x.Mileage);
|
||||||
|
}
|
||||||
|
public bool AutoInsertOdometerRecord(OdometerRecord odometer)
|
||||||
|
{
|
||||||
|
var lastReportedMileage = GetLastOdometerRecordMileage(odometer.VehicleId, new List<OdometerRecord>());
|
||||||
|
odometer.InitialMileage = lastReportedMileage != default ? lastReportedMileage : odometer.Mileage;
|
||||||
|
|
||||||
|
var result = _odometerRecordDataAccess.SaveOdometerRecordToVehicle(odometer);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public List<OdometerRecord> AutoConvertOdometerRecord(List<OdometerRecord> odometerRecords)
|
||||||
|
{
|
||||||
|
//perform ordering
|
||||||
|
odometerRecords = odometerRecords.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList();
|
||||||
|
int previousMileage = 0;
|
||||||
|
for (int i = 0; i < odometerRecords.Count; i++)
|
||||||
|
{
|
||||||
|
var currentObject = odometerRecords[i];
|
||||||
|
if (previousMileage == default)
|
||||||
|
{
|
||||||
|
//first record
|
||||||
|
currentObject.InitialMileage = currentObject.Mileage;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//subsequent records
|
||||||
|
currentObject.InitialMileage = previousMileage;
|
||||||
|
}
|
||||||
|
//save to db.
|
||||||
|
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(currentObject);
|
||||||
|
previousMileage = currentObject.Mileage;
|
||||||
|
}
|
||||||
|
return odometerRecords;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
123
Logic/UserLogic.cs
Normal file
123
Logic/UserLogic.cs
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Logic
|
||||||
|
{
|
||||||
|
public interface IUserLogic
|
||||||
|
{
|
||||||
|
List<UserCollaborator> GetCollaboratorsForVehicle(int vehicleId);
|
||||||
|
bool AddUserAccessToVehicle(int userId, int vehicleId);
|
||||||
|
bool DeleteCollaboratorFromVehicle(int userId, int vehicleId);
|
||||||
|
OperationResponse AddCollaboratorToVehicle(int vehicleId, string username);
|
||||||
|
List<Vehicle> FilterUserVehicles(List<Vehicle> results, int userId);
|
||||||
|
bool UserCanEditVehicle(int userId, int vehicleId);
|
||||||
|
bool DeleteAllAccessToVehicle(int vehicleId);
|
||||||
|
bool DeleteAllAccessToUser(int userId);
|
||||||
|
}
|
||||||
|
public class UserLogic: IUserLogic
|
||||||
|
{
|
||||||
|
private readonly IUserAccessDataAccess _userAccess;
|
||||||
|
private readonly IUserRecordDataAccess _userData;
|
||||||
|
public UserLogic(IUserAccessDataAccess userAccess,
|
||||||
|
IUserRecordDataAccess userData) {
|
||||||
|
_userAccess = userAccess;
|
||||||
|
_userData = userData;
|
||||||
|
}
|
||||||
|
public List<UserCollaborator> GetCollaboratorsForVehicle(int vehicleId)
|
||||||
|
{
|
||||||
|
var result = _userAccess.GetUserAccessByVehicleId(vehicleId);
|
||||||
|
var convertedResult = new List<UserCollaborator>();
|
||||||
|
//convert useraccess to usercollaborator
|
||||||
|
foreach(UserAccess userAccess in result)
|
||||||
|
{
|
||||||
|
var userCollaborator = new UserCollaborator
|
||||||
|
{
|
||||||
|
UserName = _userData.GetUserRecordById(userAccess.Id.UserId).UserName,
|
||||||
|
UserVehicle = userAccess.Id
|
||||||
|
};
|
||||||
|
convertedResult.Add(userCollaborator);
|
||||||
|
}
|
||||||
|
return convertedResult;
|
||||||
|
}
|
||||||
|
public OperationResponse AddCollaboratorToVehicle(int vehicleId, string username)
|
||||||
|
{
|
||||||
|
//try to find existing user.
|
||||||
|
var existingUser = _userData.GetUserRecordByUserName(username);
|
||||||
|
if (existingUser.Id != default)
|
||||||
|
{
|
||||||
|
//user exists.
|
||||||
|
//check if user is already a collaborator
|
||||||
|
var userAccess = _userAccess.GetUserAccessByVehicleAndUserId(existingUser.Id, vehicleId);
|
||||||
|
if (userAccess != null)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "User is already a collaborator" };
|
||||||
|
}
|
||||||
|
var result = AddUserAccessToVehicle(existingUser.Id, vehicleId);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = true, Message = "Collaborator Added" };
|
||||||
|
}
|
||||||
|
return new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage };
|
||||||
|
}
|
||||||
|
return new OperationResponse { Success = false, Message = $"Unable to find user {username} in the system" };
|
||||||
|
}
|
||||||
|
public bool DeleteCollaboratorFromVehicle(int userId, int vehicleId)
|
||||||
|
{
|
||||||
|
var result = _userAccess.DeleteUserAccess(userId, vehicleId);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public bool AddUserAccessToVehicle(int userId, int vehicleId)
|
||||||
|
{
|
||||||
|
if (userId == -1)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var userVehicle = new UserVehicle { UserId = userId, VehicleId = vehicleId };
|
||||||
|
var userAccess = new UserAccess { Id = userVehicle };
|
||||||
|
var result = _userAccess.SaveUserAccess(userAccess);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public List<Vehicle> FilterUserVehicles(List<Vehicle> results, int userId)
|
||||||
|
{
|
||||||
|
//user is root user.
|
||||||
|
if (userId == -1)
|
||||||
|
{
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
var accessibleVehicles = _userAccess.GetUserAccessByUserId(userId);
|
||||||
|
if (accessibleVehicles.Any())
|
||||||
|
{
|
||||||
|
var vehicleIds = accessibleVehicles.Select(x => x.Id.VehicleId);
|
||||||
|
return results.Where(x => vehicleIds.Contains(x.Id)).ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new List<Vehicle>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool UserCanEditVehicle(int userId, int vehicleId)
|
||||||
|
{
|
||||||
|
if (userId == -1)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var userAccess = _userAccess.GetUserAccessByVehicleAndUserId(userId, vehicleId);
|
||||||
|
if (userAccess != null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public bool DeleteAllAccessToVehicle(int vehicleId)
|
||||||
|
{
|
||||||
|
var result = _userAccess.DeleteAllAccessRecordsByVehicleId(vehicleId);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public bool DeleteAllAccessToUser(int userId)
|
||||||
|
{
|
||||||
|
var result = _userAccess.DeleteAllAccessRecordsByUserId(userId);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
107
Logic/VehicleLogic.cs
Normal file
107
Logic/VehicleLogic.cs
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Logic
|
||||||
|
{
|
||||||
|
public interface IVehicleLogic
|
||||||
|
{
|
||||||
|
int GetMaxMileage(int vehicleId);
|
||||||
|
int GetMinMileage(int vehicleId);
|
||||||
|
bool GetVehicleHasUrgentOrPastDueReminders(int vehicleId);
|
||||||
|
}
|
||||||
|
public class VehicleLogic: IVehicleLogic
|
||||||
|
{
|
||||||
|
private readonly IServiceRecordDataAccess _serviceRecordDataAccess;
|
||||||
|
private readonly IGasRecordDataAccess _gasRecordDataAccess;
|
||||||
|
private readonly ICollisionRecordDataAccess _collisionRecordDataAccess;
|
||||||
|
private readonly IUpgradeRecordDataAccess _upgradeRecordDataAccess;
|
||||||
|
private readonly IOdometerRecordDataAccess _odometerRecordDataAccess;
|
||||||
|
private readonly IReminderRecordDataAccess _reminderRecordDataAccess;
|
||||||
|
private readonly IReminderHelper _reminderHelper;
|
||||||
|
public VehicleLogic(
|
||||||
|
IServiceRecordDataAccess serviceRecordDataAccess,
|
||||||
|
IGasRecordDataAccess gasRecordDataAccess,
|
||||||
|
ICollisionRecordDataAccess collisionRecordDataAccess,
|
||||||
|
IUpgradeRecordDataAccess upgradeRecordDataAccess,
|
||||||
|
IOdometerRecordDataAccess odometerRecordDataAccess,
|
||||||
|
IReminderRecordDataAccess reminderRecordDataAccess,
|
||||||
|
IReminderHelper reminderHelper
|
||||||
|
) {
|
||||||
|
_serviceRecordDataAccess = serviceRecordDataAccess;
|
||||||
|
_gasRecordDataAccess = gasRecordDataAccess;
|
||||||
|
_collisionRecordDataAccess = collisionRecordDataAccess;
|
||||||
|
_upgradeRecordDataAccess = upgradeRecordDataAccess;
|
||||||
|
_odometerRecordDataAccess = odometerRecordDataAccess;
|
||||||
|
_reminderRecordDataAccess = reminderRecordDataAccess;
|
||||||
|
_reminderHelper = reminderHelper;
|
||||||
|
}
|
||||||
|
public int GetMaxMileage(int vehicleId)
|
||||||
|
{
|
||||||
|
var numbersArray = new List<int>();
|
||||||
|
var serviceRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId);
|
||||||
|
if (serviceRecords.Any())
|
||||||
|
{
|
||||||
|
numbersArray.Add(serviceRecords.Max(x => x.Mileage));
|
||||||
|
}
|
||||||
|
var repairRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId);
|
||||||
|
if (repairRecords.Any())
|
||||||
|
{
|
||||||
|
numbersArray.Add(repairRecords.Max(x => x.Mileage));
|
||||||
|
}
|
||||||
|
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
||||||
|
if (gasRecords.Any())
|
||||||
|
{
|
||||||
|
numbersArray.Add(gasRecords.Max(x => x.Mileage));
|
||||||
|
}
|
||||||
|
var upgradeRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
|
||||||
|
if (upgradeRecords.Any())
|
||||||
|
{
|
||||||
|
numbersArray.Add(upgradeRecords.Max(x => x.Mileage));
|
||||||
|
}
|
||||||
|
var odometerRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
|
||||||
|
if (odometerRecords.Any())
|
||||||
|
{
|
||||||
|
numbersArray.Add(odometerRecords.Max(x => x.Mileage));
|
||||||
|
}
|
||||||
|
return numbersArray.Any() ? numbersArray.Max() : 0;
|
||||||
|
}
|
||||||
|
public int GetMinMileage(int vehicleId)
|
||||||
|
{
|
||||||
|
var numbersArray = new List<int>();
|
||||||
|
var serviceRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId).Where(x => x.Mileage != default);
|
||||||
|
if (serviceRecords.Any())
|
||||||
|
{
|
||||||
|
numbersArray.Add(serviceRecords.Min(x => x.Mileage));
|
||||||
|
}
|
||||||
|
var repairRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId).Where(x => x.Mileage != default);
|
||||||
|
if (repairRecords.Any())
|
||||||
|
{
|
||||||
|
numbersArray.Add(repairRecords.Min(x => x.Mileage));
|
||||||
|
}
|
||||||
|
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId).Where(x => x.Mileage != default);
|
||||||
|
if (gasRecords.Any())
|
||||||
|
{
|
||||||
|
numbersArray.Add(gasRecords.Min(x => x.Mileage));
|
||||||
|
}
|
||||||
|
var upgradeRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId).Where(x => x.Mileage != default);
|
||||||
|
if (upgradeRecords.Any())
|
||||||
|
{
|
||||||
|
numbersArray.Add(upgradeRecords.Min(x => x.Mileage));
|
||||||
|
}
|
||||||
|
var odometerRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId).Where(x => x.Mileage != default);
|
||||||
|
if (odometerRecords.Any())
|
||||||
|
{
|
||||||
|
numbersArray.Add(odometerRecords.Min(x => x.Mileage));
|
||||||
|
}
|
||||||
|
return numbersArray.Any() ? numbersArray.Min() : 0;
|
||||||
|
}
|
||||||
|
public bool GetVehicleHasUrgentOrPastDueReminders(int vehicleId)
|
||||||
|
{
|
||||||
|
var currentMileage = GetMaxMileage(vehicleId);
|
||||||
|
var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId);
|
||||||
|
var results = _reminderHelper.GetReminderRecordViewModels(reminders, currentMileage, DateTime.Now);
|
||||||
|
return results.Any(x => x.Urgency == ReminderUrgency.VeryUrgent || x.Urgency == ReminderUrgency.PastDue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
using CarCareTracker.Models;
|
|
||||||
using CsvHelper.Configuration;
|
|
||||||
|
|
||||||
namespace CarCareTracker.MapProfile
|
|
||||||
{
|
|
||||||
public class FuellyMapper: ClassMap<ImportModel>
|
|
||||||
{
|
|
||||||
public FuellyMapper()
|
|
||||||
{
|
|
||||||
Map(m => m.Date).Name(["date", "fuelup_date"]);
|
|
||||||
Map(m => m.Odometer).Name(["odometer"]);
|
|
||||||
Map(m => m.FuelConsumed).Name(["gallons", "liters", "litres", "consumption", "quantity", "fueleconomy"]);
|
|
||||||
Map(m => m.Cost).Name(["cost", "total cost", "totalcost", "total price"]);
|
|
||||||
Map(m => m.Notes).Name("notes", "note");
|
|
||||||
Map(m => m.Price).Name(["price"]);
|
|
||||||
Map(m => m.PartialFuelUp).Name(["partial_fuelup"]);
|
|
||||||
Map(m => m.IsFillToFull).Name(["isfilltofull", "filled up"]);
|
|
||||||
Map(m => m.Description).Name(["description"]);
|
|
||||||
Map(m => m.MissedFuelUp).Name(["missed_fuelup"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
32
MapProfile/ImportMappers.cs
Normal file
32
MapProfile/ImportMappers.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using CarCareTracker.Models;
|
||||||
|
using CsvHelper.Configuration;
|
||||||
|
|
||||||
|
namespace CarCareTracker.MapProfile
|
||||||
|
{
|
||||||
|
public class ImportMapper: ClassMap<ImportModel>
|
||||||
|
{
|
||||||
|
public ImportMapper()
|
||||||
|
{
|
||||||
|
Map(m => m.Date).Name(["date", "fuelup_date"]);
|
||||||
|
Map(m => m.DateCreated).Name(["datecreated"]);
|
||||||
|
Map(m => m.DateModified).Name(["datemodified"]);
|
||||||
|
Map(m => m.InitialOdometer).Name(["initialodometer"]);
|
||||||
|
Map(m => m.Odometer).Name(["odometer"]);
|
||||||
|
Map(m => m.FuelConsumed).Name(["gallons", "liters", "litres", "consumption", "quantity", "fuelconsumed"]);
|
||||||
|
Map(m => m.Cost).Name(["cost", "total cost", "totalcost", "total price"]);
|
||||||
|
Map(m => m.Notes).Name("notes", "note");
|
||||||
|
Map(m => m.Price).Name(["price"]);
|
||||||
|
Map(m => m.PartialFuelUp).Name(["partial_fuelup"]);
|
||||||
|
Map(m => m.IsFillToFull).Name(["isfilltofull", "filled up"]);
|
||||||
|
Map(m => m.Description).Name(["description"]);
|
||||||
|
Map(m => m.MissedFuelUp).Name(["missed_fuelup", "missedfuelup"]);
|
||||||
|
Map(m => m.PartSupplier).Name(["partsupplier"]);
|
||||||
|
Map(m => m.PartQuantity).Name(["partquantity"]);
|
||||||
|
Map(m => m.PartNumber).Name(["partnumber"]);
|
||||||
|
Map(m => m.Progress).Name(["progress"]);
|
||||||
|
Map(m => m.Type).Name(["type"]);
|
||||||
|
Map(m => m.Priority).Name(["priority"]);
|
||||||
|
Map(m => m.Tags).Name(["tags"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
using CarCareTracker.Helper;
|
using CarCareTracker.Logic;
|
||||||
using CarCareTracker.Models;
|
using CarCareTracker.Models;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Components.Web;
|
|
||||||
using Microsoft.AspNetCore.DataProtection;
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
@@ -15,20 +13,20 @@ namespace CarCareTracker.Middleware
|
|||||||
{
|
{
|
||||||
private IHttpContextAccessor _httpContext;
|
private IHttpContextAccessor _httpContext;
|
||||||
private IDataProtector _dataProtector;
|
private IDataProtector _dataProtector;
|
||||||
private ILoginHelper _loginHelper;
|
private ILoginLogic _loginLogic;
|
||||||
private bool enableAuth;
|
private bool enableAuth;
|
||||||
public Authen(
|
public Authen(
|
||||||
IOptionsMonitor<AuthenticationSchemeOptions> options,
|
IOptionsMonitor<AuthenticationSchemeOptions> options,
|
||||||
UrlEncoder encoder,
|
UrlEncoder encoder,
|
||||||
ILoggerFactory logger,
|
ILoggerFactory logger,
|
||||||
IConfiguration configuration,
|
IConfiguration configuration,
|
||||||
ILoginHelper loginHelper,
|
ILoginLogic loginLogic,
|
||||||
IDataProtectionProvider securityProvider,
|
IDataProtectionProvider securityProvider,
|
||||||
IHttpContextAccessor httpContext) : base(options, logger, encoder)
|
IHttpContextAccessor httpContext) : base(options, logger, encoder)
|
||||||
{
|
{
|
||||||
_httpContext = httpContext;
|
_httpContext = httpContext;
|
||||||
_dataProtector = securityProvider.CreateProtector("login");
|
_dataProtector = securityProvider.CreateProtector("login");
|
||||||
_loginHelper = loginHelper;
|
_loginLogic = loginLogic;
|
||||||
enableAuth = bool.Parse(configuration["EnableAuth"]);
|
enableAuth = bool.Parse(configuration["EnableAuth"]);
|
||||||
}
|
}
|
||||||
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
|
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||||
@@ -39,7 +37,9 @@ namespace CarCareTracker.Middleware
|
|||||||
var appIdentity = new ClaimsIdentity("Custom");
|
var appIdentity = new ClaimsIdentity("Custom");
|
||||||
var userIdentity = new List<Claim>
|
var userIdentity = new List<Claim>
|
||||||
{
|
{
|
||||||
new(ClaimTypes.Name, "admin")
|
new(ClaimTypes.Name, "admin"),
|
||||||
|
new(ClaimTypes.NameIdentifier, "-1"),
|
||||||
|
new(ClaimTypes.Role, nameof(UserData.IsRootUser))
|
||||||
};
|
};
|
||||||
appIdentity.AddClaims(userIdentity);
|
appIdentity.AddClaims(userIdentity);
|
||||||
AuthenticationTicket ticket = new AuthenticationTicket(new ClaimsPrincipal(appIdentity), this.Scheme.Name);
|
AuthenticationTicket ticket = new AuthenticationTicket(new ClaimsPrincipal(appIdentity), this.Scheme.Name);
|
||||||
@@ -64,16 +64,26 @@ namespace CarCareTracker.Middleware
|
|||||||
if (splitString.Count() != 2)
|
if (splitString.Count() != 2)
|
||||||
{
|
{
|
||||||
return AuthenticateResult.Fail("Invalid credentials");
|
return AuthenticateResult.Fail("Invalid credentials");
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
var validUser = _loginHelper.ValidateUserCredentials(new LoginModel { UserName = splitString[0], Password = splitString[1] });
|
var userData = _loginLogic.ValidateUserCredentials(new LoginModel { UserName = splitString[0], Password = splitString[1] });
|
||||||
if (validUser)
|
if (userData.Id != default)
|
||||||
{
|
{
|
||||||
var appIdentity = new ClaimsIdentity("Custom");
|
var appIdentity = new ClaimsIdentity("Custom");
|
||||||
var userIdentity = new List<Claim>
|
var userIdentity = new List<Claim>
|
||||||
{
|
{
|
||||||
new(ClaimTypes.Name, splitString[0])
|
new(ClaimTypes.Name, splitString[0]),
|
||||||
|
new(ClaimTypes.NameIdentifier, userData.Id.ToString())
|
||||||
};
|
};
|
||||||
|
if (userData.IsAdmin)
|
||||||
|
{
|
||||||
|
userIdentity.Add(new(ClaimTypes.Role, nameof(UserData.IsAdmin)));
|
||||||
|
}
|
||||||
|
if (userData.IsRootUser)
|
||||||
|
{
|
||||||
|
userIdentity.Add(new(ClaimTypes.Role, nameof(UserData.IsRootUser)));
|
||||||
|
}
|
||||||
appIdentity.AddClaims(userIdentity);
|
appIdentity.AddClaims(userIdentity);
|
||||||
AuthenticationTicket ticket = new AuthenticationTicket(new ClaimsPrincipal(appIdentity), this.Scheme.Name);
|
AuthenticationTicket ticket = new AuthenticationTicket(new ClaimsPrincipal(appIdentity), this.Scheme.Name);
|
||||||
return AuthenticateResult.Success(ticket);
|
return AuthenticateResult.Success(ticket);
|
||||||
@@ -82,33 +92,56 @@ namespace CarCareTracker.Middleware
|
|||||||
}
|
}
|
||||||
else if (!string.IsNullOrWhiteSpace(access_token))
|
else if (!string.IsNullOrWhiteSpace(access_token))
|
||||||
{
|
{
|
||||||
//decrypt the access token.
|
try
|
||||||
var decryptedCookie = _dataProtector.Unprotect(access_token);
|
|
||||||
AuthCookie authCookie = JsonSerializer.Deserialize<AuthCookie>(decryptedCookie);
|
|
||||||
if (authCookie != null)
|
|
||||||
{
|
{
|
||||||
//validate auth cookie
|
//decrypt the access token.
|
||||||
if (authCookie.ExpiresOn < DateTime.Now)
|
var decryptedCookie = _dataProtector.Unprotect(access_token);
|
||||||
|
AuthCookie authCookie = JsonSerializer.Deserialize<AuthCookie>(decryptedCookie);
|
||||||
|
if (authCookie != null)
|
||||||
{
|
{
|
||||||
//if cookie is expired
|
//validate auth cookie
|
||||||
return AuthenticateResult.Fail("Expired credentials");
|
if (authCookie.ExpiresOn < DateTime.Now)
|
||||||
}
|
|
||||||
else if (authCookie.Id == default || string.IsNullOrWhiteSpace(authCookie.UserName))
|
|
||||||
{
|
|
||||||
return AuthenticateResult.Fail("Corrupted credentials");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var appIdentity = new ClaimsIdentity("Custom");
|
|
||||||
var userIdentity = new List<Claim>
|
|
||||||
{
|
{
|
||||||
new(ClaimTypes.Name, authCookie.UserName)
|
//if cookie is expired
|
||||||
};
|
return AuthenticateResult.Fail("Expired credentials");
|
||||||
appIdentity.AddClaims(userIdentity);
|
}
|
||||||
AuthenticationTicket ticket = new AuthenticationTicket(new ClaimsPrincipal(appIdentity), this.Scheme.Name);
|
else if (authCookie.UserData is null || authCookie.UserData.Id == default || string.IsNullOrWhiteSpace(authCookie.UserData.UserName))
|
||||||
return AuthenticateResult.Success(ticket);
|
{
|
||||||
|
return AuthenticateResult.Fail("Corrupted credentials");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!_loginLogic.CheckIfUserIsValid(authCookie.UserData.Id))
|
||||||
|
{
|
||||||
|
return AuthenticateResult.Fail("Cookie points to non-existant user.");
|
||||||
|
}
|
||||||
|
//validate if user is still valid
|
||||||
|
var appIdentity = new ClaimsIdentity("Custom");
|
||||||
|
var userIdentity = new List<Claim>
|
||||||
|
{
|
||||||
|
new(ClaimTypes.Name, authCookie.UserData.UserName),
|
||||||
|
new(ClaimTypes.NameIdentifier, authCookie.UserData.Id.ToString()),
|
||||||
|
new(ClaimTypes.Email, authCookie.UserData.EmailAddress),
|
||||||
|
new(ClaimTypes.Role, "CookieAuth")
|
||||||
|
};
|
||||||
|
if (authCookie.UserData.IsAdmin)
|
||||||
|
{
|
||||||
|
userIdentity.Add(new(ClaimTypes.Role, nameof(UserData.IsAdmin)));
|
||||||
|
}
|
||||||
|
if (authCookie.UserData.IsRootUser)
|
||||||
|
{
|
||||||
|
userIdentity.Add(new(ClaimTypes.Role, nameof(UserData.IsRootUser)));
|
||||||
|
}
|
||||||
|
appIdentity.AddClaims(userIdentity);
|
||||||
|
AuthenticationTicket ticket = new AuthenticationTicket(new ClaimsPrincipal(appIdentity), this.Scheme.Name);
|
||||||
|
return AuthenticateResult.Success(ticket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return AuthenticateResult.Fail("Corrupted credentials");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return AuthenticateResult.Fail("Invalid credentials");
|
return AuthenticateResult.Fail("Invalid credentials");
|
||||||
}
|
}
|
||||||
@@ -123,7 +156,26 @@ namespace CarCareTracker.Middleware
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Response.Redirect("/Login/Index");
|
if (Request.Path.Value == "/Vehicle/Index" && Request.QueryString.HasValue)
|
||||||
|
{
|
||||||
|
Response.Redirect($"/Login/Index?redirectURL={Request.Path.Value}{Request.QueryString.Value}");
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
Response.Redirect("/Login/Index");
|
||||||
|
}
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
protected override Task HandleForbiddenAsync(AuthenticationProperties properties)
|
||||||
|
{
|
||||||
|
if (Request.RouteValues.TryGetValue("controller", out object value))
|
||||||
|
{
|
||||||
|
if (value.ToString().ToLower() == "api")
|
||||||
|
{
|
||||||
|
Response.StatusCode = 403;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Response.Redirect("/Error/Unauthorized");
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
Models/Admin/AdminViewModel.cs
Normal file
8
Models/Admin/AdminViewModel.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public class AdminViewModel
|
||||||
|
{
|
||||||
|
public List<UserData> Users { get; set; }
|
||||||
|
public List<Token> Tokens { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,6 @@
|
|||||||
namespace CarCareTracker.Models
|
namespace CarCareTracker.Models
|
||||||
{
|
{
|
||||||
public class CollisionRecord
|
public class CollisionRecord: GenericRecord
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
|
||||||
public int VehicleId { get; set; }
|
|
||||||
public DateTime Date { get; set; }
|
|
||||||
public int Mileage { get; set; }
|
|
||||||
public string Description { get; set; }
|
|
||||||
public decimal Cost { get; set; }
|
|
||||||
public string Notes { get; set; }
|
|
||||||
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,31 @@
|
|||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int VehicleId { get; set; }
|
public int VehicleId { get; set; }
|
||||||
public string Date { get; set; }
|
public List<int> ReminderRecordId { get; set; } = new List<int>();
|
||||||
|
public string Date { get; set; } = DateTime.Now.ToShortDateString();
|
||||||
public int Mileage { get; set; }
|
public int Mileage { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public decimal Cost { get; set; }
|
public decimal Cost { get; set; }
|
||||||
public string Notes { get; set; }
|
public string Notes { get; set; }
|
||||||
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||||
public CollisionRecord ToCollisionRecord() { return new CollisionRecord { Id = Id, VehicleId = VehicleId, Date = DateTime.Parse(Date), Cost = Cost, Mileage = Mileage, Description = Description, Notes = Notes, Files = Files }; }
|
public List<SupplyUsage> Supplies { get; set; } = new List<SupplyUsage>();
|
||||||
|
public List<string> Tags { get; set; } = new List<string>();
|
||||||
|
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
|
||||||
|
public List<SupplyUsageHistory> RequisitionHistory { get; set; } = new List<SupplyUsageHistory>();
|
||||||
|
public bool CopySuppliesAttachment { get; set; } = false;
|
||||||
|
public CollisionRecord ToCollisionRecord() { return new CollisionRecord {
|
||||||
|
Id = Id,
|
||||||
|
VehicleId = VehicleId,
|
||||||
|
Date = DateTime.Parse(Date),
|
||||||
|
Cost = Cost,
|
||||||
|
Mileage = Mileage,
|
||||||
|
Description = Description,
|
||||||
|
Notes = Notes,
|
||||||
|
Files = Files,
|
||||||
|
Tags = Tags,
|
||||||
|
ExtraFields = ExtraFields,
|
||||||
|
RequisitionHistory = RequisitionHistory
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
Models/Configuration/MailConfig.cs
Normal file
12
Models/Configuration/MailConfig.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public class MailConfig
|
||||||
|
{
|
||||||
|
public string EmailServer { get; set; }
|
||||||
|
public string EmailFrom { get; set; }
|
||||||
|
public bool UseSSL { get; set; }
|
||||||
|
public int Port { get; set; }
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,9 @@
|
|||||||
public decimal Cost { get; set; }
|
public decimal Cost { get; set; }
|
||||||
public bool IsFillToFull { get; set; } = true;
|
public bool IsFillToFull { get; set; } = true;
|
||||||
public bool MissedFuelUp { get; set; } = false;
|
public bool MissedFuelUp { get; set; } = false;
|
||||||
|
public string Notes { get; set; }
|
||||||
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||||
|
public List<string> Tags { get; set; } = new List<string>();
|
||||||
|
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
Models/GasRecord/GasRecordEditModel.cs
Normal file
8
Models/GasRecord/GasRecordEditModel.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public class GasRecordEditModel
|
||||||
|
{
|
||||||
|
public List<int> RecordIds { get; set; } = new List<int>();
|
||||||
|
public GasRecord EditRecord { get; set; } = new GasRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int VehicleId { get; set; }
|
public int VehicleId { get; set; }
|
||||||
public string Date { get; set; }
|
public string Date { get; set; } = DateTime.Now.ToShortDateString();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// American moment
|
/// American moment
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -16,7 +16,10 @@
|
|||||||
public decimal Cost { get; set; }
|
public decimal Cost { get; set; }
|
||||||
public bool IsFillToFull { get; set; } = true;
|
public bool IsFillToFull { get; set; } = true;
|
||||||
public bool MissedFuelUp { get; set; } = false;
|
public bool MissedFuelUp { get; set; } = false;
|
||||||
|
public string Notes { get; set; }
|
||||||
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||||
|
public List<string> Tags { get; set; } = new List<string>();
|
||||||
|
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
|
||||||
public GasRecord ToGasRecord() { return new GasRecord {
|
public GasRecord ToGasRecord() { return new GasRecord {
|
||||||
Id = Id,
|
Id = Id,
|
||||||
Cost = Cost,
|
Cost = Cost,
|
||||||
@@ -26,7 +29,10 @@
|
|||||||
VehicleId = VehicleId,
|
VehicleId = VehicleId,
|
||||||
Files = Files,
|
Files = Files,
|
||||||
IsFillToFull = IsFillToFull,
|
IsFillToFull = IsFillToFull,
|
||||||
MissedFuelUp = MissedFuelUp
|
MissedFuelUp = MissedFuelUp,
|
||||||
|
Notes = Notes,
|
||||||
|
Tags = Tags,
|
||||||
|
ExtraFields = ExtraFields
|
||||||
}; }
|
}; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
{
|
{
|
||||||
public class GasRecordInputContainer
|
public class GasRecordInputContainer
|
||||||
{
|
{
|
||||||
public bool UseKwh { get; set; }
|
public bool UseKwh { get; set; }
|
||||||
public GasRecordInput GasRecord { get; set; }
|
public bool UseHours { get; set; }
|
||||||
|
public GasRecordInput GasRecord { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user