mirror of
https://github.com/hargata/lubelog.git
synced 2025-12-10 00:46:08 -06:00
Compare commits
1696 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b184a1664b | ||
|
|
1963fb8134 | ||
|
|
1d5aeada6d | ||
|
|
64f25ddcb2 | ||
|
|
f5efe96856 | ||
|
|
bf8bc6a119 | ||
|
|
752eb30dc4 | ||
|
|
7c2f626647 | ||
|
|
5122bb586b | ||
|
|
8dffb3d7c6 | ||
|
|
fff013497a | ||
|
|
bc10c095a7 | ||
|
|
7d203d4175 | ||
|
|
f2eeda9c65 | ||
|
|
3f5e3a4b97 | ||
|
|
ab967f1f52 | ||
|
|
2f95e0445c | ||
|
|
c3110176f2 | ||
|
|
e81c0616f7 | ||
|
|
0aae215f08 | ||
|
|
0f2a7c372b | ||
|
|
1032112885 | ||
|
|
d23b16da67 | ||
|
|
5bb0170011 | ||
|
|
07d1f5cd86 | ||
|
|
61bbfb8b1e | ||
|
|
1a805ada8e | ||
|
|
6065c14f3b | ||
|
|
76d9be7ee5 | ||
|
|
5f6b77648d | ||
|
|
d09d10a5b3 | ||
|
|
98561e7f00 | ||
|
|
780856433d | ||
|
|
5c895b4f82 | ||
|
|
ec52bc09e4 | ||
|
|
c0cfd74fc6 | ||
|
|
066e5ca648 | ||
|
|
e30f1def1e | ||
|
|
a137fbaa52 | ||
|
|
b98585006b | ||
|
|
4d9c5c7237 | ||
|
|
d4f06b96ff | ||
|
|
9f14cd0a5e | ||
|
|
d8047b07c5 | ||
|
|
b42527f15d | ||
|
|
cb432d92a6 | ||
|
|
300edd8c4e | ||
|
|
cb77d6675e | ||
|
|
d29b20b16b | ||
|
|
f3999650bd | ||
|
|
bd47ef41f0 | ||
|
|
0c4ccea9ec | ||
|
|
18243ec779 | ||
|
|
83f1a25057 | ||
|
|
7f671c1802 | ||
|
|
3f05f06824 | ||
|
|
2ab822af8f | ||
|
|
0cef3c9044 | ||
|
|
9ef2124c8a | ||
|
|
fd9d57c3db | ||
|
|
a3e0da1ebb | ||
|
|
ebca12d82a | ||
|
|
9b00933aa8 | ||
|
|
98ef7d455b | ||
|
|
7062595d4d | ||
|
|
ae19b64327 | ||
|
|
4d3d624ac8 | ||
|
|
ef0f4fa5f8 | ||
|
|
3d33a798f1 | ||
|
|
b8a568b3e8 | ||
|
|
190b7b4e23 | ||
|
|
bca2393601 | ||
|
|
5ad1ae3d5a | ||
|
|
123a6f2dd4 | ||
|
|
3de2ecc096 | ||
|
|
9a504a3e53 | ||
|
|
a90b8bdf93 | ||
|
|
50f4308417 | ||
|
|
c5ea6c01df | ||
|
|
1e32d57d16 | ||
|
|
350cdcb03a | ||
|
|
aedaccfeda | ||
|
|
044cf3bf38 | ||
|
|
dd30e7b8fa | ||
|
|
e802b8c3f9 | ||
|
|
042985df54 | ||
|
|
20365a549a | ||
|
|
5a67217843 | ||
|
|
b17c8e3bc5 | ||
|
|
3377aa15b5 | ||
|
|
a38ff16d79 | ||
|
|
772b778c98 | ||
|
|
f3fcc1700f | ||
|
|
f358d20ad0 | ||
|
|
329c8a403a | ||
|
|
d709969a93 | ||
|
|
63178b6bdb | ||
|
|
129cdf4554 | ||
|
|
7bfa00d6a1 | ||
|
|
342ac6e560 | ||
|
|
7cb7777060 | ||
|
|
b3283fc3e8 | ||
|
|
535f0ad677 | ||
|
|
e3da3215ca | ||
|
|
99a34a888e | ||
|
|
a13cf0733b | ||
|
|
fc87bd3b9c | ||
|
|
b697501e59 | ||
|
|
c7974b412f | ||
|
|
7589d139cb | ||
|
|
8a2ab47e49 | ||
|
|
08e0ff2798 | ||
|
|
fd102224fc | ||
|
|
d71e8ddcf2 | ||
|
|
96291bae76 | ||
|
|
643f7a3f79 | ||
|
|
1893a5985f | ||
|
|
487ce0a42a | ||
|
|
505bc5b3c6 | ||
|
|
8ddd04017b | ||
|
|
fce40ae9be | ||
|
|
a59f6b9e86 | ||
|
|
3bbe9538a7 | ||
|
|
ba886d8b08 | ||
|
|
0bfef450ed | ||
|
|
dcf30d73b7 | ||
|
|
5f0b7b9bb1 | ||
|
|
831f256872 | ||
|
|
1e4acf2301 | ||
|
|
68826f0924 | ||
|
|
9ac7f78695 | ||
|
|
22d9936b24 | ||
|
|
770cde977d | ||
|
|
f6924c83bf | ||
|
|
640b41d4ab | ||
|
|
c2173aa12c | ||
|
|
f4745c6dce | ||
|
|
aa64ce4194 | ||
|
|
18f086de32 | ||
|
|
59b58a836c | ||
|
|
6042b3dedb | ||
|
|
92b5840073 | ||
|
|
55b52dcfa0 | ||
|
|
98ff9eb9a6 | ||
|
|
95eab55d02 | ||
|
|
9dccce7208 | ||
|
|
3ba8f3f297 | ||
|
|
08fdd5ee05 | ||
|
|
fefe61f27e | ||
|
|
7844d2430d | ||
|
|
df0e686615 | ||
|
|
969b28f1b4 | ||
|
|
0922453dfb | ||
|
|
931ca855d2 | ||
|
|
59868f2463 | ||
|
|
6c0565102a | ||
|
|
a7886bfdc4 | ||
|
|
6c069dde17 | ||
|
|
950fc2af48 | ||
|
|
53937c9030 | ||
|
|
e12895f246 | ||
|
|
55328d1be4 | ||
|
|
8f589d7638 | ||
|
|
31671fa137 | ||
|
|
5859a020bd | ||
|
|
9f556f9c95 | ||
|
|
6aad531099 | ||
|
|
10b420cd81 | ||
|
|
5f6f713ace | ||
|
|
e490117b23 | ||
|
|
653fd47621 | ||
|
|
e9eb86ae3f | ||
|
|
31690bc8df | ||
|
|
18f9129ecb | ||
|
|
939426a451 | ||
|
|
ba621a7cf7 | ||
|
|
c6f1b8ab6e | ||
|
|
c3c9ed2c04 | ||
|
|
ed8da2a264 | ||
|
|
c0f336d197 | ||
|
|
32b14c17b4 | ||
|
|
bf25c4122a | ||
|
|
dc83d5c518 | ||
|
|
3bd246db3a | ||
|
|
da8cde234a | ||
|
|
4c16ab80e9 | ||
|
|
a7df12c88b | ||
|
|
4abcc5c1e5 | ||
|
|
6fe4d5d84b | ||
|
|
19ddc34d59 | ||
|
|
0c7b6ddf2b | ||
|
|
97914da6ad | ||
|
|
1e7401b263 | ||
|
|
56fbcd1892 | ||
|
|
bd72e04e21 | ||
|
|
4dca661c02 | ||
|
|
4731615ac5 | ||
|
|
2d88db2e68 | ||
|
|
4d5bbc39dd | ||
|
|
3618cc6456 | ||
|
|
7ebda7eafc | ||
|
|
24e76eb7c0 | ||
|
|
67f36a2940 | ||
|
|
0753d04d47 | ||
|
|
7c59051168 | ||
|
|
1108d3b822 | ||
|
|
9669e8fc65 | ||
|
|
cd8d99ff89 | ||
|
|
98e8dfe373 | ||
|
|
24ebc39aa0 | ||
|
|
9321edf6f6 | ||
|
|
159df59b22 | ||
|
|
b32322cb65 | ||
|
|
56c4d0410b | ||
|
|
dc46bc7eec | ||
|
|
4fd55ba0b8 | ||
|
|
340b9c9a00 | ||
|
|
8daa4d7c5f | ||
|
|
5b148e47da | ||
|
|
050e3ce355 | ||
|
|
d24b28beb5 | ||
|
|
36cfac402c | ||
|
|
eee4e2e56b | ||
|
|
8c770536c0 | ||
|
|
f0ad263306 | ||
|
|
c4adc5b297 | ||
|
|
128154f4c5 | ||
|
|
39370a50cb | ||
|
|
71fed1ff7e | ||
|
|
3e5d8ce0a2 | ||
|
|
6555ee25e2 | ||
|
|
0d3059a176 | ||
|
|
d8cf3a049b | ||
|
|
055b183f2a | ||
|
|
44dcd48a56 | ||
|
|
e61c1d4a70 | ||
|
|
6d961e0540 | ||
|
|
fbb2fb724d | ||
|
|
ef86337d78 | ||
|
|
0ff374389f | ||
|
|
94d9f45b13 | ||
|
|
1d734e78a7 | ||
|
|
d0f9149585 | ||
|
|
9837f81b87 | ||
|
|
725638d217 | ||
|
|
b0a5cab2b6 | ||
|
|
ebaf55e3b0 | ||
|
|
49870f13c9 | ||
|
|
a749de71e9 | ||
|
|
36b80bcef5 | ||
|
|
16f9740b6c | ||
|
|
2eab072e6d | ||
|
|
59c561ebba | ||
|
|
07f993bec8 | ||
|
|
bd6cb94ccd | ||
|
|
4206c02618 | ||
|
|
b276fc02ce | ||
|
|
e558248f7c | ||
|
|
5a113a1636 | ||
|
|
651dac3f27 | ||
|
|
4ecafbbdf7 | ||
|
|
29680cf0e9 | ||
|
|
723eb1a769 | ||
|
|
732a628c20 | ||
|
|
84d40edb0e | ||
|
|
9842f0e501 | ||
|
|
44c5f921a5 | ||
|
|
fae4aa31aa | ||
|
|
adb505c87c | ||
|
|
d21b0a9e29 | ||
|
|
15e4181aff | ||
|
|
3a4627ef02 | ||
|
|
d9e11273bd | ||
|
|
8e6f40a1b1 | ||
|
|
55f86ecb3f | ||
|
|
8eef1465cf | ||
|
|
fd0ffba7c4 | ||
|
|
afb710e6ad | ||
|
|
419b755e7a | ||
|
|
8cd5342c02 | ||
|
|
fa32ecdb5a | ||
|
|
d08726bd85 | ||
|
|
a87861069b | ||
|
|
b6d6a8765d | ||
|
|
f307c0933a | ||
|
|
9968ccb541 | ||
|
|
5d3746f168 | ||
|
|
df0c4eeca2 | ||
|
|
5b3c0aed72 | ||
|
|
040728b96d | ||
|
|
e8b7b3e4ba | ||
|
|
cf1f1a884b | ||
|
|
c470db0590 | ||
|
|
cb71650adf | ||
|
|
923d59af0a | ||
|
|
d68e1a3939 | ||
|
|
bf954a2946 | ||
|
|
d3f29be227 | ||
|
|
5afe88a33a | ||
|
|
6937eff576 | ||
|
|
6371cccc48 | ||
|
|
fc174160e0 | ||
|
|
876f99fd26 | ||
|
|
75c65b4681 | ||
|
|
76031d27d7 | ||
|
|
4079a93c3e | ||
|
|
d913ab2009 | ||
|
|
6bfbcc4374 | ||
|
|
73d9a7e6e9 | ||
|
|
3cbce8b584 | ||
|
|
e4fcb52b24 | ||
|
|
ae4f01ac9a | ||
|
|
46b3845b3e | ||
|
|
ffb126276f | ||
|
|
a9e4be823d | ||
|
|
56cae008a6 | ||
|
|
c2dd379ea3 | ||
|
|
baa569b323 | ||
|
|
64ce0f8c07 | ||
|
|
bd98e5a6cd | ||
|
|
83fc8b8682 | ||
|
|
89fa15bbb7 | ||
|
|
5e69be56aa | ||
|
|
b1112dc617 | ||
|
|
5a31460afe | ||
|
|
2bcedbc7d4 | ||
|
|
5047fdf1bc | ||
|
|
7c8c3fb1c8 | ||
|
|
9920bd472f | ||
|
|
d7839a8a05 | ||
|
|
7e07e73ef5 | ||
|
|
72a5960d40 | ||
|
|
3429f1e4f9 | ||
|
|
f8bea8bf81 | ||
|
|
43794dd223 | ||
|
|
5cc84a7b46 | ||
|
|
48248a4386 | ||
|
|
95305402e6 | ||
|
|
29f24c527f | ||
|
|
efa2bbf6cc | ||
|
|
66ed9ba699 | ||
|
|
e841e64f78 | ||
|
|
b0f46803c5 | ||
|
|
ac0bef5de0 | ||
|
|
08ea40a08e | ||
|
|
1d8e8059cd | ||
|
|
20b4396a4c | ||
|
|
4c39cb4d06 | ||
|
|
f58e6abd9f | ||
|
|
4f1e83a7d7 | ||
|
|
e39b38c2d5 | ||
|
|
b9ffa6ce91 | ||
|
|
76c6753785 | ||
|
|
54f5062377 | ||
|
|
7e60fd9e40 | ||
|
|
926947bae4 | ||
|
|
2652e47018 | ||
|
|
c1500b6ed0 | ||
|
|
125bc44d2e | ||
|
|
c317c0a058 | ||
|
|
beb9498399 | ||
|
|
4e74940684 | ||
|
|
c0f73080d2 | ||
|
|
cd0a35537b | ||
|
|
4d5020b607 | ||
|
|
7d8b7596ce | ||
|
|
08b5c9f25a | ||
|
|
82a4f8d57b | ||
|
|
538a79319e | ||
|
|
0555dcbc43 | ||
|
|
7b1f19ff9f | ||
|
|
9cac427eb9 | ||
|
|
1e5950028f | ||
|
|
7a7d343c3f | ||
|
|
ebf6388414 | ||
|
|
fa5426be53 | ||
|
|
4c60bb20c9 | ||
|
|
b02f3c8f8b | ||
|
|
d5f769e5a4 | ||
|
|
2afd1188eb | ||
|
|
1c6301242d | ||
|
|
06016727d9 | ||
|
|
1ee0c27ff9 | ||
|
|
7f03a630c6 | ||
|
|
2aa19f4f3b | ||
|
|
4be3c16adc | ||
|
|
f1f99a67dd | ||
|
|
a4f15ffe15 | ||
|
|
c11dad0cb3 | ||
|
|
2bf2469657 | ||
|
|
a23b02e962 | ||
|
|
905ee9bf27 | ||
|
|
e26869b30b | ||
|
|
90867792d9 | ||
|
|
1238802a75 | ||
|
|
8f7c50b88f | ||
|
|
df24434689 | ||
|
|
878748803d | ||
|
|
80bbf7f22f | ||
|
|
28b0ea565a | ||
|
|
07ccd1dea9 | ||
|
|
6a8fba535a | ||
|
|
f1b82ad0d3 | ||
|
|
0035bc09dd | ||
|
|
863c57d7fb | ||
|
|
00ccb68ce2 | ||
|
|
c2995dcd25 | ||
|
|
7b63366627 | ||
|
|
ababa6bf27 | ||
|
|
3f1f42d4f0 | ||
|
|
4d76bd6d36 | ||
|
|
ab34d1682c | ||
|
|
552b7a6356 | ||
|
|
f86acf673a | ||
|
|
c6f49bafca | ||
|
|
fdbb325611 | ||
|
|
8c557ced85 | ||
|
|
ad0f7de506 | ||
|
|
15ec9bb454 | ||
|
|
9fe7558cfe | ||
|
|
79633dbe1d | ||
|
|
f325306e20 | ||
|
|
4778656063 | ||
|
|
f7e00523c2 | ||
|
|
bf3df7230b | ||
|
|
c5182e0ed6 | ||
|
|
4081438cba | ||
|
|
b72fe2bf37 | ||
|
|
4d9c687709 | ||
|
|
3d4b970967 | ||
|
|
792f295c45 | ||
|
|
af28753558 | ||
|
|
24fb663599 | ||
|
|
140506c9c3 | ||
|
|
519f159c8c | ||
|
|
bb019cbcd9 | ||
|
|
84219627ff | ||
|
|
f218e878c6 | ||
|
|
520f47955b | ||
|
|
8110ee18f1 | ||
|
|
55bf817310 | ||
|
|
f2f55f8118 | ||
|
|
f48e7cd0d4 | ||
|
|
c82e0c8b9b | ||
|
|
c72877e16b | ||
|
|
ccc9076397 | ||
|
|
1c716ecf4a | ||
|
|
2cc471b944 | ||
|
|
a6c450109a | ||
|
|
e13707305b | ||
|
|
68bc0383f4 | ||
|
|
878f4f3687 | ||
|
|
48a721adda | ||
|
|
548e8da78c | ||
|
|
beb28214cf | ||
|
|
b4bb31491b | ||
|
|
0b5f007327 | ||
|
|
d31a4aeea3 | ||
|
|
97acd873eb | ||
|
|
5cf3538be3 | ||
|
|
a34921701d | ||
|
|
5fcf54de09 | ||
|
|
68372bf995 | ||
|
|
9f99ac1531 | ||
|
|
b7384fda6b | ||
|
|
8f4d610825 | ||
|
|
6bbf4b2575 | ||
|
|
32db884620 | ||
|
|
1b736b36f8 | ||
|
|
22dfe5eb04 | ||
|
|
8fd49e20d5 | ||
|
|
c791070126 | ||
|
|
807603fd4f | ||
|
|
a944e5e5ab | ||
|
|
33e916cac2 | ||
|
|
a99d71dc41 | ||
|
|
67d91f1a0d | ||
|
|
de2db7d24e | ||
|
|
b360f77ea0 | ||
|
|
e869528522 | ||
|
|
7c0317d232 | ||
|
|
0e49497da1 | ||
|
|
0380382c47 | ||
|
|
23201b8c86 | ||
|
|
5f357c9f84 | ||
|
|
244272621c | ||
|
|
5792b84880 | ||
|
|
8e644093f9 | ||
|
|
9421cb57ca | ||
|
|
bd7cbffe10 | ||
|
|
b293882f75 | ||
|
|
0984b2049b | ||
|
|
d4ec4989e7 | ||
|
|
230433f784 | ||
|
|
d4dda481be | ||
|
|
1d3b94f544 | ||
|
|
78434f0016 | ||
|
|
c75145de49 | ||
|
|
5e3480f9f3 | ||
|
|
f74fdc8ed4 | ||
|
|
9ba62f8bf8 | ||
|
|
f2b9dea2b6 | ||
|
|
f92aa22375 | ||
|
|
d65001f412 | ||
|
|
9ea223cd0a | ||
|
|
addf73bc27 | ||
|
|
3f853d0d5e | ||
|
|
4c46278be1 | ||
|
|
0edc51083c | ||
|
|
d906bec333 | ||
|
|
a47c4942b7 | ||
|
|
cd8df9e938 | ||
|
|
5c37f98274 | ||
|
|
f452436dbd | ||
|
|
9375bb103b | ||
|
|
3222579cb4 | ||
|
|
4348b50e54 | ||
|
|
3b7c58b6e8 | ||
|
|
664b89a5df | ||
|
|
628c22ad61 | ||
|
|
db62a041c4 | ||
|
|
ea3ffea797 | ||
|
|
c49c8d67a2 | ||
|
|
3b01df4c56 | ||
|
|
9221516bad | ||
|
|
1988cf54f5 | ||
|
|
8a8d8979a7 | ||
|
|
e983b39f8e | ||
|
|
b6c5cd4b46 | ||
|
|
210b27ab25 | ||
|
|
63e9e5ecec | ||
|
|
771ca15ea2 | ||
|
|
b6b403b5e2 | ||
|
|
9976c94481 | ||
|
|
b9dca8ceae | ||
|
|
03b9331a9a | ||
|
|
f629834d6a | ||
|
|
25952cce50 | ||
|
|
6eba83ccec | ||
|
|
3c1ce80528 | ||
|
|
b7851e87b2 | ||
|
|
d8e06fd968 | ||
|
|
c5a5de50a7 | ||
|
|
7715e7b4ab | ||
|
|
5a3ed3d3d4 | ||
|
|
c1e2394194 | ||
|
|
6abb569df1 | ||
|
|
e59e33bc3b | ||
|
|
a671dc1937 | ||
|
|
426b52aee4 | ||
|
|
87fe011565 | ||
|
|
30c03af5b0 | ||
|
|
c9c8fc8705 | ||
|
|
9cd8030808 | ||
|
|
5411d4152c | ||
|
|
c5a05afe1c | ||
|
|
5b44f2ae33 | ||
|
|
039b30da4f | ||
|
|
df45378bce | ||
|
|
3729d2c23f | ||
|
|
89ece413c8 | ||
|
|
c1b361397f | ||
|
|
ada0715343 | ||
|
|
5cdc687f6d | ||
|
|
48f0e16fde | ||
|
|
d6b6600ce9 | ||
|
|
82634e9e1b | ||
|
|
225e5e58bc | ||
|
|
21d135a8ab | ||
|
|
7a0636a48a | ||
|
|
0b9ca77281 | ||
|
|
feaf631b47 | ||
|
|
ec24c19821 | ||
|
|
36a120fa0f | ||
|
|
fb169d5054 | ||
|
|
59fa7b6a1d | ||
|
|
201d832b92 | ||
|
|
31b4ef5458 | ||
|
|
b06ad0cdaa | ||
|
|
f3914bc3b7 | ||
|
|
aea870974b | ||
|
|
7f6265ba05 | ||
|
|
85542cb278 | ||
|
|
f6e0873d83 | ||
|
|
745b262dfc | ||
|
|
73df755f70 | ||
|
|
762a1b98d3 | ||
|
|
571e87dd14 | ||
|
|
22eb38709a | ||
|
|
986a8420f8 | ||
|
|
cff5f8e8e9 | ||
|
|
0df6cea88c | ||
|
|
88ff2432f6 | ||
|
|
efb7fb999b | ||
|
|
1a2b503791 | ||
|
|
e68d4ffa3a | ||
|
|
d701a8964f | ||
|
|
b6929113bc | ||
|
|
fc1eac1049 | ||
|
|
189659ff1e | ||
|
|
cb19130119 | ||
|
|
1596bf1deb | ||
|
|
636cbb3d21 | ||
|
|
cff7845dd4 | ||
|
|
2d9cc3507f | ||
|
|
4c6ac96dd1 | ||
|
|
e5a594367e | ||
|
|
12aaf8c209 | ||
|
|
cafbb156af | ||
|
|
36ac61d848 | ||
|
|
df066a593e | ||
|
|
7ac9185e4c | ||
|
|
090cbba1a0 | ||
|
|
5e3529f9cc | ||
|
|
f90ddeabb4 | ||
|
|
f54419b993 | ||
|
|
cbbd7ff25f | ||
|
|
0c2c089828 | ||
|
|
6a1813399f | ||
|
|
4c8d2b3704 | ||
|
|
23f97ebd46 | ||
|
|
e3dccf0182 | ||
|
|
272596878c | ||
|
|
46953e9063 | ||
|
|
30f35855f2 | ||
|
|
df94132917 | ||
|
|
de37d689be | ||
|
|
4f941aad52 | ||
|
|
2febdf1259 | ||
|
|
349808a609 | ||
|
|
7d58d1bc40 | ||
|
|
5e91a26230 | ||
|
|
0942ae1742 | ||
|
|
cce9bd29e5 | ||
|
|
05fdeef862 | ||
|
|
dfa08b287c | ||
|
|
77920f94cd | ||
|
|
3631a036c6 | ||
|
|
1445959d05 | ||
|
|
0b45de5ba8 | ||
|
|
d86cdfcefd | ||
|
|
0c7aa304f7 | ||
|
|
e5114f491d | ||
|
|
e238bd8a12 | ||
|
|
f53ad74c72 | ||
|
|
3d456d1cd5 | ||
|
|
de32fe4d85 | ||
|
|
29a90fe814 | ||
|
|
3f31f091dc | ||
|
|
571b558181 | ||
|
|
ed0775ab71 | ||
|
|
19e19d7c15 | ||
|
|
b7e574889c | ||
|
|
2a66c97254 | ||
|
|
e14ef961b9 | ||
|
|
ec2c17be23 | ||
|
|
b5162d2044 | ||
|
|
ae428b94d1 | ||
|
|
3350f3c39a | ||
|
|
68caf82167 | ||
|
|
8c5f1c3a01 | ||
|
|
e1bbc232e1 | ||
|
|
fbc7a39996 | ||
|
|
1ce77ad1ee | ||
|
|
08cee8029f | ||
|
|
e33bcf5e57 | ||
|
|
cf5ceaa959 | ||
|
|
8293bed89c | ||
|
|
a830580c27 | ||
|
|
94c6cca25c | ||
|
|
78e0a0146c | ||
|
|
ea667ed950 | ||
|
|
f8b23b5f20 | ||
|
|
b69749b073 | ||
|
|
951eea844f | ||
|
|
f3e5aff0c9 | ||
|
|
ef3e450e4f | ||
|
|
8272fa20da | ||
|
|
9ef0a748a3 | ||
|
|
6de928aef4 | ||
|
|
34ff874949 | ||
|
|
a653f3ac7f | ||
|
|
dc96084406 | ||
|
|
e056aaa7dc | ||
|
|
73bb3c11b4 | ||
|
|
c88a040728 | ||
|
|
dfa56c2b12 | ||
|
|
104d4bab52 | ||
|
|
6916161e87 | ||
|
|
512852d217 | ||
|
|
a61c699417 | ||
|
|
1e832f014f | ||
|
|
e9a463e2e5 | ||
|
|
d0c19d0436 | ||
|
|
3428abf358 | ||
|
|
e6857331e2 | ||
|
|
1fd93d2efe | ||
|
|
84e44acbfe | ||
|
|
77014c71f2 | ||
|
|
2db01aa4ad | ||
|
|
6c3fa21cc5 | ||
|
|
26b7d101ab | ||
|
|
f3c3cdf0cb | ||
|
|
e62fa31485 | ||
|
|
5f283c1558 | ||
|
|
52163098d2 | ||
|
|
dfe27f0577 | ||
|
|
e415a3468f | ||
|
|
71302a52e4 | ||
|
|
762730eb0f | ||
|
|
3999a8a54d | ||
|
|
065291e146 | ||
|
|
99376aba1c | ||
|
|
698e8a0a95 | ||
|
|
b1b3a127dc | ||
|
|
ec55c95c71 | ||
|
|
e6eb2b473c | ||
|
|
a4b39820e4 | ||
|
|
4a20c81047 | ||
|
|
b72ab461e5 | ||
|
|
0be498d9bd | ||
|
|
00bad986e5 | ||
|
|
4710e84dcf | ||
|
|
ee55f8c884 | ||
|
|
3a74116e70 | ||
|
|
cfd83b5b4e | ||
|
|
e468261095 | ||
|
|
1362dc87df | ||
|
|
b89902bbdb | ||
|
|
f31b70a6dc | ||
|
|
47a1f0c4d5 | ||
|
|
3234b530d5 | ||
|
|
75d16544db | ||
|
|
7179b60116 | ||
|
|
7cb5d8254f | ||
|
|
6ab7ee6e4f | ||
|
|
a57ce55f8b | ||
|
|
190484762d | ||
|
|
78554ade5d | ||
|
|
364a13226a | ||
|
|
691813838c | ||
|
|
0defb0fadf | ||
|
|
08bf00ee37 | ||
|
|
522322ee2a | ||
|
|
062e3600e7 | ||
|
|
a92160f6d7 | ||
|
|
4adf967f7f | ||
|
|
fd6bd98a25 | ||
|
|
fe76f32778 | ||
|
|
897b4f2efe | ||
|
|
267f903ffe | ||
|
|
db884d0a6a | ||
|
|
d1190e7ddb | ||
|
|
dae8ab679e | ||
|
|
86ec9409c3 | ||
|
|
2c4ddb0c38 | ||
|
|
44d10f11ca | ||
|
|
6cf733b9c6 | ||
|
|
1eb6e2cedf | ||
|
|
ef4deaba8f | ||
|
|
e8c196c2fa | ||
|
|
f7c9db6353 | ||
|
|
4ce720ff97 | ||
|
|
a96011629b | ||
|
|
9dcdcf97e8 | ||
|
|
5148338f52 | ||
|
|
0d3c04d8f8 | ||
|
|
15328a14b4 | ||
|
|
2d092f722a | ||
|
|
8825cb9b9b | ||
|
|
2f17e303ab | ||
|
|
4b56c8a343 | ||
|
|
7b6b62c623 | ||
|
|
07f5e66491 | ||
|
|
fe633f3220 | ||
|
|
af1090553f | ||
|
|
92c2e66660 | ||
|
|
08372f9dcb | ||
|
|
64ea0e2eee | ||
|
|
7ab476a88f | ||
|
|
de41ca911d | ||
|
|
dde9688f96 | ||
|
|
c1ca63edc0 | ||
|
|
cbc430499f | ||
|
|
4da9fa4802 | ||
|
|
42586d9556 | ||
|
|
ea4387d4ab | ||
|
|
0707b515ab | ||
|
|
78ae71fc46 | ||
|
|
3f62cd40e7 | ||
|
|
47657c0093 | ||
|
|
a5b0fde4b6 | ||
|
|
78cc0b34b1 | ||
|
|
e3017e986b | ||
|
|
e12cd876db | ||
|
|
5292e4b814 | ||
|
|
dbdd16ab89 | ||
|
|
61c2600286 | ||
|
|
163a33ae3a | ||
|
|
37d064aa62 | ||
|
|
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 | ||
|
|
20190642a8 | ||
|
|
5d2068bd78 | ||
|
|
3a01944e30 | ||
|
|
014b6bce8d | ||
|
|
8f69399f1b | ||
|
|
200aa79dac | ||
|
|
dfb6f69d69 | ||
|
|
cd2fb2dd21 | ||
|
|
a396eb4f72 | ||
|
|
46675c944f | ||
|
|
ff7ad04f0b | ||
|
|
d69ede1447 | ||
|
|
b477cf9d51 | ||
|
|
ad8c27a2e6 | ||
|
|
52f9ae7ea1 | ||
|
|
ed1066662e | ||
|
|
e3bf6f03d7 | ||
|
|
8cc2ceecc6 | ||
|
|
9837172774 | ||
|
|
fba2a6dc68 | ||
|
|
a467ba08c6 | ||
|
|
7bfbb49efb | ||
|
|
7e4f5807d2 | ||
|
|
d5aee08f69 | ||
|
|
080d50c6bc | ||
|
|
3105622d63 | ||
|
|
eac181ff20 | ||
|
|
2a732cb343 | ||
|
|
da5e97143e | ||
|
|
9bdce69a2a | ||
|
|
8b1db34860 | ||
|
|
3c67d37e12 | ||
|
|
b73c2e979f | ||
|
|
a52fc29067 | ||
|
|
c6774d4be7 | ||
|
|
1271b3517d | ||
|
|
96914b3db4 | ||
|
|
7ad6d3369d | ||
|
|
0ae28d436b | ||
|
|
4575cf338f | ||
|
|
c526a9f207 | ||
|
|
1a3282c1ef | ||
|
|
f52e5b49c7 | ||
|
|
507fb6daf6 | ||
|
|
9d3fbd05fc | ||
|
|
2a0f884e89 | ||
|
|
26012bf27a | ||
|
|
3fa3dbaa8c | ||
|
|
95cac60c71 | ||
|
|
7878ce65ca | ||
|
|
c6c57a5de6 | ||
|
|
2ece3cd113 | ||
|
|
9504674933 | ||
|
|
3c0bdcea0e | ||
|
|
a4762d5b32 | ||
|
|
dc18bb5b8f | ||
|
|
452248e681 | ||
|
|
a7ea03014f | ||
|
|
cb89ca3426 | ||
|
|
760f7e1888 | ||
|
|
ba149568a5 | ||
|
|
2ef281bd0a | ||
|
|
859796cfe8 | ||
|
|
f1e0254f95 | ||
|
|
70d0827432 | ||
|
|
851a7af287 | ||
|
|
e46be7ba0a | ||
|
|
b4258dc11a | ||
|
|
0f35621846 | ||
|
|
374f919296 | ||
|
|
33b824b316 | ||
|
|
418e468f14 | ||
|
|
0a1f6a569d | ||
|
|
2a842d1c8c | ||
|
|
4f76991840 | ||
|
|
0487feb35e | ||
|
|
70308ed6eb | ||
|
|
bfdef5d296 | ||
|
|
a236c4a151 | ||
|
|
54d20b5573 | ||
|
|
ecd2b83cf0 | ||
|
|
80504e71c9 | ||
|
|
fb272c9c40 | ||
|
|
1c31477c37 | ||
|
|
2ecd286aa1 | ||
|
|
f28af456b3 | ||
|
|
c05b5e4c3d | ||
|
|
0f70f8212b | ||
|
|
f805e311b0 | ||
|
|
42f7bd298c | ||
|
|
e64d4f75b5 | ||
|
|
b972d5b7e5 | ||
|
|
f639c2c38b | ||
|
|
4e92155f5b | ||
|
|
78857c1b79 | ||
|
|
4e5d893850 | ||
|
|
a1fe446c2a | ||
|
|
f126a309f0 | ||
|
|
b2b129389a | ||
|
|
f2386fc9d8 | ||
|
|
d625a91ed7 | ||
|
|
b5f8d2d44e | ||
|
|
206b053d27 | ||
|
|
a2d16d7643 | ||
|
|
89345fd8eb | ||
|
|
4abf7fbba2 | ||
|
|
b5987927be | ||
|
|
bfef9b9498 | ||
|
|
6b4bbd8410 | ||
|
|
05f89073cd | ||
|
|
3776d6e11f | ||
|
|
2e301760f4 | ||
|
|
2817b5914f | ||
|
|
8276d8d720 | ||
|
|
711c7c14f7 | ||
|
|
f651f53ee6 | ||
|
|
c00ea88f73 | ||
|
|
583c83643a | ||
|
|
0775ede344 | ||
|
|
bf8ecdbe7a | ||
|
|
ed81d53175 | ||
|
|
4543e56c61 | ||
|
|
401724b66b | ||
|
|
b0773f5102 | ||
|
|
cff9289c39 | ||
|
|
69cfac1c6f | ||
|
|
0b05315671 | ||
|
|
af9c96c002 | ||
|
|
f1d4973f59 | ||
|
|
25db16c47f | ||
|
|
1286974fb6 | ||
|
|
997c045312 | ||
|
|
71c2e64daf | ||
|
|
1c2368f5a1 | ||
|
|
208eb22b8c | ||
|
|
25e32589d4 | ||
|
|
1727f0d193 | ||
|
|
0faffc2167 | ||
|
|
999649a095 | ||
|
|
cfb8e6ea55 |
50
.github/CONTRIBUTING.md
vendored
Normal file
50
.github/CONTRIBUTING.md
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
# Contributing Guidelines
|
||||
|
||||
## Asking Questions
|
||||
Before submitting a question, please check the [Troubleshooting Guide](https://docs.lubelogger.com/Installation/Troubleshooting) and search through existing issues.
|
||||
|
||||
Ideally, the Issues tab should only consist of bug reports and feature requests instead of debugging your LubeLogger installation.
|
||||
|
||||
## Feature Requests
|
||||
Feature Requests are cool, but we do want to avoid bloat and scope/feature creep.
|
||||
|
||||
Read [this](https://github.com/hargata/lubelog/wiki/Scope-and-Purpose) to better understand the scope and purpose of this project.
|
||||
|
||||
LubeLogger is a Vehicle Maintenance and Fuel Mileage Tracker.
|
||||
It is not and should not be used for the following:
|
||||
- Project Management Software(e.g.: Jira)
|
||||
- Budget Management(e.g: YNAB/Actual)
|
||||
- Inventory Management
|
||||
|
||||
Before submitting a feature request, please consider the following:
|
||||
- Will this feature benefit more than just a niche subset of users
|
||||
- Will this feature result in scope creep
|
||||
- Has this feature already been requested/exist
|
||||
|
||||
## Bug Reports
|
||||
Please fill out the issue template for bug reports.
|
||||
|
||||
## Security Vulnerabilities
|
||||
Contact us via [Email](mailto:hargatasoftworks@gmail.com)
|
||||
|
||||
## Submitting Pull Requests
|
||||
Pull Requests are welcome, but please consider the following:
|
||||
|
||||
CI/CD, Bugs, Tech-Debt Related PRs:
|
||||
- Make sure changes are not breaking.
|
||||
- If any dependencies are added, they must be cross-platform compatible.
|
||||
- Please test changes thoroughly.
|
||||
|
||||
Feature Related PRs:
|
||||
- Have you requested this feature in the Issues tab
|
||||
- Will this feature benefit more than just a niche subset of users
|
||||
- Will this feature result in scope creep
|
||||
- Do these changes fix a root cause or is it simply a workaround
|
||||
|
||||
Ideally, you should first submit a feature request in the Issues tab before submitting a PR just in case it's something we are already working on.
|
||||
|
||||
Note the following:
|
||||
|
||||
We(the maintainers) are not responsible for cleaning up, testing, or fixing your changes.
|
||||
|
||||
If your changes doesn't have a wide-ranging use-case, has not been thoroughly tested, or cannot be easily maintained, we won't merge your PR.
|
||||
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: "[BUG]"
|
||||
labels: bug
|
||||
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/Installation/Troubleshooting)
|
||||
- [ ] I have searched through existing issues.
|
||||
|
||||
**Description**
|
||||
<!-- Describe the bug below this line -->
|
||||
|
||||
**Platform**
|
||||
- [ ] Docker Image
|
||||
- [ ] Windows/Linux 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 -->
|
||||
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: "[FEATURE REQUEST]"
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Checklist**
|
||||
Please make sure you have performed the following steps before submitting a new feature request, change `[ ]` to `[x]` to mark it as done
|
||||
|
||||
- [ ] I have read the [Contributing Guidelines](https://github.com/hargata/lubelog/blob/main/.github/CONTRIBUTING.md) and [Scope and Purpose](https://github.com/hargata/lubelog/wiki/Scope-and-Purpose)
|
||||
- [ ] I have searched through existing issues.
|
||||
|
||||
**Description**
|
||||
<!-- Describe the feature request below this line -->
|
||||
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 }}
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,8 +1,6 @@
|
||||
.vs/
|
||||
bin/
|
||||
obj/
|
||||
wwwroot/images/
|
||||
cartracker.db
|
||||
wwwroot/documents/
|
||||
wwwroot/temp/
|
||||
wwwroot/imports/
|
||||
data/
|
||||
CarCareTracker.csproj.user
|
||||
Properties/launchSettings.json
|
||||
|
||||
@ -11,8 +11,11 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
||||
<PackageReference Include="CsvHelper" Version="33.1.0" />
|
||||
<PackageReference Include="LiteDB" Version="5.0.17" />
|
||||
<PackageReference Include="MailKit" Version="4.14.1" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.14.0" />
|
||||
<PackageReference Include="Npgsql" Version="9.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
</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>
|
||||
@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.8.34330.188
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CarCareTracker", "CarCareTracker.csproj", "{0DB85611-6555-4127-A66E-DADD25A16526}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CarCareTracker", "CarCareTracker.csproj", "{0DB85611-6555-4127-A66E-DADD25A16526}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
||||
2730
Controllers/APIController.cs
Normal file
2730
Controllers/APIController.cs
Normal file
File diff suppressed because it is too large
Load Diff
118
Controllers/AdminController.cs
Normal file
118
Controllers/AdminController.cs
Normal file
@ -0,0 +1,118 @@
|
||||
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().OrderBy(x=>x.Id).ToList(),
|
||||
Tokens = _loginLogic.GetAllTokens()
|
||||
};
|
||||
return View(viewModel);
|
||||
}
|
||||
public IActionResult GetTokenPartialView()
|
||||
{
|
||||
var viewModel = _loginLogic.GetAllTokens();
|
||||
return PartialView("_Tokens", viewModel);
|
||||
}
|
||||
public IActionResult GetUserPartialView()
|
||||
{
|
||||
var viewModel = _loginLogic.GetAllUsers().OrderBy(x => x.Id).ToList();
|
||||
return PartialView("_Users", viewModel);
|
||||
}
|
||||
public IActionResult GenerateNewToken(string emailAddress, bool autoNotify)
|
||||
{
|
||||
if (emailAddress.Contains(","))
|
||||
{
|
||||
string[] emailAddresses = emailAddress.Split(',');
|
||||
foreach(string emailAdd in emailAddresses)
|
||||
{
|
||||
var trimmedEmail = emailAdd.Trim();
|
||||
if (!string.IsNullOrWhiteSpace(trimmedEmail))
|
||||
{
|
||||
var result = _loginLogic.GenerateUserToken(emailAdd.Trim(), autoNotify);
|
||||
if (!result.Success)
|
||||
{
|
||||
//if fail, return prematurely
|
||||
return Json(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
var successResponse = OperationResponse.Succeed("Token Generated!");
|
||||
return Json(successResponse);
|
||||
} else
|
||||
{
|
||||
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)
|
||||
&& _userLogic.DeleteAllHouseholdByChildUserId(userId)
|
||||
&& _userLogic.DeleteAllHouseholdByParentUserId(userId);
|
||||
return Json(result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult UpdateUserAdminStatus(int userId, bool isAdmin)
|
||||
{
|
||||
var result = _loginLogic.MakeUserAdmin(userId, isAdmin);
|
||||
return Json(result);
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetUserHouseholdModal(int userId)
|
||||
{
|
||||
var households = _userLogic.GetHouseholdForParentUserId(userId);
|
||||
if (households.Any())
|
||||
{
|
||||
households = households.OrderBy(x => x.UserName).ToList();
|
||||
}
|
||||
var viewModel = new UserHouseholdAdminViewModel { Households = households, ParentUserId = userId };
|
||||
return PartialView("_AdminUserHouseholdModal", viewModel);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult RemoveUserFromHousehold(int parentUserId, int childUserId)
|
||||
{
|
||||
var result = _userLogic.DeleteUserFromHousehold(parentUserId, childUserId);
|
||||
return Json(result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult AddUserToHousehold(int parentUserId, string username)
|
||||
{
|
||||
var result = _userLogic.AddUserToHousehold(parentUserId, username);
|
||||
return Json(result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult ModifyUserHouseholdPermissions(int parentUserId, int childUserId, List<HouseholdPermission> permissions)
|
||||
{
|
||||
var result = _userLogic.UpdateUserHousehold(parentUserId, childUserId, permissions);
|
||||
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("APIAuth"))
|
||||
{
|
||||
Response.StatusCode = 403;
|
||||
return new EmptyResult();
|
||||
}
|
||||
return View("401");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,5 @@
|
||||
using CarCareTracker.External.Interfaces;
|
||||
using CarCareTracker.Models;
|
||||
using LiteDB;
|
||||
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 Microsoft.AspNetCore.Authorization;
|
||||
|
||||
@ -33,6 +26,26 @@ namespace CarCareTracker.Controllers
|
||||
return Json(fileName);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public IActionResult HandleTranslationFileUpload(IFormFile file)
|
||||
{
|
||||
var originalFileName = Path.GetFileNameWithoutExtension(file.FileName);
|
||||
if (originalFileName == "en_US")
|
||||
{
|
||||
return Json(OperationResponse.Failed("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(OperationResponse.Conditional(result));
|
||||
}
|
||||
return Json(OperationResponse.Failed());
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public IActionResult HandleMultipleFileUpload(List<IFormFile> file)
|
||||
{
|
||||
@ -40,22 +53,35 @@ namespace CarCareTracker.Controllers
|
||||
foreach (IFormFile fileToUpload in file)
|
||||
{
|
||||
var fileName = UploadFile(fileToUpload);
|
||||
uploadedFiles.Add(new UploadedFiles { Name = fileToUpload.FileName, Location = fileName});
|
||||
uploadedFiles.Add(new UploadedFiles { Name = fileToUpload.FileName, Location = fileName, IsPending = true});
|
||||
}
|
||||
return Json(uploadedFiles);
|
||||
}
|
||||
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
[HttpPost]
|
||||
public ActionResult DeleteFiles(string fileLocation)
|
||||
public IActionResult DeleteFiles(string fileLocation)
|
||||
{
|
||||
var result = _fileHelper.DeleteFile(fileLocation);
|
||||
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)
|
||||
{
|
||||
string uploadDirectory = "temp/";
|
||||
string uploadPath = Path.Combine(_webEnv.WebRootPath, uploadDirectory);
|
||||
string uploadPath = Path.Combine(_webEnv.ContentRootPath, "data", uploadDirectory);
|
||||
if (!Directory.Exists(uploadPath))
|
||||
Directory.CreateDirectory(uploadPath);
|
||||
string fileName = Guid.NewGuid() + Path.GetExtension(fileToUpload.FileName);
|
||||
@ -66,5 +92,23 @@ namespace CarCareTracker.Controllers
|
||||
}
|
||||
return Path.Combine("/", uploadDirectory, fileName);
|
||||
}
|
||||
public IActionResult UploadCoordinates(List<string> coordinates)
|
||||
{
|
||||
string uploadDirectory = "temp/";
|
||||
string uploadPath = Path.Combine(_webEnv.ContentRootPath, "data", uploadDirectory);
|
||||
if (!Directory.Exists(uploadPath))
|
||||
Directory.CreateDirectory(uploadPath);
|
||||
string fileName = Guid.NewGuid() + ".csv";
|
||||
string filePath = Path.Combine(uploadPath, fileName);
|
||||
string fileData = string.Join("\r\n", coordinates);
|
||||
System.IO.File.WriteAllText(filePath, fileData);
|
||||
var uploadedFile = new UploadedFiles { Name = "coordinates.csv", Location = Path.Combine("/", uploadDirectory, fileName), IsPending = true };
|
||||
return Json(uploadedFile);
|
||||
}
|
||||
public IActionResult PreviewFile(string fileName, string fileLocation)
|
||||
{
|
||||
var viewModel = new UploadedFiles { Name = fileName, Location = fileLocation };
|
||||
return PartialView("_AttachmentPreview", viewModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
using CarCareTracker.External.Interfaces;
|
||||
using CarCareTracker.Models;
|
||||
using LiteDB;
|
||||
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 Microsoft.AspNetCore.Authorization;
|
||||
using System.Security.Claims;
|
||||
using CarCareTracker.Logic;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace CarCareTracker.Controllers
|
||||
{
|
||||
@ -17,70 +16,681 @@ namespace CarCareTracker.Controllers
|
||||
{
|
||||
private readonly ILogger<HomeController> _logger;
|
||||
private readonly IVehicleDataAccess _dataAccess;
|
||||
private readonly IUserLogic _userLogic;
|
||||
private readonly ILoginLogic _loginLogic;
|
||||
private readonly IVehicleLogic _vehicleLogic;
|
||||
private readonly IFileHelper _fileHelper;
|
||||
private readonly IConfiguration _config;
|
||||
|
||||
public HomeController(ILogger<HomeController> logger, IVehicleDataAccess dataAccess, IFileHelper fileHelper, IConfiguration configuration)
|
||||
private readonly IConfigHelper _config;
|
||||
private readonly IExtraFieldDataAccess _extraFieldDataAccess;
|
||||
private readonly IReminderRecordDataAccess _reminderRecordDataAccess;
|
||||
private readonly IReminderHelper _reminderHelper;
|
||||
private readonly ITranslationHelper _translationHelper;
|
||||
private readonly IMailHelper _mailHelper;
|
||||
public HomeController(ILogger<HomeController> logger,
|
||||
IVehicleDataAccess dataAccess,
|
||||
IUserLogic userLogic,
|
||||
ILoginLogic loginLogic,
|
||||
IVehicleLogic vehicleLogic,
|
||||
IConfigHelper configuration,
|
||||
IFileHelper fileHelper,
|
||||
IExtraFieldDataAccess extraFieldDataAccess,
|
||||
IReminderRecordDataAccess reminderRecordDataAccess,
|
||||
IReminderHelper reminderHelper,
|
||||
ITranslationHelper translationHelper,
|
||||
IMailHelper mailHelper)
|
||||
{
|
||||
_logger = logger;
|
||||
_dataAccess = dataAccess;
|
||||
_fileHelper = fileHelper;
|
||||
_config = configuration;
|
||||
_userLogic = userLogic;
|
||||
_fileHelper = fileHelper;
|
||||
_extraFieldDataAccess = extraFieldDataAccess;
|
||||
_reminderRecordDataAccess = reminderRecordDataAccess;
|
||||
_reminderHelper = reminderHelper;
|
||||
_loginLogic = loginLogic;
|
||||
_vehicleLogic = vehicleLogic;
|
||||
_translationHelper = translationHelper;
|
||||
_mailHelper = mailHelper;
|
||||
}
|
||||
|
||||
public IActionResult Index(string tab = "garage")
|
||||
private int GetUserID()
|
||||
{
|
||||
return View(model: tab);
|
||||
return int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier));
|
||||
}
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
[Route("/kiosk")]
|
||||
public IActionResult Kiosk(string exclusions, KioskMode kioskMode = KioskMode.Vehicle)
|
||||
{
|
||||
try {
|
||||
var viewModel = new KioskViewModel
|
||||
{
|
||||
Exclusions = string.IsNullOrWhiteSpace(exclusions) ? new List<int>() : exclusions.Split(',').Select(x => int.Parse(x)).ToList(),
|
||||
KioskMode = kioskMode
|
||||
};
|
||||
return View(viewModel);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return View(new KioskViewModel());
|
||||
}
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult KioskContent(KioskViewModel kioskParameters)
|
||||
{
|
||||
var vehiclesStored = _dataAccess.GetVehicles();
|
||||
if (!User.IsInRole(nameof(UserData.IsRootUser)))
|
||||
{
|
||||
vehiclesStored = _userLogic.FilterUserVehicles(vehiclesStored, GetUserID());
|
||||
}
|
||||
vehiclesStored.RemoveAll(x => kioskParameters.Exclusions.Contains(x.Id));
|
||||
var userConfig = _config.GetUserConfig(User);
|
||||
if (userConfig.HideSoldVehicles)
|
||||
{
|
||||
vehiclesStored.RemoveAll(x => !string.IsNullOrWhiteSpace(x.SoldDate));
|
||||
}
|
||||
switch (kioskParameters.KioskMode)
|
||||
{
|
||||
case KioskMode.Vehicle:
|
||||
{
|
||||
var kioskResult = _vehicleLogic.GetVehicleInfo(vehiclesStored);
|
||||
return PartialView("_Kiosk", kioskResult);
|
||||
}
|
||||
case KioskMode.Plan:
|
||||
{
|
||||
var kioskResult = _vehicleLogic.GetPlans(vehiclesStored, true);
|
||||
return PartialView("_KioskPlan", kioskResult);
|
||||
}
|
||||
case KioskMode.Reminder:
|
||||
{
|
||||
var kioskResult = _vehicleLogic.GetReminders(vehiclesStored, false);
|
||||
return PartialView("_KioskReminder", kioskResult);
|
||||
}
|
||||
}
|
||||
var result = _vehicleLogic.GetVehicleInfo(vehiclesStored);
|
||||
return PartialView("_Kiosk", result);
|
||||
}
|
||||
public IActionResult Garage()
|
||||
{
|
||||
var vehiclesStored = _dataAccess.GetVehicles();
|
||||
return PartialView("_GarageDisplay", vehiclesStored);
|
||||
}
|
||||
public IActionResult Settings()
|
||||
{
|
||||
var userConfig = new UserConfig
|
||||
if (!User.IsInRole(nameof(UserData.IsRootUser)))
|
||||
{
|
||||
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)])
|
||||
vehiclesStored = _userLogic.FilterUserVehicles(vehiclesStored, GetUserID());
|
||||
}
|
||||
var vehicleViewModels = vehiclesStored.Select(x =>
|
||||
{
|
||||
var vehicleVM = new VehicleViewModel
|
||||
{
|
||||
Id = x.Id,
|
||||
ImageLocation = x.ImageLocation,
|
||||
Year = x.Year,
|
||||
Make = x.Make,
|
||||
Model = x.Model,
|
||||
LicensePlate = x.LicensePlate,
|
||||
SoldDate = x.SoldDate,
|
||||
IsElectric = x.IsElectric,
|
||||
IsDiesel = x.IsDiesel,
|
||||
UseHours = x.UseHours,
|
||||
OdometerOptional = x.OdometerOptional,
|
||||
ExtraFields = x.ExtraFields,
|
||||
Tags = x.Tags,
|
||||
DashboardMetrics = x.DashboardMetrics,
|
||||
VehicleIdentifier = x.VehicleIdentifier
|
||||
};
|
||||
//dashboard metrics
|
||||
if (x.DashboardMetrics.Any())
|
||||
{
|
||||
var vehicleRecords = _vehicleLogic.GetVehicleRecords(x.Id);
|
||||
var userConfig = _config.GetUserConfig(User);
|
||||
var distanceUnit = x.UseHours ? "h" : userConfig.UseMPG ? "mi." : "km";
|
||||
if (vehicleVM.DashboardMetrics.Contains(DashboardMetric.Default))
|
||||
{
|
||||
vehicleVM.LastReportedMileage = _vehicleLogic.GetMaxMileage(vehicleRecords);
|
||||
vehicleVM.HasReminders = _vehicleLogic.GetVehicleHasUrgentOrPastDueReminders(x.Id, vehicleVM.LastReportedMileage);
|
||||
}
|
||||
if (vehicleVM.DashboardMetrics.Contains(DashboardMetric.CostPerMile))
|
||||
{
|
||||
var vehicleTotalCost = _vehicleLogic.GetVehicleTotalCost(vehicleRecords);
|
||||
var maxMileage = _vehicleLogic.GetMaxMileage(vehicleRecords);
|
||||
var minMileage = _vehicleLogic.GetMinMileage(vehicleRecords);
|
||||
var totalDistance = maxMileage - minMileage;
|
||||
vehicleVM.CostPerMile = totalDistance != default ? vehicleTotalCost / totalDistance : 0.00M;
|
||||
vehicleVM.DistanceUnit = distanceUnit;
|
||||
}
|
||||
if (vehicleVM.DashboardMetrics.Contains(DashboardMetric.TotalCost))
|
||||
{
|
||||
vehicleVM.TotalCost = _vehicleLogic.GetVehicleTotalCost(vehicleRecords);
|
||||
}
|
||||
}
|
||||
return vehicleVM;
|
||||
}).ToList();
|
||||
return PartialView("_GarageDisplay", vehicleViewModels);
|
||||
}
|
||||
public IActionResult Calendar()
|
||||
{
|
||||
var vehiclesStored = _dataAccess.GetVehicles();
|
||||
if (!User.IsInRole(nameof(UserData.IsRootUser)))
|
||||
{
|
||||
vehiclesStored = _userLogic.FilterUserVehicles(vehiclesStored, GetUserID());
|
||||
}
|
||||
var reminders = _vehicleLogic.GetReminders(vehiclesStored, true);
|
||||
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);
|
||||
return PartialView("_Settings", viewModel);
|
||||
}
|
||||
public async Task<IActionResult> Sponsors()
|
||||
{
|
||||
try
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
var sponsorsData = await httpClient.GetFromJsonAsync<Sponsors>(StaticHelper.SponsorsPath) ?? new Sponsors();
|
||||
return PartialView("_Sponsors", sponsorsData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"Unable to retrieve sponsors: {ex.Message}");
|
||||
return PartialView("_Sponsors", new Sponsors());
|
||||
}
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult WriteToSettings(UserConfig userConfig)
|
||||
{
|
||||
//retrieve existing userConfig.
|
||||
var existingConfig = _config.GetUserConfig(User);
|
||||
//copy over stuff that persists
|
||||
userConfig.UserColumnPreferences = existingConfig.UserColumnPreferences;
|
||||
var result = _config.SaveUserConfig(User, userConfig);
|
||||
return Json(result);
|
||||
}
|
||||
[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 configFileContents = System.IO.File.ReadAllText("userConfig.json");
|
||||
var existingUserConfig = System.Text.Json.JsonSerializer.Deserialize<UserConfig>(configFileContents);
|
||||
if (existingUserConfig is not null)
|
||||
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))
|
||||
{
|
||||
//copy over settings that are off limits on the settings page.
|
||||
userConfig.EnableAuth = existingUserConfig.EnableAuth;
|
||||
userConfig.UserNameHash = existingUserConfig.UserNameHash;
|
||||
userConfig.UserPasswordHash = existingUserConfig.UserPasswordHash;
|
||||
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(OperationResponse.Failed());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return Json(OperationResponse.Failed());
|
||||
}
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetUserAccountInformationModal()
|
||||
{
|
||||
var emailAddress = User.FindFirstValue(ClaimTypes.Email);
|
||||
var userName = User.Identity.Name;
|
||||
return PartialView("_AccountModal", new UserData() { EmailAddress = emailAddress, UserName = userName });
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetHouseholdModal()
|
||||
{
|
||||
var households = _userLogic.GetHouseholdForParentUserId(GetUserID());
|
||||
if (households.Any())
|
||||
{
|
||||
households = households.OrderBy(x => x.UserName).ToList();
|
||||
}
|
||||
var userhouseholds = _userLogic.GetHouseholdForChildUserId(GetUserID());
|
||||
if (userhouseholds.Any())
|
||||
{
|
||||
userhouseholds = userhouseholds.OrderBy(x => x.UserName).ToList();
|
||||
}
|
||||
var viewModel = new UserHouseholdUserViewModel()
|
||||
{
|
||||
Households = households,
|
||||
UserHouseholds = userhouseholds
|
||||
};
|
||||
return PartialView("_UserHouseholdModal", viewModel);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult RemoveUserFromHousehold(int userId)
|
||||
{
|
||||
var result = _userLogic.DeleteUserFromHousehold(GetUserID(), userId);
|
||||
return Json(result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult LeaveHousehold(int userId)
|
||||
{
|
||||
var result = _userLogic.DeleteUserFromHousehold(userId, GetUserID());
|
||||
return Json(result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult ModifyUserHouseholdPermissions(int userId, List<HouseholdPermission> permissions)
|
||||
{
|
||||
var result = _userLogic.UpdateUserHousehold(GetUserID(), userId, permissions);
|
||||
return Json(result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult AddUserToHousehold(string username)
|
||||
{
|
||||
var result = _userLogic.AddUserToHousehold(GetUserID(), username);
|
||||
return Json(result);
|
||||
}
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
[HttpGet]
|
||||
public IActionResult GetRootAccountInformationModal()
|
||||
{
|
||||
var userName = User.Identity.Name;
|
||||
return PartialView("_RootAccountModal", new UserData() { UserName = userName });
|
||||
}
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
[HttpGet]
|
||||
public IActionResult GetTranslatorEditor(string userLanguage)
|
||||
{
|
||||
var translationData = _translationHelper.GetTranslations(userLanguage);
|
||||
return PartialView("_TranslationEditor", translationData);
|
||||
}
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
[HttpPost]
|
||||
public IActionResult SaveTranslation(IFormFile file)
|
||||
{
|
||||
var userLanguage = Path.GetFileNameWithoutExtension(file.FileName);
|
||||
var translationData = new Dictionary<string, string>();
|
||||
using (var sReader = new StreamReader(file.OpenReadStream()))
|
||||
{
|
||||
var sData = sReader.ReadToEnd();
|
||||
translationData = JsonSerializer.Deserialize<Dictionary<string, string>>(sData);
|
||||
}
|
||||
var result = _translationHelper.SaveTranslation(userLanguage, translationData);
|
||||
return Json(result);
|
||||
}
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
[HttpPost]
|
||||
public IActionResult ExportTranslation(IFormFile file)
|
||||
{
|
||||
var result = string.Empty;
|
||||
using (var sReader = new StreamReader(file.OpenReadStream()))
|
||||
{
|
||||
var fileName = $"{Guid.NewGuid()}.json";
|
||||
var sData = sReader.ReadToEnd();
|
||||
result = _fileHelper.WriteFileToTemp(fileName, sData);
|
||||
}
|
||||
return Json(result);
|
||||
}
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAvailableTranslations()
|
||||
{
|
||||
try
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
var translations = await httpClient.GetFromJsonAsync<Translations>(StaticHelper.TranslationDirectoryPath) ?? new Translations();
|
||||
return PartialView("_Translations", translations);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"Unable to retrieve translations: {ex.Message}");
|
||||
return PartialView("_Translations", new Translations());
|
||||
}
|
||||
}
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> DownloadTranslation(string continent, string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
var translationData = await httpClient.GetFromJsonAsync<Dictionary<string, string>>(StaticHelper.GetTranslationDownloadPath(continent, name)) ?? new Dictionary<string, string>();
|
||||
if (translationData.Any())
|
||||
{
|
||||
var result = _translationHelper.SaveTranslation(name, translationData);
|
||||
if (!result.Success)
|
||||
{
|
||||
return Json(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError($"Unable to download translation: {name}");
|
||||
return Json(false);
|
||||
}
|
||||
return Json(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"Unable to download translation: {ex.Message}");
|
||||
return Json(false);
|
||||
}
|
||||
}
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> DownloadAllTranslations()
|
||||
{
|
||||
try
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
var translations = await httpClient.GetFromJsonAsync<Translations>(StaticHelper.TranslationDirectoryPath) ?? new Translations();
|
||||
int translationsDownloaded = 0;
|
||||
foreach (string translation in translations.Asia)
|
||||
{
|
||||
try
|
||||
{
|
||||
var translationData = await httpClient.GetFromJsonAsync<Dictionary<string, string>>(StaticHelper.GetTranslationDownloadPath("Asia", translation)) ?? new Dictionary<string, string>();
|
||||
if (translationData.Any())
|
||||
{
|
||||
var result = _translationHelper.SaveTranslation(translation, translationData);
|
||||
if (result.Success)
|
||||
{
|
||||
translationsDownloaded++;
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"Error Downloading Translation {translation}: {ex.Message} ");
|
||||
}
|
||||
}
|
||||
foreach (string translation in translations.Africa)
|
||||
{
|
||||
try
|
||||
{
|
||||
var translationData = await httpClient.GetFromJsonAsync<Dictionary<string, string>>(StaticHelper.GetTranslationDownloadPath("Africa", translation)) ?? new Dictionary<string, string>();
|
||||
if (translationData.Any())
|
||||
{
|
||||
var result = _translationHelper.SaveTranslation(translation, translationData);
|
||||
if (result.Success)
|
||||
{
|
||||
translationsDownloaded++;
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"Error Downloading Translation {translation}: {ex.Message} ");
|
||||
}
|
||||
}
|
||||
foreach (string translation in translations.Europe)
|
||||
{
|
||||
try
|
||||
{
|
||||
var translationData = await httpClient.GetFromJsonAsync<Dictionary<string, string>>(StaticHelper.GetTranslationDownloadPath("Europe", translation)) ?? new Dictionary<string, string>();
|
||||
if (translationData.Any())
|
||||
{
|
||||
var result = _translationHelper.SaveTranslation(translation, translationData);
|
||||
if (result.Success)
|
||||
{
|
||||
translationsDownloaded++;
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"Error Downloading Translation {translation}: {ex.Message} ");
|
||||
}
|
||||
}
|
||||
foreach (string translation in translations.NorthAmerica)
|
||||
{
|
||||
try
|
||||
{
|
||||
var translationData = await httpClient.GetFromJsonAsync<Dictionary<string, string>>(StaticHelper.GetTranslationDownloadPath("NorthAmerica", translation)) ?? new Dictionary<string, string>();
|
||||
if (translationData.Any())
|
||||
{
|
||||
var result = _translationHelper.SaveTranslation(translation, translationData);
|
||||
if (result.Success)
|
||||
{
|
||||
translationsDownloaded++;
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"Error Downloading Translation {translation}: {ex.Message} ");
|
||||
}
|
||||
}
|
||||
foreach (string translation in translations.SouthAmerica)
|
||||
{
|
||||
try
|
||||
{
|
||||
var translationData = await httpClient.GetFromJsonAsync<Dictionary<string, string>>(StaticHelper.GetTranslationDownloadPath("SouthAmerica", translation)) ?? new Dictionary<string, string>();
|
||||
if (translationData.Any())
|
||||
{
|
||||
var result = _translationHelper.SaveTranslation(translation, translationData);
|
||||
if (result.Success)
|
||||
{
|
||||
translationsDownloaded++;
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"Error Downloading Translation {translation}: {ex.Message} ");
|
||||
}
|
||||
}
|
||||
foreach (string translation in translations.Oceania)
|
||||
{
|
||||
try
|
||||
{
|
||||
var translationData = await httpClient.GetFromJsonAsync<Dictionary<string, string>>(StaticHelper.GetTranslationDownloadPath("Oceania", translation)) ?? new Dictionary<string, string>();
|
||||
if (translationData.Any())
|
||||
{
|
||||
var result = _translationHelper.SaveTranslation(translation, translationData);
|
||||
if (result.Success)
|
||||
{
|
||||
translationsDownloaded++;
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"Error Downloading Translation {translation}: {ex.Message} ");
|
||||
}
|
||||
}
|
||||
if (translationsDownloaded > 0)
|
||||
{
|
||||
return Json(OperationResponse.Succeed($"{translationsDownloaded} Translations Downloaded"));
|
||||
} else
|
||||
{
|
||||
userConfig.EnableAuth = false;
|
||||
userConfig.UserNameHash = string.Empty;
|
||||
userConfig.UserPasswordHash = string.Empty;
|
||||
return Json(OperationResponse.Failed("No Translations Downloaded"));
|
||||
}
|
||||
System.IO.File.WriteAllText("userConfig.json", System.Text.Json.JsonSerializer.Serialize(userConfig));
|
||||
return Json(true);
|
||||
} catch (Exception ex)
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error on saving config file.");
|
||||
_logger.LogError($"Unable to retrieve translations: {ex.Message}");
|
||||
return Json(OperationResponse.Failed());
|
||||
}
|
||||
}
|
||||
public ActionResult GetVehicleSelector(int vehicleId)
|
||||
{
|
||||
var vehiclesStored = _dataAccess.GetVehicles();
|
||||
if (!User.IsInRole(nameof(UserData.IsRootUser)))
|
||||
{
|
||||
vehiclesStored = _userLogic.FilterUserVehicles(vehiclesStored, GetUserID());
|
||||
}
|
||||
if (vehicleId != default)
|
||||
{
|
||||
vehiclesStored.RemoveAll(x => x.Id == vehicleId);
|
||||
}
|
||||
var userConfig = _config.GetUserConfig(User);
|
||||
if (userConfig.HideSoldVehicles)
|
||||
{
|
||||
vehiclesStored.RemoveAll(x => !string.IsNullOrWhiteSpace(x.SoldDate));
|
||||
}
|
||||
return PartialView("_VehicleSelector", vehiclesStored);
|
||||
}
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
[HttpGet]
|
||||
public IActionResult GetCustomWidgetEditor()
|
||||
{
|
||||
if (_config.GetCustomWidgetsEnabled())
|
||||
{
|
||||
var customWidgetData = _fileHelper.GetWidgets();
|
||||
return PartialView("_WidgetEditor", customWidgetData);
|
||||
}
|
||||
return Json(string.Empty);
|
||||
}
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
[HttpPost]
|
||||
public IActionResult SaveCustomWidgets(string widgetsData)
|
||||
{
|
||||
if (_config.GetCustomWidgetsEnabled())
|
||||
{
|
||||
var saveResult = _fileHelper.SaveWidgets(widgetsData);
|
||||
return Json(saveResult);
|
||||
}
|
||||
return Json(false);
|
||||
}
|
||||
public IActionResult Privacy()
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
[HttpPost]
|
||||
public IActionResult DeleteCustomWidgets()
|
||||
{
|
||||
return View();
|
||||
if (_config.GetCustomWidgetsEnabled())
|
||||
{
|
||||
var deleteResult = _fileHelper.DeleteWidgets();
|
||||
return Json(deleteResult);
|
||||
}
|
||||
return Json(false);
|
||||
}
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
public IActionResult GetLocaleSample(string locale, string dtlocale)
|
||||
{
|
||||
var cultureInfo = new CultureInfo(locale);
|
||||
if (!string.IsNullOrWhiteSpace(dtlocale))
|
||||
{
|
||||
var datetimeCulture = CultureInfo.GetCultureInfo(dtlocale);
|
||||
cultureInfo.DateTimeFormat = datetimeCulture.DateTimeFormat;
|
||||
}
|
||||
var viewModel = new LocaleSample
|
||||
{
|
||||
ShortDateSample = DateTime.Now.ToString(cultureInfo.DateTimeFormat.ShortDatePattern, cultureInfo.DateTimeFormat),
|
||||
ShortDateTimeSample = DateTime.Now.ToString("G", cultureInfo.DateTimeFormat),
|
||||
CurrencySample = 13.45M.ToString("C", cultureInfo),
|
||||
NumberSample = 123456.ToString("N", cultureInfo),
|
||||
DecimalSample = 123456.78M.ToString("N2", cultureInfo)
|
||||
};
|
||||
return PartialView("_LocaleSample", viewModel);
|
||||
}
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
public async Task<IActionResult> ImportOpenIDConfiguration(string configUrl)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(configUrl))
|
||||
{
|
||||
try
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
var openIdConfig = await httpClient.GetFromJsonAsync<OpenIDProviderConfig>(configUrl);
|
||||
return Json(openIdConfig);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"Unable to retrieve OpenID Provider Config: {ex.Message}");
|
||||
}
|
||||
}
|
||||
return Json(new OpenIDProviderConfig());
|
||||
}
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
[Route("/setup")]
|
||||
public IActionResult Setup()
|
||||
{
|
||||
var installedLocales = CultureInfo.GetCultures(CultureTypes.AllCultures).Select(x=>x.Name).ToList();
|
||||
installedLocales.RemoveAll(x => string.IsNullOrWhiteSpace(x));
|
||||
installedLocales.Insert(0, "");
|
||||
var viewModel = new ServerSettingsViewModel
|
||||
{
|
||||
LocaleOverride = _config.GetLocaleOverride(),
|
||||
LocaleDateTimeOverride = _config.GetLocaleDateTimeOverride(),
|
||||
AvailableLocales = installedLocales,
|
||||
PostgresConnection = _config.GetServerPostgresConnection(),
|
||||
AllowedFileExtensions = _config.GetAllowedFileUploadExtensions(),
|
||||
CustomLogoURL = _config.GetLogoUrl(),
|
||||
CustomSmallLogoURL = _config.GetSmallLogoUrl(),
|
||||
MessageOfTheDay = _config.GetMOTD(),
|
||||
WebHookURL = _config.GetWebHookUrl(),
|
||||
CustomWidgetsEnabled = _config.GetCustomWidgetsEnabled(),
|
||||
InvariantAPIEnabled = _config.GetInvariantApi(),
|
||||
SMTPConfig = _config.GetMailConfig(),
|
||||
Domain = _config.GetServerDomain(),
|
||||
OIDCConfig = _config.GetOpenIDConfig(),
|
||||
OpenRegistration = _config.GetServerOpenRegistration(),
|
||||
DisableRegistration = _config.GetServerDisabledRegistration(),
|
||||
ReminderUrgencyConfig = _config.GetReminderUrgencyConfig(),
|
||||
EnableAuth = _config.GetServerAuthEnabled(),
|
||||
DefaultReminderEmail = _config.GetDefaultReminderEmail(),
|
||||
EnableRootUserOIDC = _config.GetEnableRootUserOIDC(),
|
||||
CookieLifeSpan = _config.GetAuthCookieLifeSpan().ToString(),
|
||||
KestrelAppConfig = _config.GetKestrelAppConfig()
|
||||
};
|
||||
return View(viewModel);
|
||||
}
|
||||
[HttpPost]
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
public IActionResult WriteServerConfiguration(ServerConfig serverConfig)
|
||||
{
|
||||
var result = _config.SaveServerConfig(serverConfig);
|
||||
return Json(result);
|
||||
}
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
public IActionResult SendTestEmail(string emailAddress, MailConfig mailConfig)
|
||||
{
|
||||
var result = _mailHelper.SendTestEmail(emailAddress, mailConfig);
|
||||
return Json(result);
|
||||
}
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public IActionResult Error()
|
||||
{
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
using CarCareTracker.Models;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Logic;
|
||||
using CarCareTracker.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Microsoft.IdentityModel.JsonWebTokens;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace CarCareTracker.Controllers
|
||||
@ -12,19 +13,410 @@ namespace CarCareTracker.Controllers
|
||||
public class LoginController : Controller
|
||||
{
|
||||
private IDataProtector _dataProtector;
|
||||
private ILoginLogic _loginLogic;
|
||||
private IConfigHelper _config;
|
||||
private readonly ILogger<LoginController> _logger;
|
||||
public LoginController(
|
||||
ILogger<LoginController> logger,
|
||||
IDataProtectionProvider securityProvider
|
||||
)
|
||||
IDataProtectionProvider securityProvider,
|
||||
ILoginLogic loginLogic,
|
||||
IConfigHelper config
|
||||
)
|
||||
{
|
||||
_dataProtector = securityProvider.CreateProtector("login");
|
||||
_logger = logger;
|
||||
_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;
|
||||
var pkceKeyPair = _loginLogic.GetPKCEChallengeCode();
|
||||
remoteAuthConfig.CodeChallenge = pkceKeyPair.Value;
|
||||
if (remoteAuthConfig.ValidateState)
|
||||
{
|
||||
Response.Cookies.Append("OIDC_STATE", remoteAuthConfig.State, new CookieOptions { Expires = new DateTimeOffset(DateTime.Now.AddMinutes(5)) });
|
||||
}
|
||||
if (remoteAuthConfig.UsePKCE)
|
||||
{
|
||||
Response.Cookies.Append("OIDC_VERIFIER", pkceKeyPair.Key, new CookieOptions { Expires = new DateTimeOffset(DateTime.Now.AddMinutes(5)) });
|
||||
}
|
||||
var remoteAuthURL = remoteAuthConfig.RemoteAuthURL;
|
||||
return Redirect(remoteAuthURL);
|
||||
}
|
||||
return View(model: redirectURL);
|
||||
}
|
||||
public IActionResult Registration(string token = "", string email = "")
|
||||
{
|
||||
if (_config.GetServerDisabledRegistration())
|
||||
{
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
var viewModel = new LoginModel
|
||||
{
|
||||
EmailAddress = string.IsNullOrWhiteSpace(email) ? string.Empty : email,
|
||||
Token = string.IsNullOrWhiteSpace(token) ? string.Empty : token
|
||||
};
|
||||
return View(viewModel);
|
||||
}
|
||||
public IActionResult ForgotPassword()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
public IActionResult ResetPassword(string token = "", string email = "")
|
||||
{
|
||||
var viewModel = new LoginModel
|
||||
{
|
||||
EmailAddress = string.IsNullOrWhiteSpace(email) ? string.Empty : email,
|
||||
Token = string.IsNullOrWhiteSpace(token) ? string.Empty : token
|
||||
};
|
||||
return View(viewModel);
|
||||
}
|
||||
public IActionResult GetRemoteLoginLink()
|
||||
{
|
||||
var remoteAuthConfig = _config.GetOpenIDConfig();
|
||||
var generatedState = Guid.NewGuid().ToString().Substring(0, 8);
|
||||
remoteAuthConfig.State = generatedState;
|
||||
var pkceKeyPair = _loginLogic.GetPKCEChallengeCode();
|
||||
remoteAuthConfig.CodeChallenge = pkceKeyPair.Value;
|
||||
if (remoteAuthConfig.ValidateState)
|
||||
{
|
||||
Response.Cookies.Append("OIDC_STATE", remoteAuthConfig.State, new CookieOptions { Expires = new DateTimeOffset(DateTime.Now.AddMinutes(5)) });
|
||||
}
|
||||
if (remoteAuthConfig.UsePKCE)
|
||||
{
|
||||
Response.Cookies.Append("OIDC_VERIFIER", pkceKeyPair.Key, 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)
|
||||
};
|
||||
if (openIdConfig.UsePKCE)
|
||||
{
|
||||
//retrieve stored challenge verifier
|
||||
var storedVerifier = Request.Cookies["OIDC_VERIFIER"];
|
||||
if (!string.IsNullOrWhiteSpace(storedVerifier))
|
||||
{
|
||||
httpParams.Add(new KeyValuePair<string, string>("code_verifier", storedVerifier));
|
||||
Response.Cookies.Delete("OIDC_VERIFIER");
|
||||
}
|
||||
}
|
||||
var httpRequest = new HttpRequestMessage(HttpMethod.Post, openIdConfig.TokenURL)
|
||||
{
|
||||
Content = new FormUrlEncodedContent(httpParams)
|
||||
};
|
||||
var tokenResult = await httpClient.SendAsync(httpRequest).Result.Content.ReadAsStringAsync();
|
||||
var decodedToken = JsonSerializer.Deserialize<OpenIDResult>(tokenResult);
|
||||
var userJwt = decodedToken?.id_token ?? string.Empty;
|
||||
var userAccessToken = decodedToken?.access_token ?? string.Empty;
|
||||
var tokenParser = new JsonWebTokenHandler();
|
||||
bool passedSignatureCheck = true;
|
||||
string signatureValidationError = "check jwks endpoint";
|
||||
if (!string.IsNullOrWhiteSpace(openIdConfig.JwksURL))
|
||||
{
|
||||
//validate token signature if jwks endpoint is provided
|
||||
var jwksData = await httpClient.GetStringAsync(openIdConfig.JwksURL);
|
||||
if (!string.IsNullOrWhiteSpace(jwksData))
|
||||
{
|
||||
var signingKeys = new JsonWebKeySet(jwksData).GetSigningKeys();
|
||||
var tokenValidationParams = new TokenValidationParameters
|
||||
{
|
||||
ValidateAudience = false,
|
||||
ValidateIssuer = false,
|
||||
RequireAudience = false,
|
||||
IssuerSigningKeys = signingKeys,
|
||||
ValidateIssuerSigningKey = true
|
||||
};
|
||||
var validatedIdToken = await tokenParser.ValidateTokenAsync(userJwt, tokenValidationParams);
|
||||
if (!validatedIdToken.IsValid)
|
||||
{
|
||||
passedSignatureCheck = false;
|
||||
if (validatedIdToken.Exception != null && !string.IsNullOrWhiteSpace(validatedIdToken.Exception.Message))
|
||||
{
|
||||
signatureValidationError = validatedIdToken.Exception.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (passedSignatureCheck)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(userJwt))
|
||||
{
|
||||
//validate JWT token
|
||||
var parsedToken = tokenParser.ReadJsonWebToken(userJwt);
|
||||
var userEmailAddress = string.Empty;
|
||||
if (parsedToken.Claims.Any(x => x.Type == "email"))
|
||||
{
|
||||
userEmailAddress = parsedToken.Claims.First(x => x.Type == "email").Value;
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(openIdConfig.UserInfoURL) && !string.IsNullOrWhiteSpace(userAccessToken))
|
||||
{
|
||||
//retrieve claims from userinfo endpoint if no email claims are returned within id_token
|
||||
var userInfoHttpRequest = new HttpRequestMessage(HttpMethod.Get, openIdConfig.UserInfoURL);
|
||||
userInfoHttpRequest.Headers.Add("Authorization", $"Bearer {userAccessToken}");
|
||||
var userInfoResult = await httpClient.SendAsync(userInfoHttpRequest).Result.Content.ReadAsStringAsync();
|
||||
var userInfo = JsonSerializer.Deserialize<OpenIDUserInfo>(userInfoResult);
|
||||
if (!string.IsNullOrWhiteSpace(userInfo?.email ?? string.Empty))
|
||||
{
|
||||
userEmailAddress = userInfo?.email ?? string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError($"OpenID Provider did not provide an email claim via UserInfo endpoint");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var returnedClaims = parsedToken.Claims.Select(x => x.Type);
|
||||
_logger.LogError($"OpenID Provider did not provide an email claim, claims returned: {string.Join(",", returnedClaims)}");
|
||||
}
|
||||
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(StaticHelper.LoginCookieName, 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");
|
||||
if (!string.IsNullOrWhiteSpace(tokenResult))
|
||||
{
|
||||
//if something was returned from the IdP but it's invalid, we want to log it as an error.
|
||||
_logger.LogError($"Expected id_token, received {tokenResult}");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError($"OpenID Provider did not provide a valid id_token: {signatureValidationError}");
|
||||
}
|
||||
}
|
||||
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");
|
||||
}
|
||||
public async Task<IActionResult> RemoteAuthDebug(string code, string state = "")
|
||||
{
|
||||
List<OperationResponse> results = new List<OperationResponse>();
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(code))
|
||||
{
|
||||
results.Add(OperationResponse.Succeed($"Received code from OpenID Provider: {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)
|
||||
{
|
||||
results.Add(OperationResponse.Failed($"Failed State Validation - Expected: {storedStateValue} Received: {state}"));
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add(OperationResponse.Succeed($"Passed State Validation - Expected: {storedStateValue} Received: {state}"));
|
||||
}
|
||||
}
|
||||
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)
|
||||
};
|
||||
if (openIdConfig.UsePKCE)
|
||||
{
|
||||
//retrieve stored challenge verifier
|
||||
var storedVerifier = Request.Cookies["OIDC_VERIFIER"];
|
||||
if (!string.IsNullOrWhiteSpace(storedVerifier))
|
||||
{
|
||||
httpParams.Add(new KeyValuePair<string, string>("code_verifier", storedVerifier));
|
||||
Response.Cookies.Delete("OIDC_VERIFIER");
|
||||
}
|
||||
}
|
||||
var httpRequest = new HttpRequestMessage(HttpMethod.Post, openIdConfig.TokenURL)
|
||||
{
|
||||
Content = new FormUrlEncodedContent(httpParams)
|
||||
};
|
||||
var tokenResult = await httpClient.SendAsync(httpRequest).Result.Content.ReadAsStringAsync();
|
||||
var decodedToken = JsonSerializer.Deserialize<OpenIDResult>(tokenResult);
|
||||
var userJwt = decodedToken?.id_token ?? string.Empty;
|
||||
var userAccessToken = decodedToken?.access_token ?? string.Empty;
|
||||
var tokenParser = new JsonWebTokenHandler();
|
||||
bool passedSignatureCheck = true;
|
||||
if (!string.IsNullOrWhiteSpace(openIdConfig.JwksURL))
|
||||
{
|
||||
//validate token signature if jwks endpoint is provided
|
||||
var jwksData = await httpClient.GetStringAsync(openIdConfig.JwksURL);
|
||||
if (!string.IsNullOrWhiteSpace(jwksData))
|
||||
{
|
||||
var signingKeys = new JsonWebKeySet(jwksData).GetSigningKeys();
|
||||
var tokenValidationParams = new TokenValidationParameters
|
||||
{
|
||||
ValidateAudience = false,
|
||||
ValidateIssuer = false,
|
||||
RequireAudience = false,
|
||||
IssuerSigningKeys = signingKeys,
|
||||
ValidateIssuerSigningKey = true
|
||||
};
|
||||
var validatedIdToken = await tokenParser.ValidateTokenAsync(userJwt, tokenValidationParams);
|
||||
if (!validatedIdToken.IsValid)
|
||||
{
|
||||
passedSignatureCheck = false;
|
||||
if (validatedIdToken.Exception != null && !string.IsNullOrWhiteSpace(validatedIdToken.Exception.Message))
|
||||
{
|
||||
results.Add(OperationResponse.Failed($"Failed JWT Validation: {validatedIdToken.Exception.Message}"));
|
||||
}
|
||||
} else
|
||||
{
|
||||
results.Add(OperationResponse.Succeed($"Passed JWT Validation - Valid To: {validatedIdToken.SecurityToken.ValidTo}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (passedSignatureCheck)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(userJwt))
|
||||
{
|
||||
results.Add(OperationResponse.Succeed($"Passed JWT Parsing - id_token: {userJwt}"));
|
||||
//validate JWT token
|
||||
var parsedToken = tokenParser.ReadJsonWebToken(userJwt);
|
||||
var userEmailAddress = string.Empty;
|
||||
if (parsedToken.Claims.Any(x => x.Type == "email"))
|
||||
{
|
||||
userEmailAddress = parsedToken.Claims.First(x => x.Type == "email").Value;
|
||||
results.Add(OperationResponse.Succeed($"Passed Claim Validation - email"));
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(openIdConfig.UserInfoURL) && !string.IsNullOrWhiteSpace(userAccessToken))
|
||||
{
|
||||
//retrieve claims from userinfo endpoint if no email claims are returned within id_token
|
||||
var userInfoHttpRequest = new HttpRequestMessage(HttpMethod.Get, openIdConfig.UserInfoURL);
|
||||
userInfoHttpRequest.Headers.Add("Authorization", $"Bearer {userAccessToken}");
|
||||
var userInfoResult = await httpClient.SendAsync(userInfoHttpRequest).Result.Content.ReadAsStringAsync();
|
||||
var userInfo = JsonSerializer.Deserialize<OpenIDUserInfo>(userInfoResult);
|
||||
if (!string.IsNullOrWhiteSpace(userInfo?.email ?? string.Empty))
|
||||
{
|
||||
userEmailAddress = userInfo?.email ?? string.Empty;
|
||||
results.Add(OperationResponse.Succeed($"Passed Claim Validation - Retrieved email via UserInfo endpoint"));
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add(OperationResponse.Failed($"Failed Claim Validation - Unable to retrieve email via UserInfo endpoint: {openIdConfig.UserInfoURL} using access_token: {userAccessToken} - Received {userInfoResult}"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var returnedClaims = parsedToken.Claims.Select(x => x.Type);
|
||||
results.Add(OperationResponse.Failed($"Failed Claim Validation - Expected: email Received: {string.Join(",", returnedClaims)}"));
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(userEmailAddress))
|
||||
{
|
||||
var userData = _loginLogic.ValidateOpenIDUser(new LoginModel() { EmailAddress = userEmailAddress });
|
||||
if (userData.Id != default)
|
||||
{
|
||||
results.Add(OperationResponse.Succeed($"Passed User Validation - Email: {userEmailAddress} Username: {userData.UserName}"));
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add(OperationResponse.Succeed($"Passed Email Validation - Email: {userEmailAddress} User not registered"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add(OperationResponse.Failed($"Failed Email Validation - No email received from OpenID Provider"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add(OperationResponse.Failed($"Failed to parse JWT - Expected: id_token Received: {tokenResult}"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add(OperationResponse.Failed("Failed JWT Validation: Check Signing Keys"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add(OperationResponse.Failed("No code received from OpenID Provider"));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
results.Add(OperationResponse.Failed($"Exception: {ex.Message}"));
|
||||
}
|
||||
return View(results);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult Login(LoginModel credentials)
|
||||
{
|
||||
@ -36,30 +428,18 @@ namespace CarCareTracker.Controllers
|
||||
//compare it against hashed credentials
|
||||
try
|
||||
{
|
||||
var configFileContents = System.IO.File.ReadAllText("userConfig.json");
|
||||
var existingUserConfig = System.Text.Json.JsonSerializer.Deserialize<UserConfig>(configFileContents);
|
||||
if (existingUserConfig is not null)
|
||||
var userData = _loginLogic.ValidateUserCredentials(credentials);
|
||||
if (userData.Id != default)
|
||||
{
|
||||
//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)
|
||||
AuthCookie authCookie = new AuthCookie
|
||||
{
|
||||
//auth success, create auth cookie
|
||||
//encrypt stuff.
|
||||
AuthCookie authCookie = new AuthCookie
|
||||
{
|
||||
Id = 1, //this is hardcoded for now
|
||||
UserName = credentials.UserName,
|
||||
ExpiresOn = DateTime.Now.AddDays(credentials.IsPersistent ? 30 : 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(true);
|
||||
}
|
||||
UserData = userData,
|
||||
ExpiresOn = DateTime.Now.AddDays(credentials.IsPersistent ? _config.GetAuthCookieLifeSpan() : 1)
|
||||
};
|
||||
var serializedCookie = JsonSerializer.Serialize(authCookie);
|
||||
var encryptedCookie = _dataProtector.Protect(serializedCookie);
|
||||
Response.Cookies.Append(StaticHelper.LoginCookieName, encryptedCookie, new CookieOptions { Expires = new DateTimeOffset(authCookie.ExpiresOn) });
|
||||
return Json(true);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -68,26 +448,60 @@ namespace CarCareTracker.Controllers
|
||||
}
|
||||
return Json(false);
|
||||
}
|
||||
[Authorize] //User must already be logged in to do this.
|
||||
|
||||
[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(StaticHelper.LoginCookieName, encryptedCookie, new CookieOptions { Expires = new DateTimeOffset(authCookie.ExpiresOn) });
|
||||
}
|
||||
}
|
||||
return Json(result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SendRegistrationToken(LoginModel credentials)
|
||||
{
|
||||
var result = _loginLogic.SendRegistrationToken(credentials);
|
||||
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(Roles = nameof(UserData.IsRootUser))] //User must already be logged in as root user to do this.
|
||||
[HttpPost]
|
||||
public IActionResult CreateLoginCreds(LoginModel credentials)
|
||||
{
|
||||
try
|
||||
{
|
||||
var configFileContents = System.IO.File.ReadAllText("userConfig.json");
|
||||
var existingUserConfig = 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);
|
||||
//copy over settings that are off limits on the settings page.
|
||||
existingUserConfig.EnableAuth = true;
|
||||
existingUserConfig.UserNameHash = hashedUserName;
|
||||
existingUserConfig.UserPasswordHash = hashedPassword;
|
||||
}
|
||||
System.IO.File.WriteAllText("userConfig.json", JsonSerializer.Serialize(existingUserConfig));
|
||||
return Json(true);
|
||||
var result = _loginLogic.CreateRootUserCredentials(credentials);
|
||||
return Json(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -95,25 +509,19 @@ namespace CarCareTracker.Controllers
|
||||
}
|
||||
return Json(false);
|
||||
}
|
||||
[Authorize]
|
||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||
[HttpPost]
|
||||
public IActionResult DestroyLoginCreds()
|
||||
{
|
||||
try
|
||||
{
|
||||
var configFileContents = System.IO.File.ReadAllText("userConfig.json");
|
||||
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("userConfig.json", JsonSerializer.Serialize(existingUserConfig));
|
||||
var result = _loginLogic.DeleteRootUserCredentials();
|
||||
//destroy any login cookies.
|
||||
Response.Cookies.Delete("ACCESS_TOKEN");
|
||||
return Json(true);
|
||||
if (result)
|
||||
{
|
||||
Response.Cookies.Delete(StaticHelper.LoginCookieName);
|
||||
}
|
||||
return Json(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -125,23 +533,13 @@ namespace CarCareTracker.Controllers
|
||||
[HttpPost]
|
||||
public IActionResult LogOut()
|
||||
{
|
||||
Response.Cookies.Delete("ACCESS_TOKEN");
|
||||
return Json(true);
|
||||
}
|
||||
private static string Sha256_hash(string value)
|
||||
{
|
||||
StringBuilder Sb = new StringBuilder();
|
||||
|
||||
using (var hash = SHA256.Create())
|
||||
Response.Cookies.Delete(StaticHelper.LoginCookieName);
|
||||
var remoteAuthConfig = _config.GetOpenIDConfig();
|
||||
if (remoteAuthConfig.DisableRegularLogin && !string.IsNullOrWhiteSpace(remoteAuthConfig.LogOutURL))
|
||||
{
|
||||
Encoding enc = Encoding.UTF8;
|
||||
byte[] result = hash.ComputeHash(enc.GetBytes(value));
|
||||
|
||||
foreach (byte b in result)
|
||||
Sb.Append(b.ToString("x2"));
|
||||
return Json(remoteAuthConfig.LogOutURL);
|
||||
}
|
||||
|
||||
return Sb.ToString();
|
||||
return Json("/Login");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
868
Controllers/MigrationController.cs
Normal file
868
Controllers/MigrationController.cs
Normal file
@ -0,0 +1,868 @@
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Models;
|
||||
using LiteDB;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Npgsql;
|
||||
using System.IO.Compression;
|
||||
using JsonSerializer=System.Text.Json.JsonSerializer;
|
||||
|
||||
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, 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 SCHEMA IF NOT EXISTS app",
|
||||
"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)",
|
||||
"CREATE TABLE IF NOT EXISTS app.inspectionrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
|
||||
"CREATE TABLE IF NOT EXISTS app.inspectionrecordtemplates (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
|
||||
"CREATE TABLE IF NOT EXISTS app.userhouseholdrecords (parentUserId INT, childUserId INT, data jsonb not null, PRIMARY KEY(parentUserId, childUserId))"
|
||||
};
|
||||
foreach(string cmd in cmds)
|
||||
{
|
||||
using (var ctext = conn.CreateCommand(cmd))
|
||||
{
|
||||
ctext.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
public IActionResult Export()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_configHelper.GetServerPostgresConnection()))
|
||||
{
|
||||
return Json(OperationResponse.Failed("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>();
|
||||
var inspectionrecords = new List<InspectionRecord>();
|
||||
var inspectionrecordtemplates = new List<InspectionRecordInput>();
|
||||
var userhouseholdrecords = new List<UserHousehold>();
|
||||
#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 = 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(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(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(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(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(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(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(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(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(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(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(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(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(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);
|
||||
};
|
||||
}
|
||||
cmd = $"SELECT data FROM app.inspectionrecords";
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||
while (reader.Read())
|
||||
{
|
||||
inspectionrecords.Add(JsonSerializer.Deserialize<InspectionRecord>(reader["data"] as string));
|
||||
}
|
||||
}
|
||||
foreach (var record in inspectionrecords)
|
||||
{
|
||||
using (var db = new LiteDatabase(fullFileName))
|
||||
{
|
||||
var table = db.GetCollection<InspectionRecord>("inspectionrecords");
|
||||
table.Upsert(record);
|
||||
}
|
||||
;
|
||||
}
|
||||
cmd = $"SELECT data FROM app.inspectionrecordtemplates";
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||
while (reader.Read())
|
||||
{
|
||||
inspectionrecordtemplates.Add(JsonSerializer.Deserialize<InspectionRecordInput>(reader["data"] as string));
|
||||
}
|
||||
}
|
||||
foreach (var record in inspectionrecordtemplates)
|
||||
{
|
||||
using (var db = new LiteDatabase(fullFileName))
|
||||
{
|
||||
var table = db.GetCollection<InspectionRecordInput>("inspectionrecordtemplates");
|
||||
table.Upsert(record);
|
||||
};
|
||||
}
|
||||
cmd = $"SELECT data FROM app.userhouseholdrecords";
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||
while (reader.Read())
|
||||
{
|
||||
UserHousehold result = JsonSerializer.Deserialize<UserHousehold>(reader["data"] as string);
|
||||
userhouseholdrecords.Add(result);
|
||||
}
|
||||
}
|
||||
foreach (var record in userhouseholdrecords)
|
||||
{
|
||||
using (var db = new LiteDatabase(fullFileName))
|
||||
{
|
||||
var table = db.GetCollection<UserHousehold>("userhouseholdrecords");
|
||||
table.Upsert(record);
|
||||
}
|
||||
;
|
||||
}
|
||||
#endregion
|
||||
var destFilePath = $"{fullFolderPath}.zip";
|
||||
ZipFile.CreateFromDirectory(fullFolderPath, destFilePath);
|
||||
return Json(OperationResponse.Succeed($"/{tempFolder}.zip"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return Json(OperationResponse.Failed());
|
||||
}
|
||||
}
|
||||
public IActionResult Import(string fileName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_configHelper.GetServerPostgresConnection()))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Postgres connection not set up"));
|
||||
}
|
||||
var fullFileName = _fileHelper.GetFullFilePath(fileName);
|
||||
if (string.IsNullOrWhiteSpace(fullFileName))
|
||||
{
|
||||
return Json(OperationResponse.Failed());
|
||||
}
|
||||
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>();
|
||||
var inspectionrecords = new List<InspectionRecord>();
|
||||
var inspectionrecordtemplates = new List<InspectionRecordInput>();
|
||||
var userhouseholdrecords = new List<UserHousehold>();
|
||||
#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", 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", 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", 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", 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", 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", 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", 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", 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", 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", 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", 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", 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", 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", JsonSerializer.Serialize(record));
|
||||
ctext.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
using (var db = new LiteDatabase(fullFileName))
|
||||
{
|
||||
var table = db.GetCollection<InspectionRecord>("inspectionrecords");
|
||||
inspectionrecords = table.FindAll().ToList();
|
||||
};
|
||||
foreach (var record in inspectionrecords)
|
||||
{
|
||||
string cmd = $"INSERT INTO app.inspectionrecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.inspectionrecords_id_seq', (SELECT MAX(id) from app.inspectionrecords));";
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("id", record.Id);
|
||||
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
|
||||
ctext.Parameters.AddWithValue("data", JsonSerializer.Serialize(record));
|
||||
ctext.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
using (var db = new LiteDatabase(fullFileName))
|
||||
{
|
||||
var table = db.GetCollection<InspectionRecordInput>("inspectionrecordtemplates");
|
||||
inspectionrecordtemplates = table.FindAll().ToList();
|
||||
};
|
||||
foreach (var record in inspectionrecordtemplates)
|
||||
{
|
||||
string cmd = $"INSERT INTO app.inspectionrecordtemplates (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.inspectionrecordtemplates_id_seq', (SELECT MAX(id) from app.inspectionrecordtemplates));";
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("id", record.Id);
|
||||
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
|
||||
ctext.Parameters.AddWithValue("data", JsonSerializer.Serialize(record));
|
||||
ctext.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
using (var db = new LiteDatabase(fullFileName))
|
||||
{
|
||||
var table = db.GetCollection<UserHousehold>("userhouseholdrecords");
|
||||
userhouseholdrecords = table.FindAll().ToList();
|
||||
}
|
||||
;
|
||||
foreach (var record in userhouseholdrecords)
|
||||
{
|
||||
string cmd = $"INSERT INTO app.userhouseholdrecords (parentUserId, childUserId, data) VALUES(@parentUserId, @childUserId, CAST(@data AS jsonb))";
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("parentUserId", record.Id.ParentUserId);
|
||||
ctext.Parameters.AddWithValue("childUserId", record.Id.ChildUserId);
|
||||
ctext.Parameters.AddWithValue("data", JsonSerializer.Serialize(record));
|
||||
ctext.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
return Json(OperationResponse.Succeed("Data Imported Successfully"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return Json(OperationResponse.Failed());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
216
Controllers/Vehicle/GasController.cs
Normal file
216
Controllers/Vehicle/GasController.cs
Normal file
@ -0,0 +1,216 @@
|
||||
using CarCareTracker.Filter;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace CarCareTracker.Controllers
|
||||
{
|
||||
public partial class VehicleController
|
||||
{
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetGasRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
||||
//check if the user uses MPG or Liters per 100km.
|
||||
var userConfig = _config.GetUserConfig(User);
|
||||
bool useMPG = userConfig.UseMPG;
|
||||
var vehicleData = _dataAccess.GetVehicleById(vehicleId);
|
||||
bool useUKMPG = !vehicleData.IsElectric && userConfig.UseUKMPG; //do not apply UK conversion on electric vehicles.
|
||||
var computedResults = _gasHelper.GetGasRecordViewModels(result, useMPG, useUKMPG);
|
||||
if (userConfig.UseDescending)
|
||||
{
|
||||
computedResults = computedResults.OrderByDescending(x => DateTime.Parse(x.Date)).ThenByDescending(x => x.Mileage).ToList();
|
||||
}
|
||||
var vehicleIsElectric = vehicleData.IsElectric;
|
||||
var vehicleUseHours = vehicleData.UseHours;
|
||||
var viewModel = new GasRecordViewModelContainer()
|
||||
{
|
||||
UseKwh = vehicleIsElectric,
|
||||
UseHours = vehicleUseHours,
|
||||
GasRecords = computedResults
|
||||
};
|
||||
return PartialView("Gas/_Gas", viewModel);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SaveGasRecordToVehicleId(GasRecordInput gasRecord)
|
||||
{
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), gasRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
gasRecord.Files = gasRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||
var convertedRecord = gasRecord.ToGasRecord();
|
||||
var result = _gasRecordDataAccess.SaveGasRecordToVehicle(convertedRecord);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromGasRecord(convertedRecord, gasRecord.Id == default ? "gasrecord.add" : "gasrecord.update", User.Identity.Name));
|
||||
}
|
||||
if (convertedRecord.Id != default && gasRecord.Id == default && _config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
{
|
||||
_odometerLogic.AutoInsertOdometerRecord(new OdometerRecord
|
||||
{
|
||||
Date = DateTime.Parse(gasRecord.Date),
|
||||
VehicleId = gasRecord.VehicleId,
|
||||
Mileage = gasRecord.Mileage,
|
||||
Notes = $"Auto Insert From Gas Record. {gasRecord.Notes}",
|
||||
Files = StaticHelper.CreateAttachmentFromRecord(ImportMode.GasRecord, convertedRecord.Id, $"Gas Record - {gasRecord.Mileage.ToString()}")
|
||||
});
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetAddGasRecordPartialView(int vehicleId)
|
||||
{
|
||||
var vehicleData = _dataAccess.GetVehicleById(vehicleId);
|
||||
var vehicleIsElectric = vehicleData.IsElectric;
|
||||
var vehicleUseHours = vehicleData.UseHours;
|
||||
return PartialView("Gas/_GasModal", new GasRecordInputContainer() { UseKwh = vehicleIsElectric, UseHours = vehicleUseHours, GasRecord = new GasRecordInput() { ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.GasRecord).ExtraFields } });
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetGasRecordForEditById(int gasRecordId)
|
||||
{
|
||||
var result = _gasRecordDataAccess.GetGasRecordById(gasRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), result.VehicleId, HouseholdPermission.View))
|
||||
{
|
||||
return Redirect("/Error/Unauthorized");
|
||||
}
|
||||
var convertedResult = new GasRecordInput
|
||||
{
|
||||
Id = result.Id,
|
||||
Mileage = result.Mileage,
|
||||
VehicleId = result.VehicleId,
|
||||
Cost = result.Cost,
|
||||
Date = result.Date.ToShortDateString(),
|
||||
Files = result.Files,
|
||||
Gallons = result.Gallons,
|
||||
IsFillToFull = result.IsFillToFull,
|
||||
MissedFuelUp = result.MissedFuelUp,
|
||||
Notes = result.Notes,
|
||||
Tags = result.Tags,
|
||||
ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.GasRecord).ExtraFields)
|
||||
};
|
||||
var vehicleData = _dataAccess.GetVehicleById(convertedResult.VehicleId);
|
||||
var vehicleIsElectric = vehicleData.IsElectric;
|
||||
var vehicleUseHours = vehicleData.UseHours;
|
||||
var viewModel = new GasRecordInputContainer()
|
||||
{
|
||||
UseKwh = vehicleIsElectric,
|
||||
UseHours = vehicleUseHours,
|
||||
GasRecord = convertedResult
|
||||
};
|
||||
return PartialView("Gas/_GasModal", viewModel);
|
||||
}
|
||||
private OperationResponse DeleteGasRecordWithChecks(int gasRecordId)
|
||||
{
|
||||
var existingRecord = _gasRecordDataAccess.GetGasRecordById(gasRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Delete))
|
||||
{
|
||||
return OperationResponse.Failed("Access Denied");
|
||||
}
|
||||
var result = _gasRecordDataAccess.DeleteGasRecordById(existingRecord.Id);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromGasRecord(existingRecord, "gasrecord.delete", User.Identity.Name));
|
||||
}
|
||||
return OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult DeleteGasRecordById(int gasRecordId)
|
||||
{
|
||||
var result = DeleteGasRecordWithChecks(gasRecordId);
|
||||
return Json(result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SaveUserGasTabPreferences(string gasUnit, string fuelMileageUnit)
|
||||
{
|
||||
var currentConfig = _config.GetUserConfig(User);
|
||||
currentConfig.PreferredGasUnit = gasUnit;
|
||||
currentConfig.PreferredGasMileageUnit = fuelMileageUnit;
|
||||
var result = _config.SaveUserConfig(User, currentConfig);
|
||||
return Json(result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult GetGasRecordsEditModal(List<int> recordIds)
|
||||
{
|
||||
var extraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.GasRecord).ExtraFields;
|
||||
return PartialView("Gas/_GasRecordsModal", new GasRecordEditModel { RecordIds = recordIds, EditRecord = new GasRecord { ExtraFields = extraFields } });
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SaveMultipleGasRecords(GasRecordEditModel editModel)
|
||||
{
|
||||
var dateIsEdited = editModel.EditRecord.Date != default;
|
||||
var mileageIsEdited = editModel.EditRecord.Mileage != default;
|
||||
var consumptionIsEdited = editModel.EditRecord.Gallons != default;
|
||||
var costIsEdited = editModel.EditRecord.Cost != default;
|
||||
var noteIsEdited = !string.IsNullOrWhiteSpace(editModel.EditRecord.Notes);
|
||||
var tagsIsEdited = editModel.EditRecord.Tags.Any();
|
||||
var extraFieldIsEdited = editModel.EditRecord.ExtraFields.Any();
|
||||
//handle clear overrides
|
||||
if (tagsIsEdited && editModel.EditRecord.Tags.Contains("---"))
|
||||
{
|
||||
editModel.EditRecord.Tags = new List<string>();
|
||||
}
|
||||
if (noteIsEdited && editModel.EditRecord.Notes == "---")
|
||||
{
|
||||
editModel.EditRecord.Notes = "";
|
||||
}
|
||||
bool result = false;
|
||||
foreach (int recordId in editModel.RecordIds)
|
||||
{
|
||||
var existingRecord = _gasRecordDataAccess.GetGasRecordById(recordId);
|
||||
//security check
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
if (dateIsEdited)
|
||||
{
|
||||
existingRecord.Date = editModel.EditRecord.Date;
|
||||
}
|
||||
if (consumptionIsEdited)
|
||||
{
|
||||
existingRecord.Gallons = editModel.EditRecord.Gallons;
|
||||
}
|
||||
if (costIsEdited)
|
||||
{
|
||||
existingRecord.Cost = editModel.EditRecord.Cost;
|
||||
}
|
||||
if (mileageIsEdited)
|
||||
{
|
||||
existingRecord.Mileage = editModel.EditRecord.Mileage;
|
||||
}
|
||||
if (noteIsEdited)
|
||||
{
|
||||
existingRecord.Notes = editModel.EditRecord.Notes;
|
||||
}
|
||||
if (tagsIsEdited)
|
||||
{
|
||||
existingRecord.Tags = editModel.EditRecord.Tags;
|
||||
}
|
||||
if (extraFieldIsEdited)
|
||||
{
|
||||
foreach (ExtraField extraField in editModel.EditRecord.ExtraFields)
|
||||
{
|
||||
if (existingRecord.ExtraFields.Any(x => x.Name == extraField.Name))
|
||||
{
|
||||
var insertIndex = existingRecord.ExtraFields.FindIndex(x => x.Name == extraField.Name);
|
||||
existingRecord.ExtraFields.RemoveAll(x => x.Name == extraField.Name);
|
||||
existingRecord.ExtraFields.Insert(insertIndex, extraField);
|
||||
}
|
||||
else
|
||||
{
|
||||
existingRecord.ExtraFields.Add(extraField);
|
||||
}
|
||||
}
|
||||
}
|
||||
result = _gasRecordDataAccess.SaveGasRecordToVehicle(existingRecord);
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
670
Controllers/Vehicle/ImportController.cs
Normal file
670
Controllers/Vehicle/ImportController.cs
Normal file
@ -0,0 +1,670 @@
|
||||
using CarCareTracker.Filter;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.MapProfile;
|
||||
using CarCareTracker.Models;
|
||||
using CsvHelper;
|
||||
using CsvHelper.Configuration;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Globalization;
|
||||
|
||||
namespace CarCareTracker.Controllers
|
||||
{
|
||||
public partial class VehicleController
|
||||
{
|
||||
[HttpGet]
|
||||
public IActionResult GetBulkImportModalPartialView(ImportMode mode)
|
||||
{
|
||||
return PartialView("_BulkDataImporter", mode);
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GenerateCsvSample(ImportMode mode)
|
||||
{
|
||||
string uploadDirectory = "temp/";
|
||||
string uploadPath = Path.Combine(_webEnv.ContentRootPath, "data", uploadDirectory);
|
||||
if (!Directory.Exists(uploadPath))
|
||||
Directory.CreateDirectory(uploadPath);
|
||||
var fileNameToExport = $"temp/{Guid.NewGuid()}.csv";
|
||||
var fullExportFilePath = _fileHelper.GetFullFilePath(fileNameToExport, false);
|
||||
switch (mode)
|
||||
{
|
||||
case ImportMode.ServiceRecord:
|
||||
case ImportMode.RepairRecord:
|
||||
case ImportMode.UpgradeRecord:
|
||||
{
|
||||
var exportData = new List<GenericRecordExportModel> { new GenericRecordExportModel
|
||||
{
|
||||
Date = DateTime.Now.ToShortDateString(),
|
||||
Description = "Test",
|
||||
Cost = 123.45M.ToString("C"),
|
||||
Notes = "Test Note",
|
||||
Odometer = 12345.ToString(),
|
||||
Tags = "test1 test2"
|
||||
} };
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
//custom writer
|
||||
StaticHelper.WriteGenericRecordExportModel(csv, exportData);
|
||||
}
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ImportMode.GasRecord:
|
||||
{
|
||||
var exportData = new List<GasRecordExportModel> { new GasRecordExportModel
|
||||
{
|
||||
Date = DateTime.Now.ToShortDateString(),
|
||||
Odometer = 12345.ToString(),
|
||||
FuelConsumed = 12.34M.ToString(),
|
||||
Cost = 45.67M.ToString("C"),
|
||||
IsFillToFull = true.ToString(),
|
||||
MissedFuelUp = false.ToString(),
|
||||
Notes = "Test Note",
|
||||
Tags = "test1 test2"
|
||||
} };
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
//custom writer
|
||||
StaticHelper.WriteGasRecordExportModel(csv, exportData);
|
||||
}
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ImportMode.OdometerRecord:
|
||||
{
|
||||
var exportData = new List<OdometerRecordExportModel> { new OdometerRecordExportModel
|
||||
{
|
||||
Date = DateTime.Now.ToShortDateString(),
|
||||
InitialOdometer = 12345.ToString(),
|
||||
Odometer = 12345.ToString(),
|
||||
Notes = "Test Note",
|
||||
Tags = "test1 test2"
|
||||
} };
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
//custom writer
|
||||
StaticHelper.WriteOdometerRecordExportModel(csv, exportData);
|
||||
}
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ImportMode.TaxRecord:
|
||||
{
|
||||
var exportData = new List<TaxRecordExportModel> { new TaxRecordExportModel
|
||||
{
|
||||
Date = DateTime.Now.ToShortDateString(),
|
||||
Description = "Test",
|
||||
Cost = 123.45M.ToString("C"),
|
||||
Notes = "Test Note",
|
||||
Tags = "test1 test2"
|
||||
} };
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
//custom writer
|
||||
StaticHelper.WriteTaxRecordExportModel(csv, exportData);
|
||||
}
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ImportMode.SupplyRecord:
|
||||
{
|
||||
var exportData = new List<SupplyRecordExportModel> { new SupplyRecordExportModel
|
||||
{
|
||||
Date = DateTime.Now.ToShortDateString(),
|
||||
PartNumber = "TEST-123456",
|
||||
PartSupplier = "Test Supplier",
|
||||
PartQuantity = 1.5M.ToString(),
|
||||
Description = "Test",
|
||||
Cost = 123.45M.ToString("C"),
|
||||
Notes = "Test Note",
|
||||
Tags = "test1 test2"
|
||||
} };
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
//custom writer
|
||||
StaticHelper.WriteSupplyRecordExportModel(csv, exportData);
|
||||
}
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ImportMode.PlanRecord:
|
||||
{
|
||||
var exportData = new List<PlanRecordExportModel> { new PlanRecordExportModel
|
||||
{
|
||||
DateCreated = DateTime.Now.ToString(),
|
||||
DateModified = DateTime.Now.ToString(),
|
||||
Description = "Test",
|
||||
Type = ImportMode.RepairRecord.ToString(),
|
||||
Priority = PlanPriority.Normal.ToString(),
|
||||
Progress = PlanProgress.Testing.ToString(),
|
||||
Cost = 123.45M.ToString("C"),
|
||||
Notes = "Test Note"
|
||||
} };
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
//custom writer
|
||||
StaticHelper.WritePlanRecordExportModel(csv, exportData);
|
||||
}
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return Json(OperationResponse.Failed("No parameters"));
|
||||
}
|
||||
try
|
||||
{
|
||||
var fileBytes = _fileHelper.GetFileBytes(fullExportFilePath, true);
|
||||
if (fileBytes.Length > 0)
|
||||
{
|
||||
return File(fileBytes, "text/csv", $"{mode.ToString().ToLower()}sample.csv");
|
||||
}
|
||||
else
|
||||
{
|
||||
return Json(OperationResponse.Failed("An error has occurred while generating CSV sample: file has zero bytes"));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return Json(OperationResponse.Failed($"An error has occurred while generating CSV sample: {ex.Message}"));
|
||||
}
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter), Arguments = new object[] { false, true, HouseholdPermission.View })]
|
||||
[HttpGet]
|
||||
public IActionResult ExportFromVehicleToCsv(int vehicleId, ImportMode mode)
|
||||
{
|
||||
if (vehicleId == default && mode != ImportMode.SupplyRecord)
|
||||
{
|
||||
return Json(false);
|
||||
}
|
||||
string uploadDirectory = "temp/";
|
||||
string uploadPath = Path.Combine(_webEnv.ContentRootPath, "data", uploadDirectory);
|
||||
if (!Directory.Exists(uploadPath))
|
||||
Directory.CreateDirectory(uploadPath);
|
||||
var fileNameToExport = $"temp/{Guid.NewGuid()}.csv";
|
||||
var fullExportFilePath = _fileHelper.GetFullFilePath(fileNameToExport, false);
|
||||
if (mode == ImportMode.ServiceRecord)
|
||||
{
|
||||
var vehicleRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId);
|
||||
if (vehicleRecords.Any())
|
||||
{
|
||||
var exportData = vehicleRecords.Select(x => new GenericRecordExportModel
|
||||
{
|
||||
Date = x.Date.ToShortDateString(),
|
||||
Description = x.Description,
|
||||
Cost = x.Cost.ToString("C"),
|
||||
Notes = x.Notes,
|
||||
Odometer = x.Mileage.ToString(),
|
||||
Tags = string.Join(" ", x.Tags),
|
||||
ExtraFields = x.ExtraFields
|
||||
});
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
//custom writer
|
||||
StaticHelper.WriteGenericRecordExportModel(csv, exportData);
|
||||
}
|
||||
writer.Dispose();
|
||||
}
|
||||
return Json($"/{fileNameToExport}");
|
||||
}
|
||||
}
|
||||
else if (mode == ImportMode.RepairRecord)
|
||||
{
|
||||
var vehicleRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId);
|
||||
if (vehicleRecords.Any())
|
||||
{
|
||||
var exportData = vehicleRecords.Select(x => new GenericRecordExportModel
|
||||
{
|
||||
Date = x.Date.ToShortDateString(),
|
||||
Description = x.Description,
|
||||
Cost = x.Cost.ToString("C"),
|
||||
Notes = x.Notes,
|
||||
Odometer = x.Mileage.ToString(),
|
||||
Tags = string.Join(" ", x.Tags),
|
||||
ExtraFields = x.ExtraFields
|
||||
});
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
StaticHelper.WriteGenericRecordExportModel(csv, exportData);
|
||||
}
|
||||
}
|
||||
return Json($"/{fileNameToExport}");
|
||||
}
|
||||
}
|
||||
else if (mode == ImportMode.UpgradeRecord)
|
||||
{
|
||||
var vehicleRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
|
||||
if (vehicleRecords.Any())
|
||||
{
|
||||
var exportData = vehicleRecords.Select(x => new GenericRecordExportModel
|
||||
{
|
||||
Date = x.Date.ToShortDateString(),
|
||||
Description = x.Description,
|
||||
Cost = x.Cost.ToString("C"),
|
||||
Notes = x.Notes,
|
||||
Odometer = x.Mileage.ToString(),
|
||||
Tags = string.Join(" ", x.Tags),
|
||||
ExtraFields = x.ExtraFields
|
||||
});
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
StaticHelper.WriteGenericRecordExportModel(csv, exportData);
|
||||
}
|
||||
}
|
||||
return Json($"/{fileNameToExport}");
|
||||
}
|
||||
}
|
||||
else if (mode == ImportMode.OdometerRecord)
|
||||
{
|
||||
var vehicleRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
|
||||
if (vehicleRecords.Any())
|
||||
{
|
||||
var exportData = vehicleRecords.Select(x => new OdometerRecordExportModel
|
||||
{
|
||||
Date = x.Date.ToShortDateString(),
|
||||
Notes = x.Notes,
|
||||
InitialOdometer = x.InitialMileage.ToString(),
|
||||
Odometer = x.Mileage.ToString(),
|
||||
Tags = string.Join(" ", x.Tags),
|
||||
ExtraFields = x.ExtraFields
|
||||
});
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
StaticHelper.WriteOdometerRecordExportModel(csv, exportData);
|
||||
}
|
||||
}
|
||||
return Json($"/{fileNameToExport}");
|
||||
}
|
||||
}
|
||||
else if (mode == ImportMode.SupplyRecord)
|
||||
{
|
||||
var vehicleRecords = _supplyRecordDataAccess.GetSupplyRecordsByVehicleId(vehicleId);
|
||||
if (vehicleRecords.Any())
|
||||
{
|
||||
var exportData = vehicleRecords.Select(x => new SupplyRecordExportModel
|
||||
{
|
||||
Date = x.Date.ToShortDateString(),
|
||||
Description = x.Description,
|
||||
Cost = x.Cost.ToString("C"),
|
||||
PartNumber = x.PartNumber,
|
||||
PartQuantity = x.Quantity.ToString(),
|
||||
PartSupplier = x.PartSupplier,
|
||||
Notes = x.Notes,
|
||||
Tags = string.Join(" ", x.Tags),
|
||||
ExtraFields = x.ExtraFields
|
||||
});
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
StaticHelper.WriteSupplyRecordExportModel(csv, exportData);
|
||||
}
|
||||
}
|
||||
return Json($"/{fileNameToExport}");
|
||||
}
|
||||
}
|
||||
else if (mode == ImportMode.TaxRecord)
|
||||
{
|
||||
var vehicleRecords = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId);
|
||||
if (vehicleRecords.Any())
|
||||
{
|
||||
var exportData = vehicleRecords.Select(x => new TaxRecordExportModel
|
||||
{
|
||||
Date = x.Date.ToShortDateString(),
|
||||
Description = x.Description,
|
||||
Cost = x.Cost.ToString("C"),
|
||||
Notes = x.Notes,
|
||||
Tags = string.Join(" ", x.Tags),
|
||||
ExtraFields = x.ExtraFields
|
||||
});
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
StaticHelper.WriteTaxRecordExportModel(csv, exportData);
|
||||
}
|
||||
}
|
||||
return Json($"/{fileNameToExport}");
|
||||
}
|
||||
}
|
||||
else if (mode == ImportMode.PlanRecord)
|
||||
{
|
||||
var vehicleRecords = _planRecordDataAccess.GetPlanRecordsByVehicleId(vehicleId);
|
||||
if (vehicleRecords.Any())
|
||||
{
|
||||
var exportData = vehicleRecords.Select(x => new PlanRecordExportModel
|
||||
{
|
||||
DateCreated = x.DateCreated.ToString("G"),
|
||||
DateModified = x.DateModified.ToString("G"),
|
||||
Description = x.Description,
|
||||
Cost = x.Cost.ToString("C"),
|
||||
Type = x.ImportMode.ToString(),
|
||||
Priority = x.Priority.ToString(),
|
||||
Progress = x.Progress.ToString(),
|
||||
Notes = x.Notes,
|
||||
ExtraFields = x.ExtraFields
|
||||
});
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
StaticHelper.WritePlanRecordExportModel(csv, exportData);
|
||||
}
|
||||
}
|
||||
return Json($"/{fileNameToExport}");
|
||||
}
|
||||
}
|
||||
else if (mode == ImportMode.GasRecord)
|
||||
{
|
||||
var vehicleRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
||||
var vehicleData = _dataAccess.GetVehicleById(vehicleId);
|
||||
bool useMPG = _config.GetUserConfig(User).UseMPG;
|
||||
bool useUKMPG = !vehicleData.IsElectric && _config.GetUserConfig(User).UseUKMPG; //do not apply UK conversion on electric vehicles.
|
||||
var convertedRecords = _gasHelper.GetGasRecordViewModels(vehicleRecords, useMPG, useUKMPG);
|
||||
var exportData = convertedRecords.Select(x => new GasRecordExportModel
|
||||
{
|
||||
Date = x.Date.ToString(),
|
||||
Cost = x.Cost.ToString(),
|
||||
FuelConsumed = x.Gallons.ToString(),
|
||||
FuelEconomy = x.MilesPerGallon.ToString(),
|
||||
Odometer = x.Mileage.ToString(),
|
||||
IsFillToFull = x.IsFillToFull.ToString(),
|
||||
MissedFuelUp = x.MissedFuelUp.ToString(),
|
||||
Notes = x.Notes,
|
||||
Tags = string.Join(" ", x.Tags),
|
||||
ExtraFields = x.ExtraFields
|
||||
});
|
||||
using (var writer = new StreamWriter(fullExportFilePath))
|
||||
{
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
StaticHelper.WriteGasRecordExportModel(csv, exportData);
|
||||
}
|
||||
}
|
||||
return Json($"/{fileNameToExport}");
|
||||
}
|
||||
return Json(OperationResponse.Failed(StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter), Arguments = new object[] { false, true, HouseholdPermission.Edit })]
|
||||
[HttpPost]
|
||||
public IActionResult ImportToVehicleIdFromCsv(int vehicleId, ImportMode mode, string fileName)
|
||||
{
|
||||
if (vehicleId == default && mode != ImportMode.SupplyRecord)
|
||||
{
|
||||
return Json(false);
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(fileName))
|
||||
{
|
||||
return Json(false);
|
||||
}
|
||||
var fullFileName = _fileHelper.GetFullFilePath(fileName);
|
||||
if (string.IsNullOrWhiteSpace(fullFileName))
|
||||
{
|
||||
return Json(false);
|
||||
}
|
||||
try
|
||||
{
|
||||
using (var reader = new StreamReader(fullFileName))
|
||||
{
|
||||
var config = new CsvConfiguration(CultureInfo.InvariantCulture);
|
||||
config.MissingFieldFound = null;
|
||||
config.HeaderValidated = null;
|
||||
config.PrepareHeaderForMatch = args => { return args.Header.Trim().ToLower(); };
|
||||
using (var csv = new CsvReader(reader, config))
|
||||
{
|
||||
csv.Context.RegisterClassMap<ImportMapper>();
|
||||
var records = csv.GetRecords<ImportModel>().ToList();
|
||||
if (records.Any())
|
||||
{
|
||||
var requiredExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)mode).ExtraFields.Where(x => x.IsRequired).Select(y => y.Name);
|
||||
foreach (ImportModel importModel in records)
|
||||
{
|
||||
var parsedDate = DateTime.Now.Date;
|
||||
if (!string.IsNullOrWhiteSpace(importModel.Date))
|
||||
{
|
||||
parsedDate = DateTime.Parse(importModel.Date);
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(importModel.Day) && !string.IsNullOrWhiteSpace(importModel.Month) && !string.IsNullOrWhiteSpace(importModel.Year))
|
||||
{
|
||||
parsedDate = new DateTime(int.Parse(importModel.Year), int.Parse(importModel.Month), int.Parse(importModel.Day));
|
||||
}
|
||||
if (mode == ImportMode.GasRecord)
|
||||
{
|
||||
//convert to gas model.
|
||||
var convertedRecord = new GasRecord()
|
||||
{
|
||||
VehicleId = vehicleId,
|
||||
Date = parsedDate,
|
||||
Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)),
|
||||
Gallons = decimal.Parse(importModel.FuelConsumed, NumberStyles.Any),
|
||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList(),
|
||||
ExtraFields = importModel.ExtraFields.Any() ? importModel.ExtraFields.Select(x => new ExtraField { Name = x.Key, Value = x.Value, IsRequired = requiredExtraFields.Contains(x.Key) }).ToList() : new List<ExtraField>()
|
||||
};
|
||||
if (string.IsNullOrWhiteSpace(importModel.Cost) && !string.IsNullOrWhiteSpace(importModel.Price))
|
||||
{
|
||||
//cost was not given but price is.
|
||||
//fuelly sometimes exports CSVs without total cost.
|
||||
var parsedPrice = decimal.Parse(importModel.Price, NumberStyles.Any);
|
||||
convertedRecord.Cost = convertedRecord.Gallons * parsedPrice;
|
||||
}
|
||||
else
|
||||
{
|
||||
convertedRecord.Cost = decimal.Parse(importModel.Cost, NumberStyles.Any);
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(importModel.IsFillToFull) && !string.IsNullOrWhiteSpace(importModel.PartialFuelUp))
|
||||
{
|
||||
var parsedBool = importModel.PartialFuelUp.Trim() == "1";
|
||||
convertedRecord.IsFillToFull = !parsedBool;
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(importModel.IsFillToFull))
|
||||
{
|
||||
var possibleFillToFullValues = new List<string> { "1", "true", "full" };
|
||||
var parsedBool = possibleFillToFullValues.Contains(importModel.IsFillToFull.Trim().ToLower());
|
||||
convertedRecord.IsFillToFull = parsedBool;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(importModel.MissedFuelUp))
|
||||
{
|
||||
var possibleMissedFuelUpValues = new List<string> { "1", "true" };
|
||||
var parsedBool = possibleMissedFuelUpValues.Contains(importModel.MissedFuelUp.Trim().ToLower());
|
||||
convertedRecord.MissedFuelUp = parsedBool;
|
||||
}
|
||||
//insert record into db, check to make sure fuelconsumed is not zero so we don't get a divide by zero error.
|
||||
if (convertedRecord.Gallons > 0)
|
||||
{
|
||||
_gasRecordDataAccess.SaveGasRecordToVehicle(convertedRecord);
|
||||
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
{
|
||||
_odometerLogic.AutoInsertOdometerRecord(new OdometerRecord
|
||||
{
|
||||
Date = convertedRecord.Date,
|
||||
VehicleId = convertedRecord.VehicleId,
|
||||
Mileage = convertedRecord.Mileage,
|
||||
Notes = $"Auto Insert From Gas Record via CSV Import. {convertedRecord.Notes}",
|
||||
Files = StaticHelper.CreateAttachmentFromRecord(ImportMode.GasRecord, convertedRecord.Id, $"Gas Record - {convertedRecord.Mileage.ToString()}")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (mode == ImportMode.ServiceRecord)
|
||||
{
|
||||
var convertedRecord = new ServiceRecord()
|
||||
{
|
||||
VehicleId = vehicleId,
|
||||
Date = parsedDate,
|
||||
Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)),
|
||||
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Service Record on {parsedDate.ToShortDateString()}" : importModel.Description,
|
||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList(),
|
||||
ExtraFields = importModel.ExtraFields.Any() ? importModel.ExtraFields.Select(x => new ExtraField { Name = x.Key, Value = x.Value, IsRequired = requiredExtraFields.Contains(x.Key) }).ToList() : new List<ExtraField>()
|
||||
};
|
||||
_serviceRecordDataAccess.SaveServiceRecordToVehicle(convertedRecord);
|
||||
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
{
|
||||
_odometerLogic.AutoInsertOdometerRecord(new OdometerRecord
|
||||
{
|
||||
Date = convertedRecord.Date,
|
||||
VehicleId = convertedRecord.VehicleId,
|
||||
Mileage = convertedRecord.Mileage,
|
||||
Notes = $"Auto Insert From Service Record via CSV Import. {convertedRecord.Notes}",
|
||||
Files = StaticHelper.CreateAttachmentFromRecord(ImportMode.ServiceRecord, convertedRecord.Id, convertedRecord.Description)
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (mode == ImportMode.OdometerRecord)
|
||||
{
|
||||
var convertedRecord = new OdometerRecord()
|
||||
{
|
||||
VehicleId = vehicleId,
|
||||
Date = parsedDate,
|
||||
InitialMileage = string.IsNullOrWhiteSpace(importModel.InitialOdometer) ? 0 : decimal.ToInt32(decimal.Parse(importModel.InitialOdometer, NumberStyles.Any)),
|
||||
Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)),
|
||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList(),
|
||||
ExtraFields = importModel.ExtraFields.Any() ? importModel.ExtraFields.Select(x => new ExtraField { Name = x.Key, Value = x.Value, IsRequired = requiredExtraFields.Contains(x.Key) }).ToList() : new List<ExtraField>()
|
||||
};
|
||||
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(convertedRecord);
|
||||
}
|
||||
else if (mode == ImportMode.PlanRecord)
|
||||
{
|
||||
var progressIsEnum = Enum.TryParse(importModel.Progress, out PlanProgress parsedProgress);
|
||||
var typeIsEnum = Enum.TryParse(importModel.Type, out ImportMode parsedType);
|
||||
var priorityIsEnum = Enum.TryParse(importModel.Priority, out PlanPriority parsedPriority);
|
||||
var convertedRecord = new PlanRecord()
|
||||
{
|
||||
VehicleId = vehicleId,
|
||||
DateCreated = DateTime.Parse(importModel.DateCreated),
|
||||
DateModified = DateTime.Parse(importModel.DateModified),
|
||||
Progress = parsedProgress,
|
||||
ImportMode = parsedType,
|
||||
Priority = parsedPriority,
|
||||
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Plan Record on {importModel.DateCreated}" : importModel.Description,
|
||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||
ExtraFields = importModel.ExtraFields.Any() ? importModel.ExtraFields.Select(x => new ExtraField { Name = x.Key, Value = x.Value, IsRequired = requiredExtraFields.Contains(x.Key) }).ToList() : new List<ExtraField>()
|
||||
};
|
||||
_planRecordDataAccess.SavePlanRecordToVehicle(convertedRecord);
|
||||
}
|
||||
else if (mode == ImportMode.RepairRecord)
|
||||
{
|
||||
var convertedRecord = new CollisionRecord()
|
||||
{
|
||||
VehicleId = vehicleId,
|
||||
Date = parsedDate,
|
||||
Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)),
|
||||
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Repair Record on {parsedDate.ToShortDateString()}" : importModel.Description,
|
||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList(),
|
||||
ExtraFields = importModel.ExtraFields.Any() ? importModel.ExtraFields.Select(x => new ExtraField { Name = x.Key, Value = x.Value, IsRequired = requiredExtraFields.Contains(x.Key) }).ToList() : new List<ExtraField>()
|
||||
};
|
||||
_collisionRecordDataAccess.SaveCollisionRecordToVehicle(convertedRecord);
|
||||
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
{
|
||||
_odometerLogic.AutoInsertOdometerRecord(new OdometerRecord
|
||||
{
|
||||
Date = convertedRecord.Date,
|
||||
VehicleId = convertedRecord.VehicleId,
|
||||
Mileage = convertedRecord.Mileage,
|
||||
Notes = $"Auto Insert From Repair Record via CSV Import. {convertedRecord.Notes}",
|
||||
Files = StaticHelper.CreateAttachmentFromRecord(ImportMode.RepairRecord, convertedRecord.Id, convertedRecord.Description)
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (mode == ImportMode.UpgradeRecord)
|
||||
{
|
||||
var convertedRecord = new UpgradeRecord()
|
||||
{
|
||||
VehicleId = vehicleId,
|
||||
Date = parsedDate,
|
||||
Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)),
|
||||
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Upgrade Record on {parsedDate.ToShortDateString()}" : importModel.Description,
|
||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList(),
|
||||
ExtraFields = importModel.ExtraFields.Any() ? importModel.ExtraFields.Select(x => new ExtraField { Name = x.Key, Value = x.Value, IsRequired = requiredExtraFields.Contains(x.Key) }).ToList() : new List<ExtraField>()
|
||||
};
|
||||
_upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(convertedRecord);
|
||||
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
{
|
||||
_odometerLogic.AutoInsertOdometerRecord(new OdometerRecord
|
||||
{
|
||||
Date = convertedRecord.Date,
|
||||
VehicleId = convertedRecord.VehicleId,
|
||||
Mileage = convertedRecord.Mileage,
|
||||
Notes = $"Auto Insert From Upgrade Record via CSV Import. {convertedRecord.Notes}",
|
||||
Files = StaticHelper.CreateAttachmentFromRecord(ImportMode.UpgradeRecord, convertedRecord.Id, convertedRecord.Description)
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (mode == ImportMode.SupplyRecord)
|
||||
{
|
||||
var convertedRecord = new SupplyRecord()
|
||||
{
|
||||
VehicleId = vehicleId,
|
||||
Date = parsedDate,
|
||||
PartNumber = importModel.PartNumber,
|
||||
PartSupplier = importModel.PartSupplier,
|
||||
Quantity = decimal.Parse(importModel.PartQuantity, NumberStyles.Any),
|
||||
Description = importModel.Description,
|
||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||
Notes = importModel.Notes,
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList(),
|
||||
ExtraFields = importModel.ExtraFields.Any() ? importModel.ExtraFields.Select(x => new ExtraField { Name = x.Key, Value = x.Value, IsRequired = requiredExtraFields.Contains(x.Key) }).ToList() : new List<ExtraField>()
|
||||
};
|
||||
_supplyRecordDataAccess.SaveSupplyRecordToVehicle(convertedRecord);
|
||||
}
|
||||
else if (mode == ImportMode.TaxRecord)
|
||||
{
|
||||
var convertedRecord = new TaxRecord()
|
||||
{
|
||||
VehicleId = vehicleId,
|
||||
Date = parsedDate,
|
||||
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Tax Record on {parsedDate.ToShortDateString()}" : importModel.Description,
|
||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList(),
|
||||
ExtraFields = importModel.ExtraFields.Any() ? importModel.ExtraFields.Select(x => new ExtraField { Name = x.Key, Value = x.Value, IsRequired = requiredExtraFields.Contains(x.Key) }).ToList() : new List<ExtraField>()
|
||||
};
|
||||
_taxRecordDataAccess.SaveTaxRecordToVehicle(convertedRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Json(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error Occurred While Bulk Inserting");
|
||||
return Json(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
270
Controllers/Vehicle/InspectionController.cs
Normal file
270
Controllers/Vehicle/InspectionController.cs
Normal file
@ -0,0 +1,270 @@
|
||||
using CarCareTracker.Filter;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace CarCareTracker.Controllers
|
||||
{
|
||||
public partial class VehicleController
|
||||
{
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetInspectionRecordTemplatesByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _inspectionRecordTemplateDataAccess.GetInspectionRecordTemplatesByVehicleId(vehicleId);
|
||||
return PartialView("Inspection/_InspectionRecordTemplateSelector", result);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetInspectionRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _inspectionRecordDataAccess.GetInspectionRecordsByVehicleId(vehicleId);
|
||||
bool _useDescending = _config.GetUserConfig(User).UseDescending;
|
||||
if (_useDescending)
|
||||
{
|
||||
result = result.OrderByDescending(x => x.Date).ThenByDescending(x => x.Mileage).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = result.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList();
|
||||
}
|
||||
return PartialView("Inspection/_InspectionRecords", result);
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetAddInspectionRecordTemplatePartialView()
|
||||
{
|
||||
return PartialView("Inspection/_InspectionRecordTemplateEditModal", new InspectionRecordInput());
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetEditInspectionRecordTemplatePartialView(int inspectionRecordTemplateId)
|
||||
{
|
||||
var existingRecord = _inspectionRecordTemplateDataAccess.GetInspectionRecordTemplateById(inspectionRecordTemplateId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.View))
|
||||
{
|
||||
return Redirect("/Error/Unauthorized");
|
||||
}
|
||||
if (existingRecord.ReminderRecordId.Any())
|
||||
{
|
||||
bool reminderMissing = false;
|
||||
//check if reminder still exists and is still recurring.
|
||||
foreach (int reminderRecordId in existingRecord.ReminderRecordId)
|
||||
{
|
||||
var existingReminder = _reminderRecordDataAccess.GetReminderRecordById(reminderRecordId);
|
||||
if (existingReminder is null || existingReminder.Id == default || !existingReminder.IsRecurring)
|
||||
{
|
||||
reminderMissing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (reminderMissing)
|
||||
{
|
||||
//clear out reminders attached to record.
|
||||
existingRecord.ReminderRecordId = new List<int>();
|
||||
}
|
||||
}
|
||||
return PartialView("Inspection/_InspectionRecordTemplateEditModal", existingRecord);
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetAddInspectionRecordFieldPartialView()
|
||||
{
|
||||
return PartialView("Inspection/_InspectionRecordField", new InspectionRecordTemplateField());
|
||||
}
|
||||
public IActionResult GetAddInspectionRecordFieldOptionsPartialView()
|
||||
{
|
||||
return PartialView("Inspection/_InspectionRecordFieldOptions", new List<InspectionRecordTemplateFieldOption>());
|
||||
}
|
||||
public IActionResult GetAddInspectionRecordFieldOptionPartialView()
|
||||
{
|
||||
return PartialView("Inspection/_InspectionRecordFieldOption", new InspectionRecordTemplateFieldOption());
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SaveInspectionRecordTemplateToVehicleId(InspectionRecordInput inspectionRecordTemplate)
|
||||
{
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), inspectionRecordTemplate.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
var result = _inspectionRecordTemplateDataAccess.SaveInspectionReportTemplateToVehicle(inspectionRecordTemplate);
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
private OperationResponse DeleteInspectionRecordTemplateWithChecks(int inspectionRecordTemplateId)
|
||||
{
|
||||
var existingRecord = _inspectionRecordTemplateDataAccess.GetInspectionRecordTemplateById(inspectionRecordTemplateId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Delete))
|
||||
{
|
||||
return OperationResponse.Failed("Access Denied");
|
||||
}
|
||||
var result = _inspectionRecordTemplateDataAccess.DeleteInspectionRecordTemplateById(existingRecord.Id);
|
||||
return OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage);
|
||||
}
|
||||
private OperationResponse DeleteInspectionRecordWithChecks(int inspectionRecordId)
|
||||
{
|
||||
var existingRecord = _inspectionRecordDataAccess.GetInspectionRecordById(inspectionRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Delete))
|
||||
{
|
||||
return OperationResponse.Failed("Access Denied");
|
||||
}
|
||||
var result = _inspectionRecordDataAccess.DeleteInspectionRecordById(existingRecord.Id);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromInspectionRecord(existingRecord, "inspectionrecord.delete", User.Identity.Name));
|
||||
}
|
||||
return OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult DeleteInspectionRecordTemplateById(int inspectionRecordTemplateId)
|
||||
{
|
||||
var result = DeleteInspectionRecordTemplateWithChecks(inspectionRecordTemplateId);
|
||||
return Json(result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult DeleteInspectionRecordById(int inspectionRecordId)
|
||||
{
|
||||
var result = DeleteInspectionRecordWithChecks(inspectionRecordId);
|
||||
return Json(result);
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetAddInspectionRecordPartialView(int inspectionRecordTemplateId)
|
||||
{
|
||||
var existingRecord = _inspectionRecordTemplateDataAccess.GetInspectionRecordTemplateById(inspectionRecordTemplateId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
//populate date
|
||||
existingRecord.Date = DateTime.Now.ToShortDateString();
|
||||
if (existingRecord.ReminderRecordId.Any())
|
||||
{
|
||||
bool reminderMissing = false;
|
||||
//check if reminder still exists and is still recurring.
|
||||
foreach (int reminderRecordId in existingRecord.ReminderRecordId)
|
||||
{
|
||||
var existingReminder = _reminderRecordDataAccess.GetReminderRecordById(reminderRecordId);
|
||||
if (existingReminder is null || existingReminder.Id == default || !existingReminder.IsRecurring)
|
||||
{
|
||||
reminderMissing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (reminderMissing)
|
||||
{
|
||||
//clear out reminders attached to record.
|
||||
existingRecord.ReminderRecordId = new List<int>();
|
||||
}
|
||||
}
|
||||
return PartialView("Inspection/_InspectionRecordModal", existingRecord);
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetViewInspectionRecordPartialView(int inspectionRecordId)
|
||||
{
|
||||
var result = _inspectionRecordDataAccess.GetInspectionRecordById(inspectionRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), result.VehicleId, HouseholdPermission.View))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
return PartialView("Inspection/_InspectionRecordViewModal", result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SaveInspectionRecordToVehicleId(InspectionRecordInput inspectionRecord)
|
||||
{
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), inspectionRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
//move files from temp.
|
||||
inspectionRecord.Files = inspectionRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||
//push back any reminders
|
||||
if (inspectionRecord.ReminderRecordId.Any())
|
||||
{
|
||||
foreach (int reminderRecordId in inspectionRecord.ReminderRecordId)
|
||||
{
|
||||
PushbackRecurringReminderRecordWithChecks(reminderRecordId, DateTime.Parse(inspectionRecord.Date), inspectionRecord.Mileage);
|
||||
}
|
||||
}
|
||||
var convertedRecord = inspectionRecord.ToInspectionRecord();
|
||||
var result = _inspectionRecordDataAccess.SaveInspectionRecordToVehicle(convertedRecord);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromInspectionRecord(convertedRecord, "inspectionrecord.add", User.Identity.Name));
|
||||
}
|
||||
if (convertedRecord.Id != 0)
|
||||
{
|
||||
//insert into service record
|
||||
List<UploadedFiles> newAttachments = new List<UploadedFiles>();
|
||||
newAttachments.Add(new UploadedFiles { Name = inspectionRecord.Description, Location = StaticHelper.GetRecordAttachment(ImportMode.InspectionRecord, convertedRecord.Id)});
|
||||
newAttachments.AddRange(inspectionRecord.Files);
|
||||
_serviceRecordDataAccess.SaveServiceRecordToVehicle(new ServiceRecord
|
||||
{
|
||||
Date = DateTime.Parse(inspectionRecord.Date),
|
||||
VehicleId = inspectionRecord.VehicleId,
|
||||
Mileage = inspectionRecord.Mileage,
|
||||
Description = inspectionRecord.Description,
|
||||
Cost = inspectionRecord.Cost,
|
||||
Notes = $"Auto Insert From Inspection Record: {inspectionRecord.Description}",
|
||||
Files = newAttachments
|
||||
});
|
||||
//auto-insert into odometer if configured
|
||||
if (inspectionRecord.Id == default && _config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
{
|
||||
_odometerLogic.AutoInsertOdometerRecord(new OdometerRecord
|
||||
{
|
||||
Date = DateTime.Parse(inspectionRecord.Date),
|
||||
VehicleId = inspectionRecord.VehicleId,
|
||||
Mileage = inspectionRecord.Mileage,
|
||||
Notes = $"Auto Insert From Inspection Record: {inspectionRecord.Description}",
|
||||
Files = StaticHelper.CreateAttachmentFromRecord(ImportMode.InspectionRecord, convertedRecord.Id, convertedRecord.Description)
|
||||
});
|
||||
}
|
||||
//create action items
|
||||
var inspectionFieldsWithActionItems = inspectionRecord.Fields.Where(x => x.HasActionItem);
|
||||
if (inspectionFieldsWithActionItems.Any())
|
||||
{
|
||||
foreach (InspectionRecordTemplateField inspectionField in inspectionFieldsWithActionItems)
|
||||
{
|
||||
if (inspectionField.ToInspectionRecordResult().Failed)
|
||||
{
|
||||
_planRecordDataAccess.SavePlanRecordToVehicle(new PlanRecord
|
||||
{
|
||||
DateCreated = DateTime.Now,
|
||||
DateModified = DateTime.Now,
|
||||
VehicleId = inspectionRecord.VehicleId,
|
||||
Description = inspectionField.ActionItemDescription,
|
||||
ImportMode = inspectionField.ActionItemType,
|
||||
Priority = inspectionField.ActionItemPriority,
|
||||
Progress = PlanProgress.Backlog,
|
||||
Notes = $"Auto Insert From Inspection Record: {inspectionRecord.Description}",
|
||||
Files = StaticHelper.CreateAttachmentFromRecord(ImportMode.InspectionRecord, convertedRecord.Id, convertedRecord.Description)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult UpdateInspectionRecord(InspectionRecordInput inspectionRecord)
|
||||
{
|
||||
var existingRecord = _inspectionRecordDataAccess.GetInspectionRecordById(inspectionRecord.Id);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
existingRecord.Tags = inspectionRecord.Tags;
|
||||
existingRecord.Files = inspectionRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||
var result = _inspectionRecordDataAccess.SaveInspectionRecordToVehicle(existingRecord);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromInspectionRecord(existingRecord, "inspectionrecord.update", User.Identity.Name));
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
106
Controllers/Vehicle/NoteController.cs
Normal file
106
Controllers/Vehicle/NoteController.cs
Normal file
@ -0,0 +1,106 @@
|
||||
using CarCareTracker.Filter;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace CarCareTracker.Controllers
|
||||
{
|
||||
public partial class VehicleController
|
||||
{
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetNotesByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _noteDataAccess.GetNotesByVehicleId(vehicleId);
|
||||
result = result.OrderByDescending(x => x.Pinned).ThenBy(x => x.Description).ToList();
|
||||
return PartialView("Note/_Notes", result);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetPinnedNotesByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _noteDataAccess.GetNotesByVehicleId(vehicleId);
|
||||
result = result.Where(x => x.Pinned).ToList();
|
||||
return Json(result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SaveNoteToVehicleId(Note note)
|
||||
{
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), note.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
note.Files = note.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||
bool isCreate = note.Id == default; //needed here since Notes don't use an input object.
|
||||
var result = _noteDataAccess.SaveNoteToVehicle(note);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromNoteRecord(note, isCreate ? "noterecord.add" : "noterecord.update", User.Identity.Name));
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetAddNotePartialView()
|
||||
{
|
||||
var extraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.NoteRecord).ExtraFields;
|
||||
return PartialView("Note/_NoteModal", new Note() { ExtraFields = extraFields });
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetNoteForEditById(int noteId)
|
||||
{
|
||||
var result = _noteDataAccess.GetNoteById(noteId);
|
||||
result.ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.NoteRecord).ExtraFields);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), result.VehicleId, HouseholdPermission.View))
|
||||
{
|
||||
return Redirect("/Error/Unauthorized");
|
||||
}
|
||||
return PartialView("Note/_NoteModal", result);
|
||||
}
|
||||
private OperationResponse DeleteNoteWithChecks(int noteId)
|
||||
{
|
||||
var existingRecord = _noteDataAccess.GetNoteById(noteId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Delete))
|
||||
{
|
||||
return OperationResponse.Failed("Access Denied");
|
||||
}
|
||||
var result = _noteDataAccess.DeleteNoteById(existingRecord.Id);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromNoteRecord(existingRecord, "noterecord.delete", User.Identity.Name));
|
||||
}
|
||||
return OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult DeleteNoteById(int noteId)
|
||||
{
|
||||
var result = DeleteNoteWithChecks(noteId);
|
||||
return Json(result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult PinNotes(List<int> noteIds, bool isToggle = false, bool pinStatus = false)
|
||||
{
|
||||
var result = false;
|
||||
foreach (int noteId in noteIds)
|
||||
{
|
||||
var existingNote = _noteDataAccess.GetNoteById(noteId);
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingNote.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
if (isToggle)
|
||||
{
|
||||
existingNote.Pinned = !existingNote.Pinned;
|
||||
}
|
||||
else
|
||||
{
|
||||
existingNote.Pinned = pinStatus;
|
||||
}
|
||||
result = _noteDataAccess.SaveNoteToVehicle(existingNote);
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
186
Controllers/Vehicle/OdometerController.cs
Normal file
186
Controllers/Vehicle/OdometerController.cs
Normal file
@ -0,0 +1,186 @@
|
||||
using CarCareTracker.Filter;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace CarCareTracker.Controllers
|
||||
{
|
||||
public partial class VehicleController
|
||||
{
|
||||
[HttpPost]
|
||||
public IActionResult ForceRecalculateDistanceByVehicleId(int vehicleId)
|
||||
{
|
||||
//security check
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), vehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
var result = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
|
||||
result = _odometerLogic.AutoConvertOdometerRecord(result);
|
||||
return Json(OperationResponse.Conditional(result.Any(), string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetOdometerRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
|
||||
//determine if conversion is needed.
|
||||
if (result.All(x => x.InitialMileage == default))
|
||||
{
|
||||
result = _odometerLogic.AutoConvertOdometerRecord(result);
|
||||
}
|
||||
bool _useDescending = _config.GetUserConfig(User).UseDescending;
|
||||
if (_useDescending)
|
||||
{
|
||||
result = result.OrderByDescending(x => x.Date).ThenByDescending(x => x.Mileage).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = result.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList();
|
||||
}
|
||||
return PartialView("Odometer/_OdometerRecords", result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SaveOdometerRecordToVehicleId(OdometerRecordInput odometerRecord)
|
||||
{
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), odometerRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
//move files from temp.
|
||||
odometerRecord.Files = odometerRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||
var convertedRecord = odometerRecord.ToOdometerRecord();
|
||||
var result = _odometerRecordDataAccess.SaveOdometerRecordToVehicle(convertedRecord);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromOdometerRecord(convertedRecord, odometerRecord.Id == default ? "odometerrecord.add" : "odometerrecord.update", User.Identity.Name));
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetAddOdometerRecordPartialView(int vehicleId)
|
||||
{
|
||||
return PartialView("Odometer/_OdometerRecordModal", new OdometerRecordInput() { InitialMileage = _odometerLogic.GetLastOdometerRecordMileage(vehicleId, new List<OdometerRecord>()), ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.OdometerRecord).ExtraFields });
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult GetOdometerRecordsEditModal(List<int> recordIds)
|
||||
{
|
||||
var extraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.OdometerRecord).ExtraFields;
|
||||
return PartialView("Odometer/_OdometerRecordsModal", new OdometerRecordEditModel { RecordIds = recordIds, EditRecord = new OdometerRecord { ExtraFields = extraFields } });
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SaveMultipleOdometerRecords(OdometerRecordEditModel editModel)
|
||||
{
|
||||
var dateIsEdited = editModel.EditRecord.Date != default;
|
||||
var initialMileageIsEdited = editModel.EditRecord.InitialMileage != default;
|
||||
var mileageIsEdited = editModel.EditRecord.Mileage != default;
|
||||
var noteIsEdited = !string.IsNullOrWhiteSpace(editModel.EditRecord.Notes);
|
||||
var tagsIsEdited = editModel.EditRecord.Tags.Any();
|
||||
var extraFieldIsEdited = editModel.EditRecord.ExtraFields.Any();
|
||||
//handle clear overrides
|
||||
if (tagsIsEdited && editModel.EditRecord.Tags.Contains("---"))
|
||||
{
|
||||
editModel.EditRecord.Tags = new List<string>();
|
||||
}
|
||||
if (noteIsEdited && editModel.EditRecord.Notes == "---")
|
||||
{
|
||||
editModel.EditRecord.Notes = "";
|
||||
}
|
||||
bool result = false;
|
||||
foreach (int recordId in editModel.RecordIds)
|
||||
{
|
||||
var existingRecord = _odometerRecordDataAccess.GetOdometerRecordById(recordId);
|
||||
//security check
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
if (dateIsEdited)
|
||||
{
|
||||
existingRecord.Date = editModel.EditRecord.Date;
|
||||
}
|
||||
if (initialMileageIsEdited)
|
||||
{
|
||||
existingRecord.InitialMileage = editModel.EditRecord.InitialMileage;
|
||||
}
|
||||
if (mileageIsEdited)
|
||||
{
|
||||
existingRecord.Mileage = editModel.EditRecord.Mileage;
|
||||
}
|
||||
if (noteIsEdited)
|
||||
{
|
||||
existingRecord.Notes = editModel.EditRecord.Notes;
|
||||
}
|
||||
if (tagsIsEdited)
|
||||
{
|
||||
existingRecord.Tags = editModel.EditRecord.Tags;
|
||||
}
|
||||
if (extraFieldIsEdited)
|
||||
{
|
||||
foreach (ExtraField extraField in editModel.EditRecord.ExtraFields)
|
||||
{
|
||||
if (existingRecord.ExtraFields.Any(x => x.Name == extraField.Name))
|
||||
{
|
||||
var insertIndex = existingRecord.ExtraFields.FindIndex(x => x.Name == extraField.Name);
|
||||
existingRecord.ExtraFields.RemoveAll(x => x.Name == extraField.Name);
|
||||
existingRecord.ExtraFields.Insert(insertIndex, extraField);
|
||||
}
|
||||
else
|
||||
{
|
||||
existingRecord.ExtraFields.Add(extraField);
|
||||
}
|
||||
}
|
||||
}
|
||||
result = _odometerRecordDataAccess.SaveOdometerRecordToVehicle(existingRecord);
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetOdometerRecordForEditById(int odometerRecordId)
|
||||
{
|
||||
var result = _odometerRecordDataAccess.GetOdometerRecordById(odometerRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), result.VehicleId, HouseholdPermission.View))
|
||||
{
|
||||
return Redirect("/Error/Unauthorized");
|
||||
}
|
||||
//convert to Input object.
|
||||
var convertedResult = new OdometerRecordInput
|
||||
{
|
||||
Id = result.Id,
|
||||
Date = result.Date.ToShortDateString(),
|
||||
InitialMileage = result.InitialMileage,
|
||||
Mileage = result.Mileage,
|
||||
Notes = result.Notes,
|
||||
VehicleId = result.VehicleId,
|
||||
Files = result.Files,
|
||||
Tags = result.Tags,
|
||||
ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.OdometerRecord).ExtraFields)
|
||||
};
|
||||
return PartialView("Odometer/_OdometerRecordModal", convertedResult);
|
||||
}
|
||||
private OperationResponse DeleteOdometerRecordWithChecks(int odometerRecordId)
|
||||
{
|
||||
var existingRecord = _odometerRecordDataAccess.GetOdometerRecordById(odometerRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Delete))
|
||||
{
|
||||
return OperationResponse.Failed("Access Denied");
|
||||
}
|
||||
var result = _odometerRecordDataAccess.DeleteOdometerRecordById(existingRecord.Id);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromOdometerRecord(existingRecord, "odometerrecord.delete", User.Identity.Name));
|
||||
}
|
||||
return OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult DeleteOdometerRecordById(int odometerRecordId)
|
||||
{
|
||||
var result = DeleteOdometerRecordWithChecks(odometerRecordId);
|
||||
return Json(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
334
Controllers/Vehicle/PlanController.cs
Normal file
334
Controllers/Vehicle/PlanController.cs
Normal file
@ -0,0 +1,334 @@
|
||||
using CarCareTracker.Filter;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace CarCareTracker.Controllers
|
||||
{
|
||||
public partial class VehicleController
|
||||
{
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetPlanRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _planRecordDataAccess.GetPlanRecordsByVehicleId(vehicleId);
|
||||
return PartialView("Plan/_PlanRecords", result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SavePlanRecordToVehicleId(PlanRecordInput planRecord)
|
||||
{
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), planRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
//populate createdDate
|
||||
if (planRecord.Id == default)
|
||||
{
|
||||
planRecord.DateCreated = DateTime.Now.ToString("G");
|
||||
}
|
||||
planRecord.DateModified = DateTime.Now.ToString("G");
|
||||
//move files from temp.
|
||||
planRecord.Files = planRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||
if (planRecord.Supplies.Any())
|
||||
{
|
||||
planRecord.RequisitionHistory.AddRange(RequisitionSupplyRecordsByUsage(planRecord.Supplies, DateTime.Parse(planRecord.DateCreated), planRecord.Description));
|
||||
if (planRecord.CopySuppliesAttachment)
|
||||
{
|
||||
planRecord.Files.AddRange(GetSuppliesAttachments(planRecord.Supplies));
|
||||
}
|
||||
}
|
||||
if (planRecord.DeletedRequisitionHistory.Any())
|
||||
{
|
||||
_vehicleLogic.RestoreSupplyRecordsByUsage(planRecord.DeletedRequisitionHistory, planRecord.Description);
|
||||
}
|
||||
var result = _planRecordDataAccess.SavePlanRecordToVehicle(planRecord.ToPlanRecord());
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromPlanRecord(planRecord.ToPlanRecord(), planRecord.Id == default ? "planrecord.add" : "planrecord.update", User.Identity.Name));
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SavePlanRecordTemplateToVehicleId(PlanRecordInput planRecord)
|
||||
{
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), planRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
//check if template name already taken.
|
||||
var existingRecord = _planRecordTemplateDataAccess.GetPlanRecordTemplatesByVehicleId(planRecord.VehicleId).Where(x => x.Description == planRecord.Description).Any();
|
||||
if (planRecord.Id == default && existingRecord)
|
||||
{
|
||||
return Json(OperationResponse.Failed("A template with that description already exists for this vehicle"));
|
||||
}
|
||||
planRecord.Files = planRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||
var result = _planRecordTemplateDataAccess.SavePlanRecordTemplateToVehicle(planRecord);
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetPlanRecordTemplatesForVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _planRecordTemplateDataAccess.GetPlanRecordTemplatesByVehicleId(vehicleId);
|
||||
return PartialView("Plan/_PlanRecordTemplateModal", result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult DeletePlanRecordTemplateById(int planRecordTemplateId)
|
||||
{
|
||||
var existingRecord = _planRecordTemplateDataAccess.GetPlanRecordTemplateById(planRecordTemplateId);
|
||||
if (existingRecord.Id == default)
|
||||
{
|
||||
return Json(OperationResponse.Failed(StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Delete))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
var result = _planRecordTemplateDataAccess.DeletePlanRecordTemplateById(planRecordTemplateId);
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult OrderPlanSupplies(int planRecordTemplateId)
|
||||
{
|
||||
var existingRecord = _planRecordTemplateDataAccess.GetPlanRecordTemplateById(planRecordTemplateId);
|
||||
if (existingRecord.Id == default)
|
||||
{
|
||||
return Json(OperationResponse.Failed("Unable to find template"));
|
||||
}
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.View))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
if (existingRecord.Supplies.Any())
|
||||
{
|
||||
var suppliesToOrder = CheckSupplyRecordsAvailability(existingRecord.Supplies);
|
||||
return PartialView("Plan/_PlanOrderSupplies", suppliesToOrder);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Json(OperationResponse.Failed("Template has No Supplies"));
|
||||
}
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult ConvertPlanRecordTemplateToPlanRecord(int planRecordTemplateId)
|
||||
{
|
||||
var existingRecord = _planRecordTemplateDataAccess.GetPlanRecordTemplateById(planRecordTemplateId);
|
||||
if (existingRecord.Id == default)
|
||||
{
|
||||
return Json(OperationResponse.Failed("Unable to find template"));
|
||||
}
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
if (existingRecord.Supplies.Any())
|
||||
{
|
||||
//check if all supplies are available
|
||||
var supplyAvailability = CheckSupplyRecordsAvailability(existingRecord.Supplies);
|
||||
if (supplyAvailability.Any(x => x.Missing))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Missing Supplies, Please Delete This Template and Recreate It."));
|
||||
}
|
||||
else if (supplyAvailability.Any(x => x.Insufficient))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Insufficient Supplies"));
|
||||
}
|
||||
}
|
||||
if (existingRecord.ReminderRecordId != default)
|
||||
{
|
||||
//check if reminder still exists and is still recurring.
|
||||
var existingReminder = _reminderRecordDataAccess.GetReminderRecordById(existingRecord.ReminderRecordId);
|
||||
if (existingReminder is null || existingReminder.Id == default || !existingReminder.IsRecurring)
|
||||
{
|
||||
return Json(OperationResponse.Failed("Missing or Non-recurring Reminder, Please Delete This Template and Recreate It."));
|
||||
}
|
||||
}
|
||||
//populate createdDate
|
||||
existingRecord.DateCreated = DateTime.Now.ToString("G");
|
||||
existingRecord.DateModified = DateTime.Now.ToString("G");
|
||||
existingRecord.Id = default;
|
||||
if (existingRecord.Supplies.Any())
|
||||
{
|
||||
existingRecord.RequisitionHistory = RequisitionSupplyRecordsByUsage(existingRecord.Supplies, DateTime.Parse(existingRecord.DateCreated), existingRecord.Description);
|
||||
if (existingRecord.CopySuppliesAttachment)
|
||||
{
|
||||
existingRecord.Files.AddRange(GetSuppliesAttachments(existingRecord.Supplies));
|
||||
}
|
||||
}
|
||||
var result = _planRecordDataAccess.SavePlanRecordToVehicle(existingRecord.ToPlanRecord());
|
||||
return Json(OperationResponse.Conditional(result, "Plan Record Added", StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetAddPlanRecordPartialView()
|
||||
{
|
||||
return PartialView("Plan/_PlanRecordModal", new PlanRecordInput() { ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.PlanRecord).ExtraFields });
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult GetAddPlanRecordPartialView(PlanRecordInput? planModel)
|
||||
{
|
||||
if (planModel is not null)
|
||||
{
|
||||
planModel.ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.PlanRecord).ExtraFields;
|
||||
return PartialView("Plan/_PlanRecordModal", planModel);
|
||||
}
|
||||
return PartialView("Plan/_PlanRecordModal", new PlanRecordInput() { ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.PlanRecord).ExtraFields });
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult UpdatePlanRecordProgress(int planRecordId, PlanProgress planProgress, int odometer = 0)
|
||||
{
|
||||
if (planRecordId == default)
|
||||
{
|
||||
return Json(OperationResponse.Failed(StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
var existingRecord = _planRecordDataAccess.GetPlanRecordById(planRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
existingRecord.Progress = planProgress;
|
||||
existingRecord.DateModified = DateTime.Now;
|
||||
var result = _planRecordDataAccess.SavePlanRecordToVehicle(existingRecord);
|
||||
if (planProgress == PlanProgress.Done)
|
||||
{
|
||||
int newRecordId = 0;
|
||||
//convert plan record to service/upgrade/repair record.
|
||||
if (existingRecord.ImportMode == ImportMode.ServiceRecord)
|
||||
{
|
||||
var newRecord = new ServiceRecord()
|
||||
{
|
||||
VehicleId = existingRecord.VehicleId,
|
||||
Date = DateTime.Now.Date,
|
||||
Mileage = odometer,
|
||||
Description = existingRecord.Description,
|
||||
Cost = existingRecord.Cost,
|
||||
Notes = existingRecord.Notes,
|
||||
Files = existingRecord.Files,
|
||||
RequisitionHistory = existingRecord.RequisitionHistory,
|
||||
ExtraFields = existingRecord.ExtraFields
|
||||
};
|
||||
_serviceRecordDataAccess.SaveServiceRecordToVehicle(newRecord);
|
||||
newRecordId = newRecord.Id;
|
||||
}
|
||||
else if (existingRecord.ImportMode == ImportMode.RepairRecord)
|
||||
{
|
||||
var newRecord = new CollisionRecord()
|
||||
{
|
||||
VehicleId = existingRecord.VehicleId,
|
||||
Date = DateTime.Now.Date,
|
||||
Mileage = odometer,
|
||||
Description = existingRecord.Description,
|
||||
Cost = existingRecord.Cost,
|
||||
Notes = existingRecord.Notes,
|
||||
Files = existingRecord.Files,
|
||||
RequisitionHistory = existingRecord.RequisitionHistory,
|
||||
ExtraFields = existingRecord.ExtraFields
|
||||
};
|
||||
_collisionRecordDataAccess.SaveCollisionRecordToVehicle(newRecord);
|
||||
newRecordId = newRecord.Id;
|
||||
}
|
||||
else if (existingRecord.ImportMode == ImportMode.UpgradeRecord)
|
||||
{
|
||||
var newRecord = new UpgradeRecord()
|
||||
{
|
||||
VehicleId = existingRecord.VehicleId,
|
||||
Date = DateTime.Now.Date,
|
||||
Mileage = odometer,
|
||||
Description = existingRecord.Description,
|
||||
Cost = existingRecord.Cost,
|
||||
Notes = existingRecord.Notes,
|
||||
Files = existingRecord.Files,
|
||||
RequisitionHistory = existingRecord.RequisitionHistory,
|
||||
ExtraFields = existingRecord.ExtraFields
|
||||
};
|
||||
_upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(newRecord);
|
||||
newRecordId = newRecord.Id;
|
||||
}
|
||||
if (newRecordId != default && _config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
{
|
||||
_odometerLogic.AutoInsertOdometerRecord(new OdometerRecord
|
||||
{
|
||||
Date = DateTime.Now.Date,
|
||||
VehicleId = existingRecord.VehicleId,
|
||||
Mileage = odometer,
|
||||
Notes = $"Auto Insert From Plan Record: {existingRecord.Description}",
|
||||
ExtraFields = existingRecord.ExtraFields,
|
||||
Files = StaticHelper.CreateAttachmentFromRecord(existingRecord.ImportMode, newRecordId, existingRecord.Description)
|
||||
});
|
||||
}
|
||||
//push back any reminders
|
||||
if (existingRecord.ReminderRecordId != default)
|
||||
{
|
||||
PushbackRecurringReminderRecordWithChecks(existingRecord.ReminderRecordId, DateTime.Now, odometer);
|
||||
}
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetPlanRecordTemplateForEditById(int planRecordTemplateId)
|
||||
{
|
||||
var result = _planRecordTemplateDataAccess.GetPlanRecordTemplateById(planRecordTemplateId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), result.VehicleId, HouseholdPermission.View))
|
||||
{
|
||||
return Redirect("/Error/Unauthorized");
|
||||
}
|
||||
return PartialView("Plan/_PlanRecordTemplateEditModal", result);
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetPlanRecordForEditById(int planRecordId)
|
||||
{
|
||||
var result = _planRecordDataAccess.GetPlanRecordById(planRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), result.VehicleId, HouseholdPermission.View))
|
||||
{
|
||||
return Redirect("/Error/Unauthorized");
|
||||
}
|
||||
//convert to Input object.
|
||||
var convertedResult = new PlanRecordInput
|
||||
{
|
||||
Id = result.Id,
|
||||
Description = result.Description,
|
||||
DateCreated = result.DateCreated.ToString("G"),
|
||||
DateModified = result.DateModified.ToString("G"),
|
||||
ImportMode = result.ImportMode,
|
||||
Priority = result.Priority,
|
||||
Progress = result.Progress,
|
||||
Cost = result.Cost,
|
||||
Notes = result.Notes,
|
||||
VehicleId = result.VehicleId,
|
||||
Files = result.Files,
|
||||
RequisitionHistory = result.RequisitionHistory,
|
||||
ReminderRecordId = result.ReminderRecordId,
|
||||
ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.PlanRecord).ExtraFields)
|
||||
};
|
||||
return PartialView("Plan/_PlanRecordModal", convertedResult);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult DeletePlanRecordById(int planRecordId)
|
||||
{
|
||||
var existingRecord = _planRecordDataAccess.GetPlanRecordById(planRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Delete))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
//restore any requisitioned supplies if it has not been converted to other record types.
|
||||
if (existingRecord.RequisitionHistory.Any() && existingRecord.Progress != PlanProgress.Done)
|
||||
{
|
||||
_vehicleLogic.RestoreSupplyRecordsByUsage(existingRecord.RequisitionHistory, existingRecord.Description);
|
||||
}
|
||||
var result = _planRecordDataAccess.DeletePlanRecordById(existingRecord.Id);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromPlanRecord(existingRecord, "planrecord.delete", User.Identity.Name));
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
193
Controllers/Vehicle/ReminderController.cs
Normal file
193
Controllers/Vehicle/ReminderController.cs
Normal file
@ -0,0 +1,193 @@
|
||||
using CarCareTracker.Filter;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace CarCareTracker.Controllers
|
||||
{
|
||||
public partial class VehicleController
|
||||
{
|
||||
private List<ReminderRecordViewModel> GetRemindersAndUrgency(int vehicleId, DateTime dateCompare)
|
||||
{
|
||||
var currentMileage = _vehicleLogic.GetMaxMileage(vehicleId);
|
||||
var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId);
|
||||
List<ReminderRecordViewModel> results = _reminderHelper.GetReminderRecordViewModels(reminders, currentMileage, dateCompare);
|
||||
return results;
|
||||
}
|
||||
private bool GetAndUpdateVehicleUrgentOrPastDueReminders(int vehicleId)
|
||||
{
|
||||
var result = GetRemindersAndUrgency(vehicleId, DateTime.Now);
|
||||
//check if user wants auto-refresh past-due reminders
|
||||
if (_config.GetUserConfig(User).EnableAutoReminderRefresh && _userLogic.UserCanEditVehicle(GetUserID(), vehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
//check for past due reminders that are eligible for recurring.
|
||||
var pastDueAndRecurring = result.Where(x => x.Urgency == ReminderUrgency.PastDue && x.IsRecurring);
|
||||
if (pastDueAndRecurring.Any())
|
||||
{
|
||||
foreach (ReminderRecordViewModel reminderRecord in pastDueAndRecurring)
|
||||
{
|
||||
//update based on recurring intervals.
|
||||
//pull reminderRecord based on ID
|
||||
var existingReminder = _reminderRecordDataAccess.GetReminderRecordById(reminderRecord.Id);
|
||||
existingReminder = _reminderHelper.GetUpdatedRecurringReminderRecord(existingReminder, null, null);
|
||||
//save to db.
|
||||
_reminderRecordDataAccess.SaveReminderRecordToVehicle(existingReminder);
|
||||
//set urgency to not urgent so it gets excluded in count.
|
||||
reminderRecord.Urgency = ReminderUrgency.NotUrgent;
|
||||
}
|
||||
}
|
||||
}
|
||||
//check for very urgent or past due reminders that were not eligible for recurring.
|
||||
var pastDueAndUrgentReminders = result.Where(x => x.Urgency == ReminderUrgency.VeryUrgent || x.Urgency == ReminderUrgency.PastDue);
|
||||
if (pastDueAndUrgentReminders.Any())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetVehicleHaveUrgentOrPastDueReminders(int vehicleId)
|
||||
{
|
||||
var result = GetAndUpdateVehicleUrgentOrPastDueReminders(vehicleId);
|
||||
return Json(result);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetReminderRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = GetRemindersAndUrgency(vehicleId, DateTime.Now);
|
||||
result = result.OrderByDescending(x => x.Urgency).ToList();
|
||||
return PartialView("Reminder/_ReminderRecords", result);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetRecurringReminderRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = GetRemindersAndUrgency(vehicleId, DateTime.Now);
|
||||
result.RemoveAll(x => !x.IsRecurring);
|
||||
result = result.OrderByDescending(x => x.Urgency).ThenBy(x => x.Description).ToList();
|
||||
return PartialView("_RecurringReminderSelector", result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult PushbackRecurringReminderRecord(int reminderRecordId)
|
||||
{
|
||||
var result = PushbackRecurringReminderRecordWithChecks(reminderRecordId, null, null);
|
||||
return Json(result);
|
||||
}
|
||||
private OperationResponse PushbackRecurringReminderRecordWithChecks(int reminderRecordId, DateTime? currentDate, int? currentMileage)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingReminder = _reminderRecordDataAccess.GetReminderRecordById(reminderRecordId);
|
||||
if (existingReminder is not null && existingReminder.Id != default && existingReminder.IsRecurring)
|
||||
{
|
||||
//security check
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingReminder.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return OperationResponse.Failed("Access Denied");
|
||||
}
|
||||
existingReminder = _reminderHelper.GetUpdatedRecurringReminderRecord(existingReminder, currentDate, currentMileage);
|
||||
//save to db.
|
||||
var reminderUpdateResult = _reminderRecordDataAccess.SaveReminderRecordToVehicle(existingReminder);
|
||||
if (!reminderUpdateResult)
|
||||
{
|
||||
_logger.LogError("Unable to update reminder either because the reminder no longer exists or is no longer recurring");
|
||||
return OperationResponse.Failed("Unable to update reminder either because the reminder no longer exists or is no longer recurring");
|
||||
}
|
||||
return OperationResponse.Succeed();
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError("Unable to update reminder because it no longer exists.");
|
||||
return OperationResponse.Failed("Unable to update reminder because it no longer exists.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return OperationResponse.Failed(StaticHelper.GenericErrorMessage);
|
||||
}
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SaveReminderRecordToVehicleId(ReminderRecordInput reminderRecord)
|
||||
{
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), reminderRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
var result = _reminderRecordDataAccess.SaveReminderRecordToVehicle(reminderRecord.ToReminderRecord());
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromReminderRecord(reminderRecord.ToReminderRecord(), reminderRecord.Id == default ? "reminderrecord.add" : "reminderrecord.update", User.Identity.Name));
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult GetAddReminderRecordPartialView(ReminderRecordInput? reminderModel)
|
||||
{
|
||||
if (reminderModel is not null)
|
||||
{
|
||||
return PartialView("Reminder/_ReminderRecordModal", reminderModel);
|
||||
}
|
||||
else
|
||||
{
|
||||
return PartialView("Reminder/_ReminderRecordModal", new ReminderRecordInput());
|
||||
}
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetReminderRecordForEditById(int reminderRecordId)
|
||||
{
|
||||
var result = _reminderRecordDataAccess.GetReminderRecordById(reminderRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), result.VehicleId, HouseholdPermission.View))
|
||||
{
|
||||
return Redirect("/Error/Unauthorized");
|
||||
}
|
||||
//convert to Input object.
|
||||
var convertedResult = new ReminderRecordInput
|
||||
{
|
||||
Id = result.Id,
|
||||
Date = result.Date.ToShortDateString(),
|
||||
Description = result.Description,
|
||||
Notes = result.Notes,
|
||||
VehicleId = result.VehicleId,
|
||||
Mileage = result.Mileage,
|
||||
Metric = result.Metric,
|
||||
IsRecurring = result.IsRecurring,
|
||||
FixedIntervals = result.FixedIntervals,
|
||||
UseCustomThresholds = result.UseCustomThresholds,
|
||||
CustomThresholds = result.CustomThresholds,
|
||||
ReminderMileageInterval = result.ReminderMileageInterval,
|
||||
ReminderMonthInterval = result.ReminderMonthInterval,
|
||||
CustomMileageInterval = result.CustomMileageInterval,
|
||||
CustomMonthInterval = result.CustomMonthInterval,
|
||||
CustomMonthIntervalUnit = result.CustomMonthIntervalUnit,
|
||||
Tags = result.Tags
|
||||
};
|
||||
return PartialView("Reminder/_ReminderRecordModal", convertedResult);
|
||||
}
|
||||
private OperationResponse DeleteReminderRecordWithChecks(int reminderRecordId)
|
||||
{
|
||||
var existingRecord = _reminderRecordDataAccess.GetReminderRecordById(reminderRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Delete))
|
||||
{
|
||||
return OperationResponse.Failed("Access Denied");
|
||||
}
|
||||
var result = _reminderRecordDataAccess.DeleteReminderRecordById(existingRecord.Id);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromReminderRecord(existingRecord, "reminderrecord.delete", User.Identity.Name));
|
||||
}
|
||||
return OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult DeleteReminderRecordById(int reminderRecordId)
|
||||
{
|
||||
var result = DeleteReminderRecordWithChecks(reminderRecordId);
|
||||
return Json(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
133
Controllers/Vehicle/RepairController.cs
Normal file
133
Controllers/Vehicle/RepairController.cs
Normal file
@ -0,0 +1,133 @@
|
||||
using CarCareTracker.Filter;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace CarCareTracker.Controllers
|
||||
{
|
||||
public partial class VehicleController
|
||||
{
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetCollisionRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId);
|
||||
bool _useDescending = _config.GetUserConfig(User).UseDescending;
|
||||
if (_useDescending)
|
||||
{
|
||||
result = result.OrderByDescending(x => x.Date).ThenByDescending(x => x.Mileage).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = result.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList();
|
||||
}
|
||||
return PartialView("Collision/_CollisionRecords", result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SaveCollisionRecordToVehicleId(CollisionRecordInput collisionRecord)
|
||||
{
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), collisionRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
//move files from temp.
|
||||
collisionRecord.Files = collisionRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||
if (collisionRecord.Supplies.Any())
|
||||
{
|
||||
collisionRecord.RequisitionHistory.AddRange(RequisitionSupplyRecordsByUsage(collisionRecord.Supplies, DateTime.Parse(collisionRecord.Date), collisionRecord.Description));
|
||||
if (collisionRecord.CopySuppliesAttachment)
|
||||
{
|
||||
collisionRecord.Files.AddRange(GetSuppliesAttachments(collisionRecord.Supplies));
|
||||
}
|
||||
}
|
||||
if (collisionRecord.DeletedRequisitionHistory.Any())
|
||||
{
|
||||
_vehicleLogic.RestoreSupplyRecordsByUsage(collisionRecord.DeletedRequisitionHistory, collisionRecord.Description);
|
||||
}
|
||||
//push back any reminders
|
||||
if (collisionRecord.ReminderRecordId.Any())
|
||||
{
|
||||
foreach (int reminderRecordId in collisionRecord.ReminderRecordId)
|
||||
{
|
||||
PushbackRecurringReminderRecordWithChecks(reminderRecordId, DateTime.Parse(collisionRecord.Date), collisionRecord.Mileage);
|
||||
}
|
||||
}
|
||||
var convertedRecord = collisionRecord.ToCollisionRecord();
|
||||
var result = _collisionRecordDataAccess.SaveCollisionRecordToVehicle(convertedRecord);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromGenericRecord(convertedRecord, collisionRecord.Id == default ? "repairrecord.add" : "repairrecord.update", User.Identity.Name));
|
||||
}
|
||||
if (convertedRecord.Id != default && collisionRecord.Id == default && _config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
{
|
||||
_odometerLogic.AutoInsertOdometerRecord(new OdometerRecord
|
||||
{
|
||||
Date = DateTime.Parse(collisionRecord.Date),
|
||||
VehicleId = collisionRecord.VehicleId,
|
||||
Mileage = collisionRecord.Mileage,
|
||||
Notes = $"Auto Insert From Repair Record: {collisionRecord.Description}",
|
||||
Files = StaticHelper.CreateAttachmentFromRecord(ImportMode.RepairRecord, convertedRecord.Id, convertedRecord.Description)
|
||||
});
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetAddCollisionRecordPartialView()
|
||||
{
|
||||
return PartialView("Collision/_CollisionRecordModal", new CollisionRecordInput() { ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.RepairRecord).ExtraFields });
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetCollisionRecordForEditById(int collisionRecordId)
|
||||
{
|
||||
var result = _collisionRecordDataAccess.GetCollisionRecordById(collisionRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), result.VehicleId, HouseholdPermission.View))
|
||||
{
|
||||
return Redirect("/Error/Unauthorized");
|
||||
}
|
||||
//convert to Input object.
|
||||
var convertedResult = new CollisionRecordInput
|
||||
{
|
||||
Id = result.Id,
|
||||
Cost = result.Cost,
|
||||
Date = result.Date.ToShortDateString(),
|
||||
Description = result.Description,
|
||||
Mileage = result.Mileage,
|
||||
Notes = result.Notes,
|
||||
VehicleId = result.VehicleId,
|
||||
Files = result.Files,
|
||||
Tags = result.Tags,
|
||||
RequisitionHistory = result.RequisitionHistory,
|
||||
ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.RepairRecord).ExtraFields)
|
||||
};
|
||||
return PartialView("Collision/_CollisionRecordModal", convertedResult);
|
||||
}
|
||||
private OperationResponse DeleteCollisionRecordWithChecks(int collisionRecordId)
|
||||
{
|
||||
var existingRecord = _collisionRecordDataAccess.GetCollisionRecordById(collisionRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Delete))
|
||||
{
|
||||
return OperationResponse.Failed("Access Denied");
|
||||
}
|
||||
//restore any requisitioned supplies.
|
||||
if (existingRecord.RequisitionHistory.Any())
|
||||
{
|
||||
_vehicleLogic.RestoreSupplyRecordsByUsage(existingRecord.RequisitionHistory, existingRecord.Description);
|
||||
}
|
||||
var result = _collisionRecordDataAccess.DeleteCollisionRecordById(existingRecord.Id);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromGenericRecord(existingRecord, "repairrecord.delete", User.Identity.Name));
|
||||
}
|
||||
return OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult DeleteCollisionRecordById(int collisionRecordId)
|
||||
{
|
||||
var result = DeleteCollisionRecordWithChecks(collisionRecordId);
|
||||
return Json(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
788
Controllers/Vehicle/ReportController.cs
Normal file
788
Controllers/Vehicle/ReportController.cs
Normal file
@ -0,0 +1,788 @@
|
||||
using CarCareTracker.Filter;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace CarCareTracker.Controllers
|
||||
{
|
||||
public partial class VehicleController
|
||||
{
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetReportPartialView(int vehicleId)
|
||||
{
|
||||
//get records
|
||||
var vehicleData = _dataAccess.GetVehicleById(vehicleId);
|
||||
var vehicleRecords = _vehicleLogic.GetVehicleRecords(vehicleId);
|
||||
var serviceRecords = vehicleRecords.ServiceRecords;
|
||||
var gasRecords = vehicleRecords.GasRecords;
|
||||
var collisionRecords = vehicleRecords.CollisionRecords;
|
||||
var taxRecords = vehicleRecords.TaxRecords;
|
||||
var upgradeRecords = vehicleRecords.UpgradeRecords;
|
||||
var odometerRecords = vehicleRecords.OdometerRecords;
|
||||
var userConfig = _config.GetUserConfig(User);
|
||||
var viewModel = new ReportViewModel() { ReportHeaderForVehicle = new ReportHeader() };
|
||||
//check if vehicle map exists
|
||||
viewModel.HasVehicleImageMap = !string.IsNullOrWhiteSpace(vehicleData.MapLocation);
|
||||
//check if custom widgets are configured
|
||||
viewModel.CustomWidgetsConfigured = _fileHelper.WidgetsExist();
|
||||
//get totalCostMakeUp
|
||||
viewModel.CostMakeUpForVehicle = new CostMakeUpForVehicle
|
||||
{
|
||||
ServiceRecordSum = serviceRecords.Sum(x => x.Cost),
|
||||
GasRecordSum = gasRecords.Sum(x => x.Cost),
|
||||
CollisionRecordSum = collisionRecords.Sum(x => x.Cost),
|
||||
TaxRecordSum = taxRecords.Sum(x => x.Cost),
|
||||
UpgradeRecordSum = upgradeRecords.Sum(x => x.Cost)
|
||||
};
|
||||
//get costbymonth
|
||||
List<CostForVehicleByMonth> allCosts = StaticHelper.GetBaseLineCosts();
|
||||
allCosts.AddRange(_reportHelper.GetServiceRecordSum(serviceRecords, 0));
|
||||
allCosts.AddRange(_reportHelper.GetRepairRecordSum(collisionRecords, 0));
|
||||
allCosts.AddRange(_reportHelper.GetUpgradeRecordSum(upgradeRecords, 0));
|
||||
allCosts.AddRange(_reportHelper.GetGasRecordSum(gasRecords, 0));
|
||||
allCosts.AddRange(_reportHelper.GetTaxRecordSum(taxRecords, 0));
|
||||
allCosts.AddRange(_reportHelper.GetOdometerRecordSum(odometerRecords, 0));
|
||||
viewModel.CostForVehicleByMonth = allCosts.GroupBy(x => new { x.MonthName, x.MonthId }).OrderBy(x => x.Key.MonthId).Select(x => new CostForVehicleByMonth
|
||||
{
|
||||
MonthName = x.Key.MonthName,
|
||||
Cost = x.Sum(y => y.Cost),
|
||||
DistanceTraveled = x.Max(y => y.DistanceTraveled)
|
||||
}).ToList();
|
||||
|
||||
//set available metrics
|
||||
var visibleTabs = userConfig.VisibleTabs;
|
||||
if (visibleTabs.Contains(ImportMode.OdometerRecord) || odometerRecords.Any())
|
||||
{
|
||||
viewModel.AvailableMetrics.Add(ImportMode.OdometerRecord);
|
||||
}
|
||||
if (visibleTabs.Contains(ImportMode.ServiceRecord) || serviceRecords.Any())
|
||||
{
|
||||
viewModel.AvailableMetrics.Add(ImportMode.ServiceRecord);
|
||||
}
|
||||
if (visibleTabs.Contains(ImportMode.RepairRecord) || collisionRecords.Any())
|
||||
{
|
||||
viewModel.AvailableMetrics.Add(ImportMode.RepairRecord);
|
||||
}
|
||||
if (visibleTabs.Contains(ImportMode.UpgradeRecord) || upgradeRecords.Any())
|
||||
{
|
||||
viewModel.AvailableMetrics.Add(ImportMode.UpgradeRecord);
|
||||
}
|
||||
if (visibleTabs.Contains(ImportMode.GasRecord) || gasRecords.Any())
|
||||
{
|
||||
viewModel.AvailableMetrics.Add(ImportMode.GasRecord);
|
||||
}
|
||||
if (visibleTabs.Contains(ImportMode.TaxRecord) || taxRecords.Any())
|
||||
{
|
||||
viewModel.AvailableMetrics.Add(ImportMode.TaxRecord);
|
||||
}
|
||||
|
||||
//get reminders
|
||||
var reminders = GetRemindersAndUrgency(vehicleId, DateTime.Now);
|
||||
viewModel.ReminderMakeUpForVehicle = new ReminderMakeUpForVehicle
|
||||
{
|
||||
NotUrgentCount = reminders.Where(x => x.Urgency == ReminderUrgency.NotUrgent).Count(),
|
||||
UrgentCount = reminders.Where(x => x.Urgency == ReminderUrgency.Urgent).Count(),
|
||||
VeryUrgentCount = reminders.Where(x => x.Urgency == ReminderUrgency.VeryUrgent).Count(),
|
||||
PastDueCount = reminders.Where(x => x.Urgency == ReminderUrgency.PastDue).Count()
|
||||
};
|
||||
//populate year dropdown.
|
||||
var numbersArray = new List<int>();
|
||||
if (serviceRecords.Any())
|
||||
{
|
||||
numbersArray.Add(serviceRecords.Min(x => x.Date.Year));
|
||||
}
|
||||
if (collisionRecords.Any())
|
||||
{
|
||||
numbersArray.Add(collisionRecords.Min(x => x.Date.Year));
|
||||
}
|
||||
if (gasRecords.Any())
|
||||
{
|
||||
numbersArray.Add(gasRecords.Min(x => x.Date.Year));
|
||||
}
|
||||
if (upgradeRecords.Any())
|
||||
{
|
||||
numbersArray.Add(upgradeRecords.Min(x => x.Date.Year));
|
||||
}
|
||||
if (odometerRecords.Any())
|
||||
{
|
||||
numbersArray.Add(odometerRecords.Min(x => x.Date.Year));
|
||||
}
|
||||
var minYear = numbersArray.Any() ? numbersArray.Min() : DateTime.Now.AddYears(-5).Year;
|
||||
var yearDifference = DateTime.Now.Year - minYear + 1;
|
||||
for (int i = 0; i < yearDifference; i++)
|
||||
{
|
||||
viewModel.Years.Add(DateTime.Now.AddYears(i * -1).Year);
|
||||
}
|
||||
//get collaborators
|
||||
var collaborators = _userLogic.GetCollaboratorsForVehicle(vehicleId);
|
||||
var userCanModify = _userLogic.UserCanDirectlyEditVehicle(GetUserID(), vehicleId);
|
||||
viewModel.Collaborators = new VehicleCollaboratorViewModel { CanModifyCollaborators = userCanModify, Collaborators = collaborators};
|
||||
//get MPG per month.
|
||||
var mileageData = _gasHelper.GetGasRecordViewModels(gasRecords, userConfig.UseMPG, !vehicleData.IsElectric && userConfig.UseUKMPG);
|
||||
string preferredFuelMileageUnit = _config.GetUserConfig(User).PreferredGasMileageUnit;
|
||||
var fuelEconomyMileageUnit = StaticHelper.GetFuelEconomyUnit(vehicleData.IsElectric, vehicleData.UseHours, userConfig.UseMPG, userConfig.UseUKMPG);
|
||||
var averageMPG = _gasHelper.GetAverageGasMileage(mileageData, userConfig.UseMPG);
|
||||
mileageData.RemoveAll(x => x.MilesPerGallon == default);
|
||||
bool invertedFuelMileageUnit = fuelEconomyMileageUnit == "l/100km" && preferredFuelMileageUnit == "km/l";
|
||||
var monthlyMileageData = StaticHelper.GetBaseLineCostsNoMonthName();
|
||||
monthlyMileageData.AddRange(mileageData.GroupBy(x => x.MonthId).Select(x => new CostForVehicleByMonth
|
||||
{
|
||||
MonthId = x.Key,
|
||||
Cost = x.Average(y => y.MilesPerGallon)
|
||||
}));
|
||||
monthlyMileageData = monthlyMileageData.GroupBy(x => x.MonthId).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
||||
{
|
||||
MonthId = x.Key,
|
||||
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
||||
Cost = x.Sum(y => y.Cost)
|
||||
}).ToList();
|
||||
if (invertedFuelMileageUnit)
|
||||
{
|
||||
foreach (CostForVehicleByMonth monthMileage in monthlyMileageData)
|
||||
{
|
||||
if (monthMileage.Cost != default)
|
||||
{
|
||||
monthMileage.Cost = 100 / monthMileage.Cost;
|
||||
}
|
||||
}
|
||||
var newAverageMPG = decimal.Parse(averageMPG, NumberStyles.Any);
|
||||
if (newAverageMPG != 0)
|
||||
{
|
||||
newAverageMPG = 100 / newAverageMPG;
|
||||
}
|
||||
averageMPG = newAverageMPG.ToString("F");
|
||||
}
|
||||
var mpgViewModel = new MPGForVehicleByMonth {
|
||||
CostData = monthlyMileageData,
|
||||
Unit = invertedFuelMileageUnit ? preferredFuelMileageUnit : fuelEconomyMileageUnit,
|
||||
SortedCostData = (userConfig.UseMPG || invertedFuelMileageUnit) ? monthlyMileageData.OrderByDescending(x => x.Cost).ToList() : monthlyMileageData.OrderBy(x => x.Cost).ToList()
|
||||
};
|
||||
viewModel.FuelMileageForVehicleByMonth = mpgViewModel;
|
||||
//report header
|
||||
|
||||
var maxMileage = _vehicleLogic.GetMaxMileage(vehicleRecords);
|
||||
var minMileage = _vehicleLogic.GetMinMileage(vehicleRecords);
|
||||
|
||||
viewModel.ReportHeaderForVehicle.TotalCost = _vehicleLogic.GetVehicleTotalCost(vehicleRecords);
|
||||
viewModel.ReportHeaderForVehicle.AverageMPG = $"{averageMPG} {mpgViewModel.Unit}";
|
||||
viewModel.ReportHeaderForVehicle.MaxOdometer = maxMileage;
|
||||
viewModel.ReportHeaderForVehicle.DistanceTraveled = maxMileage - minMileage;
|
||||
return PartialView("_Report", viewModel);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetCollaboratorsForVehicle(int vehicleId)
|
||||
{
|
||||
var result = _userLogic.GetCollaboratorsForVehicle(vehicleId);
|
||||
var userCanModify = _userLogic.UserCanDirectlyEditVehicle(GetUserID(), vehicleId);
|
||||
var viewModel = new VehicleCollaboratorViewModel
|
||||
{
|
||||
Collaborators = result,
|
||||
CanModifyCollaborators = userCanModify
|
||||
};
|
||||
return PartialView("_Collaborators", viewModel);
|
||||
}
|
||||
[TypeFilter(typeof(StrictCollaboratorFilter), Arguments = new object[] {false, true})]
|
||||
[HttpPost]
|
||||
public IActionResult AddCollaboratorsToVehicle(int vehicleId, string username)
|
||||
{
|
||||
var result = _userLogic.AddCollaboratorToVehicle(vehicleId, username);
|
||||
return Json(result);
|
||||
}
|
||||
[TypeFilter(typeof(StrictCollaboratorFilter), Arguments = new object[] { false, true })]
|
||||
[HttpPost]
|
||||
public IActionResult DeleteCollaboratorFromVehicle(int userId, int vehicleId)
|
||||
{
|
||||
var result = _userLogic.DeleteCollaboratorFromVehicle(userId, vehicleId);
|
||||
return Json(result);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpPost]
|
||||
public IActionResult GetSummaryForVehicle(int vehicleId, int year = 0)
|
||||
{
|
||||
var vehicleData = _dataAccess.GetVehicleById(vehicleId);
|
||||
var vehicleRecords = _vehicleLogic.GetVehicleRecords(vehicleId);
|
||||
|
||||
var serviceRecords = vehicleRecords.ServiceRecords;
|
||||
var gasRecords = vehicleRecords.GasRecords;
|
||||
var collisionRecords = vehicleRecords.CollisionRecords;
|
||||
var taxRecords = vehicleRecords.TaxRecords;
|
||||
var upgradeRecords = vehicleRecords.UpgradeRecords;
|
||||
var odometerRecords = vehicleRecords.OdometerRecords;
|
||||
|
||||
if (year != default)
|
||||
{
|
||||
serviceRecords.RemoveAll(x => x.Date.Year != year);
|
||||
gasRecords.RemoveAll(x => x.Date.Year != year);
|
||||
collisionRecords.RemoveAll(x => x.Date.Year != year);
|
||||
taxRecords.RemoveAll(x => x.Date.Year != year);
|
||||
upgradeRecords.RemoveAll(x => x.Date.Year != year);
|
||||
odometerRecords.RemoveAll(x => x.Date.Year != year);
|
||||
}
|
||||
|
||||
var userConfig = _config.GetUserConfig(User);
|
||||
|
||||
var mileageData = _gasHelper.GetGasRecordViewModels(gasRecords, userConfig.UseMPG, !vehicleData.IsElectric && userConfig.UseUKMPG);
|
||||
string preferredFuelMileageUnit = _config.GetUserConfig(User).PreferredGasMileageUnit;
|
||||
var fuelEconomyMileageUnit = StaticHelper.GetFuelEconomyUnit(vehicleData.IsElectric, vehicleData.UseHours, userConfig.UseMPG, userConfig.UseUKMPG);
|
||||
var averageMPG = _gasHelper.GetAverageGasMileage(mileageData, userConfig.UseMPG);
|
||||
bool invertedFuelMileageUnit = fuelEconomyMileageUnit == "l/100km" && preferredFuelMileageUnit == "km/l";
|
||||
|
||||
if (invertedFuelMileageUnit)
|
||||
{
|
||||
var newAverageMPG = decimal.Parse(averageMPG, NumberStyles.Any);
|
||||
if (newAverageMPG != 0)
|
||||
{
|
||||
newAverageMPG = 100 / newAverageMPG;
|
||||
}
|
||||
averageMPG = newAverageMPG.ToString("F");
|
||||
}
|
||||
|
||||
var mpgUnit = invertedFuelMileageUnit ? preferredFuelMileageUnit : fuelEconomyMileageUnit;
|
||||
|
||||
var maxMileage = _vehicleLogic.GetMaxMileage(vehicleRecords);
|
||||
var minMileage = _vehicleLogic.GetMinMileage(vehicleRecords);
|
||||
|
||||
var viewModel = new ReportHeader()
|
||||
{
|
||||
TotalCost = _vehicleLogic.GetVehicleTotalCost(vehicleRecords),
|
||||
AverageMPG = $"{averageMPG} {mpgUnit}",
|
||||
MaxOdometer = maxMileage,
|
||||
DistanceTraveled = maxMileage - minMileage
|
||||
};
|
||||
|
||||
return PartialView("_ReportHeader", viewModel);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetCostMakeUpForVehicle(int vehicleId, int year = 0)
|
||||
{
|
||||
var serviceRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId);
|
||||
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
||||
var collisionRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId);
|
||||
var taxRecords = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId);
|
||||
var upgradeRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
|
||||
if (year != default)
|
||||
{
|
||||
serviceRecords.RemoveAll(x => x.Date.Year != year);
|
||||
gasRecords.RemoveAll(x => x.Date.Year != year);
|
||||
collisionRecords.RemoveAll(x => x.Date.Year != year);
|
||||
taxRecords.RemoveAll(x => x.Date.Year != year);
|
||||
upgradeRecords.RemoveAll(x => x.Date.Year != year);
|
||||
}
|
||||
var viewModel = new CostMakeUpForVehicle
|
||||
{
|
||||
ServiceRecordSum = serviceRecords.Sum(x => x.Cost),
|
||||
GasRecordSum = gasRecords.Sum(x => x.Cost),
|
||||
CollisionRecordSum = collisionRecords.Sum(x => x.Cost),
|
||||
TaxRecordSum = taxRecords.Sum(x => x.Cost),
|
||||
UpgradeRecordSum = upgradeRecords.Sum(x => x.Cost)
|
||||
};
|
||||
return PartialView("_CostMakeUpReport", viewModel);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetCostTableForVehicle(int vehicleId, int year = 0)
|
||||
{
|
||||
var vehicleRecords = _vehicleLogic.GetVehicleRecords(vehicleId);
|
||||
var serviceRecords = vehicleRecords.ServiceRecords;
|
||||
var gasRecords = vehicleRecords.GasRecords;
|
||||
var collisionRecords = vehicleRecords.CollisionRecords;
|
||||
var taxRecords = vehicleRecords.TaxRecords;
|
||||
var upgradeRecords = vehicleRecords.UpgradeRecords;
|
||||
var odometerRecords = vehicleRecords.OdometerRecords;
|
||||
if (year != default)
|
||||
{
|
||||
serviceRecords.RemoveAll(x => x.Date.Year != year);
|
||||
gasRecords.RemoveAll(x => x.Date.Year != year);
|
||||
collisionRecords.RemoveAll(x => x.Date.Year != year);
|
||||
taxRecords.RemoveAll(x => x.Date.Year != year);
|
||||
upgradeRecords.RemoveAll(x => x.Date.Year != year);
|
||||
odometerRecords.RemoveAll(x => x.Date.Year != year);
|
||||
}
|
||||
var maxMileage = _vehicleLogic.GetMaxMileage(vehicleRecords);
|
||||
var minMileage = _vehicleLogic.GetMinMileage(vehicleRecords);
|
||||
var vehicleData = _dataAccess.GetVehicleById(vehicleId);
|
||||
var userConfig = _config.GetUserConfig(User);
|
||||
var totalDistanceTraveled = maxMileage - minMileage;
|
||||
var totalDays = _vehicleLogic.GetOwnershipDays(vehicleData.PurchaseDate, vehicleData.SoldDate, year, serviceRecords, collisionRecords, gasRecords, upgradeRecords, odometerRecords, taxRecords);
|
||||
var viewModel = new CostTableForVehicle
|
||||
{
|
||||
ServiceRecordSum = serviceRecords.Sum(x => x.Cost),
|
||||
GasRecordSum = gasRecords.Sum(x => x.Cost),
|
||||
CollisionRecordSum = collisionRecords.Sum(x => x.Cost),
|
||||
TaxRecordSum = taxRecords.Sum(x => x.Cost),
|
||||
UpgradeRecordSum = upgradeRecords.Sum(x => x.Cost),
|
||||
TotalDistance = totalDistanceTraveled,
|
||||
DistanceUnit = vehicleData.UseHours ? "Cost Per Hour" : userConfig.UseMPG ? "Cost Per Mile" : "Cost Per Kilometer",
|
||||
NumberOfDays = totalDays
|
||||
};
|
||||
return PartialView("_CostTableReport", viewModel);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
public IActionResult GetVehicleImageMap(int vehicleId)
|
||||
{
|
||||
var vehicleData = _dataAccess.GetVehicleById(vehicleId);
|
||||
VehicleImageMap imageMap = new VehicleImageMap();
|
||||
if (!string.IsNullOrWhiteSpace(vehicleData.MapLocation))
|
||||
{
|
||||
var fullFilePath = _fileHelper.GetFullFilePath(vehicleData.MapLocation);
|
||||
if (!string.IsNullOrWhiteSpace(fullFilePath))
|
||||
{
|
||||
var fullFileText = _fileHelper.GetFileText(fullFilePath);
|
||||
imageMap = JsonSerializer.Deserialize<VehicleImageMap>(fullFileText) ?? new VehicleImageMap();
|
||||
}
|
||||
}
|
||||
return PartialView("_VehicleImageMap", imageMap);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
public IActionResult GetReminderMakeUpByVehicle(int vehicleId, int daysToAdd)
|
||||
{
|
||||
var reminders = GetRemindersAndUrgency(vehicleId, DateTime.Now.AddDays(daysToAdd));
|
||||
var viewModel = new ReminderMakeUpForVehicle
|
||||
{
|
||||
NotUrgentCount = reminders.Where(x => x.Urgency == ReminderUrgency.NotUrgent).Count(),
|
||||
UrgentCount = reminders.Where(x => x.Urgency == ReminderUrgency.Urgent).Count(),
|
||||
VeryUrgentCount = reminders.Where(x => x.Urgency == ReminderUrgency.VeryUrgent).Count(),
|
||||
PastDueCount = reminders.Where(x => x.Urgency == ReminderUrgency.PastDue).Count()
|
||||
};
|
||||
return PartialView("_ReminderMakeUpReport", viewModel);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpPost]
|
||||
public IActionResult GetVehicleAttachments(int vehicleId, List<ImportMode> exportTabs)
|
||||
{
|
||||
List<GenericReportModel> attachmentData = new List<GenericReportModel>();
|
||||
if (exportTabs.Contains(ImportMode.ServiceRecord))
|
||||
{
|
||||
var records = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId).Where(x => x.Files.Any());
|
||||
attachmentData.AddRange(records.Select(x => new GenericReportModel
|
||||
{
|
||||
DataType = ImportMode.ServiceRecord,
|
||||
Date = x.Date,
|
||||
Odometer = x.Mileage,
|
||||
Files = x.Files
|
||||
}));
|
||||
}
|
||||
if (exportTabs.Contains(ImportMode.RepairRecord))
|
||||
{
|
||||
var records = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId).Where(x => x.Files.Any());
|
||||
attachmentData.AddRange(records.Select(x => new GenericReportModel
|
||||
{
|
||||
DataType = ImportMode.RepairRecord,
|
||||
Date = x.Date,
|
||||
Odometer = x.Mileage,
|
||||
Files = x.Files
|
||||
}));
|
||||
}
|
||||
if (exportTabs.Contains(ImportMode.UpgradeRecord))
|
||||
{
|
||||
var records = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId).Where(x => x.Files.Any());
|
||||
attachmentData.AddRange(records.Select(x => new GenericReportModel
|
||||
{
|
||||
DataType = ImportMode.UpgradeRecord,
|
||||
Date = x.Date,
|
||||
Odometer = x.Mileage,
|
||||
Files = x.Files
|
||||
}));
|
||||
}
|
||||
if (exportTabs.Contains(ImportMode.GasRecord))
|
||||
{
|
||||
var records = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId).Where(x => x.Files.Any());
|
||||
attachmentData.AddRange(records.Select(x => new GenericReportModel
|
||||
{
|
||||
DataType = ImportMode.GasRecord,
|
||||
Date = x.Date,
|
||||
Odometer = x.Mileage,
|
||||
Files = x.Files
|
||||
}));
|
||||
}
|
||||
if (exportTabs.Contains(ImportMode.TaxRecord))
|
||||
{
|
||||
var records = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId).Where(x => x.Files.Any());
|
||||
attachmentData.AddRange(records.Select(x => new GenericReportModel
|
||||
{
|
||||
DataType = ImportMode.TaxRecord,
|
||||
Date = x.Date,
|
||||
Odometer = 0,
|
||||
Files = x.Files
|
||||
}));
|
||||
}
|
||||
if (exportTabs.Contains(ImportMode.OdometerRecord))
|
||||
{
|
||||
var records = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId).Where(x => x.Files.Any());
|
||||
attachmentData.AddRange(records.Select(x => new GenericReportModel
|
||||
{
|
||||
DataType = ImportMode.OdometerRecord,
|
||||
Date = x.Date,
|
||||
Odometer = x.Mileage,
|
||||
Files = x.Files
|
||||
}));
|
||||
}
|
||||
if (exportTabs.Contains(ImportMode.NoteRecord))
|
||||
{
|
||||
var records = _noteDataAccess.GetNotesByVehicleId(vehicleId).Where(x => x.Files.Any());
|
||||
attachmentData.AddRange(records.Select(x => new GenericReportModel
|
||||
{
|
||||
DataType = ImportMode.NoteRecord,
|
||||
Date = DateTime.Now,
|
||||
Odometer = 0,
|
||||
Files = x.Files
|
||||
}));
|
||||
}
|
||||
if (attachmentData.Any())
|
||||
{
|
||||
attachmentData = attachmentData.OrderBy(x => x.Date).ThenBy(x => x.Odometer).ToList();
|
||||
var result = _fileHelper.MakeAttachmentsExport(attachmentData);
|
||||
if (string.IsNullOrWhiteSpace(result))
|
||||
{
|
||||
return Json(OperationResponse.Failed());
|
||||
}
|
||||
return Json(OperationResponse.Succeed(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Json(OperationResponse.Failed("No Attachments Found"));
|
||||
}
|
||||
}
|
||||
public IActionResult GetReportParameters()
|
||||
{
|
||||
var viewModel = new ReportParameter() {
|
||||
VisibleColumns = new List<string> {
|
||||
nameof(GenericReportModel.DataType),
|
||||
nameof(GenericReportModel.Date),
|
||||
nameof(GenericReportModel.Odometer),
|
||||
nameof(GenericReportModel.Description),
|
||||
nameof(GenericReportModel.Cost),
|
||||
nameof(GenericReportModel.Notes)
|
||||
}
|
||||
};
|
||||
//get all extra fields from service records, repairs, upgrades, and tax records.
|
||||
var recordTypes = new List<int>() { 0, 1, 3, 4 };
|
||||
var extraFields = new List<string>();
|
||||
foreach(int recordType in recordTypes)
|
||||
{
|
||||
extraFields.AddRange(_extraFieldDataAccess.GetExtraFieldsById(recordType).ExtraFields.Select(x => x.Name));
|
||||
}
|
||||
viewModel.ExtraFields = extraFields.Distinct().ToList();
|
||||
|
||||
return PartialView("_ReportParameters", viewModel);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
public IActionResult GetVehicleHistory(int vehicleId, ReportParameter reportParameter)
|
||||
{
|
||||
var vehicleHistory = new VehicleHistoryViewModel();
|
||||
vehicleHistory.ReportParameters = reportParameter;
|
||||
vehicleHistory.VehicleData = _dataAccess.GetVehicleById(vehicleId);
|
||||
var vehicleRecords = _vehicleLogic.GetVehicleRecords(vehicleId);
|
||||
bool useMPG = _config.GetUserConfig(User).UseMPG;
|
||||
bool useUKMPG = !vehicleHistory.VehicleData.IsElectric && _config.GetUserConfig(User).UseUKMPG;
|
||||
var gasViewModels = _gasHelper.GetGasRecordViewModels(vehicleRecords.GasRecords, useMPG, useUKMPG);
|
||||
//filter by tags
|
||||
if (reportParameter.Tags.Any())
|
||||
{
|
||||
if (reportParameter.TagFilter == TagFilter.Exclude)
|
||||
{
|
||||
vehicleRecords.OdometerRecords.RemoveAll(x => x.Tags.Any(y => reportParameter.Tags.Contains(y)));
|
||||
vehicleRecords.ServiceRecords.RemoveAll(x => x.Tags.Any(y => reportParameter.Tags.Contains(y)));
|
||||
vehicleRecords.CollisionRecords.RemoveAll(x => x.Tags.Any(y => reportParameter.Tags.Contains(y)));
|
||||
vehicleRecords.UpgradeRecords.RemoveAll(x => x.Tags.Any(y => reportParameter.Tags.Contains(y)));
|
||||
vehicleRecords.TaxRecords.RemoveAll(x => x.Tags.Any(y => reportParameter.Tags.Contains(y)));
|
||||
gasViewModels.RemoveAll(x => x.Tags.Any(y => reportParameter.Tags.Contains(y)));
|
||||
vehicleRecords.GasRecords.RemoveAll(x => x.Tags.Any(y => reportParameter.Tags.Contains(y)));
|
||||
}
|
||||
else if (reportParameter.TagFilter == TagFilter.IncludeOnly)
|
||||
{
|
||||
vehicleRecords.OdometerRecords.RemoveAll(x => !x.Tags.Any(y => reportParameter.Tags.Contains(y)));
|
||||
vehicleRecords.ServiceRecords.RemoveAll(x => !x.Tags.Any(y => reportParameter.Tags.Contains(y)));
|
||||
vehicleRecords.CollisionRecords.RemoveAll(x => !x.Tags.Any(y => reportParameter.Tags.Contains(y)));
|
||||
vehicleRecords.UpgradeRecords.RemoveAll(x => !x.Tags.Any(y => reportParameter.Tags.Contains(y)));
|
||||
vehicleRecords.TaxRecords.RemoveAll(x => !x.Tags.Any(y => reportParameter.Tags.Contains(y)));
|
||||
gasViewModels.RemoveAll(x => !x.Tags.Any(y => reportParameter.Tags.Contains(y)));
|
||||
vehicleRecords.GasRecords.RemoveAll(x => !x.Tags.Any(y => reportParameter.Tags.Contains(y)));
|
||||
}
|
||||
}
|
||||
//filter by date range.
|
||||
if (reportParameter.FilterByDateRange && !string.IsNullOrWhiteSpace(reportParameter.StartDate) && !string.IsNullOrWhiteSpace(reportParameter.EndDate))
|
||||
{
|
||||
var startDate = DateTime.Parse(reportParameter.StartDate).Date;
|
||||
var endDate = DateTime.Parse(reportParameter.EndDate).Date;
|
||||
//validate date range
|
||||
if (endDate >= startDate) //allow for same day.
|
||||
{
|
||||
vehicleHistory.StartDate = reportParameter.StartDate;
|
||||
vehicleHistory.EndDate = reportParameter.EndDate;
|
||||
//remove all records with dates after the end date and dates before the start date.
|
||||
vehicleRecords.OdometerRecords.RemoveAll(x => x.Date.Date > endDate || x.Date.Date < startDate);
|
||||
vehicleRecords.ServiceRecords.RemoveAll(x => x.Date.Date > endDate || x.Date.Date < startDate);
|
||||
vehicleRecords.CollisionRecords.RemoveAll(x => x.Date.Date > endDate || x.Date.Date < startDate);
|
||||
vehicleRecords.UpgradeRecords.RemoveAll(x => x.Date.Date > endDate || x.Date.Date < startDate);
|
||||
vehicleRecords.TaxRecords.RemoveAll(x => x.Date.Date > endDate || x.Date.Date < startDate);
|
||||
gasViewModels.RemoveAll(x => DateTime.Parse(x.Date).Date > endDate || DateTime.Parse(x.Date).Date < startDate);
|
||||
vehicleRecords.GasRecords.RemoveAll(x => x.Date.Date > endDate || x.Date.Date < startDate);
|
||||
}
|
||||
}
|
||||
var maxMileage = _vehicleLogic.GetMaxMileage(vehicleRecords);
|
||||
vehicleHistory.Odometer = maxMileage.ToString("N0");
|
||||
var minMileage = _vehicleLogic.GetMinMileage(vehicleRecords);
|
||||
var distanceTraveled = maxMileage - minMileage;
|
||||
if (!string.IsNullOrWhiteSpace(vehicleHistory.VehicleData.PurchaseDate))
|
||||
{
|
||||
var endDate = vehicleHistory.VehicleData.SoldDate;
|
||||
int daysOwned = 0;
|
||||
if (string.IsNullOrWhiteSpace(endDate))
|
||||
{
|
||||
endDate = DateTime.Now.ToShortDateString();
|
||||
}
|
||||
try
|
||||
{
|
||||
daysOwned = (DateTime.Parse(endDate) - DateTime.Parse(vehicleHistory.VehicleData.PurchaseDate)).Days;
|
||||
vehicleHistory.DaysOwned = daysOwned.ToString("N0");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
vehicleHistory.DaysOwned = string.Empty;
|
||||
}
|
||||
//calculate depreciation
|
||||
var totalDepreciation = vehicleHistory.VehicleData.PurchasePrice - vehicleHistory.VehicleData.SoldPrice;
|
||||
//we only calculate depreciation if a sold price is provided.
|
||||
if (totalDepreciation != default && vehicleHistory.VehicleData.SoldPrice != default)
|
||||
{
|
||||
vehicleHistory.TotalDepreciation = totalDepreciation;
|
||||
if (daysOwned != default)
|
||||
{
|
||||
vehicleHistory.DepreciationPerDay = Math.Abs(totalDepreciation / daysOwned);
|
||||
}
|
||||
if (distanceTraveled != default)
|
||||
{
|
||||
vehicleHistory.DepreciationPerMile = Math.Abs(totalDepreciation / distanceTraveled);
|
||||
}
|
||||
}
|
||||
}
|
||||
List<GenericReportModel> reportData = new List<GenericReportModel>();
|
||||
string preferredFuelMileageUnit = _config.GetUserConfig(User).PreferredGasMileageUnit;
|
||||
vehicleHistory.DistanceUnit = vehicleHistory.VehicleData.UseHours ? "h" : useMPG ? "mi." : "km";
|
||||
vehicleHistory.TotalGasCost = gasViewModels.Sum(x => x.Cost);
|
||||
vehicleHistory.TotalCost = vehicleRecords.ServiceRecords.Sum(x => x.Cost) + vehicleRecords.CollisionRecords.Sum(x => x.Cost) + vehicleRecords.UpgradeRecords.Sum(x => x.Cost) + vehicleRecords.TaxRecords.Sum(x => x.Cost);
|
||||
if (distanceTraveled != default)
|
||||
{
|
||||
vehicleHistory.DistanceTraveled = distanceTraveled.ToString("N0");
|
||||
vehicleHistory.TotalCostPerMile = vehicleHistory.TotalCost / distanceTraveled;
|
||||
vehicleHistory.TotalGasCostPerMile = vehicleHistory.TotalGasCost / distanceTraveled;
|
||||
}
|
||||
var averageMPG = "0";
|
||||
if (gasViewModels.Any())
|
||||
{
|
||||
averageMPG = _gasHelper.GetAverageGasMileage(gasViewModels, useMPG);
|
||||
}
|
||||
var fuelEconomyMileageUnit = StaticHelper.GetFuelEconomyUnit(vehicleHistory.VehicleData.IsElectric, vehicleHistory.VehicleData.UseHours, useMPG, useUKMPG);
|
||||
if (fuelEconomyMileageUnit == "l/100km" && preferredFuelMileageUnit == "km/l")
|
||||
{
|
||||
//conversion needed.
|
||||
var newAverageMPG = decimal.Parse(averageMPG, NumberStyles.Any);
|
||||
if (newAverageMPG != 0)
|
||||
{
|
||||
newAverageMPG = 100 / newAverageMPG;
|
||||
}
|
||||
averageMPG = newAverageMPG.ToString("F");
|
||||
fuelEconomyMileageUnit = preferredFuelMileageUnit;
|
||||
}
|
||||
vehicleHistory.MPG = $"{averageMPG} {fuelEconomyMileageUnit}";
|
||||
//insert servicerecords
|
||||
reportData.AddRange(vehicleRecords.ServiceRecords.Select(x => new GenericReportModel
|
||||
{
|
||||
Date = x.Date,
|
||||
Odometer = x.Mileage,
|
||||
Description = x.Description,
|
||||
Notes = x.Notes,
|
||||
Cost = x.Cost,
|
||||
DataType = ImportMode.ServiceRecord,
|
||||
ExtraFields = x.ExtraFields,
|
||||
RequisitionHistory = x.RequisitionHistory
|
||||
}));
|
||||
//repair records
|
||||
reportData.AddRange(vehicleRecords.CollisionRecords.Select(x => new GenericReportModel
|
||||
{
|
||||
Date = x.Date,
|
||||
Odometer = x.Mileage,
|
||||
Description = x.Description,
|
||||
Notes = x.Notes,
|
||||
Cost = x.Cost,
|
||||
DataType = ImportMode.RepairRecord,
|
||||
ExtraFields = x.ExtraFields,
|
||||
RequisitionHistory = x.RequisitionHistory
|
||||
}));
|
||||
reportData.AddRange(vehicleRecords.UpgradeRecords.Select(x => new GenericReportModel
|
||||
{
|
||||
Date = x.Date,
|
||||
Odometer = x.Mileage,
|
||||
Description = x.Description,
|
||||
Notes = x.Notes,
|
||||
Cost = x.Cost,
|
||||
DataType = ImportMode.UpgradeRecord,
|
||||
ExtraFields = x.ExtraFields,
|
||||
RequisitionHistory = x.RequisitionHistory
|
||||
}));
|
||||
reportData.AddRange(vehicleRecords.TaxRecords.Select(x => new GenericReportModel
|
||||
{
|
||||
Date = x.Date,
|
||||
Odometer = 0,
|
||||
Description = x.Description,
|
||||
Notes = x.Notes,
|
||||
Cost = x.Cost,
|
||||
DataType = ImportMode.TaxRecord,
|
||||
ExtraFields = x.ExtraFields
|
||||
}));
|
||||
vehicleHistory.VehicleHistory = reportData.OrderBy(x => x.Date).ThenBy(x => x.Odometer).ToList();
|
||||
return PartialView("_VehicleHistory", vehicleHistory);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpPost]
|
||||
public IActionResult GetMonthMPGByVehicle(int vehicleId, int year = 0)
|
||||
{
|
||||
var vehicleData = _dataAccess.GetVehicleById(vehicleId);
|
||||
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
||||
var userConfig = _config.GetUserConfig(User);
|
||||
string preferredFuelMileageUnit = _config.GetUserConfig(User).PreferredGasMileageUnit;
|
||||
var fuelEconomyMileageUnit = StaticHelper.GetFuelEconomyUnit(vehicleData.IsElectric, vehicleData.UseHours, userConfig.UseMPG, userConfig.UseUKMPG);
|
||||
bool invertedFuelMileageUnit = fuelEconomyMileageUnit == "l/100km" && preferredFuelMileageUnit == "km/l";
|
||||
var mileageData = _gasHelper.GetGasRecordViewModels(gasRecords, userConfig.UseMPG, !vehicleData.IsElectric && userConfig.UseUKMPG);
|
||||
if (year != 0)
|
||||
{
|
||||
mileageData.RemoveAll(x => DateTime.Parse(x.Date).Year != year);
|
||||
}
|
||||
mileageData.RemoveAll(x => x.MilesPerGallon == default);
|
||||
var monthlyMileageData = StaticHelper.GetBaseLineCostsNoMonthName();
|
||||
monthlyMileageData.AddRange(mileageData.GroupBy(x => x.MonthId).Select(x => new CostForVehicleByMonth
|
||||
{
|
||||
MonthId = x.Key,
|
||||
Cost = x.Average(y => y.MilesPerGallon)
|
||||
}));
|
||||
monthlyMileageData = monthlyMileageData.GroupBy(x => x.MonthId).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
||||
{
|
||||
MonthId = x.Key,
|
||||
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
||||
Cost = x.Sum(y => y.Cost)
|
||||
}).ToList();
|
||||
if (invertedFuelMileageUnit)
|
||||
{
|
||||
foreach (CostForVehicleByMonth monthMileage in monthlyMileageData)
|
||||
{
|
||||
if (monthMileage.Cost != default)
|
||||
{
|
||||
monthMileage.Cost = 100 / monthMileage.Cost;
|
||||
}
|
||||
}
|
||||
}
|
||||
var mpgViewModel = new MPGForVehicleByMonth
|
||||
{
|
||||
CostData = monthlyMileageData,
|
||||
Unit = invertedFuelMileageUnit ? preferredFuelMileageUnit : fuelEconomyMileageUnit,
|
||||
SortedCostData = (userConfig.UseMPG || invertedFuelMileageUnit) ? monthlyMileageData.OrderByDescending(x => x.Cost).ToList() : monthlyMileageData.OrderBy(x => x.Cost).ToList()
|
||||
};
|
||||
return PartialView("_MPGByMonthReport", mpgViewModel);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpPost]
|
||||
public IActionResult GetCostByMonthByVehicle(int vehicleId, List<ImportMode> selectedMetrics, int year = 0)
|
||||
{
|
||||
List<CostForVehicleByMonth> allCosts = StaticHelper.GetBaseLineCosts();
|
||||
if (selectedMetrics.Contains(ImportMode.ServiceRecord))
|
||||
{
|
||||
var serviceRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId);
|
||||
allCosts.AddRange(_reportHelper.GetServiceRecordSum(serviceRecords, year));
|
||||
}
|
||||
if (selectedMetrics.Contains(ImportMode.RepairRecord))
|
||||
{
|
||||
var repairRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId);
|
||||
allCosts.AddRange(_reportHelper.GetRepairRecordSum(repairRecords, year));
|
||||
}
|
||||
if (selectedMetrics.Contains(ImportMode.UpgradeRecord))
|
||||
{
|
||||
var upgradeRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
|
||||
allCosts.AddRange(_reportHelper.GetUpgradeRecordSum(upgradeRecords, year));
|
||||
}
|
||||
if (selectedMetrics.Contains(ImportMode.GasRecord))
|
||||
{
|
||||
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
||||
allCosts.AddRange(_reportHelper.GetGasRecordSum(gasRecords, year));
|
||||
}
|
||||
if (selectedMetrics.Contains(ImportMode.TaxRecord))
|
||||
{
|
||||
var taxRecords = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId);
|
||||
allCosts.AddRange(_reportHelper.GetTaxRecordSum(taxRecords, year));
|
||||
}
|
||||
if (selectedMetrics.Contains(ImportMode.OdometerRecord))
|
||||
{
|
||||
var odometerRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
|
||||
allCosts.AddRange(_reportHelper.GetOdometerRecordSum(odometerRecords, year));
|
||||
}
|
||||
var groupedRecord = allCosts.GroupBy(x => new { x.MonthName, x.MonthId }).OrderBy(x => x.Key.MonthId).Select(x => new CostForVehicleByMonth
|
||||
{
|
||||
MonthName = x.Key.MonthName,
|
||||
Cost = x.Sum(y => y.Cost),
|
||||
DistanceTraveled = x.Max(y => y.DistanceTraveled)
|
||||
}).ToList();
|
||||
return PartialView("_GasCostByMonthReport", groupedRecord);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpPost]
|
||||
public IActionResult GetCostByMonthAndYearByVehicle(int vehicleId, List<ImportMode> selectedMetrics, int year = 0)
|
||||
{
|
||||
List<CostForVehicleByMonth> allCosts = StaticHelper.GetBaseLineCosts();
|
||||
if (selectedMetrics.Contains(ImportMode.ServiceRecord))
|
||||
{
|
||||
var serviceRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId);
|
||||
allCosts.AddRange(_reportHelper.GetServiceRecordSum(serviceRecords, year, true));
|
||||
}
|
||||
if (selectedMetrics.Contains(ImportMode.RepairRecord))
|
||||
{
|
||||
var repairRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId);
|
||||
allCosts.AddRange(_reportHelper.GetRepairRecordSum(repairRecords, year, true));
|
||||
}
|
||||
if (selectedMetrics.Contains(ImportMode.UpgradeRecord))
|
||||
{
|
||||
var upgradeRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
|
||||
allCosts.AddRange(_reportHelper.GetUpgradeRecordSum(upgradeRecords, year, true));
|
||||
}
|
||||
if (selectedMetrics.Contains(ImportMode.GasRecord))
|
||||
{
|
||||
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
||||
allCosts.AddRange(_reportHelper.GetGasRecordSum(gasRecords, year, true));
|
||||
}
|
||||
if (selectedMetrics.Contains(ImportMode.TaxRecord))
|
||||
{
|
||||
var taxRecords = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId);
|
||||
allCosts.AddRange(_reportHelper.GetTaxRecordSum(taxRecords, year, true));
|
||||
}
|
||||
if (selectedMetrics.Contains(ImportMode.OdometerRecord))
|
||||
{
|
||||
var odometerRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
|
||||
allCosts.AddRange(_reportHelper.GetOdometerRecordSum(odometerRecords, year, true));
|
||||
}
|
||||
var groupedRecord = allCosts.GroupBy(x => new { x.MonthName, x.MonthId, x.Year }).OrderByDescending(x=>x.Key.Year).Select(x => new CostForVehicleByMonth
|
||||
{
|
||||
Year = x.Key.Year,
|
||||
MonthName = x.Key.MonthName,
|
||||
Cost = x.Sum(y => y.Cost),
|
||||
DistanceTraveled = x.Max(y => y.DistanceTraveled),
|
||||
MonthId = x.Key.MonthId
|
||||
}).ToList();
|
||||
var vehicleData = _dataAccess.GetVehicleById(vehicleId);
|
||||
var userConfig = _config.GetUserConfig(User);
|
||||
var viewModel = new CostDistanceTableForVehicle { CostData = groupedRecord };
|
||||
viewModel.DistanceUnit = vehicleData.UseHours ? "h" : userConfig.UseMPG ? "mi." : "km";
|
||||
return PartialView("_CostDistanceTableReport", viewModel);
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetAdditionalWidgets()
|
||||
{
|
||||
var widgets = _fileHelper.GetWidgets();
|
||||
return PartialView("_ReportWidgets", widgets);
|
||||
}
|
||||
}
|
||||
}
|
||||
133
Controllers/Vehicle/ServiceController.cs
Normal file
133
Controllers/Vehicle/ServiceController.cs
Normal file
@ -0,0 +1,133 @@
|
||||
using CarCareTracker.Filter;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace CarCareTracker.Controllers
|
||||
{
|
||||
public partial class VehicleController
|
||||
{
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetServiceRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId);
|
||||
bool _useDescending = _config.GetUserConfig(User).UseDescending;
|
||||
if (_useDescending)
|
||||
{
|
||||
result = result.OrderByDescending(x => x.Date).ThenByDescending(x => x.Mileage).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = result.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList();
|
||||
}
|
||||
return PartialView("Service/_ServiceRecords", result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SaveServiceRecordToVehicleId(ServiceRecordInput serviceRecord)
|
||||
{
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), serviceRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
//move files from temp.
|
||||
serviceRecord.Files = serviceRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||
if (serviceRecord.Supplies.Any())
|
||||
{
|
||||
serviceRecord.RequisitionHistory.AddRange(RequisitionSupplyRecordsByUsage(serviceRecord.Supplies, DateTime.Parse(serviceRecord.Date), serviceRecord.Description));
|
||||
if (serviceRecord.CopySuppliesAttachment)
|
||||
{
|
||||
serviceRecord.Files.AddRange(GetSuppliesAttachments(serviceRecord.Supplies));
|
||||
}
|
||||
}
|
||||
if (serviceRecord.DeletedRequisitionHistory.Any())
|
||||
{
|
||||
_vehicleLogic.RestoreSupplyRecordsByUsage(serviceRecord.DeletedRequisitionHistory, serviceRecord.Description);
|
||||
}
|
||||
//push back any reminders
|
||||
if (serviceRecord.ReminderRecordId.Any())
|
||||
{
|
||||
foreach (int reminderRecordId in serviceRecord.ReminderRecordId)
|
||||
{
|
||||
PushbackRecurringReminderRecordWithChecks(reminderRecordId, DateTime.Parse(serviceRecord.Date), serviceRecord.Mileage);
|
||||
}
|
||||
}
|
||||
var convertedRecord = serviceRecord.ToServiceRecord();
|
||||
var result = _serviceRecordDataAccess.SaveServiceRecordToVehicle(convertedRecord);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromGenericRecord(convertedRecord, serviceRecord.Id == default ? "servicerecord.add" : "servicerecord.update", User.Identity.Name));
|
||||
}
|
||||
if (convertedRecord.Id != default && serviceRecord.Id == default && _config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
{
|
||||
_odometerLogic.AutoInsertOdometerRecord(new OdometerRecord
|
||||
{
|
||||
Date = DateTime.Parse(serviceRecord.Date),
|
||||
VehicleId = serviceRecord.VehicleId,
|
||||
Mileage = serviceRecord.Mileage,
|
||||
Notes = $"Auto Insert From Service Record: {serviceRecord.Description}",
|
||||
Files = StaticHelper.CreateAttachmentFromRecord(ImportMode.ServiceRecord, convertedRecord.Id, convertedRecord.Description)
|
||||
});
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetAddServiceRecordPartialView()
|
||||
{
|
||||
return PartialView("Service/_ServiceRecordModal", new ServiceRecordInput() { ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.ServiceRecord).ExtraFields });
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetServiceRecordForEditById(int serviceRecordId)
|
||||
{
|
||||
var result = _serviceRecordDataAccess.GetServiceRecordById(serviceRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), result.VehicleId, HouseholdPermission.View))
|
||||
{
|
||||
return Redirect("/Error/Unauthorized");
|
||||
}
|
||||
//convert to Input object.
|
||||
var convertedResult = new ServiceRecordInput
|
||||
{
|
||||
Id = result.Id,
|
||||
Cost = result.Cost,
|
||||
Date = result.Date.ToShortDateString(),
|
||||
Description = result.Description,
|
||||
Mileage = result.Mileage,
|
||||
Notes = result.Notes,
|
||||
VehicleId = result.VehicleId,
|
||||
Files = result.Files,
|
||||
Tags = result.Tags,
|
||||
RequisitionHistory = result.RequisitionHistory,
|
||||
ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.ServiceRecord).ExtraFields)
|
||||
};
|
||||
return PartialView("Service/_ServiceRecordModal", convertedResult);
|
||||
}
|
||||
private OperationResponse DeleteServiceRecordWithChecks(int serviceRecordId)
|
||||
{
|
||||
var existingRecord = _serviceRecordDataAccess.GetServiceRecordById(serviceRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Delete))
|
||||
{
|
||||
return OperationResponse.Failed("Access Denied");
|
||||
}
|
||||
//restore any requisitioned supplies.
|
||||
if (existingRecord.RequisitionHistory.Any())
|
||||
{
|
||||
_vehicleLogic.RestoreSupplyRecordsByUsage(existingRecord.RequisitionHistory, existingRecord.Description);
|
||||
}
|
||||
var result = _serviceRecordDataAccess.DeleteServiceRecordById(existingRecord.Id);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromGenericRecord(existingRecord, "servicerecord.delete", User.Identity.Name));
|
||||
}
|
||||
return OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult DeleteServiceRecordById(int serviceRecordId)
|
||||
{
|
||||
var result = DeleteServiceRecordWithChecks(serviceRecordId);
|
||||
return Json(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
243
Controllers/Vehicle/SupplyController.cs
Normal file
243
Controllers/Vehicle/SupplyController.cs
Normal file
@ -0,0 +1,243 @@
|
||||
using CarCareTracker.Filter;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace CarCareTracker.Controllers
|
||||
{
|
||||
public partial class VehicleController
|
||||
{
|
||||
private List<SupplyAvailability> CheckSupplyRecordsAvailability(List<SupplyUsage> supplyUsage)
|
||||
{
|
||||
//returns empty string if all supplies are available
|
||||
var result = new List<SupplyAvailability>();
|
||||
foreach (SupplyUsage supply in supplyUsage)
|
||||
{
|
||||
//get supply record.
|
||||
var supplyData = _supplyRecordDataAccess.GetSupplyRecordById(supply.SupplyId);
|
||||
if (supplyData == null)
|
||||
{
|
||||
result.Add(new SupplyAvailability { Missing = true });
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Add(new SupplyAvailability { Missing = false, Description = supplyData.Description, Required = supply.Quantity, InStock = supplyData.Quantity });
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private List<UploadedFiles> GetSuppliesAttachments(List<SupplyUsage> supplyUsage)
|
||||
{
|
||||
List<UploadedFiles> results = new List<UploadedFiles>();
|
||||
foreach (SupplyUsage supply in supplyUsage)
|
||||
{
|
||||
var result = _supplyRecordDataAccess.GetSupplyRecordById(supply.SupplyId);
|
||||
results.AddRange(result.Files);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
private List<SupplyUsageHistory> RequisitionSupplyRecordsByUsage(List<SupplyUsage> supplyUsage, DateTime dateRequisitioned, string usageDescription)
|
||||
{
|
||||
List<SupplyUsageHistory> results = new List<SupplyUsageHistory>();
|
||||
foreach (SupplyUsage supply in supplyUsage)
|
||||
{
|
||||
//get supply record.
|
||||
var result = _supplyRecordDataAccess.GetSupplyRecordById(supply.SupplyId);
|
||||
var unitCost = (result.Quantity != 0) ? result.Cost / result.Quantity : 0;
|
||||
//deduct quantity used.
|
||||
result.Quantity -= supply.Quantity;
|
||||
//deduct cost.
|
||||
result.Cost -= (supply.Quantity * unitCost);
|
||||
//check decimal places to ensure that it always has a max of 3 decimal places.
|
||||
var roundedDecimal = decimal.Round(result.Cost, 3);
|
||||
if (roundedDecimal != result.Cost)
|
||||
{
|
||||
//Too many decimals
|
||||
result.Cost = roundedDecimal;
|
||||
}
|
||||
//create new requisitionrrecord
|
||||
var requisitionRecord = new SupplyUsageHistory
|
||||
{
|
||||
Id = supply.SupplyId,
|
||||
Date = dateRequisitioned,
|
||||
Description = usageDescription,
|
||||
Quantity = supply.Quantity,
|
||||
Cost = (supply.Quantity * unitCost)
|
||||
};
|
||||
result.RequisitionHistory.Add(requisitionRecord);
|
||||
//save
|
||||
_supplyRecordDataAccess.SaveSupplyRecordToVehicle(result);
|
||||
requisitionRecord.Description = result.Description; //change the name of the description for plan/service/repair/upgrade records
|
||||
requisitionRecord.PartNumber = result.PartNumber; //populate part number if not displayed in supplies modal.
|
||||
results.Add(requisitionRecord);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetSupplyRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _supplyRecordDataAccess.GetSupplyRecordsByVehicleId(vehicleId);
|
||||
bool _useDescending = _config.GetUserConfig(User).UseDescending;
|
||||
if (_useDescending)
|
||||
{
|
||||
result = result.OrderByDescending(x => x.Date).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = result.OrderBy(x => x.Date).ToList();
|
||||
}
|
||||
return PartialView("Supply/_SupplyRecords", result);
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetSupplyRecordsForPlanRecordTemplate(int planRecordTemplateId)
|
||||
{
|
||||
var viewModel = new SupplyUsageViewModel();
|
||||
var planRecordTemplate = _planRecordTemplateDataAccess.GetPlanRecordTemplateById(planRecordTemplateId);
|
||||
if (planRecordTemplate != default && planRecordTemplate.VehicleId != default)
|
||||
{
|
||||
var supplies = _supplyRecordDataAccess.GetSupplyRecordsByVehicleId(planRecordTemplate.VehicleId);
|
||||
if (_config.GetServerEnableShopSupplies())
|
||||
{
|
||||
supplies.AddRange(_supplyRecordDataAccess.GetSupplyRecordsByVehicleId(0)); // add shop supplies
|
||||
}
|
||||
supplies.RemoveAll(x => x.Quantity <= 0);
|
||||
bool _useDescending = _config.GetUserConfig(User).UseDescending;
|
||||
if (_useDescending)
|
||||
{
|
||||
supplies = supplies.OrderByDescending(x => x.Date).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
supplies = supplies.OrderBy(x => x.Date).ToList();
|
||||
}
|
||||
viewModel.Supplies = supplies;
|
||||
viewModel.Usage = planRecordTemplate.Supplies;
|
||||
}
|
||||
return PartialView("Supply/_SupplyUsage", viewModel);
|
||||
}
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetSupplyRecordsForRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _supplyRecordDataAccess.GetSupplyRecordsByVehicleId(vehicleId);
|
||||
if (_config.GetServerEnableShopSupplies())
|
||||
{
|
||||
result.AddRange(_supplyRecordDataAccess.GetSupplyRecordsByVehicleId(0)); // add shop supplies
|
||||
}
|
||||
result.RemoveAll(x => x.Quantity <= 0);
|
||||
bool _useDescending = _config.GetUserConfig(User).UseDescending;
|
||||
if (_useDescending)
|
||||
{
|
||||
result = result.OrderByDescending(x => x.Date).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = result.OrderBy(x => x.Date).ToList();
|
||||
}
|
||||
var viewModel = new SupplyUsageViewModel
|
||||
{
|
||||
Supplies = result
|
||||
};
|
||||
return PartialView("Supply/_SupplyUsage", viewModel);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SaveSupplyRecordToVehicleId(SupplyRecordInput supplyRecord)
|
||||
{
|
||||
if (supplyRecord.VehicleId != default)
|
||||
{
|
||||
//security check only if not editing shop supply.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), supplyRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
}
|
||||
else if (!_config.GetServerEnableShopSupplies())
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
//move files from temp.
|
||||
supplyRecord.Files = supplyRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||
var result = _supplyRecordDataAccess.SaveSupplyRecordToVehicle(supplyRecord.ToSupplyRecord());
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromSupplyRecord(supplyRecord.ToSupplyRecord(), supplyRecord.Id == default ? "supplyrecord.add" : "supplyrecord.update", User.Identity.Name));
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetAddSupplyRecordPartialView()
|
||||
{
|
||||
return PartialView("Supply/_SupplyRecordModal", new SupplyRecordInput() { ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.SupplyRecord).ExtraFields });
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetSupplyRecordForEditById(int supplyRecordId)
|
||||
{
|
||||
var result = _supplyRecordDataAccess.GetSupplyRecordById(supplyRecordId);
|
||||
if (result.VehicleId != default)
|
||||
{
|
||||
//security check only if not editing shop supply.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), result.VehicleId, HouseholdPermission.View))
|
||||
{
|
||||
return Redirect("/Error/Unauthorized");
|
||||
}
|
||||
}
|
||||
else if (!_config.GetServerEnableShopSupplies())
|
||||
{
|
||||
return Redirect("/Error/Unauthorized");
|
||||
}
|
||||
if (result.RequisitionHistory.Any())
|
||||
{
|
||||
//requisition history when viewed through the supply is always immutable.
|
||||
result.RequisitionHistory = result.RequisitionHistory.Select(x => new SupplyUsageHistory { Id = default, Cost = x.Cost, Description = x.Description, Date = x.Date, PartNumber = x.PartNumber, Quantity = x.Quantity }).ToList();
|
||||
}
|
||||
//convert to Input object.
|
||||
var convertedResult = new SupplyRecordInput
|
||||
{
|
||||
Id = result.Id,
|
||||
Cost = result.Cost,
|
||||
Date = result.Date.ToShortDateString(),
|
||||
Description = result.Description,
|
||||
PartNumber = result.PartNumber,
|
||||
Quantity = result.Quantity,
|
||||
PartSupplier = result.PartSupplier,
|
||||
Notes = result.Notes,
|
||||
VehicleId = result.VehicleId,
|
||||
Files = result.Files,
|
||||
Tags = result.Tags,
|
||||
RequisitionHistory = result.RequisitionHistory,
|
||||
ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.SupplyRecord).ExtraFields)
|
||||
};
|
||||
return PartialView("Supply/_SupplyRecordModal", convertedResult);
|
||||
}
|
||||
private OperationResponse DeleteSupplyRecordWithChecks(int supplyRecordId)
|
||||
{
|
||||
var existingRecord = _supplyRecordDataAccess.GetSupplyRecordById(supplyRecordId);
|
||||
if (existingRecord.VehicleId != default)
|
||||
{
|
||||
//security check only if not editing shop supply.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Delete))
|
||||
{
|
||||
return OperationResponse.Failed("Access Denied");
|
||||
}
|
||||
}
|
||||
else if (!_config.GetServerEnableShopSupplies())
|
||||
{
|
||||
return OperationResponse.Failed("Access Denied");
|
||||
}
|
||||
var result = _supplyRecordDataAccess.DeleteSupplyRecordById(existingRecord.Id);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromSupplyRecord(existingRecord, "supplyrecord.delete", User.Identity.Name));
|
||||
}
|
||||
return OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult DeleteSupplyRecordById(int supplyRecordId)
|
||||
{
|
||||
var result = DeleteSupplyRecordWithChecks(supplyRecordId);
|
||||
return Json(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
122
Controllers/Vehicle/TaxController.cs
Normal file
122
Controllers/Vehicle/TaxController.cs
Normal file
@ -0,0 +1,122 @@
|
||||
using CarCareTracker.Filter;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace CarCareTracker.Controllers
|
||||
{
|
||||
public partial class VehicleController
|
||||
{
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetTaxRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId);
|
||||
bool _useDescending = _config.GetUserConfig(User).UseDescending;
|
||||
if (_useDescending)
|
||||
{
|
||||
result = result.OrderByDescending(x => x.Date).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = result.OrderBy(x => x.Date).ToList();
|
||||
}
|
||||
return PartialView("Tax/_TaxRecords", result);
|
||||
}
|
||||
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpPost]
|
||||
public IActionResult CheckRecurringTaxRecords(int vehicleId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = _vehicleLogic.UpdateRecurringTaxes(vehicleId);
|
||||
return Json(result);
|
||||
} catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return Json(false);
|
||||
}
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SaveTaxRecordToVehicleId(TaxRecordInput taxRecord)
|
||||
{
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), taxRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
//move files from temp.
|
||||
taxRecord.Files = taxRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||
//push back any reminders
|
||||
if (taxRecord.ReminderRecordId.Any())
|
||||
{
|
||||
foreach (int reminderRecordId in taxRecord.ReminderRecordId)
|
||||
{
|
||||
PushbackRecurringReminderRecordWithChecks(reminderRecordId, DateTime.Parse(taxRecord.Date), null);
|
||||
}
|
||||
}
|
||||
var result = _taxRecordDataAccess.SaveTaxRecordToVehicle(taxRecord.ToTaxRecord());
|
||||
_vehicleLogic.UpdateRecurringTaxes(taxRecord.VehicleId);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromTaxRecord(taxRecord.ToTaxRecord(), taxRecord.Id == default ? "taxrecord.add" : "taxrecord.update", User.Identity.Name));
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetAddTaxRecordPartialView()
|
||||
{
|
||||
return PartialView("Tax/_TaxRecordModal", new TaxRecordInput() { ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.TaxRecord).ExtraFields });
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetTaxRecordForEditById(int taxRecordId)
|
||||
{
|
||||
var result = _taxRecordDataAccess.GetTaxRecordById(taxRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), result.VehicleId, HouseholdPermission.View))
|
||||
{
|
||||
return Redirect("/Error/Unauthorized");
|
||||
}
|
||||
//convert to Input object.
|
||||
var convertedResult = new TaxRecordInput
|
||||
{
|
||||
Id = result.Id,
|
||||
Cost = result.Cost,
|
||||
Date = result.Date.ToShortDateString(),
|
||||
Description = result.Description,
|
||||
Notes = result.Notes,
|
||||
VehicleId = result.VehicleId,
|
||||
IsRecurring = result.IsRecurring,
|
||||
RecurringInterval = result.RecurringInterval,
|
||||
CustomMonthInterval = result.CustomMonthInterval,
|
||||
CustomMonthIntervalUnit = result.CustomMonthIntervalUnit,
|
||||
Files = result.Files,
|
||||
Tags = result.Tags,
|
||||
ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.TaxRecord).ExtraFields)
|
||||
};
|
||||
return PartialView("Tax/_TaxRecordModal", convertedResult);
|
||||
}
|
||||
private OperationResponse DeleteTaxRecordWithChecks(int taxRecordId)
|
||||
{
|
||||
var existingRecord = _taxRecordDataAccess.GetTaxRecordById(taxRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Delete))
|
||||
{
|
||||
return OperationResponse.Failed("Access Denied");
|
||||
}
|
||||
var result = _taxRecordDataAccess.DeleteTaxRecordById(existingRecord.Id);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromTaxRecord(existingRecord, "taxrecord.delete", User.Identity.Name));
|
||||
}
|
||||
return OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult DeleteTaxRecordById(int taxRecordId)
|
||||
{
|
||||
var result = DeleteTaxRecordWithChecks(taxRecordId);
|
||||
return Json(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
133
Controllers/Vehicle/UpgradeController.cs
Normal file
133
Controllers/Vehicle/UpgradeController.cs
Normal file
@ -0,0 +1,133 @@
|
||||
using CarCareTracker.Filter;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace CarCareTracker.Controllers
|
||||
{
|
||||
public partial class VehicleController
|
||||
{
|
||||
[TypeFilter(typeof(CollaboratorFilter))]
|
||||
[HttpGet]
|
||||
public IActionResult GetUpgradeRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
|
||||
bool _useDescending = _config.GetUserConfig(User).UseDescending;
|
||||
if (_useDescending)
|
||||
{
|
||||
result = result.OrderByDescending(x => x.Date).ThenByDescending(x => x.Mileage).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = result.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList();
|
||||
}
|
||||
return PartialView("Upgrade/_UpgradeRecords", result);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult SaveUpgradeRecordToVehicleId(UpgradeRecordInput upgradeRecord)
|
||||
{
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), upgradeRecord.VehicleId, HouseholdPermission.Edit))
|
||||
{
|
||||
return Json(OperationResponse.Failed("Access Denied"));
|
||||
}
|
||||
//move files from temp.
|
||||
upgradeRecord.Files = upgradeRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||
if (upgradeRecord.Supplies.Any())
|
||||
{
|
||||
upgradeRecord.RequisitionHistory.AddRange(RequisitionSupplyRecordsByUsage(upgradeRecord.Supplies, DateTime.Parse(upgradeRecord.Date), upgradeRecord.Description));
|
||||
if (upgradeRecord.CopySuppliesAttachment)
|
||||
{
|
||||
upgradeRecord.Files.AddRange(GetSuppliesAttachments(upgradeRecord.Supplies));
|
||||
}
|
||||
}
|
||||
if (upgradeRecord.DeletedRequisitionHistory.Any())
|
||||
{
|
||||
_vehicleLogic.RestoreSupplyRecordsByUsage(upgradeRecord.DeletedRequisitionHistory, upgradeRecord.Description);
|
||||
}
|
||||
//push back any reminders
|
||||
if (upgradeRecord.ReminderRecordId.Any())
|
||||
{
|
||||
foreach (int reminderRecordId in upgradeRecord.ReminderRecordId)
|
||||
{
|
||||
PushbackRecurringReminderRecordWithChecks(reminderRecordId, DateTime.Parse(upgradeRecord.Date), upgradeRecord.Mileage);
|
||||
}
|
||||
}
|
||||
var convertedRecord = upgradeRecord.ToUpgradeRecord();
|
||||
var result = _upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(convertedRecord);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromGenericRecord(convertedRecord, upgradeRecord.Id == default ? "upgraderecord.add" : "upgraderecord.update", User.Identity.Name));
|
||||
}
|
||||
if (convertedRecord != default && upgradeRecord.Id == default && _config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
{
|
||||
_odometerLogic.AutoInsertOdometerRecord(new OdometerRecord
|
||||
{
|
||||
Date = DateTime.Parse(upgradeRecord.Date),
|
||||
VehicleId = upgradeRecord.VehicleId,
|
||||
Mileage = upgradeRecord.Mileage,
|
||||
Notes = $"Auto Insert From Upgrade Record: {upgradeRecord.Description}",
|
||||
Files = StaticHelper.CreateAttachmentFromRecord(ImportMode.UpgradeRecord, convertedRecord.Id, convertedRecord.Description)
|
||||
});
|
||||
}
|
||||
return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage));
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetAddUpgradeRecordPartialView()
|
||||
{
|
||||
return PartialView("Upgrade/_UpgradeRecordModal", new UpgradeRecordInput() { ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.UpgradeRecord).ExtraFields });
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult GetUpgradeRecordForEditById(int upgradeRecordId)
|
||||
{
|
||||
var result = _upgradeRecordDataAccess.GetUpgradeRecordById(upgradeRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), result.VehicleId, HouseholdPermission.View))
|
||||
{
|
||||
return Redirect("/Error/Unauthorized");
|
||||
}
|
||||
//convert to Input object.
|
||||
var convertedResult = new UpgradeRecordInput
|
||||
{
|
||||
Id = result.Id,
|
||||
Cost = result.Cost,
|
||||
Date = result.Date.ToShortDateString(),
|
||||
Description = result.Description,
|
||||
Mileage = result.Mileage,
|
||||
Notes = result.Notes,
|
||||
VehicleId = result.VehicleId,
|
||||
Files = result.Files,
|
||||
Tags = result.Tags,
|
||||
RequisitionHistory = result.RequisitionHistory,
|
||||
ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.UpgradeRecord).ExtraFields)
|
||||
};
|
||||
return PartialView("Upgrade/_UpgradeRecordModal", convertedResult);
|
||||
}
|
||||
private OperationResponse DeleteUpgradeRecordWithChecks(int upgradeRecordId)
|
||||
{
|
||||
var existingRecord = _upgradeRecordDataAccess.GetUpgradeRecordById(upgradeRecordId);
|
||||
//security check.
|
||||
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Delete))
|
||||
{
|
||||
return OperationResponse.Failed("Access Denied");
|
||||
}
|
||||
//restore any requisitioned supplies.
|
||||
if (existingRecord.RequisitionHistory.Any())
|
||||
{
|
||||
_vehicleLogic.RestoreSupplyRecordsByUsage(existingRecord.RequisitionHistory, existingRecord.Description);
|
||||
}
|
||||
var result = _upgradeRecordDataAccess.DeleteUpgradeRecordById(existingRecord.Id);
|
||||
if (result)
|
||||
{
|
||||
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromGenericRecord(existingRecord, "upgraderecord.delete", User.Identity.Name));
|
||||
}
|
||||
return OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage);
|
||||
}
|
||||
[HttpPost]
|
||||
public IActionResult DeleteUpgradeRecordById(int upgradeRecordId)
|
||||
{
|
||||
var result = DeleteUpgradeRecordWithChecks(upgradeRecordId);
|
||||
return Json(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
13
Dockerfile
Normal file
13
Dockerfile
Normal file
@ -0,0 +1,13 @@
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
|
||||
WORKDIR /App
|
||||
|
||||
COPY . ./
|
||||
ARG TARGETARCH
|
||||
RUN dotnet restore -a $TARGETARCH
|
||||
RUN dotnet publish -a $TARGETARCH -c Release -o out
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||
WORKDIR /App
|
||||
COPY --from=build-env /App/out .
|
||||
EXPOSE 8080
|
||||
CMD ["./CarCareTracker"]
|
||||
9
Enum/DashboardMetric.cs
Normal file
9
Enum/DashboardMetric.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public enum DashboardMetric
|
||||
{
|
||||
Default = 0,
|
||||
TotalCost = 1,
|
||||
CostPerMile = 2
|
||||
}
|
||||
}
|
||||
12
Enum/ExtraFieldType.cs
Normal file
12
Enum/ExtraFieldType.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public enum ExtraFieldType
|
||||
{
|
||||
Text = 0,
|
||||
Number = 1,
|
||||
Decimal = 2,
|
||||
Date = 3,
|
||||
Time = 4,
|
||||
Location = 5
|
||||
}
|
||||
}
|
||||
9
Enum/HouseholdPermission.cs
Normal file
9
Enum/HouseholdPermission.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public enum HouseholdPermission
|
||||
{
|
||||
View = 0,
|
||||
Edit = 1,
|
||||
Delete = 2
|
||||
}
|
||||
}
|
||||
19
Enum/ImportMode.cs
Normal file
19
Enum/ImportMode.cs
Normal file
@ -0,0 +1,19 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public enum ImportMode
|
||||
{
|
||||
ServiceRecord = 0,
|
||||
RepairRecord = 1,
|
||||
GasRecord = 2,
|
||||
TaxRecord = 3,
|
||||
UpgradeRecord = 4,
|
||||
ReminderRecord = 5,
|
||||
NoteRecord = 6,
|
||||
SupplyRecord = 7,
|
||||
Dashboard = 8,
|
||||
PlanRecord = 9,
|
||||
OdometerRecord = 10,
|
||||
VehicleRecord = 11,
|
||||
InspectionRecord = 12
|
||||
}
|
||||
}
|
||||
9
Enum/InspectionFieldType.cs
Normal file
9
Enum/InspectionFieldType.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public enum InspectionFieldType
|
||||
{
|
||||
Text = 0,
|
||||
Check = 1,
|
||||
Radio = 2
|
||||
}
|
||||
}
|
||||
10
Enum/KioskMode.cs
Normal file
10
Enum/KioskMode.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public enum KioskMode
|
||||
{
|
||||
Vehicle = 0,
|
||||
Plan = 1,
|
||||
Reminder = 2,
|
||||
Cycle = 3
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
8
Enum/ReminderIntervalUnit.cs
Normal file
8
Enum/ReminderIntervalUnit.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public enum ReminderIntervalUnit
|
||||
{
|
||||
Months = 1,
|
||||
Days = 2
|
||||
}
|
||||
}
|
||||
9
Enum/ReminderMetric.cs
Normal file
9
Enum/ReminderMetric.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public enum ReminderMetric
|
||||
{
|
||||
Date = 0,
|
||||
Odometer = 1,
|
||||
Both = 2
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
10
Enum/ReminderUrgency.cs
Normal file
10
Enum/ReminderUrgency.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public enum ReminderUrgency
|
||||
{
|
||||
NotUrgent = 0,
|
||||
Urgent = 1,
|
||||
VeryUrgent = 2,
|
||||
PastDue = 3
|
||||
}
|
||||
}
|
||||
8
Enum/TagFilter.cs
Normal file
8
Enum/TagFilter.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace CarCareTracker.Models
|
||||
{
|
||||
public enum TagFilter
|
||||
{
|
||||
Exclude = 0,
|
||||
IncludeOnly = 1
|
||||
}
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
using CarCareTracker.External.Interfaces;
|
||||
using CarCareTracker.Models;
|
||||
using LiteDB;
|
||||
|
||||
namespace CarCareTracker.External.Implementations
|
||||
{
|
||||
public class CollisionRecordDataAccess : ICollisionRecordDataAccess
|
||||
{
|
||||
private static string dbName = "cartracker.db";
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
56
External/Implementations/GasRecordDataAccess.cs
vendored
56
External/Implementations/GasRecordDataAccess.cs
vendored
@ -1,56 +0,0 @@
|
||||
using CarCareTracker.External.Interfaces;
|
||||
using CarCareTracker.Models;
|
||||
using LiteDB;
|
||||
|
||||
namespace CarCareTracker.External.Implementations
|
||||
{
|
||||
public class GasRecordDataAccess: IGasRecordDataAccess
|
||||
{
|
||||
private static string dbName = "cartracker.db";
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
External/Implementations/Litedb/ExtraFieldDataAccess.cs
vendored
Normal file
36
External/Implementations/Litedb/ExtraFieldDataAccess.cs
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
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 List<RecordExtraField> GetExtraFields()
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<RecordExtraField>(tableName);
|
||||
return table.FindAll().ToList();
|
||||
}
|
||||
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/InspectionRecordDataAccess.cs
vendored
Normal file
54
External/Implementations/Litedb/InspectionRecordDataAccess.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 InspectionRecordDataAccess : IInspectionRecordDataAccess
|
||||
{
|
||||
private ILiteDBHelper _liteDB { get; set; }
|
||||
private static string tableName = "inspectionrecords";
|
||||
public InspectionRecordDataAccess(ILiteDBHelper liteDB)
|
||||
{
|
||||
_liteDB = liteDB;
|
||||
}
|
||||
public List<InspectionRecord> GetInspectionRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<InspectionRecord>(tableName);
|
||||
var inspectionRecords = table.Find(Query.EQ(nameof(InspectionRecord.VehicleId), vehicleId));
|
||||
return inspectionRecords.ToList() ?? new List<InspectionRecord>();
|
||||
}
|
||||
public InspectionRecord GetInspectionRecordById(int inspectionRecordId)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<InspectionRecord>(tableName);
|
||||
return table.FindById(inspectionRecordId);
|
||||
}
|
||||
public bool DeleteInspectionRecordById(int inspectionRecordId)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<InspectionRecord>(tableName);
|
||||
table.Delete(inspectionRecordId);
|
||||
db.Checkpoint();
|
||||
return true;
|
||||
}
|
||||
public bool SaveInspectionRecordToVehicle(InspectionRecord inspectionRecordId)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<InspectionRecord>(tableName);
|
||||
table.Upsert(inspectionRecordId);
|
||||
db.Checkpoint();
|
||||
return true;
|
||||
}
|
||||
public bool DeleteAllInspectionRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<InspectionRecord>(tableName);
|
||||
var planRecords = table.DeleteMany(Query.EQ(nameof(InspectionRecord.VehicleId), vehicleId));
|
||||
db.Checkpoint();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
54
External/Implementations/Litedb/InspectionRecordTemplateDataAccess.cs
vendored
Normal file
54
External/Implementations/Litedb/InspectionRecordTemplateDataAccess.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 InspectionRecordTemplateDataAccess : IInspectionRecordTemplateDataAccess
|
||||
{
|
||||
private ILiteDBHelper _liteDB { get; set; }
|
||||
private static string tableName = "inspectionrecordtemplates";
|
||||
public InspectionRecordTemplateDataAccess(ILiteDBHelper liteDB)
|
||||
{
|
||||
_liteDB = liteDB;
|
||||
}
|
||||
public List<InspectionRecordInput> GetInspectionRecordTemplatesByVehicleId(int vehicleId)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<InspectionRecordInput>(tableName);
|
||||
var inspectionRecords = table.Find(Query.EQ(nameof(InspectionRecordInput.VehicleId), vehicleId));
|
||||
return inspectionRecords.ToList() ?? new List<InspectionRecordInput>();
|
||||
}
|
||||
public InspectionRecordInput GetInspectionRecordTemplateById(int inspectionRecordTemplateId)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<InspectionRecordInput>(tableName);
|
||||
return table.FindById(inspectionRecordTemplateId);
|
||||
}
|
||||
public bool DeleteInspectionRecordTemplateById(int inspectionRecordTemplateId)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<InspectionRecordInput>(tableName);
|
||||
table.Delete(inspectionRecordTemplateId);
|
||||
db.Checkpoint();
|
||||
return true;
|
||||
}
|
||||
public bool SaveInspectionReportTemplateToVehicle(InspectionRecordInput inspectionRecordTemplate)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<InspectionRecordInput>(tableName);
|
||||
table.Upsert(inspectionRecordTemplate);
|
||||
db.Checkpoint();
|
||||
return true;
|
||||
}
|
||||
public bool DeleteAllInspectionReportTemplatesByVehicleId(int vehicleId)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<InspectionRecordInput>(tableName);
|
||||
var planRecords = table.DeleteMany(Query.EQ(nameof(InspectionRecordInput.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
81
External/Implementations/Litedb/UserAccessDataAcces.cs
vendored
Normal file
81
External/Implementations/Litedb/UserAccessDataAcces.cs
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
using CarCareTracker.External.Interfaces;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Models;
|
||||
|
||||
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>
|
||||
/// Delete 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
76
External/Implementations/Litedb/UserHouseholdDataAcces.cs
vendored
Normal file
76
External/Implementations/Litedb/UserHouseholdDataAcces.cs
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
using CarCareTracker.External.Interfaces;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Models;
|
||||
|
||||
namespace CarCareTracker.External.Implementations
|
||||
{
|
||||
public class UserHouseholdDataAccess : IUserHouseholdDataAccess
|
||||
{
|
||||
private ILiteDBHelper _liteDB { get; set; }
|
||||
private static string tableName = "userhouseholdrecords";
|
||||
public UserHouseholdDataAccess(ILiteDBHelper liteDB)
|
||||
{
|
||||
_liteDB = liteDB;
|
||||
}
|
||||
public List<UserHousehold> GetUserHouseholdByParentUserId(int parentUserId)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<UserHousehold>(tableName);
|
||||
return table.Find(x => x.Id.ParentUserId == parentUserId).ToList();
|
||||
}
|
||||
public List<UserHousehold> GetUserHouseholdByChildUserId(int childUserId)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<UserHousehold>(tableName);
|
||||
return table.Find(x => x.Id.ChildUserId == childUserId).ToList();
|
||||
}
|
||||
public UserHousehold GetUserHouseholdByParentAndChildUserId(int parentUserId, int childUserId)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<UserHousehold>(tableName);
|
||||
return table.Find(x => x.Id.ParentUserId == parentUserId && x.Id.ChildUserId == childUserId).FirstOrDefault();
|
||||
}
|
||||
public bool SaveUserHousehold(UserHousehold userHousehold)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<UserHousehold>(tableName);
|
||||
table.Upsert(userHousehold);
|
||||
db.Checkpoint();
|
||||
return true;
|
||||
}
|
||||
public bool DeleteUserHousehold(int parentUserId, int childUserId)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<UserHousehold>(tableName);
|
||||
table.DeleteMany(x => x.Id.ParentUserId == parentUserId && x.Id.ChildUserId == childUserId);
|
||||
db.Checkpoint();
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Delete all household records when a parent user is deleted.
|
||||
/// </summary>
|
||||
/// <param name="parentUserId"></param>
|
||||
/// <returns></returns>
|
||||
public bool DeleteAllHouseholdRecordsByParentUserId(int parentUserId)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<UserHousehold>(tableName);
|
||||
table.DeleteMany(x => x.Id.ParentUserId == parentUserId);
|
||||
db.Checkpoint();
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Delete all household records when a child user is deleted.
|
||||
/// </summary>
|
||||
/// <param name="childUserId"></param>
|
||||
/// <returns></returns>
|
||||
public bool DeleteAllHouseholdRecordsByChildUserId(int childUserId)
|
||||
{
|
||||
var db = _liteDB.GetLiteDB();
|
||||
var table = db.GetCollection<UserHousehold>(tableName);
|
||||
table.DeleteMany(x => x.Id.ChildUserId == childUserId);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
External/Implementations/Litedb/VehicleDataAccess.cs
vendored
Normal file
44
External/Implementations/Litedb/VehicleDataAccess.cs
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
using CarCareTracker.External.Interfaces;
|
||||
using CarCareTracker.Helper;
|
||||
using CarCareTracker.Models;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
39
External/Implementations/NoteDataAccess.cs
vendored
39
External/Implementations/NoteDataAccess.cs
vendored
@ -1,39 +0,0 @@
|
||||
using CarCareTracker.External.Interfaces;
|
||||
using CarCareTracker.Models;
|
||||
using LiteDB;
|
||||
|
||||
namespace CarCareTracker.External.Implementations
|
||||
{
|
||||
public class NoteDataAccess: INoteDataAccess
|
||||
{
|
||||
private static string dbName = "cartracker.db";
|
||||
private static string tableName = "notes";
|
||||
public Note GetNoteByVehicleId(int vehicleId)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<Note>(tableName);
|
||||
var noteToReturn = table.FindOne(Query.EQ(nameof(Note.VehicleId), vehicleId));
|
||||
return noteToReturn ?? new Note();
|
||||
};
|
||||
}
|
||||
public bool SaveNoteToVehicleId(Note note)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<Note>(tableName);
|
||||
table.Upsert(note);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
public bool DeleteNoteByVehicleId(int vehicleId)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbName))
|
||||
{
|
||||
var table = db.GetCollection<Note>(tableName);
|
||||
table.DeleteMany(Query.EQ(nameof(Note.VehicleId), vehicleId));
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
161
External/Implementations/Postgres/CollisionRecordDataAccess.cs
vendored
Normal file
161
External/Implementations/Postgres/CollisionRecordDataAccess.cs
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
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 SCHEMA IF NOT EXISTS app; 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);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
99
External/Implementations/Postgres/ExtraFieldDataAccess.cs
vendored
Normal file
99
External/Implementations/Postgres/ExtraFieldDataAccess.cs
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
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 SCHEMA IF NOT EXISTS app; 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 List<RecordExtraField> GetExtraFields()
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmd = $"SELECT data FROM app.{tableName}";
|
||||
var results = new List<RecordExtraField>();
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||
while (reader.Read())
|
||||
{
|
||||
RecordExtraField result = JsonSerializer.Deserialize<RecordExtraField>(reader["data"] as string);
|
||||
results.Add(result);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return new List<RecordExtraField>();
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
160
External/Implementations/Postgres/GasRecordDataAccess.cs
vendored
Normal file
160
External/Implementations/Postgres/GasRecordDataAccess.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 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 SCHEMA IF NOT EXISTS app; 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);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
160
External/Implementations/Postgres/InspectionRecordDataAccess.cs
vendored
Normal file
160
External/Implementations/Postgres/InspectionRecordDataAccess.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 PGInspectionRecordDataAccess : IInspectionRecordDataAccess
|
||||
{
|
||||
private NpgsqlDataSource pgDataSource;
|
||||
private readonly ILogger<PGInspectionRecordDataAccess> _logger;
|
||||
private static string tableName = "inspectionrecords";
|
||||
public PGInspectionRecordDataAccess(IConfiguration config, ILogger<PGInspectionRecordDataAccess> logger)
|
||||
{
|
||||
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||
_logger = logger;
|
||||
try
|
||||
{
|
||||
//create table if not exist.
|
||||
string initCMD = $"CREATE SCHEMA IF NOT EXISTS app; 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<InspectionRecord> GetInspectionRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||
var results = new List<InspectionRecord>();
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||
while (reader.Read())
|
||||
{
|
||||
InspectionRecord inspectionRecord = JsonSerializer.Deserialize<InspectionRecord>(reader["data"] as string);
|
||||
results.Add(inspectionRecord);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return new List<InspectionRecord>();
|
||||
}
|
||||
}
|
||||
public InspectionRecord GetInspectionRecordById(int inspectionRecordId)
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||
var result = new InspectionRecord();
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("id", inspectionRecordId);
|
||||
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||
while (reader.Read())
|
||||
{
|
||||
InspectionRecord inspectionRecord = JsonSerializer.Deserialize<InspectionRecord>(reader["data"] as string);
|
||||
result = inspectionRecord;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return new InspectionRecord();
|
||||
}
|
||||
}
|
||||
public bool DeleteInspectionRecordById(int inspectionRecordId)
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("id", inspectionRecordId);
|
||||
return ctext.ExecuteNonQuery() > 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool SaveInspectionRecordToVehicle(InspectionRecord inspectionRecordId)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (inspectionRecordId.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", inspectionRecordId.VehicleId);
|
||||
ctext.Parameters.AddWithValue("data", "{}");
|
||||
inspectionRecordId.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||
//update json data
|
||||
if (inspectionRecordId.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(inspectionRecordId);
|
||||
ctextU.Parameters.AddWithValue("id", inspectionRecordId.Id);
|
||||
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||
return ctextU.ExecuteNonQuery() > 0;
|
||||
}
|
||||
}
|
||||
return inspectionRecordId.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(inspectionRecordId);
|
||||
ctext.Parameters.AddWithValue("id", inspectionRecordId.Id);
|
||||
ctext.Parameters.AddWithValue("data", serializedData);
|
||||
return ctext.ExecuteNonQuery() > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool DeleteAllInspectionRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
160
External/Implementations/Postgres/InspectionRecordTemplateDataAccess.cs
vendored
Normal file
160
External/Implementations/Postgres/InspectionRecordTemplateDataAccess.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 PGInspectionRecordTemplateDataAccess : IInspectionRecordTemplateDataAccess
|
||||
{
|
||||
private NpgsqlDataSource pgDataSource;
|
||||
private readonly ILogger<PGInspectionRecordTemplateDataAccess> _logger;
|
||||
private static string tableName = "inspectionrecordtemplates";
|
||||
public PGInspectionRecordTemplateDataAccess(IConfiguration config, ILogger<PGInspectionRecordTemplateDataAccess> logger)
|
||||
{
|
||||
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||
_logger = logger;
|
||||
try
|
||||
{
|
||||
//create table if not exist.
|
||||
string initCMD = $"CREATE SCHEMA IF NOT EXISTS app; 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<InspectionRecordInput> GetInspectionRecordTemplatesByVehicleId(int vehicleId)
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||
var results = new List<InspectionRecordInput>();
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||
while (reader.Read())
|
||||
{
|
||||
InspectionRecordInput inspectionRecord = JsonSerializer.Deserialize<InspectionRecordInput>(reader["data"] as string);
|
||||
results.Add(inspectionRecord);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return new List<InspectionRecordInput>();
|
||||
}
|
||||
}
|
||||
public InspectionRecordInput GetInspectionRecordTemplateById(int inspectionRecordTemplateId)
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||
var result = new InspectionRecordInput();
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("id", inspectionRecordTemplateId);
|
||||
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||
while (reader.Read())
|
||||
{
|
||||
InspectionRecordInput inspectionRecord = JsonSerializer.Deserialize<InspectionRecordInput>(reader["data"] as string);
|
||||
result = inspectionRecord;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return new InspectionRecordInput();
|
||||
}
|
||||
}
|
||||
public bool DeleteInspectionRecordTemplateById(int inspectionRecordTemplateId)
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("id", inspectionRecordTemplateId);
|
||||
return ctext.ExecuteNonQuery() > 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool SaveInspectionReportTemplateToVehicle(InspectionRecordInput inspectionRecordTemplate)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (inspectionRecordTemplate.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", inspectionRecordTemplate.VehicleId);
|
||||
ctext.Parameters.AddWithValue("data", "{}");
|
||||
inspectionRecordTemplate.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||
//update json data
|
||||
if (inspectionRecordTemplate.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(inspectionRecordTemplate);
|
||||
ctextU.Parameters.AddWithValue("id", inspectionRecordTemplate.Id);
|
||||
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||
return ctextU.ExecuteNonQuery() > 0;
|
||||
}
|
||||
}
|
||||
return inspectionRecordTemplate.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(inspectionRecordTemplate);
|
||||
ctext.Parameters.AddWithValue("id", inspectionRecordTemplate.Id);
|
||||
ctext.Parameters.AddWithValue("data", serializedData);
|
||||
return ctext.ExecuteNonQuery() > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool DeleteAllInspectionReportTemplatesByVehicleId(int vehicleId)
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
154
External/Implementations/Postgres/NoteDataAccess.cs
vendored
Normal file
154
External/Implementations/Postgres/NoteDataAccess.cs
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
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 SCHEMA IF NOT EXISTS app; 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);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
} catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
160
External/Implementations/Postgres/OdometerRecordDataAccess.cs
vendored
Normal file
160
External/Implementations/Postgres/OdometerRecordDataAccess.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 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 SCHEMA IF NOT EXISTS app; 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);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
160
External/Implementations/Postgres/PlanRecordDataAccess.cs
vendored
Normal file
160
External/Implementations/Postgres/PlanRecordDataAccess.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 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 SCHEMA IF NOT EXISTS app; 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);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
160
External/Implementations/Postgres/PlanRecordTemplateDataAccess.cs
vendored
Normal file
160
External/Implementations/Postgres/PlanRecordTemplateDataAccess.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 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 SCHEMA IF NOT EXISTS app; 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);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
160
External/Implementations/Postgres/ReminderRecordDataAccess.cs
vendored
Normal file
160
External/Implementations/Postgres/ReminderRecordDataAccess.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 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 SCHEMA IF NOT EXISTS app; 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);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
160
External/Implementations/Postgres/ServiceRecordDataAccess.cs
vendored
Normal file
160
External/Implementations/Postgres/ServiceRecordDataAccess.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 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 SCHEMA IF NOT EXISTS app; 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);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
160
External/Implementations/Postgres/SupplyRecordDataAccess.cs
vendored
Normal file
160
External/Implementations/Postgres/SupplyRecordDataAccess.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 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 SCHEMA IF NOT EXISTS app; 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);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
160
External/Implementations/Postgres/TaxRecordDataAccess.cs
vendored
Normal file
160
External/Implementations/Postgres/TaxRecordDataAccess.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 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 SCHEMA IF NOT EXISTS app; 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);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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 SCHEMA IF NOT EXISTS app; 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
160
External/Implementations/Postgres/UpgradeRecordDataAccess.cs
vendored
Normal file
160
External/Implementations/Postgres/UpgradeRecordDataAccess.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 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 SCHEMA IF NOT EXISTS app; 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);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
212
External/Implementations/Postgres/UserAccessDataAccess.cs
vendored
Normal file
212
External/Implementations/Postgres/UserAccessDataAccess.cs
vendored
Normal file
@ -0,0 +1,212 @@
|
||||
using CarCareTracker.External.Interfaces;
|
||||
using CarCareTracker.Models;
|
||||
using Npgsql;
|
||||
|
||||
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 SCHEMA IF NOT EXISTS app; 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);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
108
External/Implementations/Postgres/UserConfigDataAccess.cs
vendored
Normal file
108
External/Implementations/Postgres/UserConfigDataAccess.cs
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
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 SCHEMA IF NOT EXISTS app; 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);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
189
External/Implementations/Postgres/UserHouseholdDataAccess.cs
vendored
Normal file
189
External/Implementations/Postgres/UserHouseholdDataAccess.cs
vendored
Normal file
@ -0,0 +1,189 @@
|
||||
using CarCareTracker.External.Interfaces;
|
||||
using CarCareTracker.Models;
|
||||
using Npgsql;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace CarCareTracker.External.Implementations
|
||||
{
|
||||
public class PGUserHouseholdDataAccess : IUserHouseholdDataAccess
|
||||
{
|
||||
private NpgsqlDataSource pgDataSource;
|
||||
private readonly ILogger<PGUserHouseholdDataAccess> _logger;
|
||||
private static string tableName = "userhouseholdrecords";
|
||||
public PGUserHouseholdDataAccess(IConfiguration config, ILogger<PGUserHouseholdDataAccess> logger)
|
||||
{
|
||||
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||
_logger = logger;
|
||||
try
|
||||
{
|
||||
//create table if not exist.
|
||||
string initCMD = $"CREATE SCHEMA IF NOT EXISTS app; CREATE TABLE IF NOT EXISTS app.{tableName} (parentUserId INT, childUserId INT, data jsonb not null, PRIMARY KEY(parentUserId, childUserId))";
|
||||
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||
{
|
||||
ctext.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
}
|
||||
}
|
||||
public List<UserHousehold> GetUserHouseholdByParentUserId(int parentUserId)
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmd = $"SELECT data FROM app.{tableName} WHERE parentUserId = @parentUserId";
|
||||
var results = new List<UserHousehold>();
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("parentUserId", parentUserId);
|
||||
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||
while (reader.Read())
|
||||
{
|
||||
UserHousehold result = JsonSerializer.Deserialize<UserHousehold>(reader["data"] as string);
|
||||
results.Add(result);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return new List<UserHousehold>();
|
||||
}
|
||||
}
|
||||
public List<UserHousehold> GetUserHouseholdByChildUserId(int childUserId)
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmd = $"SELECT data FROM app.{tableName} WHERE childUserId = @childUserId";
|
||||
var results = new List<UserHousehold>();
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("childUserId", childUserId);
|
||||
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||
while (reader.Read())
|
||||
{
|
||||
UserHousehold result = JsonSerializer.Deserialize<UserHousehold>(reader["data"] as string);
|
||||
results.Add(result);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return new List<UserHousehold>();
|
||||
}
|
||||
}
|
||||
public UserHousehold GetUserHouseholdByParentAndChildUserId(int parentUserId, int childUserId)
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmd = $"SELECT data FROM app.{tableName} WHERE parentUserId = @parentUserId AND childUserId = @childUserId";
|
||||
UserHousehold result = null;
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("parentUserId", parentUserId);
|
||||
ctext.Parameters.AddWithValue("childUserId", childUserId);
|
||||
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||
while (reader.Read())
|
||||
{
|
||||
result = JsonSerializer.Deserialize<UserHousehold>(reader["data"] as string);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return new UserHousehold();
|
||||
}
|
||||
}
|
||||
public bool SaveUserHousehold(UserHousehold userHousehold)
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmd = $"INSERT INTO app.{tableName} (parentUserId, childUserId, data) VALUES(@parentUserId, @childUserId, CAST(@data AS jsonb)) ON CONFLICT(parentUserId, childUserId) DO UPDATE SET data = CAST(@data AS jsonb)";
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
var serializedData = JsonSerializer.Serialize(userHousehold);
|
||||
ctext.Parameters.AddWithValue("parentUserId", userHousehold.Id.ParentUserId);
|
||||
ctext.Parameters.AddWithValue("childUserId", userHousehold.Id.ChildUserId);
|
||||
ctext.Parameters.AddWithValue("data", serializedData);
|
||||
return ctext.ExecuteNonQuery() > 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool DeleteUserHousehold(int parentUserId, int childUserId)
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmd = $"DELETE FROM app.{tableName} WHERE parentUserId = @parentUserId AND childUserId = @childUserId";
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("parentUserId", parentUserId);
|
||||
ctext.Parameters.AddWithValue("childUserId", childUserId);
|
||||
return ctext.ExecuteNonQuery() > 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Delete all household records when a parent user is deleted.
|
||||
/// </summary>
|
||||
/// <param name="parentUserId"></param>
|
||||
/// <returns></returns>
|
||||
public bool DeleteAllHouseholdRecordsByParentUserId(int parentUserId)
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmd = $"DELETE FROM app.{tableName} WHERE parentUserId = @parentUserId";
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("parentUserId", parentUserId);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Delete all household records when a child user is deleted.
|
||||
/// </summary>
|
||||
/// <param name="childUserId"></param>
|
||||
/// <returns></returns>
|
||||
public bool DeleteAllHouseholdRecordsByChildUserId(int childUserId)
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmd = $"DELETE FROM app.{tableName} WHERE childUserId = @childUserId";
|
||||
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||
{
|
||||
ctext.Parameters.AddWithValue("childUserId", childUserId);
|
||||
ctext.ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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 SCHEMA IF NOT EXISTS app; 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 SCHEMA IF NOT EXISTS app; 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,56 +0,0 @@
|
||||
using CarCareTracker.External.Interfaces;
|
||||
using CarCareTracker.Models;
|
||||
using LiteDB;
|
||||
|
||||
namespace CarCareTracker.External.Implementations
|
||||
{
|
||||
public class ServiceRecordDataAccess: IServiceRecordDataAccess
|
||||
{
|
||||
private static string dbName = "cartracker.db";
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
56
External/Implementations/TaxRecordDataAccess.cs
vendored
56
External/Implementations/TaxRecordDataAccess.cs
vendored
@ -1,56 +0,0 @@
|
||||
using CarCareTracker.External.Interfaces;
|
||||
using CarCareTracker.Models;
|
||||
using LiteDB;
|
||||
|
||||
namespace CarCareTracker.External.Implementations
|
||||
{
|
||||
public class TaxRecordDataAccess : ITaxRecordDataAccess
|
||||
{
|
||||
private static string dbName = "cartracker.db";
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
45
External/Implementations/VehicleDataAccess.cs
vendored
45
External/Implementations/VehicleDataAccess.cs
vendored
@ -1,45 +0,0 @@
|
||||
using CarCareTracker.External.Interfaces;
|
||||
using CarCareTracker.Models;
|
||||
using LiteDB;
|
||||
|
||||
namespace CarCareTracker.External.Implementations
|
||||
{
|
||||
public class VehicleDataAccess: IVehicleDataAccess
|
||||
{
|
||||
private static string dbName = "cartracker.db";
|
||||
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);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
11
External/Interfaces/IExtraFieldDataAccess.cs
vendored
Normal file
11
External/Interfaces/IExtraFieldDataAccess.cs
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
using CarCareTracker.Models;
|
||||
|
||||
namespace CarCareTracker.External.Interfaces
|
||||
{
|
||||
public interface IExtraFieldDataAccess
|
||||
{
|
||||
public List<RecordExtraField> GetExtraFields();
|
||||
public RecordExtraField GetExtraFieldsById(int importMode);
|
||||
public bool SaveExtraFields(RecordExtraField record);
|
||||
}
|
||||
}
|
||||
13
External/Interfaces/IInspectionRecordDataAccess.cs
vendored
Normal file
13
External/Interfaces/IInspectionRecordDataAccess.cs
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
using CarCareTracker.Models;
|
||||
|
||||
namespace CarCareTracker.External.Interfaces
|
||||
{
|
||||
public interface IInspectionRecordDataAccess
|
||||
{
|
||||
public List<InspectionRecord> GetInspectionRecordsByVehicleId(int vehicleId);
|
||||
public InspectionRecord GetInspectionRecordById(int inspectionRecordId);
|
||||
public bool DeleteInspectionRecordById(int inspectionRecordId);
|
||||
public bool SaveInspectionRecordToVehicle(InspectionRecord inspectionRecordId);
|
||||
public bool DeleteAllInspectionRecordsByVehicleId(int vehicleId);
|
||||
}
|
||||
}
|
||||
13
External/Interfaces/IInspectionRecordTemplateDataAccess.cs
vendored
Normal file
13
External/Interfaces/IInspectionRecordTemplateDataAccess.cs
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
using CarCareTracker.Models;
|
||||
|
||||
namespace CarCareTracker.External.Interfaces
|
||||
{
|
||||
public interface IInspectionRecordTemplateDataAccess
|
||||
{
|
||||
public List<InspectionRecordInput> GetInspectionRecordTemplatesByVehicleId(int vehicleId);
|
||||
public InspectionRecordInput GetInspectionRecordTemplateById(int inspectionRecordTemplateId);
|
||||
public bool DeleteInspectionRecordTemplateById(int inspectionRecordTemplateId);
|
||||
public bool SaveInspectionReportTemplateToVehicle(InspectionRecordInput inspectionRecordTemplate);
|
||||
public bool DeleteAllInspectionReportTemplatesByVehicleId(int vehicleId);
|
||||
}
|
||||
}
|
||||
8
External/Interfaces/INoteDataAccess.cs
vendored
8
External/Interfaces/INoteDataAccess.cs
vendored
@ -4,8 +4,10 @@ namespace CarCareTracker.External.Interfaces
|
||||
{
|
||||
public interface INoteDataAccess
|
||||
{
|
||||
public Note GetNoteByVehicleId(int vehicleId);
|
||||
public bool SaveNoteToVehicleId(Note note);
|
||||
bool DeleteNoteByVehicleId(int vehicleId);
|
||||
public List<Note> GetNotesByVehicleId(int vehicleId);
|
||||
public Note GetNoteById(int noteId);
|
||||
public bool SaveNoteToVehicle(Note note);
|
||||
public bool DeleteNoteById(int noteId);
|
||||
public bool DeleteAllNotesByVehicleId(int vehicleId);
|
||||
}
|
||||
}
|
||||
|
||||
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/IReminderRecordDataAccess.cs
vendored
Normal file
13
External/Interfaces/IReminderRecordDataAccess.cs
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
using CarCareTracker.Models;
|
||||
|
||||
namespace CarCareTracker.External.Interfaces
|
||||
{
|
||||
public interface IReminderRecordDataAccess
|
||||
{
|
||||
public List<ReminderRecord> GetReminderRecordsByVehicleId(int vehicleId);
|
||||
public ReminderRecord GetReminderRecordById(int reminderRecordId);
|
||||
public bool DeleteReminderRecordById(int reminderRecordId);
|
||||
public bool SaveReminderRecordToVehicle(ReminderRecord reminderRecord);
|
||||
public bool DeleteAllReminderRecordsByVehicleId(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);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user