Compare commits

...

438 Commits

Author SHA1 Message Date
Hargata Softworks
0707b515ab Merge pull request #525 from hargata/Hargata/sponsor.tiers
Updated Sponsors File Path
2024-05-21 15:42:58 -06:00
DESKTOP-T0O5CDB\DESK-555BD
78ae71fc46 Updated Sponsors File Path 2024-05-21 15:41:05 -06:00
Hargata Softworks
3f62cd40e7 Merge pull request #524 from hargata/Hargata/sponsor.tiers
Add Sponsor Section
2024-05-21 15:32:20 -06:00
DESKTOP-T0O5CDB\DESK-555BD
47657c0093 Added sponsor section. 2024-05-21 15:29:46 -06:00
Hargata Softworks
a5b0fde4b6 Merge pull request #522 from hargata/Hargata/swal.uncensored
Hargata/swal.uncensored
2024-05-20 12:26:10 -06:00
DESKTOP-T0O5CDB\DESK-555BD
78cc0b34b1 Updated version number 2024-05-20 12:25:07 -06:00
Hargata Softworks
e3017e986b Merge pull request #520 from hargata/Hargata/license.change
Removed commercial license restrictions from license.
2024-05-20 12:22:21 -06:00
DESKTOP-T0O5CDB\DESK-555BD
e12cd876db removed unused files 2024-05-20 12:21:54 -06:00
DESKTOP-T0O5CDB\DESK-555BD
5292e4b814 utilize uncensored version of sweet alert 2024-05-20 12:16:10 -06:00
DESKTOP-T0O5CDB\DESK-555BD
dbdd16ab89 Removed commercial license restrictions from license. 2024-05-14 08:46:47 -06:00
Hargata Softworks
ddc3c2e1b5 Merge pull request #503 from hargata/Hargata/null.mail.config
null check for mail config
2024-04-25 12:45:36 -06:00
DESKTOP-T0O5CDB\DESK-555BD
49184b287b null check for mail config 2024-04-25 12:45:21 -06:00
Hargata Softworks
f6139bda0d Merge pull request #502 from hargata/Hargata/mailkit.upgrade
fix inefficiencies
2024-04-25 11:33:14 -06:00
DESKTOP-T0O5CDB\DESK-555BD
a6471b823b fix inefficiencies 2024-04-25 11:11:54 -06:00
Hargata Softworks
7c34003647 Merge pull request #501 from hargata/Hargata/mailkit.upgrade
MailKit Upgrade
2024-04-25 10:46:53 -06:00
DESKTOP-T0O5CDB\DESK-555BD
1aa21f9980 Uprgade from .NET SMTPClient to MailKit as the default smtpclient does not support modern protocols. 2024-04-25 10:45:55 -06:00
Hargata Softworks
ce4ca50939 Merge pull request #499 from hargata/Hargata/persist.metric.bug
fix getyear method
2024-04-23 23:50:31 -06:00
DESKTOP-T0O5CDB\DESK-555BD
fb28260c4a fix getyear method 2024-04-23 23:50:06 -06:00
Hargata Softworks
626a904747 Merge pull request #498 from hargata/Hargata/persist.metric.bug
Minor bug fix
2024-04-23 23:43:18 -06:00
DESKTOP-T0O5CDB\DESK-555BD
893cdafdc5 Fixes a very minor bug where the persisted year metric blanks out when viewing a different car that doesn't have that specific year. 2024-04-23 23:42:09 -06:00
Hargata Softworks
dbfb7d7d9c Merge pull request #493 from hargata/Hargata/persist.dashboard
check against null instead of undefined,
2024-04-15 08:42:43 -06:00
DESKTOP-GENO133\IvanPlex
a66538a7db check against null instead of undefined, 2024-04-15 08:41:53 -06:00
Hargata Softworks
2f77d87d4f Merge pull request #492 from hargata/Hargata/persist.dashboard
temporarily persist dashboard metrics in sessionStorage
2024-04-15 08:25:54 -06:00
DESKTOP-GENO133\IvanPlex
de85ba984c temporarily persist dashboard metrics in sessionStorage 2024-04-15 08:20:37 -06:00
Hargata Softworks
caac1a05ae Merge pull request #480 from hargata/Hargata/fix.link.color
fix donation link colors
2024-04-12 08:04:44 -06:00
Hargata Softworks
eb5793b819 Merge pull request #490 from hargata/Hargata/fix.alt.fuel
Fix Alternate Fuel Mileage Bug
2024-04-12 08:04:28 -06:00
DESKTOP-GENO133\IvanPlex
5ef3e1e2ce updated version number 2024-04-12 08:04:04 -06:00
DESKTOP-GENO133\IvanPlex
d8b459e5ee persist regional formatting when viewing record statistics. 2024-04-12 08:01:25 -06:00
DESKTOP-GENO133\IvanPlex
7b40d58aa1 fix alternate fuel mileage auto converting to NA decimal format bug. 2024-04-12 07:54:10 -06:00
DESKTOP-T0O5CDB\DESK-555BD
809e9b838e fix donation link colors 2024-04-09 21:29:19 -06:00
Hargata Softworks
23ae36ebd9 Merge pull request #475 from hargata/Hargata/update.readme
check if function exists.
2024-04-07 21:03:31 -06:00
DESKTOP-GENO133\IvanPlex
9c3f7d20f5 fix plans not updating when deleted. 2024-04-07 21:01:06 -06:00
DESKTOP-GENO133\IvanPlex
083298303c check if function exists. 2024-04-07 20:51:55 -06:00
Hargata Softworks
224970a07e Merge pull request #474 from hargata/Hargata/update.readme
Fix the problem with time.
2024-04-07 19:15:41 -06:00
DESKTOP-GENO133\IvanPlex
86d039e5b0 Fix the problem with time. 2024-04-07 17:59:08 -06:00
Hargata Softworks
6a8038aac9 Merge pull request #473 from hargata/Hargata/update.readme
update readme
2024-04-07 13:59:02 -06:00
DESKTOP-GENO133\IvanPlex
e748f08a8e update readme 2024-04-07 13:58:32 -06:00
Hargata Softworks
3580963e9f Merge pull request #472 from hargata/Hargata/planner.improvement.part2
Improved UI UX For Planner Edit
2024-04-07 12:51:28 -06:00
DESKTOP-GENO133\IvanPlex
b008ce2ab8 Improved UI UX 2024-04-07 12:50:28 -06:00
Hargata Softworks
ea0c2c7061 Merge pull request #471 from hargata/Hargata/transl
Updated translation
2024-04-07 11:26:35 -06:00
DESKTOP-GENO133\IvanPlex
0926220933 Updated translation 2024-04-07 11:26:12 -06:00
Hargata Softworks
ca975bbdd3 Merge pull request #470 from hargata/Hargata/planner.template.edit
updated translation
2024-04-07 11:22:20 -06:00
DESKTOP-GENO133\IvanPlex
b16c5c5302 updated translation 2024-04-07 11:21:43 -06:00
Hargata Softworks
cad05fe5d9 Merge pull request #466 from hargata/Hargata/planner.improvement
Moved template modal outside of add modal.
2024-04-07 11:20:42 -06:00
Hargata Softworks
a7cd466d9c Merge pull request #469 from hargata/Hargata/planner.template.edit
Add functionality to let users edit plan record templates
2024-04-07 11:20:28 -06:00
DESKTOP-GENO133\IvanPlex
4472a67ec0 fixed label function 2024-04-07 11:19:52 -06:00
DESKTOP-GENO133\IvanPlex
c84a4029ec basic functionality to edit templates 2024-04-07 11:09:05 -06:00
DESKTOP-GENO133\IvanPlex
d7d9ab505e Add functionality to let users edit plan record templates 2024-04-07 08:31:17 -06:00
DESKTOP-GENO133\IvanPlex
c582f5f5c7 Moved template modal outside of add modal. 2024-04-05 19:36:26 -06:00
Hargata Softworks
4c30939339 Merge pull request #465 from hargata/Hargata/unused.translation.key
Updated translation file and unsaved changes label color.
2024-04-05 18:50:02 -06:00
DESKTOP-GENO133\IvanPlex
cecd6a1d2b Updated translation file and unsaved changes label color. 2024-04-05 18:48:54 -06:00
Hargata Softworks
853dcbb364 Merge pull request #464 from hargata/Hargata/unused.translation.key
removed cached translation key
2024-04-05 07:18:08 -06:00
DESKTOP-GENO133\IvanPlex
ae327ed26d removed cached translation key 2024-04-05 07:17:49 -06:00
DESKTOP-GENO133\IvanPlex
3e416aa255 Revert "removed unused translation key"
This reverts commit ab98d02106faceaca1c6c76b8f0de7bf3e28cebe.
2024-04-05 07:16:11 -06:00
DESKTOP-GENO133\IvanPlex
61c2c3fc83 removed unused translation key 2024-04-05 07:16:10 -06:00
Hargata Softworks
ca749aaf1e Merge pull request #463 from hargata/Hargata/unsaved.changes
updated cached view to only show when there are unsaved changes present.
2024-04-05 07:11:50 -06:00
DESKTOP-GENO133\IvanPlex
2a2cb3bd0c updated cached view to only show when there are unsaved changes present. 2024-04-05 07:10:09 -06:00
Hargata Softworks
44e3d19844 Merge pull request #462 from hargata/Hargata/global.search
added incremental search
2024-04-04 19:16:22 -06:00
DESKTOP-GENO133\IvanPlex
1e25fffc70 added incremental search 2024-04-04 19:14:49 -06:00
Hargata Softworks
44645ed23d Merge pull request #461 from hargata/Hargata/global.search
added global search
2024-04-04 10:48:57 -06:00
DESKTOP-GENO133\IvanPlex
fa557e5f76 added global search 2024-04-04 10:46:43 -06:00
Hargata Softworks
7202fda38e Merge pull request #458 from hargata/Hargata/cached.records
Cached Record.
2024-04-02 21:53:46 -06:00
DESKTOP-GENO133\IvanPlex
d05afe41d6 Cache the record the user was viewing if they didn't save, delete, or move it. 2024-04-02 21:51:02 -06:00
Hargata Softworks
bfc0b58728 Merge pull request #453 from hargata/Hargata/bring.back.modal
Allow users to bring back modal window they accidentally closed.
2024-04-02 07:39:25 -06:00
DESKTOP-GENO133\IvanPlex
22e8aaca81 Allow users to bring back modal window they accidentally closed. 2024-04-02 07:29:16 -06:00
Hargata Softworks
5cb1247fb2 Merge pull request #452 from hargata/Hargata/odometer.increment
Odometer Increments
2024-04-01 18:31:27 -06:00
DESKTOP-GENO133\IvanPlex
17a6d99703 Allow users to increment for last reported odometer reading when creating new records. 2024-04-01 18:25:20 -06:00
Hargata Softworks
3e7917f767 Create FUNDING.yml 2024-04-01 09:14:46 -06:00
Hargata Softworks
e9277d4dd9 Merge pull request #443 from hargata/Hargata/reminder.icons
reminders will now display urgency in icons instead of a full badge w…
2024-03-29 09:35:17 -06:00
DESKTOP-GENO133\IvanPlex
058edd8af6 reminders will now display urgency in icons instead of a full badge when viewed in small screens. 2024-03-29 08:15:55 -06:00
Hargata Softworks
8ed7dcb9ff Merge pull request #441 from hargata/Hargata/reminder.mobile
Improved Reminder page usability on mobile
2024-03-28 19:15:49 -06:00
DESKTOP-GENO133\IvanPlex
1f4827abc0 Improved Reminder page usabilty on mobile 2024-03-28 19:13:19 -06:00
Hargata Softworks
9715a0fcf7 Merge pull request #440 from hargata/Hargata/vehicle.garage.tags
Added status tags
2024-03-27 20:22:44 -06:00
DESKTOP-GENO133\IvanPlex
9bf475c352 Added status tags 2024-03-27 20:16:56 -06:00
Hargata Softworks
c2aeb4bca0 Merge pull request #438 from hargata/Hargata/garage.status
Hargata/garage.status
2024-03-27 11:41:43 -06:00
DESKTOP-GENO133\IvanPlex
07b3020999 use current mileage and date when renewing reminders. 2024-03-27 11:39:30 -06:00
DESKTOP-GENO133\IvanPlex
c2a7f39025 add depreciation calculation 2024-03-27 09:24:33 -06:00
DESKTOP-GENO133\IvanPlex
a92d422972 add purchase and sold price 2024-03-27 08:21:02 -06:00
Hargata Softworks
345eb65c3a Merge pull request #437 from hargata/Hargata/copy.supplies.attachments
Option to copy supplies attachments into records.
2024-03-26 18:33:15 -06:00
DESKTOP-GENO133\IvanPlex
a459973983 Add functionality to copy over attachments from supplies to records that are utilizing them. 2024-03-26 18:23:16 -06:00
Hargata Softworks
470dd4d78a Merge pull request #435 from hargata/Hargata/reminder.tag
Reminder Tags
2024-03-26 08:47:14 -06:00
DESKTOP-GENO133\IvanPlex
e4cb183140 improve readability on urgent reminder labels, filtering by tag now updates aggregate counts. 2024-03-26 08:40:30 -06:00
DESKTOP-GENO133\IvanPlex
6455af96bf Add tag functionality to reminders. 2024-03-26 08:11:14 -06:00
Hargata Softworks
42afa87464 Merge pull request #432 from hargata/Hargata/multiple.reminders
added translation layer
2024-03-25 06:46:59 -06:00
DESKTOP-GENO133\IvanPlex
97466eeff2 added translation layer 2024-03-25 06:45:15 -06:00
Hargata Softworks
bcbfd4ba9c Merge pull request #426 from hargata/Hargata/multiple.reminders
Select Multiple Reminders when creating new record.
2024-03-23 20:55:04 -06:00
DESKTOP-GENO133\IvanPlex
cfa052fc31 Fix styling 2024-03-23 20:52:46 -06:00
DESKTOP-GENO133\IvanPlex
3f71f6a8d8 Updated version number. 2024-03-23 20:35:41 -06:00
DESKTOP-GENO133\IvanPlex
b70e442ca3 Allow users to select multiple reminders to push back when creating new record. 2024-03-23 20:32:23 -06:00
Hargata Softworks
1f60b2aadc Merge pull request #422 from hargata/Hargata/auto.oidc
Enable auto login via OIDC
2024-03-20 14:55:14 -06:00
DESKTOP-GENO133\IvanPlex
3d2117ddaf Enable auto login via OIDC 2024-03-20 14:53:51 -06:00
Hargata Softworks
bcff18ea58 Merge pull request #421 from hargata/Hargata/extrafield.links
Add URL parser to extra fields.
2024-03-20 14:35:12 -06:00
DESKTOP-GENO133\IvanPlex
2e9821402f Add URL parser to extra fields. 2024-03-20 13:54:51 -06:00
Hargata Softworks
8914c5cd51 Merge pull request #420 from hargata/Hargata/litedb.concurrency
Hargata/litedb.concurrency
2024-03-20 13:14:24 -06:00
DESKTOP-GENO133\IvanPlex
0b240498f9 Renamed LiteDBInjection to LiteDBHelper 2024-03-20 13:13:24 -06:00
DESKTOP-GENO133\IvanPlex
16f66364cf fix backup breaking error. 2024-03-20 13:04:15 -06:00
Hargata Softworks
f2b0cec427 Merge pull request #419 from hargata/Hargata/litedb.concurrency
Added DB Checkpoint for WAL
2024-03-20 11:44:23 -06:00
DESKTOP-GENO133\IvanPlex
fac05ff5c0 Added DB Checkpoint records. 2024-03-20 11:40:55 -06:00
Hargata Softworks
1ac6dfd2a6 Merge pull request #418 from hargata/Hargata/litedb.concurrency
LiteDB Concurrency
2024-03-20 10:44:39 -06:00
DESKTOP-GENO133\IvanPlex
8bcac7344f removed unused using. 2024-03-20 10:40:53 -06:00
DESKTOP-GENO133\IvanPlex
300c986abb Replaced LiteDB's initialization with every DB call with Dependency Injection instead. 2024-03-20 10:38:32 -06:00
Hargata Softworks
91a5f92df6 Merge pull request #415 from hargata/Hargata/cleanup
Fix security vulnerability with hosted files being accessible by unau…
2024-03-18 10:10:28 -06:00
DESKTOP-GENO133\IvanPlex
d60a09d48f Fix security vulnerability with hosted files being accessible by unauthorized users.
Note that this is a retrospecitve commit to credit the user with finding the vulnerability.

Co-authored-by: Julien Stebenne <julien.stebenne@gmail.com>
2024-03-18 10:08:34 -06:00
Hargata Softworks
b22bb7c7ad Merge pull request #414 from hargata/Hargata/cleanup
Hargata/cleanup
2024-03-18 09:21:56 -06:00
DESKTOP-GENO133\IvanPlex
63cddc4ab0 fixed security vulnerability. 2024-03-18 09:18:05 -06:00
DESKTOP-GENO133\IvanPlex
790061d5c4 cleaned up unused usings. 2024-03-17 18:33:05 -06:00
Hargata Softworks
6e4e2795b6 Merge pull request #406 from hargata/Hargata/multi.gas.edit
fixed ui bug
2024-03-16 12:24:55 -06:00
DESKTOP-GENO133\IvanPlex
d4e51b714d fixed ui bug 2024-03-16 12:23:46 -06:00
Hargata Softworks
6a164dc60b Merge pull request #405 from hargata/Hargata/multi.gas.edit
Added functionality to edit multiple gas records.
2024-03-16 12:11:52 -06:00
DESKTOP-GENO133\IvanPlex
ce602dcf66 Added functionality to edit multiple gas records. 2024-03-16 12:10:40 -06:00
Hargata Softworks
2facb1ab46 Merge pull request #402 from hargata/Hargata/further.improvements
More enhancements
2024-03-16 10:04:03 -06:00
DESKTOP-GENO133\IvanPlex
3c7d575c85 fixes and ensure that users no longer have to hard refresh their sites. 2024-03-16 10:01:48 -06:00
DESKTOP-GENO133\IvanPlex
9635c3c2c5 fixed bug where translations are not being backed up. 2024-03-16 09:44:27 -06:00
DESKTOP-GENO133\IvanPlex
72427fc19d fixed average calculation 2024-03-15 17:15:05 -06:00
DESKTOP-GENO133\IvanPlex
0bbd3c5491 fixed spelling 2024-03-15 17:09:51 -06:00
DESKTOP-GENO133\IvanPlex
871de4e75a updated translation 2024-03-15 17:07:01 -06:00
DESKTOP-GENO133\IvanPlex
bf984f280e added feature to make odometer adjustments a piece of cake. 2024-03-15 16:48:23 -06:00
DESKTOP-GENO133\IvanPlex
2b8f3cf13a properly capitalized web hook descriptions. 2024-03-15 16:21:41 -06:00
Hargata Softworks
1630a5c9ec Merge pull request #401 from hargata/Hargata/webhook
added web hooks
2024-03-15 15:12:25 -06:00
DESKTOP-T0O5CDB\DESK-555BD
f17faa33f4 fixed punctuation 2024-03-15 15:09:27 -06:00
DESKTOP-T0O5CDB\DESK-555BD
c245b848a0 reminder hooks 2024-03-15 15:06:45 -06:00
DESKTOP-T0O5CDB\DESK-555BD
0ead9112c6 added vehicle deets 2024-03-15 15:01:27 -06:00
DESKTOP-T0O5CDB\DESK-555BD
44da393369 added web hooks 2024-03-15 14:59:30 -06:00
Hargata Softworks
5ae1628b7c Merge pull request #399 from hargata/Hargata/odo.modifier
Odometer Modifier
2024-03-15 14:05:41 -06:00
DESKTOP-GENO133\IvanPlex
59511d9ddd Updated version number 2024-03-15 12:49:34 -06:00
DESKTOP-GENO133\IvanPlex
82b0fba99a added functionality to modify odometer value when adding new odometer records. 2024-03-15 12:49:02 -06:00
DESKTOP-GENO133\IvanPlex
618107e515 added fields for odometer adjustments. 2024-03-15 10:16:28 -06:00
DESKTOP-GENO133\IvanPlex
35f931adf2 additional fields for vehicle level odometer settings. 2024-03-14 23:17:48 -06:00
Hargata Softworks
4a1e41cd54 Merge pull request #393 from hargata/Hargata/multi.odo.edit
Added functionality to edit multiple odometer records.
2024-03-13 10:18:13 -06:00
DESKTOP-T0O5CDB\DESK-555BD
888ec5cbbe Added functionality to edit multiple odometer records. 2024-03-13 10:16:04 -06:00
Hargata Softworks
f8f044d0cc Merge pull request #391 from hargata/Hargata/odo.changes
width issue
2024-03-11 11:42:26 -06:00
DESKTOP-GENO133\IvanPlex
36148c5539 width issue 2024-03-11 11:41:53 -06:00
Hargata Softworks
030dde0d64 Merge pull request #390 from hargata/Hargata/odo.changes
fixed admin panel text and button spacing.
2024-03-11 11:40:28 -06:00
DESKTOP-GENO133\IvanPlex
99faa951f9 fixed admin panel text and button spacing. 2024-03-11 11:39:56 -06:00
Hargata Softworks
7fb3a80ea3 Merge pull request #389 from hargata/Hargata/odo.changes
added support for meta key for MacOS users
2024-03-11 10:37:40 -06:00
DESKTOP-GENO133\IvanPlex
f277048aa9 added method to force recalculate distances 2024-03-11 10:34:42 -06:00
DESKTOP-GENO133\IvanPlex
34e3b8e145 added support for meta key for MacOS users 2024-03-11 10:01:24 -06:00
Hargata Softworks
91e8526b8e Merge pull request #388 from hargata/Hargata/odo.changes
removed logic that can cause bad data.
2024-03-10 14:19:54 -06:00
DESKTOP-GENO133\IvanPlex
926188ef64 removed logic that can cause bad data. 2024-03-10 14:18:24 -06:00
Hargata Softworks
1b5fc6729e Merge pull request #387 from hargata/Hargata/odo.changes
Odometer Changes
2024-03-10 14:13:35 -06:00
DESKTOP-GENO133\IvanPlex
3ac53ea144 added method to calculate distance. 2024-03-10 11:59:38 -06:00
DESKTOP-GENO133\IvanPlex
4dc3b4f741 fixed csv import 2024-03-10 09:05:15 -06:00
DESKTOP-GENO133\IvanPlex
7c1e6bd45c made API endpoints copyable 2024-03-10 08:56:41 -06:00
DESKTOP-GENO133\IvanPlex
00b3145e79 display distance traveled. 2024-03-10 08:02:44 -06:00
DESKTOP-GENO133\IvanPlex
def9a7770f odometer to trips improvement. 2024-03-10 06:33:39 -06:00
Hargata Softworks
5ba0bd5771 Merge pull request #381 from hargata/Hargata/fix.print
7z
2024-03-08 16:19:54 -07:00
DESKTOP-T0O5CDB\DESK-555BD
adc2de07f7 7z 2024-03-08 16:19:36 -07:00
Hargata Softworks
e12f528635 Merge pull request #380 from hargata/Hargata/fix.print
fixed the date column.
2024-03-08 16:17:46 -07:00
DESKTOP-T0O5CDB\DESK-555BD
c96ac53b91 fixed the date column. 2024-03-08 16:17:20 -07:00
Hargata Softworks
8c15bd5534 Merge pull request #378 from hargata/Hargata/fix.print
Improved Attachment Export
2024-03-08 11:49:57 -07:00
DESKTOP-T0O5CDB\DESK-555BD
90755d68b3 Improved Attachment Export 2024-03-08 11:49:30 -07:00
Hargata Softworks
94dfe9a0bb Merge pull request #377 from hargata/Hargata/fix.print
Added flex shrink
2024-03-08 11:13:36 -07:00
DESKTOP-T0O5CDB\DESK-555BD
9dbcf71856 Added flex shrink 2024-03-08 11:11:37 -07:00
Hargata Softworks
728fc3593f Merge pull request #374 from hargata/Hargata/fix.print
Fixed black border issue when printing
2024-03-07 22:49:59 -07:00
DESKTOP-T0O5CDB\DESK-555BD
1347585af2 Fixed black border issue when printing 2024-03-07 22:49:11 -07:00
Hargata Softworks
920de489be Merge pull request #372 from hargata/Hargata/delta.stats
Added MOTD.
2024-03-07 08:46:14 -07:00
DESKTOP-GENO133\IvanPlex
19cb964543 Added MOTD. 2024-03-07 08:44:58 -07:00
Hargata Softworks
eb03979ad8 Merge pull request #369 from hargata/Hargata/delta.stats
Added Total and Average Cost
2024-03-06 07:44:28 -07:00
DESKTOP-GENO133\IvanPlex
ebe871b82a reduced operations 2024-03-06 07:42:46 -07:00
DESKTOP-GENO133\IvanPlex
04a103fdc0 column specific search 2024-03-06 07:40:18 -07:00
DESKTOP-GENO133\IvanPlex
d0f80d4150 Added Total and Average Cost 2024-03-05 08:43:10 -07:00
Hargata Softworks
48c388dea7 Merge pull request #368 from redge76/Sample_postgreSQL
Sample postgreSQL configuration
2024-03-04 17:13:02 -07:00
Redge
d05f8b1f84 Sample postgrSQL connection stringin file .env
add a sample connection string to enable postgrSQL database backend
2024-03-05 01:09:10 +01:00
Redge
167d6e607e Sample docker-compose.postgresql.yml 2024-03-05 01:05:24 +01:00
Hargata Softworks
8755c6379a Merge pull request #367 from hargata/Hargata/record.delta.stats
Hargata/record.delta.stats
2024-03-04 16:20:24 -07:00
DESKTOP-GENO133\IvanPlex
1e2bd0ea4b Allow users to set their own reminder urgency threshold 2024-03-04 16:18:09 -07:00
DESKTOP-GENO133\IvanPlex
2cf93cf669 Added setting to hide sold vehicles. 2024-03-04 13:37:07 -07:00
Hargata Softworks
a18b81d52e Merge pull request #363 from hargata/Hargata/record.delta.stats
Hargata/record.delta.stats
2024-03-03 21:10:14 -07:00
DESKTOP-GENO133\IvanPlex
604c98a031 allowed users to configure their own file extensions. 2024-03-03 19:32:20 -07:00
DESKTOP-GENO133\IvanPlex
940f48b816 Updated version number 2024-03-03 09:20:02 -07:00
DESKTOP-GENO133\IvanPlex
f81545178d Added statistics between records. 2024-03-03 09:09:42 -07:00
Hargata Softworks
a87b599bdf Merge pull request #362 from hargata/Hargata/persist.columns
null check for column preferences
2024-03-02 19:13:11 -07:00
DESKTOP-GENO133\IvanPlex
2c45521fb4 null check for column preferences 2024-03-02 19:11:21 -07:00
Hargata Softworks
0870387995 Merge pull request #361 from hargata/Hargata/persist.columns
Allows users to inject root user credentials as environment variables.
2024-03-02 07:53:48 -07:00
DESKTOP-GENO133\IvanPlex
be281c78ff Allows users to inject root user credentials as environment variables. 2024-03-02 07:51:37 -07:00
Hargata Softworks
87c54335db Merge pull request #360 from hargata/Hargata/persist.columns
authenticate root user via configHelper
2024-03-02 07:13:43 -07:00
DESKTOP-GENO133\IvanPlex
12e6c1677b null checks 2024-03-02 07:13:13 -07:00
DESKTOP-GENO133\IvanPlex
f69b789346 authenticate root user via configHelper 2024-03-02 07:11:54 -07:00
Hargata Softworks
9f05295f18 Merge pull request #359 from hargata/Hargata/persist.columns
revamped column check toggle behavior
2024-03-02 06:50:52 -07:00
DESKTOP-GENO133\IvanPlex
bf14e4c8c0 added functonality to persist column visibility 2024-03-02 06:49:40 -07:00
Hargata Softworks
bd4db09637 Merge pull request #357 from hargata/Hargata/responsive.table.columns
allow table columns to grow as needed.
2024-03-02 05:48:23 -07:00
DESKTOP-GENO133\IvanPlex
4b5dcb1c7e revamped column check toggle behavior 2024-03-02 05:47:22 -07:00
DESKTOP-GENO133\IvanPlex
b7f1ac5e8f allow table columns to grow as needed. 2024-03-02 04:57:45 -07:00
Hargata Softworks
bcf3c3dc33 Merge pull request #354 from hargata/Hargata/gas.search
deprecated pinned notes
2024-03-01 04:34:18 -07:00
DESKTOP-GENO133\IvanPlex
993c271fa8 deprecated pinned notes 2024-03-01 04:31:13 -07:00
Hargata Softworks
b8b545a072 Merge pull request #353 from hargata/Hargata/gas.search
Added Search Functionality to Gas Tab
2024-03-01 04:17:19 -07:00
DESKTOP-GENO133\IvanPlex
84b748a361 added more data points to vehicle history report. 2024-03-01 04:14:53 -07:00
DESKTOP-GENO133\IvanPlex
ef2b8cadc7 added notes as a toggleable column 2024-02-29 19:06:56 -07:00
DESKTOP-GENO133\IvanPlex
d8cfa2c397 Added gas search 2024-02-29 19:01:44 -07:00
Hargata Softworks
d8c7d63f21 Merge pull request #352 from hargata/Hargata/vehicle.extra.fields
Added Additional Fields for Vehicle
2024-02-29 17:20:50 -07:00
DESKTOP-GENO133\IvanPlex
3d3aa23a65 added sold and purchased date to vehicle. 2024-02-29 17:20:03 -07:00
DESKTOP-GENO133\IvanPlex
6993fe5df8 prevent overlap of additional fields on vehicle level vs record level. 2024-02-29 16:38:31 -07:00
Hargata Softworks
48d80a8460 Merge pull request #350 from hargata/Hargata/universal.search
Updated translation
2024-02-29 14:10:34 -07:00
DESKTOP-GENO133\IvanPlex
742c5b3489 Updated translation 2024-02-29 14:09:06 -07:00
Hargata Softworks
3cd75c02ee Merge pull request #349 from hargata/Hargata/universal.search
Added Search Functionality
2024-02-29 13:57:55 -07:00
DESKTOP-GENO133\IvanPlex
854d5f0afe added search functionality to other tabs 2024-02-29 13:56:24 -07:00
DESKTOP-GENO133\IvanPlex
daabbfa759 Fixed null reference when no rows matches keyword. 2024-02-29 13:48:25 -07:00
DESKTOP-GENO133\IvanPlex
42ca4f76bf added a universal table search function 2024-02-29 13:31:32 -07:00
Hargata Softworks
6bf2801b1e Merge pull request #348 from hargata/Hargata/show.extrafields
Show Extra Fields as Columns in tables.
2024-02-29 12:18:13 -07:00
DESKTOP-GENO133\IvanPlex
3be3a28cc9 moved js function to shared file so that it will work with shop supplies 2024-02-29 12:17:26 -07:00
DESKTOP-GENO133\IvanPlex
916e1640de added extra fields functionality to supplies 2024-02-29 12:15:37 -07:00
DESKTOP-GENO133\IvanPlex
ecb3b74581 added extra fields to odometer records 2024-02-29 11:59:55 -07:00
DESKTOP-GENO133\IvanPlex
2171c7fbe3 added extra fields functionality to tax 2024-02-29 11:53:05 -07:00
DESKTOP-GENO133\IvanPlex
4a909e5c44 Added extra fields functionality to fuel tab. 2024-02-29 11:36:54 -07:00
DESKTOP-GENO133\IvanPlex
c44c239b35 Added Extra Fields ability to Upgrades 2024-02-29 10:56:03 -07:00
DESKTOP-GENO133\IvanPlex
6990046a8d Added Extra Field Columns to Repair Records 2024-02-29 10:49:46 -07:00
DESKTOP-GENO133\IvanPlex
0750b080f6 added setting to hide extra field columns 2024-02-29 10:34:24 -07:00
DESKTOP-GENO133\IvanPlex
ca09d2ca66 more stuff 2024-02-29 10:18:56 -07:00
DESKTOP-GENO133\IvanPlex
ed3749eaf2 proof of concept for toggling column visibilities 2024-02-29 10:09:58 -07:00
DESKTOP-GENO133\IvanPlex
fa3c391ee9 added ability to show extra fields and their values. 2024-02-28 21:21:45 -07:00
Hargata Softworks
c6d945b8c0 Merge pull request #347 from hargata/Hargata/max.odo.api
Added API Endpoint to retrieve last reported odometer reading.
2024-02-28 20:13:18 -07:00
DESKTOP-GENO133\IvanPlex
9dc20abbb4 Added API Endpoint to retrieve last reported odometer reading. 2024-02-28 20:12:01 -07:00
Hargata Softworks
94cd543e56 Merge pull request #346 from hargata/Hargata/user.update
Added functionality for users to update their account information after signing up.
2024-02-28 16:31:16 -07:00
DESKTOP-GENO133\IvanPlex
4f50939eb2 Updated version number 2024-02-28 16:29:46 -07:00
DESKTOP-GENO133\IvanPlex
60f792b2ef added link in mobile nav 2024-02-28 16:29:19 -07:00
DESKTOP-GENO133\IvanPlex
383945b156 Updated translation file 2024-02-28 16:26:36 -07:00
DESKTOP-GENO133\IvanPlex
0e960715ee Delete token only if user save is successful and log user out after updating profile. 2024-02-28 16:20:01 -07:00
DESKTOP-GENO133\IvanPlex
522fd2a9f5 Added empty email address for root users. everything should be functional from here on out. 2024-02-28 15:46:59 -07:00
DESKTOP-GENO133\IvanPlex
9091b3d2a8 added frontend method to retrieve and send token to user's email address. 2024-02-28 15:02:54 -07:00
DESKTOP-GENO133\IvanPlex
acc3d2f6d0 Added email helper method to send token for user account update. 2024-02-28 14:33:10 -07:00
DESKTOP-GENO133\IvanPlex
a9d7ab0193 Added logging to OIDC Login flow. 2024-02-28 14:22:32 -07:00
DESKTOP-T0O5CDB\DESK-555BD
cd720c34dd Updated logic 2024-02-28 14:18:12 -07:00
DESKTOP-GENO133\IvanPlex
c3839b1e98 added logic for updating user details. 2024-02-25 19:37:15 -07:00
Hargata Softworks
085eb2a9a0 Merge pull request #340 from hargata/Hargata/user.suggested.improvement
Bug Fixes
2024-02-24 16:57:17 -07:00
DESKTOP-GENO133\IvanPlex
f20c04d523 fixed bug in linux where oncontextmenu is fired before onrightclick. 2024-02-24 16:54:42 -07:00
DESKTOP-GENO133\IvanPlex
b7b7d6ad3e fixed tags input on android device. 2024-02-24 16:39:26 -07:00
Hargata Softworks
299444d767 Merge pull request #338 from hargata/Hargata/user.suggested.improvement
Updated version number
2024-02-24 11:42:41 -07:00
DESKTOP-GENO133\IvanPlex
0dbaa68fc0 added copy and paste support for tags input 2024-02-24 11:41:16 -07:00
DESKTOP-GENO133\IvanPlex
80fd9e136a Updated version number 2024-02-24 11:10:28 -07:00
Hargata Softworks
ba27db5f75 Merge pull request #337 from hargata/Hargata/user.suggested.improvement
added help links
2024-02-24 10:26:41 -07:00
Hargata Softworks
4629271fb2 Update issue templates 2024-02-24 10:24:55 -07:00
DESKTOP-GENO133\IvanPlex
91177af98b added help links 2024-02-24 10:19:15 -07:00
Hargata Softworks
26281d1cbb Merge pull request #336 from hargata/Hargata/user.suggested.improvement
added OIDC State validation
2024-02-24 09:53:12 -07:00
DESKTOP-GENO133\IvanPlex
a80c6e12ad added OIDC State validation 2024-02-24 06:14:44 -07:00
DESKTOP-GENO133\IvanPlex
8e208e8791 updated colors. 2024-02-22 22:43:51 -07:00
DESKTOP-GENO133\IvanPlex
6e87c2d5cc Updated website and re-organized readme 2024-02-22 22:36:56 -07:00
Hargata Softworks
3d96984735 Update README.md 2024-02-22 20:06:43 -07:00
Hargata Softworks
4626fdf04a Merge pull request #330 from hargata/Hargata/minor.improvement
added state for OIDC
2024-02-22 16:04:14 -07:00
DESKTOP-T0O5CDB\DESK-555BD
a2c013ec43 added state for OIDC 2024-02-22 15:59:35 -07:00
DESKTOP-GENO133\IvanPlex
9262131936 updated translation file. 2024-02-22 11:46:28 -07:00
Hargata Softworks
02c5302653 Update README.md 2024-02-22 11:20:19 -07:00
Hargata Softworks
fa73b61e3f Merge pull request #328 from hargata/Hargata/generic.editor
added functions for pinning notes.
2024-02-22 10:48:22 -07:00
DESKTOP-GENO133\IvanPlex
96ade10289 added functions for pinning notes. 2024-02-22 10:46:18 -07:00
Hargata Softworks
acf16a6c28 Merge pull request #327 from hargata/Hargata/generic.editor
added clear overrides
2024-02-22 10:12:13 -07:00
DESKTOP-GENO133\IvanPlex
dedf8fc2f7 added method to replenish supplies. 2024-02-22 10:11:26 -07:00
DESKTOP-GENO133\IvanPlex
7099652083 added clear overrides 2024-02-22 08:56:31 -07:00
Hargata Softworks
d0f9795e63 Merge pull request #326 from hargata/Hargata/clean.up.usings
code cleanup.
2024-02-21 22:58:00 -07:00
DESKTOP-GENO133\IvanPlex
0ffc469ac8 fixed missing end span tag. fixed deprecated js function. 2024-02-21 22:57:16 -07:00
DESKTOP-GENO133\IvanPlex
b5ea3c63a1 code cleanup. 2024-02-21 22:48:37 -07:00
Hargata Softworks
5901531ddf Merge pull request #325 from hargata/Hargata/bulk.selection
Hargata/bulk.selection
2024-02-21 22:33:19 -07:00
DESKTOP-GENO133\IvanPlex
814aa8d22b obsolete using 2024-02-21 22:30:25 -07:00
DESKTOP-GENO133\IvanPlex
d3aa55f987 Updated version number. 2024-02-21 22:29:47 -07:00
DESKTOP-GENO133\IvanPlex
8b7fb7ef0f added edit functionality for services, repairs, and upgrades 2024-02-21 22:28:25 -07:00
DESKTOP-GENO133\IvanPlex
0fab57d19c added bulk edit functionality. 2024-02-21 21:39:39 -07:00
DESKTOP-GENO133\IvanPlex
0d8822c496 reorganized folders. 2024-02-21 20:54:14 -07:00
Hargata Softworks
7235931f38 Merge pull request #322 from hargata/Hargata/bulk.selection
Bulk Operations.
2024-02-21 16:49:41 -07:00
DESKTOP-GENO133\IvanPlex
410f45c6c2 ssssss 2024-02-21 16:22:12 -07:00
DESKTOP-GENO133\IvanPlex
9a44d80be4 fixed compatibility on hybrid device. 2024-02-21 15:51:38 -07:00
DESKTOP-GENO133\IvanPlex
2f52ed64ba standardize experience across mobile devices 2024-02-21 15:05:19 -07:00
DESKTOP-GENO133\IvanPlex
dd68dec05c moved stuff around and added duplicate option. 2024-02-21 13:45:08 -07:00
DESKTOP-GENO133\IvanPlex
a8bc9f90e1 display number of records manipulated. 2024-02-21 12:57:09 -07:00
DESKTOP-GENO133\IvanPlex
8759216dd6 only select rows that are visible. 2024-02-21 12:50:11 -07:00
DESKTOP-GENO133\IvanPlex
0851e0a222 made things mobile friendly. 2024-02-21 12:38:50 -07:00
DESKTOP-GENO133\IvanPlex
40f1f1380e added select all to context menu for mobile friendliness. 2024-02-21 11:53:00 -07:00
DESKTOP-GENO133\IvanPlex
2a5ff7a911 added ability to select reminders from tax modal. 2024-02-21 10:32:25 -07:00
DESKTOP-GENO133\IvanPlex
0590f991d2 added shared method to push back recurring reminders. 2024-02-21 10:10:28 -07:00
DESKTOP-GENO133\IvanPlex
c6a96df3e9 updated readme 2024-02-20 21:21:20 -07:00
DESKTOP-GENO133\IvanPlex
0088c74b20 added ability to select rows when ctrl key is held. 2024-02-20 20:23:47 -07:00
DESKTOP-T0O5CDB\DESK-555BD
6af0d8b88e added functionality to delete records in bulk. 2024-02-19 22:32:07 -07:00
DESKTOP-T0O5CDB\DESK-555BD
5204a71b00 added option to bulk move records across service, upgrade, and repair. 2024-02-19 21:57:11 -07:00
DESKTOP-T0O5CDB\DESK-555BD
8b2866b89b added ability to select bulk data. 2024-02-19 16:48:12 -07:00
Hargata Softworks
65f638f336 Merge pull request #319 from hargata/Hargata/csv.odo.insert
Hargata/csv.odo.insert
2024-02-19 14:00:52 -07:00
DESKTOP-T0O5CDB\DESK-555BD
f92e95e01c Merge branch 'main' into Hargata/report.usability 2024-02-19 13:59:04 -07:00
DESKTOP-T0O5CDB\DESK-555BD
2aeae70060 Enabled Auto Odometer CSV when importing via CSV. 2024-02-19 13:58:23 -07:00
Hargata Softworks
98b1cd9bc5 Merge pull request #315 from hargata/Hargata/linked.planner.to.reminder
check if reminder still exists.
2024-02-18 15:04:45 -07:00
DESKTOP-GENO133\IvanPlex
a02684f921 check if reminder still exists. 2024-02-18 15:04:02 -07:00
Hargata Softworks
13ddc6309e Merge pull request #314 from hargata/Hargata/linked.planner.to.reminder
Updated version number
2024-02-18 14:42:42 -07:00
DESKTOP-GENO133\IvanPlex
2b2fd3ae28 Updated version number 2024-02-18 14:42:05 -07:00
Hargata Softworks
2dd3dc1718 Merge pull request #313 from hargata/Hargata/linked.planner.to.reminder
added ability to create plans from reminders.
2024-02-18 14:23:39 -07:00
DESKTOP-GENO133\IvanPlex
fe1b96d58c updated translation 2024-02-18 14:22:43 -07:00
DESKTOP-GENO133\IvanPlex
8dfee0fd12 added ability to create plans from reminders. 2024-02-18 14:20:20 -07:00
Hargata Softworks
275b60aa14 Merge pull request #310 from hargata/Hargata/supply.usage.history
Supply Usage History
2024-02-18 13:16:46 -07:00
DESKTOP-GENO133\IvanPlex
dd14b71e68 added front end to show used supplies. 2024-02-18 11:32:04 -07:00
DESKTOP-GENO133\IvanPlex
849171c4df moved function to shared js. 2024-02-17 21:43:19 -07:00
DESKTOP-GENO133\IvanPlex
2183c77606 added button to show supply requisition history. 2024-02-17 19:13:09 -07:00
Hargata Softworks
bedf7bad34 Merge pull request #306 from hargata/Hargata/report.usability
Improved Usability
2024-02-17 17:13:41 -07:00
DESKTOP-GENO133\IvanPlex
802c7923d5 added supply usage history 2024-02-17 17:07:31 -07:00
DESKTOP-GENO133\IvanPlex
95c8cd19f8 Updated error message 2024-02-17 10:53:29 -07:00
DESKTOP-GENO133\IvanPlex
e700a5f1c2 functionality to duplicate collaborators across vehicles. 2024-02-17 10:51:39 -07:00
DESKTOP-T0O5CDB\DESK-555BD
7fd7f7e29d added select all option to reports page. 2024-02-16 15:50:52 -07:00
DESKTOP-T0O5CDB\DESK-555BD
902ddd0269 improve usability on reports dropdown 2024-02-16 15:29:06 -07:00
Hargata Softworks
0a6424f8c0 Merge pull request #305 from hargata/Hargata/user.provisioning
revert
2024-02-16 14:07:52 -07:00
DESKTOP-T0O5CDB\DESK-555BD
3a36c624ba revert 2024-02-16 14:07:22 -07:00
Hargata Softworks
1329beb808 Merge pull request #304 from hargata/Hargata/user.provisioning
attempt to fix docker build.
2024-02-16 14:05:40 -07:00
DESKTOP-T0O5CDB\DESK-555BD
0e8ef0180f attempt to fix docker build. 2024-02-16 14:05:01 -07:00
Hargata Softworks
660f089035 Merge pull request #303 from hargata/Hargata/user.provisioning
Hargata/user.provisioning
2024-02-16 13:57:52 -07:00
DESKTOP-T0O5CDB\DESK-555BD
04f90ae6a8 Added Distance Traveled Chart 2024-02-16 13:55:22 -07:00
DESKTOP-T0O5CDB\DESK-555BD
30b4a73fef made datepicker honor locale's week start day 2024-02-16 11:58:23 -07:00
DESKTOP-T0O5CDB\DESK-555BD
b7158f3bf0 automatically log open id user in after they've registered. 2024-02-16 11:06:49 -07:00
DESKTOP-T0O5CDB\DESK-555BD
f46bbe9963 Allow OpenID Users to sign up with a token. 2024-02-16 10:48:20 -07:00
Hargata Softworks
9f73068a9e Merge pull request #301 from hargata/Hargata/oidc.auth
Updated app version.
2024-02-15 20:12:23 -07:00
DESKTOP-GENO133\IvanPlex
779b18802b Updated app version. 2024-02-15 20:11:39 -07:00
Hargata Softworks
dce9acf47f Merge pull request #300 from hargata/Hargata/oidc.auth
Hargata/OIDC.auth
2024-02-15 20:08:54 -07:00
DESKTOP-GENO133\IvanPlex
c9a925f548 Updated section name 2024-02-15 19:10:38 -07:00
DESKTOP-GENO133\IvanPlex
4eeec7887a Updated wording 2024-02-15 19:09:50 -07:00
Hargata Softworks
156c781bd7 Merge pull request #297 from hargata/Hargata/bugfix
Fixed ExtraFields upsert query.
2024-02-15 19:07:14 -07:00
DESKTOP-T0O5CDB\DESK-555BD
296cf92022 added error handling for users not registered with LubeLogger 2024-02-15 19:02:11 -07:00
DESKTOP-T0O5CDB\DESK-555BD
d5f0e57c3b Added OpenID login. 2024-02-15 18:57:22 -07:00
DESKTOP-GENO133\IvanPlex
86ba6200fc Fixed ExtraFields upsert query. 2024-02-15 09:26:01 -07:00
Hargata Softworks
ac4ea07319 Merge pull request #291 from hargata/Hargata/further.improvements
styling changes.
2024-02-14 12:22:03 -07:00
DESKTOP-T0O5CDB\DESK-555BD
6d380de603 styling changes. 2024-02-14 12:21:39 -07:00
Hargata Softworks
e789bc6925 Merge pull request #290 from hargata/Hargata/further.improvements
server timezone offset.
2024-02-14 12:15:05 -07:00
DESKTOP-T0O5CDB\DESK-555BD
f7481be91c Updated version. 2024-02-14 12:14:10 -07:00
DESKTOP-T0O5CDB\DESK-555BD
a8151bcf0e server timezone offset. 2024-02-14 12:12:49 -07:00
Hargata Softworks
0b6a6787bb Merge pull request #289 from hargata/Hargata/further.improvements
Further Improvements
2024-02-14 11:02:59 -07:00
DESKTOP-T0O5CDB\DESK-555BD
7302982366 removed empty script tag. 2024-02-14 11:01:08 -07:00
DESKTOP-T0O5CDB\DESK-555BD
19b7dfc90a added calendar view modal 2024-02-14 10:56:33 -07:00
DESKTOP-T0O5CDB\DESK-555BD
29825a6ad6 Merge branch 'main' into Hargata/further.improvements
# Conflicts:
#	wwwroot/js/garage.js
2024-02-14 09:21:16 -07:00
DESKTOP-T0O5CDB\DESK-555BD
f6493f0496 Further improvements to calendar page. 2024-02-14 09:18:47 -07:00
Hargata Softworks
c2d61eecc0 Merge pull request #285 from hargata/Hargata/encode.html
Encode HTML Inputs.
2024-02-13 17:46:13 -07:00
DESKTOP-GENO133\IvanPlex
2a4354c52e Encode HTML Inputs. 2024-02-13 17:45:41 -07:00
Hargata Softworks
e7dc4f67f5 Merge pull request #284 from hargata/Hargata/calendar.view
Lock down contoller methods for extra fields.
2024-02-13 16:48:48 -07:00
DESKTOP-T0O5CDB\DESK-555BD
8584d2cf9c Lock down contoller methods for extra fields. 2024-02-13 16:48:24 -07:00
Hargata Softworks
92b9c6953c Merge pull request #283 from hargata/Hargata/calendar.view
fixed bug for records with deleted views.
2024-02-13 16:17:12 -07:00
DESKTOP-T0O5CDB\DESK-555BD
ac1c2ca7fe fixed bug for records with deleted views. 2024-02-13 16:16:49 -07:00
Hargata Softworks
f05ca7f1f8 Merge pull request #282 from hargata/Hargata/calendar.view
Hargata/calendar.view
2024-02-13 16:03:31 -07:00
DESKTOP-T0O5CDB\DESK-555BD
ecef1c8640 cleaner code. 2024-02-13 16:02:01 -07:00
DESKTOP-T0O5CDB\DESK-555BD
43d58a4b7e Fixed bug with styling. 2024-02-13 15:49:50 -07:00
DESKTOP-T0O5CDB\DESK-555BD
8293b376a2 Added a Calendar View 2024-02-13 15:36:25 -07:00
Hargata Softworks
c243cdd54c Merge pull request #276 from hargata/Hargata/extra.fields
Extra Fields
2024-02-12 20:59:53 -07:00
Hargata Softworks
0383257356 Merge pull request #278 from hargata/Hargata/numeric.odo
Numeric keyboard for odometer field.
2024-02-12 20:56:33 -07:00
DESKTOP-GENO133\IvanPlex
73e8731bd4 Numeric keyboard for odometer field. 2024-02-12 20:56:03 -07:00
DESKTOP-GENO133\IvanPlex
b0e82889e0 updated translation, fixed postgres method for extra field insert. 2024-02-12 20:28:36 -07:00
Hargata Softworks
8e28116371 Merge pull request #277 from hargata/Hargata/documentation.static
Static File Documentation
2024-02-12 19:29:06 -07:00
DESKTOP-GENO133\IvanPlex
ed717af91c further optimization. 2024-02-12 19:26:11 -07:00
DESKTOP-GENO133\IvanPlex
7ae5a982e9 updated this thang. 2024-02-12 18:31:11 -07:00
DESKTOP-GENO133\IvanPlex
2e3f1e6763 updated translation file. 2024-02-12 18:30:44 -07:00
DESKTOP-GENO133\IvanPlex
4a2e02afc8 fixed bug where required fields don't persist. 2024-02-12 18:30:03 -07:00
DESKTOP-GENO133\IvanPlex
9c53850faa added front end for displaying extra fields. 2024-02-12 17:39:09 -07:00
DESKTOP-GENO133\IvanPlex
695b15faed added UI to add/edit/delete extra fields. 2024-02-12 17:36:13 -07:00
DESKTOP-GENO133\IvanPlex
33aeaf9825 front end logic for saving extra fields. 2024-02-12 17:32:08 -07:00
DESKTOP-GENO133\IvanPlex
dc3608524a fomatting. 2024-02-12 15:04:32 -07:00
DESKTOP-GENO133\IvanPlex
6996814888 added backend for storing extra fields. 2024-02-12 15:04:02 -07:00
DESKTOP-GENO133\IvanPlex
9bbaf49ade Static documentation cloned from otterwiki 2024-02-12 13:59:53 -07:00
DESKTOP-GENO133\IvanPlex
db737df712 removed empty extra fields from being added to object. 2024-02-12 09:15:05 -07:00
DESKTOP-GENO133\IvanPlex
bae1839c06 added JS to retrieve and validate extra fields. 2024-02-12 09:05:59 -07:00
DESKTOP-GENO133\IvanPlex
7e70f5108f changed dictionary to class object so we can enforce field requirement. 2024-02-12 03:27:26 -07:00
DESKTOP-GENO133\IvanPlex
c5c0a6900b added extra fields attribute to object classes. 2024-02-11 19:08:27 -07:00
Hargata Softworks
50b88dd7a1 Merge pull request #275 from hargata/Hargata/supplies.improvement
updated version number and fixed labels not updating in supplies page
2024-02-11 18:36:33 -07:00
DESKTOP-GENO133\IvanPlex
e44eb991f5 updated version number and fixed labels not updating in supplies page 2024-02-11 18:14:34 -07:00
Hargata Softworks
39d0d346ad Merge pull request #274 from hargata/Hargata/supplies.improvement
fixed supply requisition when used with european units.
2024-02-11 14:41:31 -07:00
DESKTOP-GENO133\IvanPlex
142865f1ce fixed supply requisition when used with european units. 2024-02-11 14:40:47 -07:00
Hargata Softworks
2c18755a0f Merge pull request #273 from hargata/Hargata/supplies.improvement
Supplies Improvement
2024-02-11 13:08:08 -07:00
DESKTOP-GENO133\IvanPlex
d3be77bf09 fixed div name, 2024-02-11 12:47:43 -07:00
DESKTOP-GENO133\IvanPlex
bcafd9e97e added tags in supplies requisition modal. 2024-02-11 12:46:34 -07:00
DESKTOP-GENO133\IvanPlex
f581e55842 added tags to general supply record tab. 2024-02-11 09:48:54 -07:00
DESKTOP-GENO133\IvanPlex
dfe4e4f1ab added check for missing supplies 2024-02-11 09:24:48 -07:00
Hargata Softworks
080e2a1667 Merge pull request #269 from hargata/Hargata/num.input
added attributes to prompt numeric inputs without actually limiting t…
2024-02-10 22:53:57 -07:00
DESKTOP-GENO133\IvanPlex
01cbee00fd added attributes to prompt numeric inputs without actually limiting the user to numbers. 2024-02-10 22:52:22 -07:00
Hargata Softworks
f0869c741f Merge pull request #266 from hargata/Hargata/postgres.fix.fix
added enable shop supplies to config helper
2024-02-10 15:15:24 -07:00
DESKTOP-T0O5CDB\DESK-555BD
6dc690011d added enable shop supplies to config helper 2024-02-10 14:32:11 -07:00
Hargata Softworks
65891c7c11 Merge pull request #265 from hargata/Hargata/postgres.fix.fix
additional fixes
2024-02-10 14:14:25 -07:00
DESKTOP-T0O5CDB\DESK-555BD
d306152d38 additional fixes 2024-02-10 14:11:31 -07:00
DESKTOP-GENO133\IvanPlex
b372f64e11 ignored more files. 2024-02-10 13:01:38 -07:00
DESKTOP-GENO133\IvanPlex
baff93bd96 updated gitignore 2024-02-10 12:57:58 -07:00
DESKTOP-GENO133\IvanPlex
abbe13b269 stop tracking userConfig.json 2024-02-10 12:57:38 -07:00
Hargata Softworks
fb43932e0d Merge pull request #264 from hargata/Hargata/postgres.fix
Updated command.
2024-02-10 11:47:15 -07:00
DESKTOP-GENO133\IvanPlex
c10aa73e5e Updated command. 2024-02-10 11:46:34 -07:00
Hargata Softworks
be09f3e9dd Merge pull request #263 from hargata/Hargata/postgres.fix
only open connection if it's closed.
2024-02-10 11:20:01 -07:00
DESKTOP-GENO133\IvanPlex
d3f94337ae only open connection if it's closed. 2024-02-10 11:19:27 -07:00
Hargata Softworks
46a227453e Merge pull request #262 from hargata/Hargata/custom.month.interval
added ability to add custom month interval to reminder.
2024-02-10 10:49:33 -07:00
DESKTOP-GENO133\IvanPlex
8981d69844 added custom month interval for taxes/fees 2024-02-10 10:47:33 -07:00
DESKTOP-GENO133\IvanPlex
09fbc37472 added ability to add custom month interval to reminder. 2024-02-10 09:33:30 -07:00
Hargata Softworks
5cee1ea7cf Merge pull request #261 from hargata/Hargata/taginput.tweaks
change make backup to create backup.
2024-02-10 08:48:09 -07:00
DESKTOP-GENO133\IvanPlex
cd9a673e62 change make backup to create backup. 2024-02-10 08:47:08 -07:00
Hargata Softworks
dd9f754e85 Merge pull request #254 from hargata/Hargata/taginput.tweaks
Minor tweaks and QOL improvement
2024-02-09 22:26:52 -07:00
DESKTOP-GENO133\IvanPlex
7d22d1ddc4 auto create config directory if it doesn't exist. 2024-02-09 22:23:18 -07:00
DESKTOP-GENO133\IvanPlex
d5f562b48f removed obsolete typeahead script and fixed input spacing on mobile devices. 2024-02-09 21:57:01 -07:00
DESKTOP-GENO133\IvanPlex
bb64ee4012 Fixed to return redirect to unauthorized page instead of hardcoded view name 2024-02-09 15:09:11 -07:00
DESKTOP-GENO133\IvanPlex
a60430b4b2 Fixed 401 redirect 2024-02-09 15:07:43 -07:00
Hargata Softworks
117a172bc2 Merge pull request #253 from hargata/Hargata/postgres
Added Postgres backend support.
2024-02-09 14:56:08 -07:00
DESKTOP-GENO133\IvanPlex
b93b7f321e fixed export file path. 2024-02-09 14:55:29 -07:00
DESKTOP-GENO133\IvanPlex
f34f3da587 added export functionality. 2024-02-09 14:32:30 -07:00
DESKTOP-GENO133\IvanPlex
8104f852d8 added partial export functionality 2024-02-09 14:05:26 -07:00
DESKTOP-GENO133\IvanPlex
32e58e6280 added import function for migration tool. 2024-02-09 13:34:10 -07:00
DESKTOP-GENO133\IvanPlex
c4dc81e4bc fixed user access issue. 2024-02-09 10:34:01 -07:00
DESKTOP-GENO133\IvanPlex
9fe0396abe added token data access for pg 2024-02-09 09:55:02 -07:00
DESKTOP-GENO133\IvanPlex
ad2b58697a added post gres backend for user record. 2024-02-09 09:46:47 -07:00
DESKTOP-GENO133\IvanPlex
4845b02fc8 updated to return null instead of empty object. 2024-02-08 20:18:17 -07:00
DESKTOP-GENO133\IvanPlex
1ed53d5e4b added pg data access for user config record. 2024-02-08 19:50:50 -07:00
DESKTOP-GENO133\IvanPlex
00622126d7 added more generic data access classes for postgres. 2024-02-08 19:26:42 -07:00
DESKTOP-GENO133\IvanPlex
b5cdd66248 added tax and reminder pg data access 2024-02-08 18:15:33 -07:00
DESKTOP-GENO133\IvanPlex
78408427b8 only init endpoint list if vehicleId is 0. 2024-02-08 17:54:42 -07:00
DESKTOP-GENO133\IvanPlex
baf9e8e833 Merge branch 'main' into Hargata/postgres 2024-02-08 17:50:30 -07:00
DESKTOP-GENO133\IvanPlex
bde00a26d5 added pg data access for repair records. 2024-02-08 17:50:06 -07:00
Hargata Softworks
6be6a2196e Merge pull request #251 from hargata/Hargata/shop.supplies
checked endpoints.
2024-02-08 17:41:50 -07:00
DESKTOP-T0O5CDB\DESK-555BD
b8dab3d4a4 checked endpoints. 2024-02-08 17:41:00 -07:00
Hargata Softworks
447c929386 Merge pull request #250 from hargata/Hargata/shop.supplies
fixed collaboratorfilter so that user can only access shop supplies
2024-02-08 17:33:18 -07:00
DESKTOP-T0O5CDB\DESK-555BD
9e37c01a83 fixed collaboratorfilter so that user can only access shop supplies 2024-02-08 17:32:06 -07:00
Hargata Softworks
3d39dc8ed8 Merge pull request #249 from hargata/Hargata/shop.supplies
consolidated settings into confighelper, fixed shop supplies access i…
2024-02-08 16:55:19 -07:00
DESKTOP-T0O5CDB\DESK-555BD
08ace8b08d consolidated settings into confighelper, fixed shop supplies access issue for non root user. 2024-02-08 16:54:01 -07:00
Hargata Softworks
cbf95b1e04 Merge pull request #248 from hargata/Hargata/shop.supplies
hide shop supplies by default unless enabled by root user.
2024-02-08 16:20:19 -07:00
DESKTOP-T0O5CDB\DESK-555BD
fd8f93ee5f hide shop supplies by default unless enabled by root user. 2024-02-08 16:18:29 -07:00
Hargata Softworks
4f146f9427 Merge pull request #247 from hargata/Hargata/shop.supplies
added garage level supplies
2024-02-08 15:36:01 -07:00
DESKTOP-T0O5CDB\DESK-555BD
19ace06c08 fixed markdown not working. 2024-02-08 15:34:00 -07:00
DESKTOP-T0O5CDB\DESK-555BD
4bfe947ce1 added garage level supplies 2024-02-08 15:30:24 -07:00
DESKTOP-GENO133\IvanPlex
4850b38e7f updated version and dependencies. 2024-02-08 08:57:17 -07:00
DESKTOP-GENO133\IvanPlex
e5f19c5f20 added injection for gas record pg data access 2024-02-08 08:48:33 -07:00
DESKTOP-GENO133\IvanPlex
8c4212678f added gas record pg data access 2024-02-08 08:47:50 -07:00
DESKTOP-GENO133\IvanPlex
573e80728c Merge branch 'main' into Hargata/postgres 2024-02-08 08:38:19 -07:00
DESKTOP-GENO133\IvanPlex
c88fa690f6 added postgres data access for service records. 2024-02-08 08:33:23 -07:00
DESKTOP-GENO133\IvanPlex
1feb89acf5 simplified vehicle data access. 2024-02-07 21:08:11 -07:00
DESKTOP-GENO133\IvanPlex
8be252e949 added note data access for postgres. 2024-02-07 21:02:54 -07:00
DESKTOP-GENO133\IvanPlex
3aaf230a60 made add vehicle method more efficient. 2024-02-07 20:33:51 -07:00
Hargata Softworks
27126638be Merge pull request #244 from hargata/Hargata/deltamileage
swap min max label on filter.
2024-02-07 13:12:38 -07:00
DESKTOP-GENO133\IvanPlex
8c3a001930 swap min max label on filter. 2024-02-07 13:11:18 -07:00
Hargata Softworks
2b2f181888 Merge pull request #243 from hargata/Hargata/deltamileage
fixed max and min labels not updating.
2024-02-07 12:49:04 -07:00
DESKTOP-GENO133\IvanPlex
66557fa126 fixed max and min labels not updating. 2024-02-07 12:48:34 -07:00
Hargata Softworks
7c00951d74 Merge pull request #242 from hargata/Hargata/deltamileage
Hargata/deltamileage
2024-02-07 12:32:36 -07:00
DESKTOP-GENO133\IvanPlex
1087ed56ce added feature to auto add to odometer when user adds via API. 2024-02-07 10:51:04 -07:00
DESKTOP-GENO133\IvanPlex
dd2cfd90b1 added method to toggle delta mileage. 2024-02-07 10:41:58 -07:00
DESKTOP-GENO133\IvanPlex
e45339f75c fixed vehicle id = 0 2024-02-07 09:19:36 -07:00
DESKTOP-GENO133\IvanPlex
9c225ff7a0 postgres backend for vehicle. 2024-02-06 20:24:05 -07:00
DESKTOP-GENO133\IvanPlex
6cdfba420f moved existing external implementations into litedb folder 2024-02-06 19:10:28 -07:00
Hargata Softworks
cc43d45c9c Merge pull request #234 from hargata/Hargata/email.reminder.template
created email template for reminder emails.
2024-02-06 16:13:04 -07:00
Hargata Softworks
dba51f171d Merge pull request #237 from hargata/Hargata/plan.template
Planner Templates
2024-02-06 16:07:26 -07:00
DESKTOP-GENO133\IvanPlex
0bbf9f783f added more translation keys. 2024-02-06 16:04:34 -07:00
DESKTOP-GENO133\IvanPlex
a52ac6a41b Front end for creating plan records from templates. 2024-02-06 15:54:32 -07:00
DESKTOP-GENO133\IvanPlex
a542c91dc3 added backend for saving and retrieving plan record templates. 2024-02-06 12:45:39 -07:00
DESKTOP-GENO133\IvanPlex
6bcbb0cc86 created email template for reminder emails. 2024-02-06 06:12:13 -07:00
DESKTOP-GENO133\IvanPlex
7a78d51c79 Update version number. 2024-02-05 20:30:13 -07:00
Hargata Softworks
3c2715840e Merge pull request #233 from hargata/Hargata/increase.upload.size
1.1.3
2024-02-05 18:29:36 -07:00
DESKTOP-GENO133\IvanPlex
dfbd90aaf4 Merge branch 'main' into Hargata/increase.upload.size
# Conflicts:
#	Views/Login/Index.cshtml
2024-02-05 18:26:14 -07:00
DESKTOP-GENO133\IvanPlex
2b3a4ce8ce more things to translate 2024-02-05 18:23:06 -07:00
DESKTOP-GENO133\IvanPlex
135292f2b4 added attachment features to Notes. 2024-02-05 18:08:54 -07:00
Hargata Softworks
499c697b0b Merge pull request #229 from hargata/Hargata/redirectURL
added redirectURL
2024-02-05 08:46:05 -07:00
DESKTOP-T0O5CDB\DESK-555BD
fb74f01609 added redirectURL 2024-02-05 08:44:49 -07:00
DESKTOP-GENO133\IvanPlex
6ab2216742 greatly increase the max upload size. 2024-02-04 15:32:34 -07:00
234 changed files with 12992 additions and 12663 deletions

6
.env
View File

@@ -6,4 +6,8 @@ MailConfig__UseSSL="false"
MailConfig__Port=587 MailConfig__Port=587
MailConfig__Username="" MailConfig__Username=""
MailConfig__Password="" MailConfig__Password=""
LOGGING__LOGLEVEL__DEFAULT=Error LOGGING__LOGLEVEL__DEFAULT=Error
# * Uncoment this line if you use postgresSQL as database backend.
# * Check the docker-compose.postgresql.yml file
#POSTGRES_CONNECTION="Host=postgres;Username=lubelogger;Password=lubepass;Database=lubelogger;"

14
.github/FUNDING.yml vendored Normal file
View 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
View File

@@ -0,0 +1,30 @@
---
name: Bug report
about: Report a bug
title: ''
labels: ''
assignees: ''
---
**Checklist**
Please make sure you have performed the following steps before opening a new bug ticket, change `[ ]` to `[x]` to mark it as done
- [ ] I have read and tried the steps outlined in the [Troubleshooting Guide](https://docs.lubelogger.com/Troubleshooting)
- [ ] I have searched through existing issues.
**Description**
<!-- Describe the bug below this line -->
**Platform**
- [ ] Docker Image
- [ ] Windows Standalone Executable
**Browser Console Errors(F12)**
<!-- Attach a screenshot or codeblock containing the browser console error -->
**App/Container Console Error**
<!-- Attach a screenshot or codeblock containing the app/container console error -->
**Screenshots(optional)**
<!-- Attach a screenshot describing the bug -->

4
.gitignore vendored
View File

@@ -8,3 +8,7 @@ wwwroot/documents/
wwwroot/temp/ wwwroot/temp/
wwwroot/imports/ wwwroot/imports/
wwwroot/translations/ wwwroot/translations/
config/userConfig.json
CarCareTracker.csproj.user
Properties/launchSettings.json
data/cartracker-log.db

View File

@@ -13,6 +13,9 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="CsvHelper" Version="30.0.1" /> <PackageReference Include="CsvHelper" Version="30.0.1" />
<PackageReference Include="LiteDB" Version="5.0.17" /> <PackageReference Include="LiteDB" Version="5.0.17" />
<PackageReference Include="MailKit" Version="4.5.0" />
<PackageReference Include="Npgsql" Version="8.0.2" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.3.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -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>

View File

@@ -1,5 +1,4 @@
using CarCareTracker.External.Implementations; using CarCareTracker.External.Interfaces;
using CarCareTracker.External.Interfaces;
using CarCareTracker.Filter; using CarCareTracker.Filter;
using CarCareTracker.Helper; using CarCareTracker.Helper;
using CarCareTracker.Logic; using CarCareTracker.Logic;
@@ -27,8 +26,11 @@ namespace CarCareTracker.Controllers
private readonly IReminderHelper _reminderHelper; private readonly IReminderHelper _reminderHelper;
private readonly IGasHelper _gasHelper; private readonly IGasHelper _gasHelper;
private readonly IUserLogic _userLogic; private readonly IUserLogic _userLogic;
private readonly IVehicleLogic _vehicleLogic;
private readonly IOdometerLogic _odometerLogic;
private readonly IFileHelper _fileHelper; private readonly IFileHelper _fileHelper;
private readonly IMailHelper _mailHelper; private readonly IMailHelper _mailHelper;
private readonly IConfigHelper _config;
public APIController(IVehicleDataAccess dataAccess, public APIController(IVehicleDataAccess dataAccess,
IGasHelper gasHelper, IGasHelper gasHelper,
IReminderHelper reminderHelper, IReminderHelper reminderHelper,
@@ -44,7 +46,10 @@ namespace CarCareTracker.Controllers
IUserRecordDataAccess userRecordDataAccess, IUserRecordDataAccess userRecordDataAccess,
IMailHelper mailHelper, IMailHelper mailHelper,
IFileHelper fileHelper, IFileHelper fileHelper,
IUserLogic userLogic) IConfigHelper config,
IUserLogic userLogic,
IVehicleLogic vehicleLogic,
IOdometerLogic odometerLogic)
{ {
_dataAccess = dataAccess; _dataAccess = dataAccess;
_noteDataAccess = noteDataAccess; _noteDataAccess = noteDataAccess;
@@ -61,7 +66,10 @@ namespace CarCareTracker.Controllers
_gasHelper = gasHelper; _gasHelper = gasHelper;
_reminderHelper = reminderHelper; _reminderHelper = reminderHelper;
_userLogic = userLogic; _userLogic = userLogic;
_odometerLogic = odometerLogic;
_vehicleLogic = vehicleLogic;
_fileHelper = fileHelper; _fileHelper = fileHelper;
_config = config;
} }
public IActionResult Index() public IActionResult Index()
{ {
@@ -126,6 +134,18 @@ namespace CarCareTracker.Controllers
Cost = decimal.Parse(input.Cost) Cost = decimal.Parse(input.Cost)
}; };
_serviceRecordDataAccess.SaveServiceRecordToVehicle(serviceRecord); _serviceRecordDataAccess.SaveServiceRecordToVehicle(serviceRecord);
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
{
var odometerRecord = new OdometerRecord()
{
VehicleId = vehicleId,
Date = DateTime.Parse(input.Date),
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
Mileage = int.Parse(input.Odometer)
};
_odometerLogic.AutoInsertOdometerRecord(odometerRecord);
}
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), vehicleId, User.Identity.Name, $"Added Service Record via API - Description: {serviceRecord.Description}");
response.Success = true; response.Success = true;
response.Message = "Service Record Added"; response.Message = "Service Record Added";
return Json(response); return Json(response);
@@ -182,6 +202,18 @@ namespace CarCareTracker.Controllers
Cost = decimal.Parse(input.Cost) Cost = decimal.Parse(input.Cost)
}; };
_collisionRecordDataAccess.SaveCollisionRecordToVehicle(repairRecord); _collisionRecordDataAccess.SaveCollisionRecordToVehicle(repairRecord);
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
{
var odometerRecord = new OdometerRecord()
{
VehicleId = vehicleId,
Date = DateTime.Parse(input.Date),
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
Mileage = int.Parse(input.Odometer)
};
_odometerLogic.AutoInsertOdometerRecord(odometerRecord);
}
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), vehicleId, User.Identity.Name, $"Added Repair Record via API - Description: {repairRecord.Description}");
response.Success = true; response.Success = true;
response.Message = "Repair Record Added"; response.Message = "Repair Record Added";
return Json(response); return Json(response);
@@ -238,6 +270,18 @@ namespace CarCareTracker.Controllers
Cost = decimal.Parse(input.Cost) Cost = decimal.Parse(input.Cost)
}; };
_upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(upgradeRecord); _upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(upgradeRecord);
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
{
var odometerRecord = new OdometerRecord()
{
VehicleId = vehicleId,
Date = DateTime.Parse(input.Date),
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
Mileage = int.Parse(input.Odometer)
};
_odometerLogic.AutoInsertOdometerRecord(odometerRecord);
}
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), vehicleId, User.Identity.Name, $"Added Upgrade Record via API - Description: {upgradeRecord.Description}");
response.Success = true; response.Success = true;
response.Message = "Upgrade Record Added"; response.Message = "Upgrade Record Added";
return Json(response); return Json(response);
@@ -291,6 +335,7 @@ namespace CarCareTracker.Controllers
Cost = decimal.Parse(input.Cost) Cost = decimal.Parse(input.Cost)
}; };
_taxRecordDataAccess.SaveTaxRecordToVehicle(taxRecord); _taxRecordDataAccess.SaveTaxRecordToVehicle(taxRecord);
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), vehicleId, User.Identity.Name, $"Added Tax Record via API - Description: {taxRecord.Description}");
response.Success = true; response.Success = true;
response.Message = "Tax Record Added"; response.Message = "Tax Record Added";
return Json(response); return Json(response);
@@ -305,11 +350,24 @@ namespace CarCareTracker.Controllers
} }
[TypeFilter(typeof(CollaboratorFilter))] [TypeFilter(typeof(CollaboratorFilter))]
[HttpGet] [HttpGet]
[Route("/api/vehicle/odometerrecords/latest")]
public IActionResult LastOdometer(int vehicleId)
{
var result = _vehicleLogic.GetMaxMileage(vehicleId);
return Json(result);
}
[TypeFilter(typeof(CollaboratorFilter))]
[HttpGet]
[Route("/api/vehicle/odometerrecords")] [Route("/api/vehicle/odometerrecords")]
public IActionResult OdometerRecords(int vehicleId) public IActionResult OdometerRecords(int vehicleId)
{ {
var vehicleRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId); var vehicleRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
var result = vehicleRecords.Select(x => new OdometerRecordExportModel { Date = x.Date.ToShortDateString(), Odometer = x.Mileage.ToString(), Notes = x.Notes }); //determine if conversion is needed.
if (vehicleRecords.All(x => x.InitialMileage == default))
{
vehicleRecords = _odometerLogic.AutoConvertOdometerRecord(vehicleRecords);
}
var result = vehicleRecords.Select(x => new OdometerRecordExportModel { Date = x.Date.ToShortDateString(), InitialOdometer = x.InitialMileage.ToString(), Odometer = x.Mileage.ToString(), Notes = x.Notes });
return Json(result); return Json(result);
} }
[TypeFilter(typeof(CollaboratorFilter))] [TypeFilter(typeof(CollaboratorFilter))]
@@ -340,9 +398,11 @@ namespace CarCareTracker.Controllers
VehicleId = vehicleId, VehicleId = vehicleId,
Date = DateTime.Parse(input.Date), Date = DateTime.Parse(input.Date),
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes, Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
InitialMileage = (string.IsNullOrWhiteSpace(input.InitialOdometer) || int.Parse(input.InitialOdometer) == default) ? _odometerLogic.GetLastOdometerRecordMileage(vehicleId, new List<OdometerRecord>()) : int.Parse(input.InitialOdometer),
Mileage = int.Parse(input.Odometer) Mileage = int.Parse(input.Odometer)
}; };
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(odometerRecord); _odometerRecordDataAccess.SaveOdometerRecordToVehicle(odometerRecord);
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), vehicleId, User.Identity.Name, $"Added Odometer Record via API - Mileage: {odometerRecord.Mileage.ToString()}");
response.Success = true; response.Success = true;
response.Message = "Odometer Record Added"; response.Message = "Odometer Record Added";
return Json(response); return Json(response);
@@ -413,6 +473,18 @@ namespace CarCareTracker.Controllers
Cost = decimal.Parse(input.Cost) Cost = decimal.Parse(input.Cost)
}; };
_gasRecordDataAccess.SaveGasRecordToVehicle(gasRecord); _gasRecordDataAccess.SaveGasRecordToVehicle(gasRecord);
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
{
var odometerRecord = new OdometerRecord()
{
VehicleId = vehicleId,
Date = DateTime.Parse(input.Date),
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
Mileage = int.Parse(input.Odometer)
};
_odometerLogic.AutoInsertOdometerRecord(odometerRecord);
}
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), vehicleId, User.Identity.Name, $"Added Gas record via API - Mileage: {gasRecord.Mileage.ToString()}");
response.Success = true; response.Success = true;
response.Message = "Gas Record Added"; response.Message = "Gas Record Added";
return Json(response); return Json(response);
@@ -430,7 +502,7 @@ namespace CarCareTracker.Controllers
[Route("/api/vehicle/reminders")] [Route("/api/vehicle/reminders")]
public IActionResult Reminders(int vehicleId) public IActionResult Reminders(int vehicleId)
{ {
var currentMileage = GetMaxMileage(vehicleId); var currentMileage = _vehicleLogic.GetMaxMileage(vehicleId);
var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId); var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId);
var results = _reminderHelper.GetReminderRecordViewModels(reminders, currentMileage, DateTime.Now).Select(x=> new ReminderExportModel { Description = x.Description, Urgency = x.Urgency.ToString(), Metric = x.Metric.ToString(), Notes = x.Notes}); var results = _reminderHelper.GetReminderRecordViewModels(reminders, currentMileage, DateTime.Now).Select(x=> new ReminderExportModel { Description = x.Description, Urgency = x.Urgency.ToString(), Metric = x.Metric.ToString(), Notes = x.Notes});
return Json(results); return Json(results);
@@ -446,7 +518,7 @@ namespace CarCareTracker.Controllers
{ {
var vehicleId = vehicle.Id; var vehicleId = vehicle.Id;
//get reminders //get reminders
var currentMileage = GetMaxMileage(vehicleId); var currentMileage = _vehicleLogic.GetMaxMileage(vehicleId);
var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId); var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId);
var results = _reminderHelper.GetReminderRecordViewModels(reminders, currentMileage, DateTime.Now).OrderByDescending(x => x.Urgency).ToList(); var results = _reminderHelper.GetReminderRecordViewModels(reminders, currentMileage, DateTime.Now).OrderByDescending(x => x.Urgency).ToList();
results.RemoveAll(x => !urgencies.Contains(x.Urgency)); results.RemoveAll(x => !urgencies.Contains(x.Urgency));
@@ -496,35 +568,5 @@ namespace CarCareTracker.Controllers
var result = _fileHelper.RestoreBackup("/defaults/demo_default.zip", true); var result = _fileHelper.RestoreBackup("/defaults/demo_default.zip", true);
return Json(result); return Json(result);
} }
private int GetMaxMileage(int vehicleId)
{
var numbersArray = new List<int>();
var serviceRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId);
if (serviceRecords.Any())
{
numbersArray.Add(serviceRecords.Max(x => x.Mileage));
}
var repairRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId);
if (repairRecords.Any())
{
numbersArray.Add(repairRecords.Max(x => x.Mileage));
}
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
if (gasRecords.Any())
{
numbersArray.Add(gasRecords.Max(x => x.Mileage));
}
var upgradeRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
if (upgradeRecords.Any())
{
numbersArray.Add(upgradeRecords.Max(x => x.Mileage));
}
var odometerRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
if (odometerRecords.Any())
{
numbersArray.Add(odometerRecords.Max(x => x.Mileage));
}
return numbersArray.Any() ? numbersArray.Max() : 0;
}
} }
} }

View File

@@ -3,8 +3,6 @@ using CarCareTracker.Logic;
using CarCareTracker.Models; using CarCareTracker.Models;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Net;
using System.Net.Mail;
namespace CarCareTracker.Controllers namespace CarCareTracker.Controllers
{ {

View File

@@ -1,12 +1,5 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models; using CarCareTracker.Models;
using LiteDB;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
using static System.Net.Mime.MediaTypeNames;
using System.Drawing;
using System.Linq.Expressions;
using Microsoft.Extensions.Logging;
using CarCareTracker.Helper; using CarCareTracker.Helper;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;

View File

@@ -15,20 +15,34 @@ namespace CarCareTracker.Controllers
private readonly ILogger<HomeController> _logger; private readonly ILogger<HomeController> _logger;
private readonly IVehicleDataAccess _dataAccess; private readonly IVehicleDataAccess _dataAccess;
private readonly IUserLogic _userLogic; private readonly IUserLogic _userLogic;
private readonly ILoginLogic _loginLogic;
private readonly IVehicleLogic _vehicleLogic;
private readonly IFileHelper _fileHelper; private readonly IFileHelper _fileHelper;
private readonly IConfigHelper _config; private readonly IConfigHelper _config;
private readonly IExtraFieldDataAccess _extraFieldDataAccess;
public HomeController(ILogger<HomeController> logger, private readonly IReminderRecordDataAccess _reminderRecordDataAccess;
private readonly IReminderHelper _reminderHelper;
public HomeController(ILogger<HomeController> logger,
IVehicleDataAccess dataAccess, IVehicleDataAccess dataAccess,
IUserLogic userLogic, IUserLogic userLogic,
ILoginLogic loginLogic,
IVehicleLogic vehicleLogic,
IConfigHelper configuration, IConfigHelper configuration,
IFileHelper fileHelper) IFileHelper fileHelper,
IExtraFieldDataAccess extraFieldDataAccess,
IReminderRecordDataAccess reminderRecordDataAccess,
IReminderHelper reminderHelper)
{ {
_logger = logger; _logger = logger;
_dataAccess = dataAccess; _dataAccess = dataAccess;
_config = configuration; _config = configuration;
_userLogic = userLogic; _userLogic = userLogic;
_fileHelper = fileHelper; _fileHelper = fileHelper;
_extraFieldDataAccess = extraFieldDataAccess;
_reminderRecordDataAccess = reminderRecordDataAccess;
_reminderHelper = reminderHelper;
_loginLogic = loginLogic;
_vehicleLogic = vehicleLogic;
} }
private int GetUserID() private int GetUserID()
{ {
@@ -45,9 +59,53 @@ namespace CarCareTracker.Controllers
{ {
vehiclesStored = _userLogic.FilterUserVehicles(vehiclesStored, GetUserID()); vehiclesStored = _userLogic.FilterUserVehicles(vehiclesStored, GetUserID());
} }
return PartialView("_GarageDisplay", vehiclesStored); var vehicleViewModels = vehiclesStored.Select(x => 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,
UseHours = x.UseHours,
ExtraFields = x.ExtraFields,
Tags = x.Tags,
LastReportedMileage = _vehicleLogic.GetMaxMileage(x.Id),
HasReminders = _vehicleLogic.GetVehicleHasUrgentOrPastDueReminders(x.Id)
}).ToList();
return PartialView("_GarageDisplay", vehicleViewModels);
} }
public IActionResult Settings() public IActionResult Calendar()
{
var vehiclesStored = _dataAccess.GetVehicles();
if (!User.IsInRole(nameof(UserData.IsRootUser)))
{
vehiclesStored = _userLogic.FilterUserVehicles(vehiclesStored, GetUserID());
}
List<ReminderRecordViewModel> reminders = new List<ReminderRecordViewModel>();
foreach (Vehicle vehicle in vehiclesStored)
{
var vehicleReminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicle.Id);
vehicleReminders.RemoveAll(x => x.Metric == ReminderMetric.Odometer);
//we don't care about mileages so we can basically fake the current vehicle mileage.
if (vehicleReminders.Any())
{
var reminderUrgency = _reminderHelper.GetReminderRecordViewModels(vehicleReminders, 0, DateTime.Now);
reminderUrgency = reminderUrgency.Select(x => new ReminderRecordViewModel { Id = x.Id, Date = x.Date, Urgency = x.Urgency, Description = $"{vehicle.Year} {vehicle.Make} {vehicle.Model} #{vehicle.LicensePlate} - {x.Description}" }).ToList();
reminders.AddRange(reminderUrgency);
}
}
return PartialView("_Calendar", reminders);
}
public IActionResult ViewCalendarReminder(int reminderId)
{
var reminder = _reminderRecordDataAccess.GetReminderRecordById(reminderId);
var reminderUrgency = _reminderHelper.GetReminderRecordViewModels(new List<ReminderRecord> { reminder }, 0, DateTime.Now).FirstOrDefault();
return PartialView("_ReminderRecordCalendarModal", reminderUrgency);
}
public async Task<IActionResult> Settings()
{ {
var userConfig = _config.GetUserConfig(User); var userConfig = _config.GetUserConfig(User);
var languages = _fileHelper.GetLanguages(); var languages = _fileHelper.GetLanguages();
@@ -56,19 +114,111 @@ namespace CarCareTracker.Controllers
UserConfig = userConfig, UserConfig = userConfig,
UILanguages = languages UILanguages = languages
}; };
try
{
var httpClient = new HttpClient();
var sponsorsData = await httpClient.GetFromJsonAsync<Sponsors>(StaticHelper.SponsorsPath) ?? new Sponsors();
viewModel.Sponsors = sponsorsData;
}
catch (Exception ex)
{
_logger.LogError($"Unable to retrieve sponsors: {ex.Message}");
}
return PartialView("_Settings", viewModel); return PartialView("_Settings", viewModel);
} }
[HttpPost] [HttpPost]
public IActionResult WriteToSettings(UserConfig userConfig) public IActionResult WriteToSettings(UserConfig userConfig)
{ {
//retrieve existing userConfig.
var existingConfig = _config.GetUserConfig(User);
//copy over stuff that persists
userConfig.UserColumnPreferences = existingConfig.UserColumnPreferences;
userConfig.ReminderUrgencyConfig = existingConfig.ReminderUrgencyConfig;
var result = _config.SaveUserConfig(User, userConfig); var result = _config.SaveUserConfig(User, userConfig);
return Json(result); return Json(result);
} }
[HttpPost]
public IActionResult SaveReminderUrgencyThreshold(ReminderUrgencyConfig reminderUrgencyConfig)
{
//retrieve existing userConfig.
var existingConfig = _config.GetUserConfig(User);
existingConfig.ReminderUrgencyConfig = reminderUrgencyConfig;
var result = _config.SaveUserConfig(User, existingConfig);
return Json(result);
}
public IActionResult Privacy() public IActionResult Privacy()
{ {
return View(); return View();
} }
[Authorize(Roles = nameof(UserData.IsRootUser))]
public IActionResult GetExtraFieldsModal(int importMode = 0)
{
var recordExtraFields = _extraFieldDataAccess.GetExtraFieldsById(importMode);
if (recordExtraFields.Id != importMode)
{
recordExtraFields.Id = importMode;
}
return PartialView("_ExtraFields", recordExtraFields);
}
[Authorize(Roles = nameof(UserData.IsRootUser))]
public IActionResult UpdateExtraFields(RecordExtraField record)
{
try
{
var result = _extraFieldDataAccess.SaveExtraFields(record);
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
var recordExtraFields = _extraFieldDataAccess.GetExtraFieldsById(record.Id);
return PartialView("_ExtraFields", recordExtraFields);
}
[HttpPost]
public IActionResult GenerateTokenForUser()
{
try
{
//get current user email address.
var emailAddress = User.FindFirstValue(ClaimTypes.Email);
if (!string.IsNullOrWhiteSpace(emailAddress))
{
var result = _loginLogic.GenerateTokenForEmailAddress(emailAddress, false);
return Json(result);
}
return Json(false);
} catch (Exception ex)
{
_logger.LogError(ex.Message);
return Json(false);
}
}
[HttpPost]
public IActionResult UpdateUserAccount(LoginModel userAccount)
{
try
{
var userId = GetUserID();
if (userId > 0)
{
var result = _loginLogic.UpdateUserDetails(userId, userAccount);
return Json(result);
}
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage});
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage });
}
}
[HttpGet]
public IActionResult GetUserAccountInformationModal()
{
var emailAddress = User.FindFirstValue(ClaimTypes.Email);
var userName = User.Identity.Name;
return PartialView("_AccountModal", new UserData() { EmailAddress = emailAddress, UserName = userName });
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error() public IActionResult Error()
{ {

View File

@@ -4,9 +4,7 @@ using CarCareTracker.Models;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Net; using System.IdentityModel.Tokens.Jwt;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json; using System.Text.Json;
namespace CarCareTracker.Controllers namespace CarCareTracker.Controllers
@@ -15,20 +13,35 @@ namespace CarCareTracker.Controllers
{ {
private IDataProtector _dataProtector; private IDataProtector _dataProtector;
private ILoginLogic _loginLogic; private ILoginLogic _loginLogic;
private IConfigHelper _config;
private readonly ILogger<LoginController> _logger; private readonly ILogger<LoginController> _logger;
public LoginController( public LoginController(
ILogger<LoginController> logger, ILogger<LoginController> logger,
IDataProtectionProvider securityProvider, IDataProtectionProvider securityProvider,
ILoginLogic loginLogic ILoginLogic loginLogic,
) IConfigHelper config
)
{ {
_dataProtector = securityProvider.CreateProtector("login"); _dataProtector = securityProvider.CreateProtector("login");
_logger = logger; _logger = logger;
_loginLogic = loginLogic; _loginLogic = loginLogic;
_config = config;
} }
public IActionResult Index() public IActionResult Index(string redirectURL = "")
{ {
return View(); var remoteAuthConfig = _config.GetOpenIDConfig();
if (remoteAuthConfig.DisableRegularLogin && !string.IsNullOrWhiteSpace(remoteAuthConfig.LogOutURL))
{
var generatedState = Guid.NewGuid().ToString().Substring(0, 8);
remoteAuthConfig.State = generatedState;
if (remoteAuthConfig.ValidateState)
{
Response.Cookies.Append("OIDC_STATE", remoteAuthConfig.State, new CookieOptions { Expires = new DateTimeOffset(DateTime.Now.AddMinutes(5)) });
}
var remoteAuthURL = remoteAuthConfig.RemoteAuthURL;
return Redirect(remoteAuthURL);
}
return View(model: redirectURL);
} }
public IActionResult Registration() public IActionResult Registration()
{ {
@@ -42,6 +55,100 @@ namespace CarCareTracker.Controllers
{ {
return View(); return View();
} }
public IActionResult GetRemoteLoginLink()
{
var remoteAuthConfig = _config.GetOpenIDConfig();
var generatedState = Guid.NewGuid().ToString().Substring(0, 8);
remoteAuthConfig.State = generatedState;
if (remoteAuthConfig.ValidateState)
{
Response.Cookies.Append("OIDC_STATE", remoteAuthConfig.State, new CookieOptions { Expires = new DateTimeOffset(DateTime.Now.AddMinutes(5)) });
}
var remoteAuthURL = remoteAuthConfig.RemoteAuthURL;
return Json(remoteAuthURL);
}
public async Task<IActionResult> RemoteAuth(string code, string state = "")
{
try
{
if (!string.IsNullOrWhiteSpace(code))
{
//received code from OIDC provider
//create http client to retrieve user token from OIDC
var httpClient = new HttpClient();
var openIdConfig = _config.GetOpenIDConfig();
//check if validate state is enabled.
if (openIdConfig.ValidateState)
{
var storedStateValue = Request.Cookies["OIDC_STATE"];
if (!string.IsNullOrWhiteSpace(storedStateValue))
{
Response.Cookies.Delete("OIDC_STATE");
}
if (string.IsNullOrWhiteSpace(storedStateValue) || string.IsNullOrWhiteSpace(state) || storedStateValue != state)
{
_logger.LogInformation("Failed OIDC State Validation - Try disabling state validation if you are confident this is not a malicious attempt.");
return new RedirectResult("/Login");
}
}
var httpParams = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("code", code),
new KeyValuePair<string, string>("grant_type", "authorization_code"),
new KeyValuePair<string, string>("client_id", openIdConfig.ClientId),
new KeyValuePair<string, string>("client_secret", openIdConfig.ClientSecret),
new KeyValuePair<string, string>("redirect_uri", openIdConfig.RedirectURL)
};
var httpRequest = new HttpRequestMessage(HttpMethod.Post, openIdConfig.TokenURL)
{
Content = new FormUrlEncodedContent(httpParams)
};
var tokenResult = await httpClient.SendAsync(httpRequest).Result.Content.ReadAsStringAsync();
var userJwt = JsonSerializer.Deserialize<OpenIDResult>(tokenResult)?.id_token ?? string.Empty;
if (!string.IsNullOrWhiteSpace(userJwt))
{
//validate JWT token
var tokenParser = new JwtSecurityTokenHandler();
var parsedToken = tokenParser.ReadJwtToken(userJwt);
var userEmailAddress = parsedToken.Claims.First(x => x.Type == "email").Value;
if (!string.IsNullOrWhiteSpace(userEmailAddress))
{
var userData = _loginLogic.ValidateOpenIDUser(new LoginModel() { EmailAddress = userEmailAddress });
if (userData.Id != default)
{
AuthCookie authCookie = new AuthCookie
{
UserData = userData,
ExpiresOn = DateTime.Now.AddDays(1)
};
var serializedCookie = JsonSerializer.Serialize(authCookie);
var encryptedCookie = _dataProtector.Protect(serializedCookie);
Response.Cookies.Append("ACCESS_TOKEN", encryptedCookie, new CookieOptions { Expires = new DateTimeOffset(authCookie.ExpiresOn) });
return new RedirectResult("/Home");
} else
{
_logger.LogInformation($"User {userEmailAddress} tried to login via OpenID but is not a registered user in LubeLogger.");
return View("OpenIDRegistration", model: userEmailAddress);
}
} else
{
_logger.LogInformation("OpenID Provider did not provide a valid email address for the user");
}
} else
{
_logger.LogInformation("OpenID Provider did not provide a valid id_token");
}
} else
{
_logger.LogInformation("OpenID Provider did not provide a code.");
}
} catch (Exception ex)
{
_logger.LogError(ex.Message);
return new RedirectResult("/Login");
}
return new RedirectResult("/Login");
}
[HttpPost] [HttpPost]
public IActionResult Login(LoginModel credentials) public IActionResult Login(LoginModel credentials)
{ {
@@ -81,6 +188,27 @@ namespace CarCareTracker.Controllers
return Json(result); return Json(result);
} }
[HttpPost] [HttpPost]
public IActionResult RegisterOpenIdUser(LoginModel credentials)
{
var result = _loginLogic.RegisterOpenIdUser(credentials);
if (result.Success)
{
var userData = _loginLogic.ValidateOpenIDUser(new LoginModel() { EmailAddress = credentials.EmailAddress });
if (userData.Id != default)
{
AuthCookie authCookie = new AuthCookie
{
UserData = userData,
ExpiresOn = DateTime.Now.AddDays(1)
};
var serializedCookie = JsonSerializer.Serialize(authCookie);
var encryptedCookie = _dataProtector.Protect(serializedCookie);
Response.Cookies.Append("ACCESS_TOKEN", encryptedCookie, new CookieOptions { Expires = new DateTimeOffset(authCookie.ExpiresOn) });
}
}
return Json(result);
}
[HttpPost]
public IActionResult RequestResetPassword(LoginModel credentials) public IActionResult RequestResetPassword(LoginModel credentials)
{ {
var result = _loginLogic.RequestResetPassword(credentials); var result = _loginLogic.RequestResetPassword(credentials);
@@ -132,7 +260,12 @@ namespace CarCareTracker.Controllers
public IActionResult LogOut() public IActionResult LogOut()
{ {
Response.Cookies.Delete("ACCESS_TOKEN"); Response.Cookies.Delete("ACCESS_TOKEN");
return Json(true); var remoteAuthConfig = _config.GetOpenIDConfig();
if (remoteAuthConfig.DisableRegularLogin && !string.IsNullOrWhiteSpace(remoteAuthConfig.LogOutURL))
{
return Json(remoteAuthConfig.LogOutURL);
}
return Json("/Login");
} }
} }
} }

View File

@@ -0,0 +1,754 @@
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Npgsql;
using System.IO.Compression;
namespace CarCareTracker.Controllers
{
[Authorize(Roles = nameof(UserData.IsRootUser))]
public class MigrationController : Controller
{
private IConfigHelper _configHelper;
private IFileHelper _fileHelper;
private readonly ILogger<MigrationController> _logger;
public MigrationController(IConfigHelper configHelper, IFileHelper fileHelper, IConfiguration serverConfig, ILogger<MigrationController> logger)
{
_configHelper = configHelper;
_fileHelper = fileHelper;
_logger = logger;
}
public IActionResult Index()
{
if (!string.IsNullOrWhiteSpace(_configHelper.GetServerPostgresConnection()))
{
return View();
} else
{
return new RedirectResult("/Error/Unauthorized");
}
}
private void InitializeTables(NpgsqlDataSource conn)
{
var cmds = new List<string>
{
"CREATE TABLE IF NOT EXISTS app.vehicles (id INT GENERATED BY DEFAULT AS IDENTITY primary key, data jsonb not null)",
"CREATE TABLE IF NOT EXISTS app.collisionrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
"CREATE TABLE IF NOT EXISTS app.upgraderecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
"CREATE TABLE IF NOT EXISTS app.servicerecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
"CREATE TABLE IF NOT EXISTS app.gasrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
"CREATE TABLE IF NOT EXISTS app.notes (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
"CREATE TABLE IF NOT EXISTS app.odometerrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
"CREATE TABLE IF NOT EXISTS app.reminderrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
"CREATE TABLE IF NOT EXISTS app.planrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
"CREATE TABLE IF NOT EXISTS app.planrecordtemplates (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
"CREATE TABLE IF NOT EXISTS app.supplyrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
"CREATE TABLE IF NOT EXISTS app.taxrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
"CREATE TABLE IF NOT EXISTS app.userrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, username TEXT not null, emailaddress TEXT not null, password TEXT not null, isadmin BOOLEAN)",
"CREATE TABLE IF NOT EXISTS app.tokenrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, body TEXT not null, emailaddress TEXT not null)",
"CREATE TABLE IF NOT EXISTS app.userconfigrecords (id INT primary key, data jsonb not null)",
"CREATE TABLE IF NOT EXISTS app.useraccessrecords (userId INT, vehicleId INT, PRIMARY KEY(userId, vehicleId))",
"CREATE TABLE IF NOT EXISTS app.extrafields (id INT primary key, data jsonb not null)"
};
foreach(string cmd in cmds)
{
using (var ctext = conn.CreateCommand(cmd))
{
ctext.ExecuteNonQuery();
}
}
}
public IActionResult Export()
{
if (string.IsNullOrWhiteSpace(_configHelper.GetServerPostgresConnection()))
{
return Json(new OperationResponse { Success = false, Message = "Postgres connection not set up" });
}
var tempFolder = $"temp/{Guid.NewGuid()}";
var tempPath = $"{tempFolder}/cartracker.db";
var fullFolderPath = _fileHelper.GetFullFilePath(tempFolder, false);
Directory.CreateDirectory(fullFolderPath);
var fullFileName = _fileHelper.GetFullFilePath(tempPath, false);
try
{
var pgDataSource = NpgsqlDataSource.Create(_configHelper.GetServerPostgresConnection());
InitializeTables(pgDataSource);
//pull records
var vehicles = new List<Vehicle>();
var repairrecords = new List<CollisionRecord>();
var upgraderecords = new List<UpgradeRecord>();
var servicerecords = new List<ServiceRecord>();
var gasrecords = new List<GasRecord>();
var noterecords = new List<Note>();
var odometerrecords = new List<OdometerRecord>();
var reminderrecords = new List<ReminderRecord>();
var planrecords = new List<PlanRecord>();
var planrecordtemplates = new List<PlanRecordInput>();
var supplyrecords = new List<SupplyRecord>();
var taxrecords = new List<TaxRecord>();
var userrecords = new List<UserData>();
var tokenrecords = new List<Token>();
var userconfigrecords = new List<UserConfigData>();
var useraccessrecords = new List<UserAccess>();
var extrafields = new List<RecordExtraField>();
#region "Part1"
string cmd = $"SELECT data FROM app.vehicles";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
Vehicle vehicle = System.Text.Json.JsonSerializer.Deserialize<Vehicle>(reader["data"] as string);
vehicles.Add(vehicle);
}
}
foreach (var vehicle in vehicles)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<Vehicle>("vehicles");
table.Upsert(vehicle);
};
}
cmd = $"SELECT data FROM app.collisionrecords";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
repairrecords.Add(System.Text.Json.JsonSerializer.Deserialize<CollisionRecord>(reader["data"] as string));
}
}
foreach (var record in repairrecords)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<CollisionRecord>("collisionrecords");
table.Upsert(record);
};
}
cmd = $"SELECT data FROM app.upgraderecords";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
upgraderecords.Add(System.Text.Json.JsonSerializer.Deserialize<UpgradeRecord>(reader["data"] as string));
}
}
foreach (var record in upgraderecords)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<UpgradeRecord>("upgraderecords");
table.Upsert(record);
};
}
cmd = $"SELECT data FROM app.servicerecords";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
servicerecords.Add(System.Text.Json.JsonSerializer.Deserialize<ServiceRecord>(reader["data"] as string));
}
}
foreach (var record in servicerecords)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<ServiceRecord>("servicerecords");
table.Upsert(record);
};
}
#endregion
#region "Part2"
cmd = $"SELECT data FROM app.gasrecords";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
gasrecords.Add(System.Text.Json.JsonSerializer.Deserialize<GasRecord>(reader["data"] as string));
}
}
foreach (var record in gasrecords)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<GasRecord>("gasrecords");
table.Upsert(record);
};
}
cmd = $"SELECT data FROM app.notes";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
noterecords.Add(System.Text.Json.JsonSerializer.Deserialize<Note>(reader["data"] as string));
}
}
foreach (var record in noterecords)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<Note>("notes");
table.Upsert(record);
};
}
cmd = $"SELECT data FROM app.odometerrecords";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
odometerrecords.Add(System.Text.Json.JsonSerializer.Deserialize<OdometerRecord>(reader["data"] as string));
}
}
foreach (var record in odometerrecords)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<OdometerRecord>("odometerrecords");
table.Upsert(record);
};
}
cmd = $"SELECT data FROM app.reminderrecords";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
reminderrecords.Add(System.Text.Json.JsonSerializer.Deserialize<ReminderRecord>(reader["data"] as string));
}
}
foreach (var record in reminderrecords)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<ReminderRecord>("reminderrecords");
table.Upsert(record);
};
}
#endregion
#region "Part3"
cmd = $"SELECT data FROM app.planrecords";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
planrecords.Add(System.Text.Json.JsonSerializer.Deserialize<PlanRecord>(reader["data"] as string));
}
}
foreach (var record in planrecords)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<PlanRecord>("planrecords");
table.Upsert(record);
};
}
cmd = $"SELECT data FROM app.planrecordtemplates";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
planrecordtemplates.Add(System.Text.Json.JsonSerializer.Deserialize<PlanRecordInput>(reader["data"] as string));
}
}
foreach (var record in planrecordtemplates)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<PlanRecordInput>("planrecordtemplates");
table.Upsert(record);
};
}
cmd = $"SELECT data FROM app.supplyrecords";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
supplyrecords.Add(System.Text.Json.JsonSerializer.Deserialize<SupplyRecord>(reader["data"] as string));
}
}
foreach (var record in supplyrecords)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<SupplyRecord>("supplyrecords");
table.Upsert(record);
};
}
cmd = $"SELECT data FROM app.taxrecords";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
taxrecords.Add(System.Text.Json.JsonSerializer.Deserialize<TaxRecord>(reader["data"] as string));
}
}
foreach (var record in taxrecords)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<TaxRecord>("taxrecords");
table.Upsert(record);
};
}
#endregion
#region "Part4"
cmd = $"SELECT id, username, emailaddress, password, isadmin FROM app.userrecords";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
UserData result = new UserData();
result.Id = int.Parse(reader["id"].ToString());
result.UserName = reader["username"].ToString();
result.EmailAddress = reader["emailaddress"].ToString();
result.Password = reader["password"].ToString();
result.IsAdmin = bool.Parse(reader["isadmin"].ToString());
userrecords.Add(result);
}
}
foreach (var record in userrecords)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<UserData>("userrecords");
table.Upsert(record);
};
}
cmd = $"SELECT id, emailaddress, body FROM app.tokenrecords";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
Token result = new Token();
result.Id = int.Parse(reader["id"].ToString());
result.EmailAddress = reader["emailaddress"].ToString();
result.Body = reader["body"].ToString();
tokenrecords.Add(result);
}
}
foreach (var record in tokenrecords)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<Token>("tokenrecords");
table.Upsert(record);
};
}
cmd = $"SELECT data FROM app.userconfigrecords";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
userconfigrecords.Add(System.Text.Json.JsonSerializer.Deserialize<UserConfigData>(reader["data"] as string));
}
}
foreach (var record in userconfigrecords)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<UserConfigData>("userconfigrecords");
table.Upsert(record);
};
}
cmd = $"SELECT userId, vehicleId FROM app.useraccessrecords";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
UserAccess result = new UserAccess()
{
Id = new UserVehicle
{
UserId = int.Parse(reader["userId"].ToString()),
VehicleId = int.Parse(reader["vehicleId"].ToString())
}
};
useraccessrecords.Add(result);
}
}
foreach (var record in useraccessrecords)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<UserAccess>("useraccessrecords");
table.Upsert(record);
};
}
#endregion
#region "Part5"
cmd = $"SELECT data FROM app.extrafields";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
extrafields.Add(System.Text.Json.JsonSerializer.Deserialize<RecordExtraField>(reader["data"] as string));
}
}
foreach (var record in extrafields)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<RecordExtraField>("extrafields");
table.Upsert(record);
};
}
#endregion
var destFilePath = $"{fullFolderPath}.zip";
ZipFile.CreateFromDirectory(fullFolderPath, destFilePath);
return Json(new OperationResponse { Success = true, Message = $"/{tempFolder}.zip" });
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage });
}
}
public IActionResult Import(string fileName)
{
if (string.IsNullOrWhiteSpace(_configHelper.GetServerPostgresConnection()))
{
return Json(new OperationResponse { Success = false, Message = "Postgres connection not set up" });
}
var fullFileName = _fileHelper.GetFullFilePath(fileName);
if (string.IsNullOrWhiteSpace(fullFileName))
{
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage });
}
try
{
var pgDataSource = NpgsqlDataSource.Create(_configHelper.GetServerPostgresConnection());
InitializeTables(pgDataSource);
//pull records
var vehicles = new List<Vehicle>();
var repairrecords = new List<CollisionRecord>();
var upgraderecords = new List<UpgradeRecord>();
var servicerecords = new List<ServiceRecord>();
var gasrecords = new List<GasRecord>();
var noterecords = new List<Note>();
var odometerrecords = new List<OdometerRecord>();
var reminderrecords = new List<ReminderRecord>();
var planrecords = new List<PlanRecord>();
var planrecordtemplates = new List<PlanRecordInput>();
var supplyrecords = new List<SupplyRecord>();
var taxrecords = new List<TaxRecord>();
var userrecords = new List<UserData>();
var tokenrecords = new List<Token>();
var userconfigrecords = new List<UserConfigData>();
var useraccessrecords = new List<UserAccess>();
var extrafields = new List<RecordExtraField>();
#region "Part1"
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<Vehicle>("vehicles");
vehicles = table.FindAll().ToList();
};
foreach(var vehicle in vehicles)
{
string cmd = $"INSERT INTO app.vehicles (id, data) VALUES(@id, CAST(@data AS jsonb)); SELECT setval('app.vehicles_id_seq', (SELECT MAX(id) from app.vehicles));";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", vehicle.Id);
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(vehicle));
ctext.ExecuteNonQuery();
}
}
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<CollisionRecord>("collisionrecords");
repairrecords = table.FindAll().ToList();
};
foreach (var record in repairrecords)
{
string cmd = $"INSERT INTO app.collisionrecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.collisionrecords_id_seq', (SELECT MAX(id) from app.collisionrecords));";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", record.Id);
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
ctext.ExecuteNonQuery();
}
}
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<ServiceRecord>("servicerecords");
servicerecords = table.FindAll().ToList();
};
foreach (var record in servicerecords)
{
string cmd = $"INSERT INTO app.servicerecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.servicerecords_id_seq', (SELECT MAX(id) from app.servicerecords));";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", record.Id);
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
ctext.ExecuteNonQuery();
}
}
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<UpgradeRecord>("upgraderecords");
upgraderecords = table.FindAll().ToList();
};
foreach (var record in upgraderecords)
{
string cmd = $"INSERT INTO app.upgraderecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.upgraderecords_id_seq', (SELECT MAX(id) from app.upgraderecords));";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", record.Id);
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
ctext.ExecuteNonQuery();
}
}
#endregion
#region "Part2"
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<GasRecord>("gasrecords");
gasrecords = table.FindAll().ToList();
};
foreach (var record in gasrecords)
{
string cmd = $"INSERT INTO app.gasrecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.gasrecords_id_seq', (SELECT MAX(id) from app.gasrecords));";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", record.Id);
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
ctext.ExecuteNonQuery();
}
}
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<Note>("notes");
noterecords = table.FindAll().ToList();
};
foreach (var record in noterecords)
{
string cmd = $"INSERT INTO app.notes (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.notes_id_seq', (SELECT MAX(id) from app.notes));";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", record.Id);
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
ctext.ExecuteNonQuery();
}
}
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<OdometerRecord>("odometerrecords");
odometerrecords = table.FindAll().ToList();
};
foreach (var record in odometerrecords)
{
string cmd = $"INSERT INTO app.odometerrecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.odometerrecords_id_seq', (SELECT MAX(id) from app.odometerrecords));";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", record.Id);
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
ctext.ExecuteNonQuery();
}
}
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<ReminderRecord>("reminderrecords");
reminderrecords = table.FindAll().ToList();
};
foreach (var record in reminderrecords)
{
string cmd = $"INSERT INTO app.reminderrecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.reminderrecords_id_seq', (SELECT MAX(id) from app.reminderrecords));";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", record.Id);
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
ctext.ExecuteNonQuery();
}
}
#endregion
#region "Part3"
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<PlanRecord>("planrecords");
planrecords = table.FindAll().ToList();
};
foreach (var record in planrecords)
{
string cmd = $"INSERT INTO app.planrecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.planrecords_id_seq', (SELECT MAX(id) from app.planrecords));";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", record.Id);
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
ctext.ExecuteNonQuery();
}
}
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<PlanRecordInput>("planrecordtemplates");
planrecordtemplates = table.FindAll().ToList();
};
foreach (var record in planrecordtemplates)
{
string cmd = $"INSERT INTO app.planrecordtemplates (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.planrecordtemplates_id_seq', (SELECT MAX(id) from app.planrecordtemplates));";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", record.Id);
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
ctext.ExecuteNonQuery();
}
}
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<SupplyRecord>("supplyrecords");
supplyrecords = table.FindAll().ToList();
};
foreach (var record in supplyrecords)
{
string cmd = $"INSERT INTO app.supplyrecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.supplyrecords_id_seq', (SELECT MAX(id) from app.supplyrecords));";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", record.Id);
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
ctext.ExecuteNonQuery();
}
}
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<TaxRecord>("taxrecords");
taxrecords = table.FindAll().ToList();
};
foreach (var record in taxrecords)
{
string cmd = $"INSERT INTO app.taxrecords (id, vehicleId, data) VALUES(@id, @vehicleId, CAST(@data AS jsonb)); SELECT setval('app.taxrecords_id_seq', (SELECT MAX(id) from app.taxrecords));";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", record.Id);
ctext.Parameters.AddWithValue("vehicleId", record.VehicleId);
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
ctext.ExecuteNonQuery();
}
}
#endregion
#region "Part4"
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<UserData>("userrecords");
userrecords = table.FindAll().ToList();
};
foreach (var record in userrecords)
{
string cmd = $"INSERT INTO app.userrecords (id, username, emailaddress, password, isadmin) VALUES(@id, @username, @emailaddress, @password, @isadmin); SELECT setval('app.userrecords_id_seq', (SELECT MAX(id) from app.userrecords));";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", record.Id);
ctext.Parameters.AddWithValue("username", record.UserName);
ctext.Parameters.AddWithValue("emailaddress", record.EmailAddress);
ctext.Parameters.AddWithValue("password", record.Password);
ctext.Parameters.AddWithValue("isadmin", record.IsAdmin);
ctext.ExecuteNonQuery();
}
}
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<Token>("tokenrecords");
tokenrecords = table.FindAll().ToList();
};
foreach (var record in tokenrecords)
{
string cmd = $"INSERT INTO app.tokenrecords (id, emailaddress, body) VALUES(@id, @emailaddress, @body); SELECT setval('app.tokenrecords_id_seq', (SELECT MAX(id) from app.tokenrecords));";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", record.Id);
ctext.Parameters.AddWithValue("emailaddress", record.EmailAddress);
ctext.Parameters.AddWithValue("body", record.Body);
ctext.ExecuteNonQuery();
}
}
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<UserConfigData>("userconfigrecords");
userconfigrecords = table.FindAll().ToList();
};
foreach (var record in userconfigrecords)
{
string cmd = $"INSERT INTO app.userconfigrecords (id, data) VALUES(@id, CAST(@data AS jsonb))";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", record.Id);
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
ctext.ExecuteNonQuery();
}
}
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<UserAccess>("useraccessrecords");
useraccessrecords = table.FindAll().ToList();
};
foreach (var record in useraccessrecords)
{
string cmd = $"INSERT INTO app.useraccessrecords (userId, vehicleId) VALUES(@userId, @vehicleId)";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("userId", record.Id.UserId);
ctext.Parameters.AddWithValue("vehicleId", record.Id.VehicleId);
ctext.ExecuteNonQuery();
}
}
#endregion
#region "Part5"
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<RecordExtraField>("extrafields");
extrafields = table.FindAll().ToList();
};
foreach (var record in extrafields)
{
string cmd = $"INSERT INTO app.extrafields (id, data) VALUES(@id, CAST(@data AS jsonb))";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", record.Id);
ctext.Parameters.AddWithValue("data", System.Text.Json.JsonSerializer.Serialize(record));
ctext.ExecuteNonQuery();
}
}
#endregion
return Json(new OperationResponse { Success = true, Message = "Data Imported Successfully" });
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage });
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -12,6 +12,7 @@
SupplyRecord = 7, SupplyRecord = 7,
Dashboard = 8, Dashboard = 8,
PlanRecord = 9, PlanRecord = 9,
OdometerRecord = 10 OdometerRecord = 10,
VehicleRecord = 11
} }
} }

View File

@@ -2,6 +2,7 @@
{ {
public enum ReminderMonthInterval public enum ReminderMonthInterval
{ {
Other = 0,
OneMonth = 1, OneMonth = 1,
ThreeMonths = 3, ThreeMonths = 3,
SixMonths = 6, SixMonths = 6,

View File

@@ -1,57 +0,0 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
namespace CarCareTracker.External.Implementations
{
public class CollisionRecordDataAccess : ICollisionRecordDataAccess
{
private static string dbName = StaticHelper.DbName;
private static string tableName = "collisionrecords";
public List<CollisionRecord> GetCollisionRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<CollisionRecord>(tableName);
var collisionRecords = table.Find(Query.EQ(nameof(CollisionRecord.VehicleId), vehicleId));
return collisionRecords.ToList() ?? new List<CollisionRecord>();
};
}
public CollisionRecord GetCollisionRecordById(int collisionRecordId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<CollisionRecord>(tableName);
return table.FindById(collisionRecordId);
};
}
public bool DeleteCollisionRecordById(int collisionRecordId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<CollisionRecord>(tableName);
table.Delete(collisionRecordId);
return true;
};
}
public bool SaveCollisionRecordToVehicle(CollisionRecord collisionRecord)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<CollisionRecord>(tableName);
table.Upsert(collisionRecord);
return true;
};
}
public bool DeleteAllCollisionRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<CollisionRecord>(tableName);
var collisionRecords = table.DeleteMany(Query.EQ(nameof(CollisionRecord.VehicleId), vehicleId));
return true;
};
}
}
}

View File

@@ -1,57 +0,0 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
namespace CarCareTracker.External.Implementations
{
public class GasRecordDataAccess: IGasRecordDataAccess
{
private static string dbName = StaticHelper.DbName;
private static string tableName = "gasrecords";
public List<GasRecord> GetGasRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<GasRecord>(tableName);
var gasRecords = table.Find(Query.EQ(nameof(GasRecord.VehicleId), vehicleId));
return gasRecords.ToList() ?? new List<GasRecord>();
};
}
public GasRecord GetGasRecordById(int gasRecordId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<GasRecord>(tableName);
return table.FindById(gasRecordId);
};
}
public bool DeleteGasRecordById(int gasRecordId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<GasRecord>(tableName);
table.Delete(gasRecordId);
return true;
};
}
public bool SaveGasRecordToVehicle(GasRecord gasRecord)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<GasRecord>(tableName);
table.Upsert(gasRecord);
return true;
};
}
public bool DeleteAllGasRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<GasRecord>(tableName);
var gasRecords = table.DeleteMany(Query.EQ(nameof(GasRecord.VehicleId), vehicleId));
return true;
};
}
}
}

View 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;
}
}
}

View File

@@ -0,0 +1,30 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
namespace CarCareTracker.External.Implementations
{
public class ExtraFieldDataAccess : IExtraFieldDataAccess
{
private ILiteDBHelper _liteDB { get; set; }
private static string tableName = "extrafields";
public ExtraFieldDataAccess(ILiteDBHelper liteDB)
{
_liteDB = liteDB;
}
public RecordExtraField GetExtraFieldsById(int importMode)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<RecordExtraField>(tableName);
return table.FindById(importMode) ?? new RecordExtraField();
}
public bool SaveExtraFields(RecordExtraField record)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<RecordExtraField>(tableName);
table.Upsert(record);
db.Checkpoint();
return true;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View File

@@ -0,0 +1,82 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
namespace CarCareTracker.External.Implementations
{
public class UserAccessDataAccess : IUserAccessDataAccess
{
private ILiteDBHelper _liteDB { get; set; }
private static string tableName = "useraccessrecords";
public UserAccessDataAccess(ILiteDBHelper liteDB)
{
_liteDB = liteDB;
}
/// <summary>
/// Gets a list of vehicles user have access to.
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public List<UserAccess> GetUserAccessByUserId(int userId)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<UserAccess>(tableName);
return table.Find(x => x.Id.UserId == userId).ToList();
}
public UserAccess GetUserAccessByVehicleAndUserId(int userId, int vehicleId)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<UserAccess>(tableName);
return table.Find(x => x.Id.UserId == userId && x.Id.VehicleId == vehicleId).FirstOrDefault();
}
public List<UserAccess> GetUserAccessByVehicleId(int vehicleId)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<UserAccess>(tableName);
return table.Find(x => x.Id.VehicleId == vehicleId).ToList();
}
public bool SaveUserAccess(UserAccess userAccess)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<UserAccess>(tableName);
table.Upsert(userAccess);
db.Checkpoint();
return true;
}
public bool DeleteUserAccess(int userId, int vehicleId)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<UserAccess>(tableName);
table.DeleteMany(x => x.Id.UserId == userId && x.Id.VehicleId == vehicleId);
db.Checkpoint();
return true;
}
/// <summary>
/// Delete all access records when a vehicle is deleted.
/// </summary>
/// <param name="vehicleId"></param>
/// <returns></returns>
public bool DeleteAllAccessRecordsByVehicleId(int vehicleId)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<UserAccess>(tableName);
table.DeleteMany(x => x.Id.VehicleId == vehicleId);
db.Checkpoint();
return true;
}
/// <summary>
/// Delee all access records when a user is deleted.
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public bool DeleteAllAccessRecordsByUserId(int userId)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<UserAccess>(tableName);
table.DeleteMany(x => x.Id.UserId == userId);
db.Checkpoint();
return true;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View File

@@ -0,0 +1,45 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
namespace CarCareTracker.External.Implementations
{
public class VehicleDataAccess : IVehicleDataAccess
{
private ILiteDBHelper _liteDB { get; set; }
private static string tableName = "vehicles";
public VehicleDataAccess(ILiteDBHelper liteDB)
{
_liteDB = liteDB;
}
public bool SaveVehicle(Vehicle vehicle)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<Vehicle>(tableName);
var result = table.Upsert(vehicle);
db.Checkpoint();
return true;
}
public bool DeleteVehicle(int vehicleId)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<Vehicle>(tableName);
var result = table.Delete(vehicleId);
db.Checkpoint();
return result;
}
public List<Vehicle> GetVehicles()
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<Vehicle>(tableName);
return table.FindAll().ToList();
}
public Vehicle GetVehicleById(int vehicleId)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<Vehicle>(tableName);
return table.FindById(vehicleId);
}
}
}

View File

@@ -1,57 +0,0 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
namespace CarCareTracker.External.Implementations
{
public class NoteDataAccess: INoteDataAccess
{
private static string dbName = StaticHelper.DbName;
private static string tableName = "notes";
public List<Note> GetNotesByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<Note>(tableName);
var noteToReturn = table.Find(Query.EQ(nameof(Note.VehicleId), vehicleId));
return noteToReturn.ToList() ?? new List<Note>();
};
}
public Note GetNoteById(int noteId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<Note>(tableName);
return table.FindById(noteId);
};
}
public bool SaveNoteToVehicle(Note note)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<Note>(tableName);
table.Upsert(note);
return true;
};
}
public bool DeleteNoteById(int noteId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<Note>(tableName);
table.Delete(noteId);
return true;
};
}
public bool DeleteAllNotesByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<Note>(tableName);
var notes = table.DeleteMany(Query.EQ(nameof(Note.VehicleId), vehicleId));
return true;
};
}
}
}

View File

@@ -1,57 +0,0 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
namespace CarCareTracker.External.Implementations
{
public class OdometerRecordDataAccess : IOdometerRecordDataAccess
{
private static string dbName = StaticHelper.DbName;
private static string tableName = "odometerrecords";
public List<OdometerRecord> GetOdometerRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
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)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<OdometerRecord>(tableName);
return table.FindById(odometerRecordId);
};
}
public bool DeleteOdometerRecordById(int odometerRecordId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<OdometerRecord>(tableName);
table.Delete(odometerRecordId);
return true;
};
}
public bool SaveOdometerRecordToVehicle(OdometerRecord odometerRecord)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<OdometerRecord>(tableName);
table.Upsert(odometerRecord);
return true;
};
}
public bool DeleteAllOdometerRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<OdometerRecord>(tableName);
var odometerRecords = table.DeleteMany(Query.EQ(nameof(OdometerRecord.VehicleId), vehicleId));
return true;
};
}
}
}

View File

@@ -1,57 +0,0 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
namespace CarCareTracker.External.Implementations
{
public class PlanRecordDataAccess : IPlanRecordDataAccess
{
private static string dbName = StaticHelper.DbName;
private static string tableName = "planrecords";
public List<PlanRecord> GetPlanRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
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)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<PlanRecord>(tableName);
return table.FindById(planRecordId);
};
}
public bool DeletePlanRecordById(int planRecordId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<PlanRecord>(tableName);
table.Delete(planRecordId);
return true;
};
}
public bool SavePlanRecordToVehicle(PlanRecord planRecord)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<PlanRecord>(tableName);
table.Upsert(planRecord);
return true;
};
}
public bool DeleteAllPlanRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<PlanRecord>(tableName);
var planRecords = table.DeleteMany(Query.EQ(nameof(PlanRecord.VehicleId), vehicleId));
return true;
};
}
}
}

View File

@@ -0,0 +1,160 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
using System.Text.Json;
namespace CarCareTracker.External.Implementations
{
public class PGCollisionRecordDataAccess : ICollisionRecordDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGCollisionRecordDataAccess> _logger;
private static string tableName = "collisionrecords";
public PGCollisionRecordDataAccess(IConfiguration config, ILogger<PGCollisionRecordDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public List<CollisionRecord> GetCollisionRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
var results = new List<CollisionRecord>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
CollisionRecord collisionRecord = JsonSerializer.Deserialize<CollisionRecord>(reader["data"] as string);
results.Add(collisionRecord);
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<CollisionRecord>();
}
}
public CollisionRecord GetCollisionRecordById(int collisionRecordId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
var result = new CollisionRecord();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", collisionRecordId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
CollisionRecord collisionRecord = JsonSerializer.Deserialize<CollisionRecord>(reader["data"] as string);
result = collisionRecord;
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new CollisionRecord();
}
}
public bool DeleteCollisionRecordById(int collisionRecordId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", collisionRecordId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool SaveCollisionRecordToVehicle(CollisionRecord collisionRecord)
{
try
{
if (collisionRecord.Id == default)
{
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", collisionRecord.VehicleId);
ctext.Parameters.AddWithValue("data", "{}");
collisionRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
//update json data
if (collisionRecord.Id != default)
{
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctextU = pgDataSource.CreateCommand(cmdU))
{
var serializedData = JsonSerializer.Serialize(collisionRecord);
ctextU.Parameters.AddWithValue("id", collisionRecord.Id);
ctextU.Parameters.AddWithValue("data", serializedData);
return ctextU.ExecuteNonQuery() > 0;
}
}
return collisionRecord.Id != default;
}
}
else
{
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
var serializedData = JsonSerializer.Serialize(collisionRecord);
ctext.Parameters.AddWithValue("id", collisionRecord.Id);
ctext.Parameters.AddWithValue("data", serializedData);
return ctext.ExecuteNonQuery() > 0;
}
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteAllCollisionRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", vehicleId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,76 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
using System.Text.Json;
namespace CarCareTracker.External.Implementations
{
public class PGExtraFieldDataAccess : IExtraFieldDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGExtraFieldDataAccess> _logger;
private static string tableName = "extrafields";
public PGExtraFieldDataAccess(IConfiguration config, ILogger<PGExtraFieldDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT primary key, data jsonb not null)";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public RecordExtraField GetExtraFieldsById(int importMode)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
var results = new RecordExtraField();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", importMode);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
RecordExtraField result = JsonSerializer.Deserialize<RecordExtraField>(reader["data"] as string);
results = result;
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new RecordExtraField();
}
}
public bool SaveExtraFields(RecordExtraField record)
{
try
{
var existingRecord = GetExtraFieldsById(record.Id);
string cmd = $"INSERT INTO app.{tableName} (id, data) VALUES(@id, CAST(@data AS jsonb)) ON CONFLICT(id) DO UPDATE SET data = CAST(@data AS jsonb)";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", record.Id);
ctext.Parameters.AddWithValue("data", JsonSerializer.Serialize(record));
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,159 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
using System.Text.Json;
namespace CarCareTracker.External.Implementations
{
public class PGGasRecordDataAccess: IGasRecordDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGGasRecordDataAccess> _logger;
private static string tableName = "gasrecords";
public PGGasRecordDataAccess(IConfiguration config, ILogger<PGGasRecordDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public List<GasRecord> GetGasRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
var results = new List<GasRecord>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
GasRecord gasRecord = JsonSerializer.Deserialize<GasRecord>(reader["data"] as string);
results.Add(gasRecord);
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<GasRecord>();
}
}
public GasRecord GetGasRecordById(int gasRecordId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
var result = new GasRecord();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", gasRecordId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
GasRecord gasRecord = JsonSerializer.Deserialize<GasRecord>(reader["data"] as string);
result = gasRecord;
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new GasRecord();
}
}
public bool DeleteGasRecordById(int gasRecordId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", gasRecordId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool SaveGasRecordToVehicle(GasRecord gasRecord)
{
try
{
if (gasRecord.Id == default)
{
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", gasRecord.VehicleId);
ctext.Parameters.AddWithValue("data", "{}");
gasRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
//update json data
if (gasRecord.Id != default)
{
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctextU = pgDataSource.CreateCommand(cmdU))
{
var serializedData = JsonSerializer.Serialize(gasRecord);
ctextU.Parameters.AddWithValue("id", gasRecord.Id);
ctextU.Parameters.AddWithValue("data", serializedData);
return ctextU.ExecuteNonQuery() > 0;
}
}
return gasRecord.Id != default;
}
}
else
{
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
var serializedData = JsonSerializer.Serialize(gasRecord);
ctext.Parameters.AddWithValue("id", gasRecord.Id);
ctext.Parameters.AddWithValue("data", serializedData);
return ctext.ExecuteNonQuery() > 0;
}
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteAllGasRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", vehicleId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,153 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
using System.Text.Json;
namespace CarCareTracker.External.Implementations
{
public class PGNoteDataAccess: INoteDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGNoteDataAccess> _logger;
private static string tableName = "notes";
public PGNoteDataAccess(IConfiguration config, ILogger<PGNoteDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
} catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public List<Note> GetNotesByVehicleId(int vehicleId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
var results = new List<Note>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
Note note = JsonSerializer.Deserialize<Note>(reader["data"] as string);
results.Add(note);
}
}
return results;
} catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<Note>();
}
}
public Note GetNoteById(int noteId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
var result = new Note();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", noteId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
Note note = JsonSerializer.Deserialize<Note>(reader["data"] as string);
result = note;
}
}
return result;
} catch (Exception ex)
{
_logger.LogError(ex.Message);
return new Note();
}
}
public bool SaveNoteToVehicle(Note note)
{
try
{
if (note.Id == default)
{
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", note.VehicleId);
ctext.Parameters.AddWithValue("data", "{}");
note.Id = Convert.ToInt32(ctext.ExecuteScalar());
//update json data
if (note.Id != default)
{
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctextU = pgDataSource.CreateCommand(cmdU))
{
var serializedData = JsonSerializer.Serialize(note);
ctextU.Parameters.AddWithValue("id", note.Id);
ctextU.Parameters.AddWithValue("data", serializedData);
return ctextU.ExecuteNonQuery() > 0;
}
}
return note.Id != default;
}
}
else
{
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
var serializedData = JsonSerializer.Serialize(note);
ctext.Parameters.AddWithValue("id", note.Id);
ctext.Parameters.AddWithValue("data", serializedData);
return ctext.ExecuteNonQuery() > 0;
}
}
} catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteNoteById(int noteId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", noteId);
return ctext.ExecuteNonQuery() > 0;
}
} catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteAllNotesByVehicleId(int vehicleId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", vehicleId);
return ctext.ExecuteNonQuery() > 0;
}
} catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,159 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
using System.Text.Json;
namespace CarCareTracker.External.Implementations
{
public class PGOdometerRecordDataAccess : IOdometerRecordDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGOdometerRecordDataAccess> _logger;
private static string tableName = "odometerrecords";
public PGOdometerRecordDataAccess(IConfiguration config, ILogger<PGOdometerRecordDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public List<OdometerRecord> GetOdometerRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
var results = new List<OdometerRecord>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
OdometerRecord odometerRecord = JsonSerializer.Deserialize<OdometerRecord>(reader["data"] as string);
results.Add(odometerRecord);
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<OdometerRecord>();
}
}
public OdometerRecord GetOdometerRecordById(int odometerRecordId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
var result = new OdometerRecord();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", odometerRecordId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
OdometerRecord odometerRecord = JsonSerializer.Deserialize<OdometerRecord>(reader["data"] as string);
result = odometerRecord;
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new OdometerRecord();
}
}
public bool DeleteOdometerRecordById(int odometerRecordId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", odometerRecordId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool SaveOdometerRecordToVehicle(OdometerRecord odometerRecord)
{
try
{
if (odometerRecord.Id == default)
{
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", odometerRecord.VehicleId);
ctext.Parameters.AddWithValue("data", "{}");
odometerRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
//update json data
if (odometerRecord.Id != default)
{
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctextU = pgDataSource.CreateCommand(cmdU))
{
var serializedData = JsonSerializer.Serialize(odometerRecord);
ctextU.Parameters.AddWithValue("id", odometerRecord.Id);
ctextU.Parameters.AddWithValue("data", serializedData);
return ctextU.ExecuteNonQuery() > 0;
}
}
return odometerRecord.Id != default;
}
}
else
{
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
var serializedData = JsonSerializer.Serialize(odometerRecord);
ctext.Parameters.AddWithValue("id", odometerRecord.Id);
ctext.Parameters.AddWithValue("data", serializedData);
return ctext.ExecuteNonQuery() > 0;
}
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteAllOdometerRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", vehicleId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,159 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
using System.Text.Json;
namespace CarCareTracker.External.Implementations
{
public class PGPlanRecordDataAccess : IPlanRecordDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGPlanRecordDataAccess> _logger;
private static string tableName = "planrecords";
public PGPlanRecordDataAccess(IConfiguration config, ILogger<PGPlanRecordDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public List<PlanRecord> GetPlanRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
var results = new List<PlanRecord>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
PlanRecord planRecord = JsonSerializer.Deserialize<PlanRecord>(reader["data"] as string);
results.Add(planRecord);
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<PlanRecord>();
}
}
public PlanRecord GetPlanRecordById(int planRecordId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
var result = new PlanRecord();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", planRecordId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
PlanRecord planRecord = JsonSerializer.Deserialize<PlanRecord>(reader["data"] as string);
result = planRecord;
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new PlanRecord();
}
}
public bool DeletePlanRecordById(int planRecordId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", planRecordId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool SavePlanRecordToVehicle(PlanRecord planRecord)
{
try
{
if (planRecord.Id == default)
{
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", planRecord.VehicleId);
ctext.Parameters.AddWithValue("data", "{}");
planRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
//update json data
if (planRecord.Id != default)
{
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctextU = pgDataSource.CreateCommand(cmdU))
{
var serializedData = JsonSerializer.Serialize(planRecord);
ctextU.Parameters.AddWithValue("id", planRecord.Id);
ctextU.Parameters.AddWithValue("data", serializedData);
return ctextU.ExecuteNonQuery() > 0;
}
}
return planRecord.Id != default;
}
}
else
{
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
var serializedData = JsonSerializer.Serialize(planRecord);
ctext.Parameters.AddWithValue("id", planRecord.Id);
ctext.Parameters.AddWithValue("data", serializedData);
return ctext.ExecuteNonQuery() > 0;
}
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteAllPlanRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", vehicleId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,159 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
using System.Text.Json;
namespace CarCareTracker.External.Implementations
{
public class PGPlanRecordTemplateDataAccess : IPlanRecordTemplateDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGPlanRecordTemplateDataAccess> _logger;
private static string tableName = "planrecordtemplates";
public PGPlanRecordTemplateDataAccess(IConfiguration config, ILogger<PGPlanRecordTemplateDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public List<PlanRecordInput> GetPlanRecordTemplatesByVehicleId(int vehicleId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
var results = new List<PlanRecordInput>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
PlanRecordInput planRecord = JsonSerializer.Deserialize<PlanRecordInput>(reader["data"] as string);
results.Add(planRecord);
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<PlanRecordInput>();
}
}
public PlanRecordInput GetPlanRecordTemplateById(int planRecordId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
var result = new PlanRecordInput();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", planRecordId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
PlanRecordInput planRecord = JsonSerializer.Deserialize<PlanRecordInput>(reader["data"] as string);
result = planRecord;
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new PlanRecordInput();
}
}
public bool DeletePlanRecordTemplateById(int planRecordId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", planRecordId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool SavePlanRecordTemplateToVehicle(PlanRecordInput planRecord)
{
try
{
if (planRecord.Id == default)
{
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", planRecord.VehicleId);
ctext.Parameters.AddWithValue("data", "{}");
planRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
//update json data
if (planRecord.Id != default)
{
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctextU = pgDataSource.CreateCommand(cmdU))
{
var serializedData = JsonSerializer.Serialize(planRecord);
ctextU.Parameters.AddWithValue("id", planRecord.Id);
ctextU.Parameters.AddWithValue("data", serializedData);
return ctextU.ExecuteNonQuery() > 0;
}
}
return planRecord.Id != default;
}
}
else
{
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
var serializedData = JsonSerializer.Serialize(planRecord);
ctext.Parameters.AddWithValue("id", planRecord.Id);
ctext.Parameters.AddWithValue("data", serializedData);
return ctext.ExecuteNonQuery() > 0;
}
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteAllPlanRecordTemplatesByVehicleId(int vehicleId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", vehicleId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,159 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
using System.Text.Json;
namespace CarCareTracker.External.Implementations
{
public class PGReminderRecordDataAccess : IReminderRecordDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGReminderRecordDataAccess> _logger;
private static string tableName = "reminderrecords";
public PGReminderRecordDataAccess(IConfiguration config, ILogger<PGReminderRecordDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public List<ReminderRecord> GetReminderRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
var results = new List<ReminderRecord>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
ReminderRecord reminderRecord = JsonSerializer.Deserialize<ReminderRecord>(reader["data"] as string);
results.Add(reminderRecord);
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<ReminderRecord>();
}
}
public ReminderRecord GetReminderRecordById(int reminderRecordId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
var result = new ReminderRecord();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", reminderRecordId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
ReminderRecord reminderRecord = JsonSerializer.Deserialize<ReminderRecord>(reader["data"] as string);
result = reminderRecord;
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new ReminderRecord();
}
}
public bool DeleteReminderRecordById(int reminderRecordId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", reminderRecordId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool SaveReminderRecordToVehicle(ReminderRecord reminderRecord)
{
try
{
if (reminderRecord.Id == default)
{
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", reminderRecord.VehicleId);
ctext.Parameters.AddWithValue("data", "{}");
reminderRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
//update json data
if (reminderRecord.Id != default)
{
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctextU = pgDataSource.CreateCommand(cmdU))
{
var serializedData = JsonSerializer.Serialize(reminderRecord);
ctextU.Parameters.AddWithValue("id", reminderRecord.Id);
ctextU.Parameters.AddWithValue("data", serializedData);
return ctextU.ExecuteNonQuery() > 0;
}
}
return reminderRecord.Id != default;
}
}
else
{
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
var serializedData = JsonSerializer.Serialize(reminderRecord);
ctext.Parameters.AddWithValue("id", reminderRecord.Id);
ctext.Parameters.AddWithValue("data", serializedData);
return ctext.ExecuteNonQuery() > 0;
}
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteAllReminderRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", vehicleId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,159 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
using System.Text.Json;
namespace CarCareTracker.External.Implementations
{
public class PGServiceRecordDataAccess: IServiceRecordDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGServiceRecordDataAccess> _logger;
private static string tableName = "servicerecords";
public PGServiceRecordDataAccess(IConfiguration config, ILogger<PGServiceRecordDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public List<ServiceRecord> GetServiceRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
var results = new List<ServiceRecord>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
ServiceRecord serviceRecord = JsonSerializer.Deserialize<ServiceRecord>(reader["data"] as string);
results.Add(serviceRecord);
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<ServiceRecord>();
}
}
public ServiceRecord GetServiceRecordById(int serviceRecordId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
var result = new ServiceRecord();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", serviceRecordId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
ServiceRecord serviceRecord = JsonSerializer.Deserialize<ServiceRecord>(reader["data"] as string);
result = serviceRecord;
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new ServiceRecord();
}
}
public bool DeleteServiceRecordById(int serviceRecordId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", serviceRecordId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool SaveServiceRecordToVehicle(ServiceRecord serviceRecord)
{
try
{
if (serviceRecord.Id == default)
{
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", serviceRecord.VehicleId);
ctext.Parameters.AddWithValue("data", "{}");
serviceRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
//update json data
if (serviceRecord.Id != default)
{
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctextU = pgDataSource.CreateCommand(cmdU))
{
var serializedData = JsonSerializer.Serialize(serviceRecord);
ctextU.Parameters.AddWithValue("id", serviceRecord.Id);
ctextU.Parameters.AddWithValue("data", serializedData);
return ctextU.ExecuteNonQuery() > 0;
}
}
return serviceRecord.Id != default;
}
}
else
{
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
var serializedData = JsonSerializer.Serialize(serviceRecord);
ctext.Parameters.AddWithValue("id", serviceRecord.Id);
ctext.Parameters.AddWithValue("data", serializedData);
return ctext.ExecuteNonQuery() > 0;
}
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteAllServiceRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", vehicleId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,159 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
using System.Text.Json;
namespace CarCareTracker.External.Implementations
{
public class PGSupplyRecordDataAccess : ISupplyRecordDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGSupplyRecordDataAccess> _logger;
private static string tableName = "supplyrecords";
public PGSupplyRecordDataAccess(IConfiguration config, ILogger<PGSupplyRecordDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public List<SupplyRecord> GetSupplyRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
var results = new List<SupplyRecord>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
SupplyRecord supplyRecord = JsonSerializer.Deserialize<SupplyRecord>(reader["data"] as string);
results.Add(supplyRecord);
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<SupplyRecord>();
}
}
public SupplyRecord GetSupplyRecordById(int supplyRecordId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
var result = new SupplyRecord();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", supplyRecordId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
SupplyRecord supplyRecord = JsonSerializer.Deserialize<SupplyRecord>(reader["data"] as string);
result = supplyRecord;
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new SupplyRecord();
}
}
public bool DeleteSupplyRecordById(int supplyRecordId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", supplyRecordId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool SaveSupplyRecordToVehicle(SupplyRecord supplyRecord)
{
try
{
if (supplyRecord.Id == default)
{
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", supplyRecord.VehicleId);
ctext.Parameters.AddWithValue("data", "{}");
supplyRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
//update json data
if (supplyRecord.Id != default)
{
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctextU = pgDataSource.CreateCommand(cmdU))
{
var serializedData = JsonSerializer.Serialize(supplyRecord);
ctextU.Parameters.AddWithValue("id", supplyRecord.Id);
ctextU.Parameters.AddWithValue("data", serializedData);
return ctextU.ExecuteNonQuery() > 0;
}
}
return supplyRecord.Id != default;
}
}
else
{
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
var serializedData = JsonSerializer.Serialize(supplyRecord);
ctext.Parameters.AddWithValue("id", supplyRecord.Id);
ctext.Parameters.AddWithValue("data", serializedData);
return ctext.ExecuteNonQuery() > 0;
}
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteAllSupplyRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", vehicleId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,159 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
using System.Text.Json;
namespace CarCareTracker.External.Implementations
{
public class PGTaxRecordDataAccess : ITaxRecordDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGTaxRecordDataAccess> _logger;
private static string tableName = "taxrecords";
public PGTaxRecordDataAccess(IConfiguration config, ILogger<PGTaxRecordDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public List<TaxRecord> GetTaxRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
var results = new List<TaxRecord>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
TaxRecord taxRecord = JsonSerializer.Deserialize<TaxRecord>(reader["data"] as string);
results.Add(taxRecord);
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<TaxRecord>();
}
}
public TaxRecord GetTaxRecordById(int taxRecordId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
var result = new TaxRecord();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", taxRecordId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
TaxRecord taxRecord = JsonSerializer.Deserialize<TaxRecord>(reader["data"] as string);
result = taxRecord;
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new TaxRecord();
}
}
public bool DeleteTaxRecordById(int taxRecordId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", taxRecordId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool SaveTaxRecordToVehicle(TaxRecord taxRecord)
{
try
{
if (taxRecord.Id == default)
{
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", taxRecord.VehicleId);
ctext.Parameters.AddWithValue("data", "{}");
taxRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
//update json data
if (taxRecord.Id != default)
{
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctextU = pgDataSource.CreateCommand(cmdU))
{
var serializedData = JsonSerializer.Serialize(taxRecord);
ctextU.Parameters.AddWithValue("id", taxRecord.Id);
ctextU.Parameters.AddWithValue("data", serializedData);
return ctextU.ExecuteNonQuery() > 0;
}
}
return taxRecord.Id != default;
}
}
else
{
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
var serializedData = JsonSerializer.Serialize(taxRecord);
ctext.Parameters.AddWithValue("id", taxRecord.Id);
ctext.Parameters.AddWithValue("data", serializedData);
return ctext.ExecuteNonQuery() > 0;
}
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteAllTaxRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", vehicleId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,143 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
namespace CarCareTracker.External.Implementations
{
public class PGTokenRecordDataAccess : ITokenRecordDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGTokenRecordDataAccess> _logger;
private static string tableName = "tokenrecords";
public PGTokenRecordDataAccess(IConfiguration config, ILogger<PGTokenRecordDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, body TEXT not null, emailaddress TEXT not null)";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public List<Token> GetTokens()
{
try
{
string cmd = $"SELECT id, emailaddress, body FROM app.{tableName}";
var results = new List<Token>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
Token result = new Token();
result.Id = int.Parse(reader["id"].ToString());
result.EmailAddress = reader["emailaddress"].ToString();
result.Body = reader["body"].ToString();
results.Add(result);
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<Token>();
}
}
public Token GetTokenRecordByBody(string tokenBody)
{
try
{
string cmd = $"SELECT id, emailaddress, body FROM app.{tableName} WHERE body = @body";
var result = new Token();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("body", tokenBody);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
result.Id = int.Parse(reader["id"].ToString());
result.EmailAddress = reader["emailaddress"].ToString();
result.Body = reader["body"].ToString();
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new Token();
}
}
public Token GetTokenRecordByEmailAddress(string emailAddress)
{
try
{
string cmd = $"SELECT id, emailaddress, body FROM app.{tableName} WHERE emailaddress = @emailaddress";
var result = new Token();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("emailaddress", emailAddress);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
result.Id = int.Parse(reader["id"].ToString());
result.EmailAddress = reader["emailaddress"].ToString();
result.Body = reader["body"].ToString();
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new Token();
}
}
public bool CreateNewToken(Token token)
{
try
{
string cmd = $"INSERT INTO app.{tableName} (emailaddress, body) VALUES(@emailaddress, @body) RETURNING id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("emailaddress", token.EmailAddress);
ctext.Parameters.AddWithValue("body", token.Body);
token.Id = Convert.ToInt32(ctext.ExecuteScalar());
return token.Id != default;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteToken(int tokenId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", tokenId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,159 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
using System.Text.Json;
namespace CarCareTracker.External.Implementations
{
public class PGUpgradeRecordDataAccess : IUpgradeRecordDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGUpgradeRecordDataAccess> _logger;
private static string tableName = "upgraderecords";
public PGUpgradeRecordDataAccess(IConfiguration config, ILogger<PGUpgradeRecordDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public List<UpgradeRecord> GetUpgradeRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
var results = new List<UpgradeRecord>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
UpgradeRecord upgradeRecord = JsonSerializer.Deserialize<UpgradeRecord>(reader["data"] as string);
results.Add(upgradeRecord);
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<UpgradeRecord>();
}
}
public UpgradeRecord GetUpgradeRecordById(int upgradeRecordId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
var result = new UpgradeRecord();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", upgradeRecordId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
UpgradeRecord upgradeRecord = JsonSerializer.Deserialize<UpgradeRecord>(reader["data"] as string);
result = upgradeRecord;
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new UpgradeRecord();
}
}
public bool DeleteUpgradeRecordById(int upgradeRecordId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", upgradeRecordId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool SaveUpgradeRecordToVehicle(UpgradeRecord upgradeRecord)
{
try
{
if (upgradeRecord.Id == default)
{
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", upgradeRecord.VehicleId);
ctext.Parameters.AddWithValue("data", "{}");
upgradeRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
//update json data
if (upgradeRecord.Id != default)
{
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctextU = pgDataSource.CreateCommand(cmdU))
{
var serializedData = JsonSerializer.Serialize(upgradeRecord);
ctextU.Parameters.AddWithValue("id", upgradeRecord.Id);
ctextU.Parameters.AddWithValue("data", serializedData);
return ctextU.ExecuteNonQuery() > 0;
}
}
return upgradeRecord.Id != default;
}
}
else
{
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
var serializedData = JsonSerializer.Serialize(upgradeRecord);
ctext.Parameters.AddWithValue("id", upgradeRecord.Id);
ctext.Parameters.AddWithValue("data", serializedData);
return ctext.ExecuteNonQuery() > 0;
}
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteAllUpgradeRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", vehicleId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,211 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
using System.Net.Mail;
namespace CarCareTracker.External.Implementations
{
public class PGUserAccessDataAccess : IUserAccessDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGUserAccessDataAccess> _logger;
private static string tableName = "useraccessrecords";
public PGUserAccessDataAccess(IConfiguration config, ILogger<PGUserAccessDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (userId INT, vehicleId INT, PRIMARY KEY(userId, vehicleId))";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
/// <summary>
/// Gets a list of vehicles user have access to.
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public List<UserAccess> GetUserAccessByUserId(int userId)
{
try
{
string cmd = $"SELECT userId, vehicleId FROM app.{tableName} WHERE userId = @userId";
var results = new List<UserAccess>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("userId", userId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
UserAccess result = new UserAccess()
{
Id = new UserVehicle
{
UserId = int.Parse(reader["userId"].ToString()),
VehicleId = int.Parse(reader["vehicleId"].ToString())
}
};
results.Add(result);
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<UserAccess>();
}
}
public UserAccess GetUserAccessByVehicleAndUserId(int userId, int vehicleId)
{
try
{
string cmd = $"SELECT userId, vehicleId FROM app.{tableName} WHERE userId = @userId AND vehicleId = @vehicleId";
UserAccess result = null;
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("userId", userId);
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
result = new UserAccess()
{
Id = new UserVehicle
{
UserId = int.Parse(reader["userId"].ToString()),
VehicleId = int.Parse(reader["vehicleId"].ToString())
}
};
return result;
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new UserAccess();
}
}
public List<UserAccess> GetUserAccessByVehicleId(int vehicleId)
{
try
{
string cmd = $"SELECT userId, vehicleId FROM app.{tableName} WHERE vehicleId = @vehicleId";
var results = new List<UserAccess>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
UserAccess result = new UserAccess()
{
Id = new UserVehicle
{
UserId = int.Parse(reader["userId"].ToString()),
VehicleId = int.Parse(reader["vehicleId"].ToString())
}
};
results.Add(result);
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<UserAccess>();
}
}
public bool SaveUserAccess(UserAccess userAccess)
{
try
{
string cmd = $"INSERT INTO app.{tableName} (userId, vehicleId) VALUES(@userId, @vehicleId)";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("userId", userAccess.Id.UserId);
ctext.Parameters.AddWithValue("vehicleId", userAccess.Id.VehicleId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteUserAccess(int userId, int vehicleId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE userId = @userId AND vehicleId = @vehicleId";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("userId", userId);
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
/// <summary>
/// Delete all access records when a vehicle is deleted.
/// </summary>
/// <param name="vehicleId"></param>
/// <returns></returns>
public bool DeleteAllAccessRecordsByVehicleId(int vehicleId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @vehicleId";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
/// <summary>
/// Delee all access records when a user is deleted.
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public bool DeleteAllAccessRecordsByUserId(int userId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE userId = @userId";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("userId", userId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,107 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
using System.Text.Json;
namespace CarCareTracker.External.Implementations
{
public class PGUserConfigDataAccess: IUserConfigDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGUserConfigDataAccess> _logger;
private static string tableName = "userconfigrecords";
public PGUserConfigDataAccess(IConfiguration config, ILogger<PGUserConfigDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT primary key, data jsonb not null)";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public UserConfigData GetUserConfig(int userId)
{
try
{
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
UserConfigData result = null;
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", userId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
UserConfigData userConfig = JsonSerializer.Deserialize<UserConfigData>(reader["data"] as string);
result = userConfig;
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new UserConfigData();
}
}
public bool SaveUserConfig(UserConfigData userConfigData)
{
var existingRecord = GetUserConfig(userConfigData.Id);
try
{
if (existingRecord == null)
{
string cmd = $"INSERT INTO app.{tableName} (id, data) VALUES(@id, CAST(@data AS jsonb))";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
var serializedData = JsonSerializer.Serialize(userConfigData);
ctext.Parameters.AddWithValue("id", userConfigData.Id);
ctext.Parameters.AddWithValue("data", serializedData);
return ctext.ExecuteNonQuery() > 0;
}
}
else
{
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
var serializedData = JsonSerializer.Serialize(userConfigData);
ctext.Parameters.AddWithValue("id", userConfigData.Id);
ctext.Parameters.AddWithValue("data", serializedData);
return ctext.ExecuteNonQuery() > 0;
}
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteUserConfig(int userId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", userId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,194 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
namespace CarCareTracker.External.Implementations
{
public class PGUserRecordDataAccess : IUserRecordDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGUserRecordDataAccess> _logger;
private static string tableName = "userrecords";
public PGUserRecordDataAccess(IConfiguration config, ILogger<PGUserRecordDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, username TEXT not null, emailaddress TEXT not null, password TEXT not null, isadmin BOOLEAN)";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public List<UserData> GetUsers()
{
try
{
string cmd = $"SELECT id, username, emailaddress, password, isadmin FROM app.{tableName}";
var results = new List<UserData>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
UserData result = new UserData();
result.Id = int.Parse(reader["id"].ToString());
result.UserName = reader["username"].ToString();
result.EmailAddress = reader["emailaddress"].ToString();
result.Password = reader["password"].ToString();
result.IsAdmin = bool.Parse(reader["isadmin"].ToString());
results.Add(result);
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<UserData>();
}
}
public UserData GetUserRecordByUserName(string userName)
{
try
{
string cmd = $"SELECT id, username, emailaddress, password, isadmin FROM app.{tableName} WHERE username = @username";
var result = new UserData();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("username", userName);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
result.Id = int.Parse(reader["id"].ToString());
result.UserName = reader["username"].ToString();
result.EmailAddress = reader["emailaddress"].ToString();
result.Password = reader["password"].ToString();
result.IsAdmin = bool.Parse(reader["isadmin"].ToString());
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new UserData();
}
}
public UserData GetUserRecordByEmailAddress(string emailAddress)
{
try
{
string cmd = $"SELECT id, username, emailaddress, password, isadmin FROM app.{tableName} WHERE emailaddress = @emailaddress";
var result = new UserData();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("emailaddress", emailAddress);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
result.Id = int.Parse(reader["id"].ToString());
result.UserName = reader["username"].ToString();
result.EmailAddress = reader["emailaddress"].ToString();
result.Password = reader["password"].ToString();
result.IsAdmin = bool.Parse(reader["isadmin"].ToString());
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new UserData();
}
}
public UserData GetUserRecordById(int userId)
{
try
{
string cmd = $"SELECT id, username, emailaddress, password, isadmin FROM app.{tableName} WHERE id = @id";
var result = new UserData();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", userId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
result.Id = int.Parse(reader["id"].ToString());
result.UserName = reader["username"].ToString();
result.EmailAddress = reader["emailaddress"].ToString();
result.Password = reader["password"].ToString();
result.IsAdmin = bool.Parse(reader["isadmin"].ToString());
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new UserData();
}
}
public bool SaveUserRecord(UserData userRecord)
{
try
{
if (userRecord.Id == default)
{
string cmd = $"INSERT INTO app.{tableName} (username, emailaddress, password, isadmin) VALUES(@username, @emailaddress, @password, @isadmin) RETURNING id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("username", userRecord.UserName);
ctext.Parameters.AddWithValue("emailaddress", userRecord.EmailAddress);
ctext.Parameters.AddWithValue("password", userRecord.Password);
ctext.Parameters.AddWithValue("isadmin", userRecord.IsAdmin);
userRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
return userRecord.Id != default;
}
}
else
{
string cmd = $"UPDATE app.{tableName} SET username = @username, emailaddress = @emailaddress, password = @password, isadmin = @isadmin WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", userRecord.Id);
ctext.Parameters.AddWithValue("username", userRecord.UserName);
ctext.Parameters.AddWithValue("emailaddress", userRecord.EmailAddress);
ctext.Parameters.AddWithValue("password", userRecord.Password);
ctext.Parameters.AddWithValue("isadmin", userRecord.IsAdmin);
return ctext.ExecuteNonQuery() > 0;
}
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteUserRecord(int userId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", userId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@@ -0,0 +1,138 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
using System.Text.Json;
namespace CarCareTracker.External.Implementations
{
public class PGVehicleDataAccess: IVehicleDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGVehicleDataAccess> _logger;
private static string tableName = "vehicles";
public PGVehicleDataAccess(IConfiguration config, ILogger<PGVehicleDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, data jsonb not null)";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
} catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public bool SaveVehicle(Vehicle vehicle)
{
try
{
if (string.IsNullOrWhiteSpace(vehicle.ImageLocation))
{
vehicle.ImageLocation = "/defaults/noimage.png";
}
if (vehicle.Id == default)
{
string cmd = $"INSERT INTO app.{tableName} (data) VALUES(CAST(@data AS jsonb)) RETURNING id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("data", "{}");
vehicle.Id = Convert.ToInt32(ctext.ExecuteScalar());
//update json data
if (vehicle.Id != default)
{
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctextU = pgDataSource.CreateCommand(cmdU))
{
var serializedData = JsonSerializer.Serialize(vehicle);
ctextU.Parameters.AddWithValue("id", vehicle.Id);
ctextU.Parameters.AddWithValue("data", serializedData);
return ctextU.ExecuteNonQuery() > 0;
}
}
return vehicle.Id != default;
}
}
else
{
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
var serializedData = JsonSerializer.Serialize(vehicle);
ctext.Parameters.AddWithValue("id", vehicle.Id);
ctext.Parameters.AddWithValue("data", serializedData);
return ctext.ExecuteNonQuery() > 0;
}
}
} catch (Exception ex)
{
_logger.LogError(ex.Message);
}
return false;
}
public bool DeleteVehicle(int vehicleId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", vehicleId);
return ctext.ExecuteNonQuery() > 0;
}
} catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public List<Vehicle> GetVehicles()
{
try
{
string cmd = $"SELECT id, data FROM app.{tableName} ORDER BY id ASC";
var results = new List<Vehicle>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
Vehicle vehicle = JsonSerializer.Deserialize<Vehicle>(reader["data"] as string);
results.Add(vehicle);
}
}
return results;
} catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<Vehicle>();
}
}
public Vehicle GetVehicleById(int vehicleId)
{
try
{
string cmd = $"SELECT id, data FROM app.{tableName} WHERE id = @id";
Vehicle vehicle = new Vehicle();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("id", vehicleId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
vehicle = JsonSerializer.Deserialize<Vehicle>(reader["data"] as string);
}
}
return vehicle;
} catch (Exception ex)
{
_logger.LogError(ex.Message);
return new Vehicle();
}
}
}
}

View File

@@ -1,57 +0,0 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
namespace CarCareTracker.External.Implementations
{
public class ReminderRecordDataAccess : IReminderRecordDataAccess
{
private static string dbName = StaticHelper.DbName;
private static string tableName = "reminderrecords";
public List<ReminderRecord> GetReminderRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<ReminderRecord>(tableName);
var reminderRecords = table.Find(Query.EQ(nameof(ReminderRecord.VehicleId), vehicleId));
return reminderRecords.ToList() ?? new List<ReminderRecord>();
};
}
public ReminderRecord GetReminderRecordById(int reminderRecordId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<ReminderRecord>(tableName);
return table.FindById(reminderRecordId);
};
}
public bool DeleteReminderRecordById(int reminderRecordId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<ReminderRecord>(tableName);
table.Delete(reminderRecordId);
return true;
};
}
public bool SaveReminderRecordToVehicle(ReminderRecord reminderRecord)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<ReminderRecord>(tableName);
table.Upsert(reminderRecord);
return true;
};
}
public bool DeleteAllReminderRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<ReminderRecord>(tableName);
var reminderRecords = table.DeleteMany(Query.EQ(nameof(ReminderRecord.VehicleId), vehicleId));
return true;
};
}
}
}

View File

@@ -1,57 +0,0 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
namespace CarCareTracker.External.Implementations
{
public class ServiceRecordDataAccess: IServiceRecordDataAccess
{
private static string dbName = StaticHelper.DbName;
private static string tableName = "servicerecords";
public List<ServiceRecord> GetServiceRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<ServiceRecord>(tableName);
var serviceRecords = table.Find(Query.EQ(nameof(ServiceRecord.VehicleId), vehicleId));
return serviceRecords.ToList() ?? new List<ServiceRecord>();
};
}
public ServiceRecord GetServiceRecordById(int serviceRecordId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<ServiceRecord>(tableName);
return table.FindById(serviceRecordId);
};
}
public bool DeleteServiceRecordById(int serviceRecordId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<ServiceRecord>(tableName);
table.Delete(serviceRecordId);
return true;
};
}
public bool SaveServiceRecordToVehicle(ServiceRecord serviceRecord)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<ServiceRecord>(tableName);
table.Upsert(serviceRecord);
return true;
};
}
public bool DeleteAllServiceRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<ServiceRecord>(tableName);
var serviceRecords = table.DeleteMany(Query.EQ(nameof(ServiceRecord.VehicleId), vehicleId));
return true;
};
}
}
}

View File

@@ -1,57 +0,0 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
namespace CarCareTracker.External.Implementations
{
public class SupplyRecordDataAccess : ISupplyRecordDataAccess
{
private static string dbName = StaticHelper.DbName;
private static string tableName = "supplyrecords";
public List<SupplyRecord> GetSupplyRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
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)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<SupplyRecord>(tableName);
return table.FindById(supplyRecordId);
};
}
public bool DeleteSupplyRecordById(int supplyRecordId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<SupplyRecord>(tableName);
table.Delete(supplyRecordId);
return true;
};
}
public bool SaveSupplyRecordToVehicle(SupplyRecord supplyRecord)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<SupplyRecord>(tableName);
table.Upsert(supplyRecord);
return true;
};
}
public bool DeleteAllSupplyRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<SupplyRecord>(tableName);
var supplyRecords = table.DeleteMany(Query.EQ(nameof(SupplyRecord.VehicleId), vehicleId));
return true;
};
}
}
}

View File

@@ -1,57 +0,0 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
namespace CarCareTracker.External.Implementations
{
public class TaxRecordDataAccess : ITaxRecordDataAccess
{
private static string dbName = StaticHelper.DbName;
private static string tableName = "taxrecords";
public List<TaxRecord> GetTaxRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<TaxRecord>(tableName);
var taxRecords = table.Find(Query.EQ(nameof(TaxRecord.VehicleId), vehicleId));
return taxRecords.ToList() ?? new List<TaxRecord>();
};
}
public TaxRecord GetTaxRecordById(int taxRecordId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<TaxRecord>(tableName);
return table.FindById(taxRecordId);
};
}
public bool DeleteTaxRecordById(int taxRecordId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<TaxRecord>(tableName);
table.Delete(taxRecordId);
return true;
};
}
public bool SaveTaxRecordToVehicle(TaxRecord taxRecord)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<TaxRecord>(tableName);
table.Upsert(taxRecord);
return true;
};
}
public bool DeleteAllTaxRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<TaxRecord>(tableName);
var taxRecords = table.DeleteMany(Query.EQ(nameof(TaxRecord.VehicleId), vehicleId));
return true;
};
}
}
}

View File

@@ -1,57 +0,0 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
namespace CarCareTracker.External.Implementations
{
public class TokenRecordDataAccess : ITokenRecordDataAccess
{
private static string dbName = StaticHelper.DbName;
private static string tableName = "tokenrecords";
public List<Token> GetTokens()
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<Token>(tableName);
return table.FindAll().ToList();
};
}
public Token GetTokenRecordByBody(string tokenBody)
{
using (var db = new LiteDatabase(dbName))
{
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)
{
using (var db = new LiteDatabase(dbName))
{
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)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<Token>(tableName);
table.Insert(token);
return true;
};
}
public bool DeleteToken(int tokenId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<Token>(tableName);
table.Delete(tokenId);
return true;
};
}
}
}

View File

@@ -1,57 +0,0 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
namespace CarCareTracker.External.Implementations
{
public class UpgradeRecordDataAccess : IUpgradeRecordDataAccess
{
private static string dbName = StaticHelper.DbName;
private static string tableName = "upgraderecords";
public List<UpgradeRecord> GetUpgradeRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UpgradeRecord>(tableName);
var upgradeRecords = table.Find(Query.EQ(nameof(UpgradeRecord.VehicleId), vehicleId));
return upgradeRecords.ToList() ?? new List<UpgradeRecord>();
};
}
public UpgradeRecord GetUpgradeRecordById(int upgradeRecordId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UpgradeRecord>(tableName);
return table.FindById(upgradeRecordId);
};
}
public bool DeleteUpgradeRecordById(int upgradeRecordId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UpgradeRecord>(tableName);
table.Delete(upgradeRecordId);
return true;
};
}
public bool SaveUpgradeRecordToVehicle(UpgradeRecord upgradeRecord)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UpgradeRecord>(tableName);
table.Upsert(upgradeRecord);
return true;
};
}
public bool DeleteAllUpgradeRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UpgradeRecord>(tableName);
var upgradeRecords = table.DeleteMany(Query.EQ(nameof(UpgradeRecord.VehicleId), vehicleId));
return true;
};
}
}
}

View File

@@ -1,88 +0,0 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
namespace CarCareTracker.External.Implementations
{
public class UserAccessDataAccess : IUserAccessDataAccess
{
private static string dbName = StaticHelper.DbName;
private static string tableName = "useraccessrecords";
/// <summary>
/// Gets a list of vehicles user have access to.
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public List<UserAccess> GetUserAccessByUserId(int userId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UserAccess>(tableName);
return table.Find(x=>x.Id.UserId == userId).ToList();
};
}
public UserAccess GetUserAccessByVehicleAndUserId(int userId, int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
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)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UserAccess>(tableName);
return table.Find(x => x.Id.VehicleId == vehicleId).ToList();
};
}
public bool SaveUserAccess(UserAccess userAccess)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UserAccess>(tableName);
table.Upsert(userAccess);
return true;
};
}
public bool DeleteUserAccess(int userId, int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UserAccess>(tableName);
table.DeleteMany(x => x.Id.UserId == userId && x.Id.VehicleId == vehicleId);
return true;
};
}
/// <summary>
/// Delete all access records when a vehicle is deleted.
/// </summary>
/// <param name="vehicleId"></param>
/// <returns></returns>
public bool DeleteAllAccessRecordsByVehicleId(int vehicleId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UserAccess>(tableName);
table.DeleteMany(x=>x.Id.VehicleId == vehicleId);
return true;
};
}
/// <summary>
/// Delee all access records when a user is deleted.
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public bool DeleteAllAccessRecordsByUserId(int userId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UserAccess>(tableName);
table.DeleteMany(x => x.Id.UserId == userId);
return true;
};
}
}
}

View File

@@ -1,40 +0,0 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace CarCareTracker.External.Implementations
{
public class UserConfigDataAccess: IUserConfigDataAccess
{
private static string dbName = StaticHelper.DbName;
private static string tableName = "userconfigrecords";
public UserConfigData GetUserConfig(int userId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UserConfigData>(tableName);
return table.FindById(userId);
};
}
public bool SaveUserConfig(UserConfigData userConfigData)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UserConfigData>(tableName);
table.Upsert(userConfigData);
return true;
};
}
public bool DeleteUserConfig(int userId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UserConfigData>(tableName);
table.Delete(userId);
return true;
};
}
}
}

View File

@@ -1,66 +0,0 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
namespace CarCareTracker.External.Implementations
{
public class UserRecordDataAccess : IUserRecordDataAccess
{
private static string dbName = StaticHelper.DbName;
private static string tableName = "userrecords";
public List<UserData> GetUsers()
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UserData>(tableName);
return table.FindAll().ToList();
};
}
public UserData GetUserRecordByUserName(string userName)
{
using (var db = new LiteDatabase(dbName))
{
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)
{
using (var db = new LiteDatabase(dbName))
{
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)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UserData>(tableName);
var userRecord = table.FindById(userId);
return userRecord ?? new UserData();
};
}
public bool SaveUserRecord(UserData userRecord)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UserData>(tableName);
table.Upsert(userRecord);
return true;
};
}
public bool DeleteUserRecord(int userId)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<UserData>(tableName);
table.Delete(userId);
return true;
};
}
}
}

View File

@@ -1,46 +0,0 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using LiteDB;
namespace CarCareTracker.External.Implementations
{
public class VehicleDataAccess: IVehicleDataAccess
{
private static string dbName = StaticHelper.DbName;
private static string tableName = "vehicles";
public bool SaveVehicle(Vehicle vehicle)
{
using (var db = new LiteDatabase(dbName))
{
var table = db.GetCollection<Vehicle>(tableName);
var result = 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);
};
}
}
}

View File

@@ -0,0 +1,10 @@
using CarCareTracker.Models;
namespace CarCareTracker.External.Interfaces
{
public interface IExtraFieldDataAccess
{
public RecordExtraField GetExtraFieldsById(int importMode);
public bool SaveExtraFields(RecordExtraField record);
}
}

View 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);
}
}

View File

@@ -1,4 +1,5 @@
using CarCareTracker.Logic; using CarCareTracker.Helper;
using CarCareTracker.Logic;
using CarCareTracker.Models; using CarCareTracker.Models;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
@@ -9,18 +10,36 @@ namespace CarCareTracker.Filter
public class CollaboratorFilter: ActionFilterAttribute public class CollaboratorFilter: ActionFilterAttribute
{ {
private readonly IUserLogic _userLogic; private readonly IUserLogic _userLogic;
public CollaboratorFilter(IUserLogic userLogic) { private readonly IConfigHelper _config;
public CollaboratorFilter(IUserLogic userLogic, IConfigHelper config) {
_userLogic = userLogic; _userLogic = userLogic;
_config = config;
} }
public override void OnActionExecuting(ActionExecutingContext filterContext) public override void OnActionExecuting(ActionExecutingContext filterContext)
{ {
if (!filterContext.HttpContext.User.IsInRole(nameof(UserData.IsRootUser))) if (!filterContext.HttpContext.User.IsInRole(nameof(UserData.IsRootUser)))
{ {
var vehicleId = int.Parse(filterContext.ActionArguments["vehicleId"].ToString()); var vehicleId = int.Parse(filterContext.ActionArguments["vehicleId"].ToString());
var userId = int.Parse(filterContext.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier)); if (vehicleId != default)
if (!_userLogic.UserCanEditVehicle(userId, vehicleId))
{ {
filterContext.Result = new RedirectResult("/Error/Unauthorized"); var userId = int.Parse(filterContext.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier));
if (!_userLogic.UserCanEditVehicle(userId, vehicleId))
{
filterContext.Result = new RedirectResult("/Error/Unauthorized");
}
} else
{
var shopSupplyEndpoints = new List<string> { "ImportToVehicleIdFromCsv", "GetSupplyRecordsByVehicleId", "ExportFromVehicleToCsv" };
if (shopSupplyEndpoints.Contains(filterContext.RouteData.Values["action"].ToString()) && !_config.GetServerEnableShopSupplies())
{
//user trying to access shop supplies but shop supplies is not enabled by root user.
filterContext.Result = new RedirectResult("/Error/Unauthorized");
}
else if (!shopSupplyEndpoints.Contains(filterContext.RouteData.Values["action"].ToString()))
{
//user trying to access any other endpoints using 0 as vehicle id.
filterContext.Result = new RedirectResult("/Error/Unauthorized");
}
} }
} }
} }

View File

@@ -7,9 +7,18 @@ namespace CarCareTracker.Helper
{ {
public interface IConfigHelper public interface IConfigHelper
{ {
OpenIDConfig GetOpenIDConfig();
ReminderUrgencyConfig GetReminderUrgencyConfig();
UserConfig GetUserConfig(ClaimsPrincipal user); UserConfig GetUserConfig(ClaimsPrincipal user);
bool SaveUserConfig(ClaimsPrincipal user, UserConfig configData); bool SaveUserConfig(ClaimsPrincipal user, UserConfig configData);
bool AuthenticateRootUser(string username, string password);
string GetWebHookUrl();
string GetMOTD();
string GetLogoUrl(); string GetLogoUrl();
string GetServerLanguage();
bool GetServerEnableShopSupplies();
string GetServerPostgresConnection();
string GetAllowedFileUploadExtensions();
public bool DeleteUserConfig(int userId); public bool DeleteUserConfig(int userId);
} }
public class ConfigHelper : IConfigHelper public class ConfigHelper : IConfigHelper
@@ -25,6 +34,34 @@ namespace CarCareTracker.Helper
_userConfig = userConfig; _userConfig = userConfig;
_cache = memoryCache; _cache = memoryCache;
} }
public string GetWebHookUrl()
{
var webhook = _config["LUBELOGGER_WEBHOOK"];
if (string.IsNullOrWhiteSpace(webhook))
{
webhook = "";
}
return webhook;
}
public string GetMOTD()
{
var motd = _config["LUBELOGGER_MOTD"];
if (string.IsNullOrWhiteSpace(motd))
{
motd = "";
}
return motd;
}
public OpenIDConfig GetOpenIDConfig()
{
OpenIDConfig openIdConfig = _config.GetSection("OpenIDConfig").Get<OpenIDConfig>() ?? new OpenIDConfig();
return openIdConfig;
}
public ReminderUrgencyConfig GetReminderUrgencyConfig()
{
ReminderUrgencyConfig reminderUrgencyConfig = _config.GetSection("ReminderUrgencyConfig").Get<ReminderUrgencyConfig>() ?? new ReminderUrgencyConfig();
return reminderUrgencyConfig;
}
public string GetLogoUrl() public string GetLogoUrl()
{ {
var logoUrl = _config["LUBELOGGER_LOGO_URL"]; var logoUrl = _config["LUBELOGGER_LOGO_URL"];
@@ -34,6 +71,43 @@ namespace CarCareTracker.Helper
} }
return logoUrl; return logoUrl;
} }
public string GetAllowedFileUploadExtensions()
{
var allowedFileExtensions = _config["LUBELOGGER_ALLOWED_FILE_EXTENSIONS"];
if (string.IsNullOrWhiteSpace(allowedFileExtensions)){
return StaticHelper.DefaultAllowedFileExtensions;
}
return allowedFileExtensions;
}
public bool AuthenticateRootUser(string username, string password)
{
var rootUsername = _config[nameof(UserConfig.UserNameHash)] ?? string.Empty;
var rootPassword = _config[nameof(UserConfig.UserPasswordHash)] ?? string.Empty;
if (string.IsNullOrWhiteSpace(rootUsername) || string.IsNullOrWhiteSpace(rootPassword))
{
return false;
}
return username == rootUsername && password == rootPassword;
}
public string GetServerLanguage()
{
var serverLanguage = _config[nameof(UserConfig.UserLanguage)] ?? "en_US";
return serverLanguage;
}
public string GetServerPostgresConnection()
{
if (!string.IsNullOrWhiteSpace(_config["POSTGRES_CONNECTION"]))
{
return _config["POSTGRES_CONNECTION"];
} else
{
return string.Empty;
}
}
public bool GetServerEnableShopSupplies()
{
return bool.Parse(_config[nameof(UserConfig.EnableShopSupplies)] ?? "false");
}
public bool SaveUserConfig(ClaimsPrincipal user, UserConfig configData) public bool SaveUserConfig(ClaimsPrincipal user, UserConfig configData)
{ {
var storedUserId = user.FindFirstValue(ClaimTypes.NameIdentifier); var storedUserId = user.FindFirstValue(ClaimTypes.NameIdentifier);
@@ -53,20 +127,9 @@ namespace CarCareTracker.Helper
File.WriteAllText(StaticHelper.UserConfigPath, System.Text.Json.JsonSerializer.Serialize(new UserConfig())); File.WriteAllText(StaticHelper.UserConfigPath, System.Text.Json.JsonSerializer.Serialize(new UserConfig()));
} }
var configFileContents = File.ReadAllText(StaticHelper.UserConfigPath); var configFileContents = File.ReadAllText(StaticHelper.UserConfigPath);
var existingUserConfig = System.Text.Json.JsonSerializer.Deserialize<UserConfig>(configFileContents); configData.EnableAuth = bool.Parse(_config[nameof(UserConfig.EnableAuth)] ?? "false");
if (existingUserConfig is not null) configData.UserNameHash = _config[nameof(UserConfig.UserNameHash)] ?? string.Empty;
{ configData.UserPasswordHash = _config[nameof(UserConfig.UserPasswordHash)] ?? string.Empty;
//copy over settings that are off limits on the settings page.
configData.EnableAuth = existingUserConfig.EnableAuth;
configData.UserNameHash = existingUserConfig.UserNameHash;
configData.UserPasswordHash = existingUserConfig.UserPasswordHash;
}
else
{
configData.EnableAuth = false;
configData.UserNameHash = string.Empty;
configData.UserPasswordHash = string.Empty;
}
File.WriteAllText(StaticHelper.UserConfigPath, System.Text.Json.JsonSerializer.Serialize(configData)); File.WriteAllText(StaticHelper.UserConfigPath, System.Text.Json.JsonSerializer.Serialize(configData));
_cache.Set<UserConfig>($"userConfig_{userId}", configData); _cache.Set<UserConfig>($"userConfig_{userId}", configData);
return true; return true;
@@ -111,7 +174,12 @@ namespace CarCareTracker.Helper
PreferredGasMileageUnit = _config[nameof(UserConfig.PreferredGasMileageUnit)], PreferredGasMileageUnit = _config[nameof(UserConfig.PreferredGasMileageUnit)],
PreferredGasUnit = _config[nameof(UserConfig.PreferredGasUnit)], PreferredGasUnit = _config[nameof(UserConfig.PreferredGasUnit)],
UserLanguage = _config[nameof(UserConfig.UserLanguage)], UserLanguage = _config[nameof(UserConfig.UserLanguage)],
VisibleTabs = _config.GetSection("VisibleTabs").Get<List<ImportMode>>(), HideSoldVehicles = bool.Parse(_config[nameof(UserConfig.HideSoldVehicles)]),
EnableShopSupplies = bool.Parse(_config[nameof(UserConfig.EnableShopSupplies)]),
EnableExtraFieldColumns = bool.Parse(_config[nameof(UserConfig.EnableExtraFieldColumns)]),
VisibleTabs = _config.GetSection(nameof(UserConfig.VisibleTabs)).Get<List<ImportMode>>(),
UserColumnPreferences = _config.GetSection(nameof(UserConfig.UserColumnPreferences)).Get<List<UserColumnPreference>>() ?? new List<UserColumnPreference>(),
ReminderUrgencyConfig = _config.GetSection(nameof(UserConfig.ReminderUrgencyConfig)).Get<ReminderUrgencyConfig>() ?? new ReminderUrgencyConfig(),
DefaultTab = (ImportMode)int.Parse(_config[nameof(UserConfig.DefaultTab)]) DefaultTab = (ImportMode)int.Parse(_config[nameof(UserConfig.DefaultTab)])
}; };
int userId = 0; int userId = 0;

View File

@@ -18,10 +18,12 @@ namespace CarCareTracker.Helper
{ {
private readonly IWebHostEnvironment _webEnv; private readonly IWebHostEnvironment _webEnv;
private readonly ILogger<IFileHelper> _logger; private readonly ILogger<IFileHelper> _logger;
public FileHelper(IWebHostEnvironment webEnv, ILogger<IFileHelper> logger) private ILiteDBHelper _liteDB;
public FileHelper(IWebHostEnvironment webEnv, ILogger<IFileHelper> logger, ILiteDBHelper liteDB)
{ {
_webEnv = webEnv; _webEnv = webEnv;
_logger = logger; _logger = logger;
_liteDB = liteDB;
} }
public List<string> GetLanguages() public List<string> GetLanguages()
{ {
@@ -93,6 +95,7 @@ namespace CarCareTracker.Helper
//copy over images and documents. //copy over images and documents.
var imagePath = Path.Combine(tempPath, "images"); var imagePath = Path.Combine(tempPath, "images");
var documentPath = Path.Combine(tempPath, "documents"); var documentPath = Path.Combine(tempPath, "documents");
var translationPath = Path.Combine(tempPath, "translations");
var dataPath = Path.Combine(tempPath, StaticHelper.DbName); var dataPath = Path.Combine(tempPath, StaticHelper.DbName);
var configPath = Path.Combine(tempPath, StaticHelper.UserConfigPath); var configPath = Path.Combine(tempPath, StaticHelper.UserConfigPath);
if (Directory.Exists(imagePath)) if (Directory.Exists(imagePath))
@@ -139,8 +142,32 @@ namespace CarCareTracker.Helper
File.Copy(file, $"{existingPath}/{Path.GetFileName(file)}", true); File.Copy(file, $"{existingPath}/{Path.GetFileName(file)}", true);
} }
} }
if (Directory.Exists(translationPath))
{
var existingPath = Path.Combine(_webEnv.WebRootPath, "translations");
if (!Directory.Exists(existingPath))
{
Directory.CreateDirectory(existingPath);
}
else if (clearExisting)
{
var filesToDelete = Directory.GetFiles(existingPath);
foreach (string file in filesToDelete)
{
File.Delete(file);
}
}
//copy each files from temp folder to newPath
var filesToUpload = Directory.GetFiles(translationPath);
foreach (string file in filesToUpload)
{
File.Copy(file, $"{existingPath}/{Path.GetFileName(file)}", true);
}
}
if (File.Exists(dataPath)) if (File.Exists(dataPath))
{ {
//Relinquish current DB file lock
_liteDB.DisposeLiteDB();
//data path will always exist as it is created on startup if not. //data path will always exist as it is created on startup if not.
File.Move(dataPath, StaticHelper.DbName, true); File.Move(dataPath, StaticHelper.DbName, true);
} }
@@ -173,7 +200,7 @@ namespace CarCareTracker.Helper
foreach (UploadedFiles file in reportModel.Files) foreach (UploadedFiles file in reportModel.Files)
{ {
var fileToCopy = GetFullFilePath(file.Location); var fileToCopy = GetFullFilePath(file.Location);
var destFileName = $"{tempPath}/{fileIndex}{Path.GetExtension(file.Location)}"; var destFileName = $"{tempPath}/{fileIndex}_{reportModel.DataType}_{reportModel.Date.ToString("yyyy-MM-dd")}_{file.Name}{Path.GetExtension(file.Location)}";
File.Copy(fileToCopy, destFileName); File.Copy(fileToCopy, destFileName);
fileIndex++; fileIndex++;
} }
@@ -191,6 +218,7 @@ namespace CarCareTracker.Helper
var tempPath = Path.Combine(_webEnv.WebRootPath, $"temp/{folderName}"); var tempPath = Path.Combine(_webEnv.WebRootPath, $"temp/{folderName}");
var imagePath = Path.Combine(_webEnv.WebRootPath, "images"); var imagePath = Path.Combine(_webEnv.WebRootPath, "images");
var documentPath = Path.Combine(_webEnv.WebRootPath, "documents"); var documentPath = Path.Combine(_webEnv.WebRootPath, "documents");
var translationPath = Path.Combine(_webEnv.WebRootPath, "translations");
var dataPath = StaticHelper.DbName; var dataPath = StaticHelper.DbName;
var configPath = StaticHelper.UserConfigPath; var configPath = StaticHelper.UserConfigPath;
if (!Directory.Exists(tempPath)) if (!Directory.Exists(tempPath))
@@ -215,6 +243,16 @@ namespace CarCareTracker.Helper
File.Copy(file, $"{newPath}/{Path.GetFileName(file)}"); File.Copy(file, $"{newPath}/{Path.GetFileName(file)}");
} }
} }
if (Directory.Exists(translationPath))
{
var files = Directory.GetFiles(translationPath);
foreach(var file in files)
{
var newPath = Path.Combine(tempPath, "translations");
Directory.CreateDirectory(newPath);
File.Copy(file, $"{newPath}/{Path.GetFileName(file)}");
}
}
if (File.Exists(dataPath)) if (File.Exists(dataPath))
{ {
var newPath = Path.Combine(tempPath, "data"); var newPath = Path.Combine(tempPath, "data");

View File

@@ -71,7 +71,8 @@ namespace CarCareTracker.Helper
IsFillToFull = currentObject.IsFillToFull, IsFillToFull = currentObject.IsFillToFull,
MissedFuelUp = currentObject.MissedFuelUp, MissedFuelUp = currentObject.MissedFuelUp,
Notes = currentObject.Notes, Notes = currentObject.Notes,
Tags = currentObject.Tags Tags = currentObject.Tags,
ExtraFields = currentObject.ExtraFields
}; };
if (currentObject.MissedFuelUp) if (currentObject.MissedFuelUp)
{ {
@@ -124,7 +125,8 @@ namespace CarCareTracker.Helper
IsFillToFull = currentObject.IsFillToFull, IsFillToFull = currentObject.IsFillToFull,
MissedFuelUp = currentObject.MissedFuelUp, MissedFuelUp = currentObject.MissedFuelUp,
Notes = currentObject.Notes, Notes = currentObject.Notes,
Tags = currentObject.Tags Tags = currentObject.Tags,
ExtraFields = currentObject.ExtraFields
}); });
} }
previousMileage = currentObject.Mileage; previousMileage = currentObject.Mileage;

36
Helper/LiteDBHelper.cs Normal file
View File

@@ -0,0 +1,36 @@
using LiteDB;
namespace CarCareTracker.Helper;
public interface ILiteDBHelper
{
LiteDatabase GetLiteDB();
void DisposeLiteDB();
}
public class LiteDBHelper: ILiteDBHelper
{
public LiteDatabase db { get; set; }
public LiteDBHelper()
{
if (db == null)
{
db = new LiteDatabase(StaticHelper.DbName);
}
}
public LiteDatabase GetLiteDB()
{
if (db == null)
{
db = new LiteDatabase(StaticHelper.DbName);
}
return db;
}
public void DisposeLiteDB()
{
if (db != null)
{
db.Dispose();
db = null;
}
}
}

View File

@@ -1,6 +1,6 @@
using CarCareTracker.Models; using CarCareTracker.Models;
using System.Net.Mail; using MimeKit;
using System.Net; using MailKit.Net.Smtp;
namespace CarCareTracker.Helper namespace CarCareTracker.Helper
{ {
@@ -8,16 +8,23 @@ namespace CarCareTracker.Helper
{ {
OperationResponse NotifyUserForRegistration(string emailAddress, string token); OperationResponse NotifyUserForRegistration(string emailAddress, string token);
OperationResponse NotifyUserForPasswordReset(string emailAddress, string token); OperationResponse NotifyUserForPasswordReset(string emailAddress, string token);
OperationResponse NotifyUserForAccountUpdate(string emailAddress, string token);
OperationResponse NotifyUserForReminders(Vehicle vehicle, List<string> emailAddresses, List<ReminderRecordViewModel> reminders); OperationResponse NotifyUserForReminders(Vehicle vehicle, List<string> emailAddresses, List<ReminderRecordViewModel> reminders);
} }
public class MailHelper : IMailHelper public class MailHelper : IMailHelper
{ {
private readonly MailConfig mailConfig; private readonly MailConfig mailConfig;
private readonly IFileHelper _fileHelper;
private readonly ILogger<MailHelper> _logger;
public MailHelper( public MailHelper(
IConfiguration config IConfiguration config,
IFileHelper fileHelper,
ILogger<MailHelper> logger
) { ) {
//load mailConfig from Configuration //load mailConfig from Configuration
mailConfig = config.GetSection("MailConfig").Get<MailConfig>(); mailConfig = config.GetSection("MailConfig").Get<MailConfig>() ?? new MailConfig();
_fileHelper = fileHelper;
_logger = logger;
} }
public OperationResponse NotifyUserForRegistration(string emailAddress, string token) public OperationResponse NotifyUserForRegistration(string emailAddress, string token)
{ {
@@ -30,7 +37,7 @@ namespace CarCareTracker.Helper
} }
string emailSubject = "Your Registration Token for LubeLogger"; string emailSubject = "Your Registration Token for LubeLogger";
string emailBody = $"A token has been generated on your behalf, please complete your registration for LubeLogger using the token: {token}"; string emailBody = $"A token has been generated on your behalf, please complete your registration for LubeLogger using the token: {token}";
var result = SendEmail(emailAddress, emailSubject, emailBody); var result = SendEmail(new List<string> { emailAddress }, emailSubject, emailBody);
if (result) if (result)
{ {
return new OperationResponse { Success = true, Message = "Email Sent!" }; return new OperationResponse { Success = true, Message = "Email Sent!" };
@@ -51,7 +58,29 @@ namespace CarCareTracker.Helper
} }
string emailSubject = "Your Password Reset Token for LubeLogger"; string emailSubject = "Your Password Reset Token for LubeLogger";
string emailBody = $"A token has been generated on your behalf, please reset your password for LubeLogger using the token: {token}"; string emailBody = $"A token has been generated on your behalf, please reset your password for LubeLogger using the token: {token}";
var result = SendEmail(emailAddress, emailSubject, emailBody); var result = SendEmail(new List<string> { emailAddress }, emailSubject, emailBody);
if (result)
{
return new OperationResponse { Success = true, Message = "Email Sent!" };
}
else
{
return new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage };
}
}
public OperationResponse NotifyUserForAccountUpdate(string emailAddress, string token)
{
if (string.IsNullOrWhiteSpace(mailConfig.EmailServer))
{
return new OperationResponse { Success = false, Message = "SMTP Server Not Setup" };
}
if (string.IsNullOrWhiteSpace(emailAddress) || string.IsNullOrWhiteSpace(token))
{
return new OperationResponse { Success = false, Message = "Email Address or Token is invalid" };
}
string emailSubject = "Your User Account Update Token for LubeLogger";
string emailBody = $"A token has been generated on your behalf, please update your account for LubeLogger using the token: {token}";
var result = SendEmail(new List<string> { emailAddress}, emailSubject, emailBody);
if (result) if (result)
{ {
return new OperationResponse { Success = true, Message = "Email Sent!" }; return new OperationResponse { Success = true, Message = "Email Sent!" };
@@ -75,53 +104,59 @@ namespace CarCareTracker.Helper
{ {
return new OperationResponse { Success = false, Message = "No reminders could be found" }; return new OperationResponse { Success = false, Message = "No reminders could be found" };
} }
//get email template, this file has to exist since it's a static file.
var emailTemplatePath = _fileHelper.GetFullFilePath(StaticHelper.ReminderEmailTemplate);
string emailSubject = $"Vehicle Reminders From LubeLogger - {DateTime.Now.ToShortDateString()}"; string emailSubject = $"Vehicle Reminders From LubeLogger - {DateTime.Now.ToShortDateString()}";
//construct html table. //construct html table.
string emailBody = $"<h4>{vehicle.Year} {vehicle.Make} {vehicle.Model} #{vehicle.LicensePlate}</h4><br /><table style='width:100%'><tr><th style='padding:8px;'>Urgency</th><th style='padding:8px;'>Description</th></tr>"; string emailBody = File.ReadAllText(emailTemplatePath);
emailBody = emailBody.Replace("{VehicleInformation}", $"{vehicle.Year} {vehicle.Make} {vehicle.Model} #{vehicle.LicensePlate}");
string tableBody = "";
foreach(ReminderRecordViewModel reminder in reminders) foreach(ReminderRecordViewModel reminder in reminders)
{ {
emailBody += $"<tr><td style='padding:8px; text-align:center;'>{reminder.Urgency}</td><td style='padding:8px; text-align:center;'>{reminder.Description}</td></tr>"; var dueOn = reminder.Metric == ReminderMetric.Both ? $"{reminder.Date} or {reminder.Mileage}" : reminder.Metric == ReminderMetric.Date ? $"{reminder.Date.ToShortDateString()}" : $"{reminder.Mileage}";
tableBody += $"<tr class='{reminder.Urgency}'><td>{StaticHelper.GetTitleCaseReminderUrgency(reminder.Urgency)}</td><td>{reminder.Description}</td><td>{dueOn}</td></tr>";
} }
emailBody += "</table>"; emailBody = emailBody.Replace("{TableBody}", tableBody);
try try
{ {
foreach (string emailAddress in emailAddresses) SendEmail(emailAddresses, emailSubject, emailBody);
{
SendEmail(emailAddress, emailSubject, emailBody, true, true);
}
return new OperationResponse { Success = true, Message = "Email Sent!" }; return new OperationResponse { Success = true, Message = "Email Sent!" };
} catch (Exception ex) } catch (Exception ex)
{ {
return new OperationResponse { Success = false, Message = ex.Message }; return new OperationResponse { Success = false, Message = ex.Message };
} }
} }
private bool SendEmail(string emailTo, string emailSubject, string emailBody, bool isBodyHtml = false, bool useAsync = false) { private bool SendEmail(List<string> emailTo, string emailSubject, string emailBody) {
string to = emailTo;
string from = mailConfig.EmailFrom; string from = mailConfig.EmailFrom;
var server = mailConfig.EmailServer; var server = mailConfig.EmailServer;
MailMessage message = new MailMessage(from, to); var message = new MimeMessage();
message.Subject = emailSubject; message.From.Add(new MailboxAddress(from, from));
message.Body = emailBody; foreach(string emailRecipient in emailTo)
message.IsBodyHtml = isBodyHtml;
SmtpClient client = new SmtpClient(server);
client.EnableSsl = mailConfig.UseSSL;
client.Port = mailConfig.Port;
client.Credentials = new NetworkCredential(mailConfig.Username, mailConfig.Password);
try
{ {
if (useAsync) message.To.Add(new MailboxAddress(emailRecipient, emailRecipient));
{ }
client.SendMailAsync(message, new CancellationToken()); message.Subject = emailSubject;
}
else var builder = new BodyBuilder();
builder.HtmlBody = emailBody;
message.Body = builder.ToMessageBody();
using (var client = new SmtpClient())
{
client.Connect(server, mailConfig.Port, MailKit.Security.SecureSocketOptions.Auto);
client.Authenticate(mailConfig.Username, mailConfig.Password);
try
{ {
client.Send(message); client.Send(message);
client.Disconnect(true);
return true;
} catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
} }
return true;
}
catch (Exception ex)
{
return false;
} }
} }
} }

View File

@@ -4,44 +4,66 @@ namespace CarCareTracker.Helper
{ {
public interface IReminderHelper public interface IReminderHelper
{ {
ReminderRecord GetUpdatedRecurringReminderRecord(ReminderRecord existingReminder); ReminderRecord GetUpdatedRecurringReminderRecord(ReminderRecord existingReminder, DateTime? currentDate, int? currentMileage);
List<ReminderRecordViewModel> GetReminderRecordViewModels(List<ReminderRecord> reminders, int currentMileage, DateTime dateCompare); List<ReminderRecordViewModel> GetReminderRecordViewModels(List<ReminderRecord> reminders, int currentMileage, DateTime dateCompare);
} }
public class ReminderHelper: IReminderHelper public class ReminderHelper: IReminderHelper
{ {
public ReminderRecord GetUpdatedRecurringReminderRecord(ReminderRecord existingReminder) private readonly IConfigHelper _config;
public ReminderHelper(IConfigHelper config)
{ {
_config = config;
}
public ReminderRecord GetUpdatedRecurringReminderRecord(ReminderRecord existingReminder, DateTime? currentDate, int? currentMileage)
{
var newDate = currentDate ?? existingReminder.Date;
var newMileage = currentMileage ?? existingReminder.Mileage;
if (existingReminder.Metric == ReminderMetric.Both) if (existingReminder.Metric == ReminderMetric.Both)
{ {
existingReminder.Date = existingReminder.Date.AddMonths((int)existingReminder.ReminderMonthInterval); if (existingReminder.ReminderMonthInterval != ReminderMonthInterval.Other)
{
existingReminder.Date = newDate.AddMonths((int)existingReminder.ReminderMonthInterval);
} else
{
existingReminder.Date = newDate.Date.AddMonths(existingReminder.CustomMonthInterval);
}
if (existingReminder.ReminderMileageInterval != ReminderMileageInterval.Other) if (existingReminder.ReminderMileageInterval != ReminderMileageInterval.Other)
{ {
existingReminder.Mileage += (int)existingReminder.ReminderMileageInterval; existingReminder.Mileage = newMileage + (int)existingReminder.ReminderMileageInterval;
} }
else else
{ {
existingReminder.Mileage += existingReminder.CustomMileageInterval; existingReminder.Mileage = newMileage + existingReminder.CustomMileageInterval;
} }
} }
else if (existingReminder.Metric == ReminderMetric.Odometer) else if (existingReminder.Metric == ReminderMetric.Odometer)
{ {
if (existingReminder.ReminderMileageInterval != ReminderMileageInterval.Other) if (existingReminder.ReminderMileageInterval != ReminderMileageInterval.Other)
{ {
existingReminder.Mileage += (int)existingReminder.ReminderMileageInterval; existingReminder.Mileage = newMileage + (int)existingReminder.ReminderMileageInterval;
} else } else
{ {
existingReminder.Mileage += existingReminder.CustomMileageInterval; existingReminder.Mileage = newMileage + existingReminder.CustomMileageInterval;
} }
} }
else if (existingReminder.Metric == ReminderMetric.Date) else if (existingReminder.Metric == ReminderMetric.Date)
{ {
existingReminder.Date = existingReminder.Date.AddMonths((int)existingReminder.ReminderMonthInterval); if (existingReminder.ReminderMonthInterval != ReminderMonthInterval.Other)
{
existingReminder.Date = newDate.AddMonths((int)existingReminder.ReminderMonthInterval);
}
else
{
existingReminder.Date = newDate.AddMonths(existingReminder.CustomMonthInterval);
}
} }
return existingReminder; return existingReminder;
} }
public List<ReminderRecordViewModel> GetReminderRecordViewModels(List<ReminderRecord> reminders, int currentMileage, DateTime dateCompare) public List<ReminderRecordViewModel> GetReminderRecordViewModels(List<ReminderRecord> reminders, int currentMileage, DateTime dateCompare)
{ {
List<ReminderRecordViewModel> reminderViewModels = new List<ReminderRecordViewModel>(); List<ReminderRecordViewModel> reminderViewModels = new List<ReminderRecordViewModel>();
var reminderUrgencyConfig = _config.GetReminderUrgencyConfig();
foreach (var reminder in reminders) foreach (var reminder in reminders)
{ {
var reminderViewModel = new ReminderRecordViewModel() var reminderViewModel = new ReminderRecordViewModel()
@@ -53,7 +75,8 @@ namespace CarCareTracker.Helper
Description = reminder.Description, Description = reminder.Description,
Notes = reminder.Notes, Notes = reminder.Notes,
Metric = reminder.Metric, Metric = reminder.Metric,
IsRecurring = reminder.IsRecurring IsRecurring = reminder.IsRecurring,
Tags = reminder.Tags
}; };
if (reminder.Metric == ReminderMetric.Both) if (reminder.Metric == ReminderMetric.Both)
{ {
@@ -67,24 +90,24 @@ namespace CarCareTracker.Helper
reminderViewModel.Urgency = ReminderUrgency.PastDue; reminderViewModel.Urgency = ReminderUrgency.PastDue;
reminderViewModel.Metric = ReminderMetric.Odometer; reminderViewModel.Metric = ReminderMetric.Odometer;
} }
else if (reminder.Date < dateCompare.AddDays(7)) else if (reminder.Date < dateCompare.AddDays(reminderUrgencyConfig.VeryUrgentDays))
{ {
//if less than a week from today or less than 50 miles from current mileage then very urgent. //if less than a week from today or less than 50 miles from current mileage then very urgent.
reminderViewModel.Urgency = ReminderUrgency.VeryUrgent; reminderViewModel.Urgency = ReminderUrgency.VeryUrgent;
//have to specify by which metric this reminder is urgent. //have to specify by which metric this reminder is urgent.
reminderViewModel.Metric = ReminderMetric.Date; reminderViewModel.Metric = ReminderMetric.Date;
} }
else if (reminder.Mileage < currentMileage + 50) else if (reminder.Mileage < currentMileage + reminderUrgencyConfig.VeryUrgentDistance)
{ {
reminderViewModel.Urgency = ReminderUrgency.VeryUrgent; reminderViewModel.Urgency = ReminderUrgency.VeryUrgent;
reminderViewModel.Metric = ReminderMetric.Odometer; reminderViewModel.Metric = ReminderMetric.Odometer;
} }
else if (reminder.Date < dateCompare.AddDays(30)) else if (reminder.Date < dateCompare.AddDays(reminderUrgencyConfig.UrgentDays))
{ {
reminderViewModel.Urgency = ReminderUrgency.Urgent; reminderViewModel.Urgency = ReminderUrgency.Urgent;
reminderViewModel.Metric = ReminderMetric.Date; reminderViewModel.Metric = ReminderMetric.Date;
} }
else if (reminder.Mileage < currentMileage + 100) else if (reminder.Mileage < currentMileage + reminderUrgencyConfig.UrgentDistance)
{ {
reminderViewModel.Urgency = ReminderUrgency.Urgent; reminderViewModel.Urgency = ReminderUrgency.Urgent;
reminderViewModel.Metric = ReminderMetric.Odometer; reminderViewModel.Metric = ReminderMetric.Odometer;
@@ -96,11 +119,11 @@ namespace CarCareTracker.Helper
{ {
reminderViewModel.Urgency = ReminderUrgency.PastDue; reminderViewModel.Urgency = ReminderUrgency.PastDue;
} }
else if (reminder.Date < dateCompare.AddDays(7)) else if (reminder.Date < dateCompare.AddDays(reminderUrgencyConfig.VeryUrgentDays))
{ {
reminderViewModel.Urgency = ReminderUrgency.VeryUrgent; reminderViewModel.Urgency = ReminderUrgency.VeryUrgent;
} }
else if (reminder.Date < dateCompare.AddDays(30)) else if (reminder.Date < dateCompare.AddDays(reminderUrgencyConfig.UrgentDays))
{ {
reminderViewModel.Urgency = ReminderUrgency.Urgent; reminderViewModel.Urgency = ReminderUrgency.Urgent;
} }
@@ -112,11 +135,11 @@ namespace CarCareTracker.Helper
reminderViewModel.Urgency = ReminderUrgency.PastDue; reminderViewModel.Urgency = ReminderUrgency.PastDue;
reminderViewModel.Metric = ReminderMetric.Odometer; reminderViewModel.Metric = ReminderMetric.Odometer;
} }
else if (reminder.Mileage < currentMileage + 50) else if (reminder.Mileage < currentMileage + reminderUrgencyConfig.VeryUrgentDistance)
{ {
reminderViewModel.Urgency = ReminderUrgency.VeryUrgent; reminderViewModel.Urgency = ReminderUrgency.VeryUrgent;
} }
else if (reminder.Mileage < currentMileage + 100) else if (reminder.Mileage < currentMileage + reminderUrgencyConfig.UrgentDistance)
{ {
reminderViewModel.Urgency = ReminderUrgency.Urgent; reminderViewModel.Urgency = ReminderUrgency.Urgent;
} }

View File

@@ -5,6 +5,7 @@ namespace CarCareTracker.Helper
{ {
public interface IReportHelper public interface IReportHelper
{ {
IEnumerable<CostForVehicleByMonth> GetOdometerRecordSum(List<OdometerRecord> odometerRecords, int year = 0);
IEnumerable<CostForVehicleByMonth> GetServiceRecordSum(List<ServiceRecord> serviceRecords, int year = 0); IEnumerable<CostForVehicleByMonth> GetServiceRecordSum(List<ServiceRecord> serviceRecords, int year = 0);
IEnumerable<CostForVehicleByMonth> GetRepairRecordSum(List<CollisionRecord> repairRecords, int year = 0); IEnumerable<CostForVehicleByMonth> GetRepairRecordSum(List<CollisionRecord> repairRecords, int year = 0);
IEnumerable<CostForVehicleByMonth> GetUpgradeRecordSum(List<UpgradeRecord> upgradeRecords, int year = 0); IEnumerable<CostForVehicleByMonth> GetUpgradeRecordSum(List<UpgradeRecord> upgradeRecords, int year = 0);
@@ -13,6 +14,20 @@ namespace CarCareTracker.Helper
} }
public class ReportHelper: IReportHelper public class ReportHelper: IReportHelper
{ {
public IEnumerable<CostForVehicleByMonth> GetOdometerRecordSum(List<OdometerRecord> odometerRecords, int year = 0)
{
if (year != default)
{
odometerRecords.RemoveAll(x => x.Date.Year != year);
}
return odometerRecords.GroupBy(x => x.Date.Month).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
{
MonthId = x.Key,
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
Cost = 0,
DistanceTraveled = x.Sum(y=>y.DistanceTraveled)
});
}
public IEnumerable<CostForVehicleByMonth> GetServiceRecordSum(List<ServiceRecord> serviceRecords, int year = 0) public IEnumerable<CostForVehicleByMonth> GetServiceRecordSum(List<ServiceRecord> serviceRecords, int year = 0)
{ {
if (year != default) if (year != default)

View File

@@ -8,9 +8,27 @@ namespace CarCareTracker.Helper
/// </summary> /// </summary>
public static class StaticHelper public static class StaticHelper
{ {
public static string VersionNumber = "1.3.3";
public static string DbName = "data/cartracker.db"; public static string DbName = "data/cartracker.db";
public static string UserConfigPath = "config/userConfig.json"; public static string UserConfigPath = "config/userConfig.json";
public static string GenericErrorMessage = "An error occurred, please try again later"; public static string GenericErrorMessage = "An error occurred, please try again later";
public static string ReminderEmailTemplate = "defaults/reminderemailtemplate.txt";
public static string DefaultAllowedFileExtensions = ".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx";
public static string SponsorsPath = "https://hargata.github.io/hargata/sponsors.json";
public static string GetTitleCaseReminderUrgency(ReminderUrgency input)
{
switch (input)
{
case ReminderUrgency.NotUrgent:
return "Not Urgent";
case ReminderUrgency.VeryUrgent:
return "Very Urgent";
case ReminderUrgency.PastDue:
return "Past Due";
default:
return input.ToString();
}
}
public static string TruncateStrings(string input, int maxLength = 25) public static string TruncateStrings(string input, int maxLength = 25)
{ {
@@ -112,7 +130,9 @@ namespace CarCareTracker.Helper
Mileage = input.Mileage, Mileage = input.Mileage,
Files = input.Files, Files = input.Files,
Notes = input.Notes, Notes = input.Notes,
Tags = input.Tags Tags = input.Tags,
ExtraFields = input.ExtraFields,
RequisitionHistory = input.RequisitionHistory
}; };
} }
public static CollisionRecord GenericToRepairRecord(GenericRecord input) public static CollisionRecord GenericToRepairRecord(GenericRecord input)
@@ -126,7 +146,9 @@ namespace CarCareTracker.Helper
Mileage = input.Mileage, Mileage = input.Mileage,
Files = input.Files, Files = input.Files,
Notes = input.Notes, Notes = input.Notes,
Tags = input.Tags Tags = input.Tags,
ExtraFields = input.ExtraFields,
RequisitionHistory = input.RequisitionHistory
}; };
} }
public static UpgradeRecord GenericToUpgradeRecord(GenericRecord input) public static UpgradeRecord GenericToUpgradeRecord(GenericRecord input)
@@ -140,10 +162,45 @@ namespace CarCareTracker.Helper
Mileage = input.Mileage, Mileage = input.Mileage,
Files = input.Files, Files = input.Files,
Notes = input.Notes, Notes = input.Notes,
Tags = input.Tags Tags = input.Tags,
ExtraFields = input.ExtraFields,
RequisitionHistory = input.RequisitionHistory
}; };
} }
public static List<ExtraField> AddExtraFields(List<ExtraField> recordExtraFields, List<ExtraField> templateExtraFields)
{
if (!templateExtraFields.Any()) {
return new List<ExtraField>();
}
if (!recordExtraFields.Any())
{
return templateExtraFields;
}
var fieldNames = templateExtraFields.Select(x => x.Name);
//remove fields that are no longer present in template.
recordExtraFields.RemoveAll(x => !fieldNames.Contains(x.Name));
if (!recordExtraFields.Any())
{
return templateExtraFields;
}
var recordFieldNames = recordExtraFields.Select(x => x.Name);
//update isrequired setting
foreach (ExtraField extraField in recordExtraFields)
{
extraField.IsRequired = templateExtraFields.Where(x => x.Name == extraField.Name).First().IsRequired;
}
//append extra fields
foreach(ExtraField extraField in templateExtraFields)
{
if (!recordFieldNames.Contains(extraField.Name))
{
recordExtraFields.Add(extraField);
}
}
return recordExtraFields;
}
public static string GetFuelEconomyUnit(bool useKwh, bool useHours, bool useMPG, bool useUKMPG) public static string GetFuelEconomyUnit(bool useKwh, bool useHours, bool useMPG, bool useUKMPG)
{ {
string fuelEconomyUnit; string fuelEconomyUnit;
@@ -166,5 +223,69 @@ namespace CarCareTracker.Helper
} }
return fuelEconomyUnit; return fuelEconomyUnit;
} }
public static long GetEpochFromDateTime(DateTime date)
{
return new DateTimeOffset(date).ToUnixTimeMilliseconds();
}
public static void InitMessage(IConfiguration config)
{
Console.WriteLine($"LubeLogger {VersionNumber}");
Console.WriteLine("Website: https://lubelogger.com");
Console.WriteLine("Documentation: https://docs.lubelogger.com");
Console.WriteLine("GitHub: https://github.com/hargata/lubelog");
var mailConfig = config.GetSection("MailConfig").Get<MailConfig>();
if (mailConfig != null && !string.IsNullOrWhiteSpace(mailConfig.EmailServer))
{
Console.WriteLine($"SMTP Configured for {mailConfig.EmailServer}");
} else
{
Console.WriteLine("SMTP Not Configured");
}
var motd = config["LUBELOGGER_MOTD"] ?? "Not Configured";
Console.WriteLine($"Message Of The Day: {motd}");
}
public static async void NotifyAsync(string webhookURL, int vehicleId, string username, string action)
{
if (string.IsNullOrWhiteSpace(webhookURL))
{
return;
}
var httpClient = new HttpClient();
var httpParams = new Dictionary<string, string>
{
{ "vehicleId", vehicleId.ToString() },
{ "username", username },
{ "action", action },
};
httpClient.PostAsJsonAsync(webhookURL, httpParams);
}
public static string GetImportModeIcon(ImportMode importMode)
{
switch (importMode)
{
case ImportMode.ServiceRecord:
return "bi-card-checklist";
case ImportMode.RepairRecord:
return "bi-exclamation-octagon";
case ImportMode.UpgradeRecord:
return "bi-wrench-adjustable";
case ImportMode.TaxRecord:
return "bi-currency-dollar";
case ImportMode.SupplyRecord:
return "bi-shop";
case ImportMode.PlanRecord:
return "bi-bar-chart-steps";
case ImportMode.OdometerRecord:
return "bi-speedometer";
case ImportMode.GasRecord:
return "bi-fuel-pump";
case ImportMode.NoteRecord:
return "bi-journal-bookmark";
case ImportMode.ReminderRecord:
return "bi-bell";
default:
return "bi-file-bar-graph";
}
}
} }
} }

View File

@@ -1,5 +1,4 @@
using CarCareTracker.Models; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Caching.Memory;
using System.Text.Json; using System.Text.Json;
namespace CarCareTracker.Helper namespace CarCareTracker.Helper

View File

@@ -1,11 +1,6 @@
LubeLogger by Hargata Softworks is licensed under the MIT License for individual
and personal use. Commercial users and/or corporate entities are required
to maintain an active subscription in order to continue using LubeLogger.
For pricing information please contact us at hargatasoftworks@gmail.com
MIT License MIT License
Copyright (c) 2023 Hargata Softworks Copyright (c) 2024 Hargata Softworks
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -2,8 +2,6 @@
using CarCareTracker.Helper; using CarCareTracker.Helper;
using CarCareTracker.Models; using CarCareTracker.Models;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using System.Net;
using System.Net.Mail;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
@@ -16,14 +14,18 @@ namespace CarCareTracker.Logic
OperationResponse GenerateUserToken(string emailAddress, bool autoNotify); OperationResponse GenerateUserToken(string emailAddress, bool autoNotify);
bool DeleteUserToken(int tokenId); bool DeleteUserToken(int tokenId);
bool DeleteUser(int userId); bool DeleteUser(int userId);
OperationResponse RegisterOpenIdUser(LoginModel credentials);
OperationResponse UpdateUserDetails(int userId, LoginModel credentials);
OperationResponse RegisterNewUser(LoginModel credentials); OperationResponse RegisterNewUser(LoginModel credentials);
OperationResponse RequestResetPassword(LoginModel credentials); OperationResponse RequestResetPassword(LoginModel credentials);
OperationResponse ResetPasswordByUser(LoginModel credentials); OperationResponse ResetPasswordByUser(LoginModel credentials);
OperationResponse ResetUserPassword(LoginModel credentials); OperationResponse ResetUserPassword(LoginModel credentials);
UserData ValidateUserCredentials(LoginModel credentials); UserData ValidateUserCredentials(LoginModel credentials);
UserData ValidateOpenIDUser(LoginModel credentials);
bool CheckIfUserIsValid(int userId); bool CheckIfUserIsValid(int userId);
bool CreateRootUserCredentials(LoginModel credentials); bool CreateRootUserCredentials(LoginModel credentials);
bool DeleteRootUserCredentials(); bool DeleteRootUserCredentials();
bool GenerateTokenForEmailAddress(string emailAddress, bool isPasswordReset);
List<UserData> GetAllUsers(); List<UserData> GetAllUsers();
List<Token> GetAllTokens(); List<Token> GetAllTokens();
@@ -33,15 +35,18 @@ namespace CarCareTracker.Logic
private readonly IUserRecordDataAccess _userData; private readonly IUserRecordDataAccess _userData;
private readonly ITokenRecordDataAccess _tokenData; private readonly ITokenRecordDataAccess _tokenData;
private readonly IMailHelper _mailHelper; private readonly IMailHelper _mailHelper;
private readonly IConfigHelper _configHelper;
private IMemoryCache _cache; private IMemoryCache _cache;
public LoginLogic(IUserRecordDataAccess userData, public LoginLogic(IUserRecordDataAccess userData,
ITokenRecordDataAccess tokenData, ITokenRecordDataAccess tokenData,
IMailHelper mailHelper, IMailHelper mailHelper,
IConfigHelper configHelper,
IMemoryCache memoryCache) IMemoryCache memoryCache)
{ {
_userData = userData; _userData = userData;
_tokenData = tokenData; _tokenData = tokenData;
_mailHelper = mailHelper; _mailHelper = mailHelper;
_configHelper = configHelper;
_cache = memoryCache; _cache = memoryCache;
} }
public bool CheckIfUserIsValid(int userId) public bool CheckIfUserIsValid(int userId)
@@ -59,6 +64,89 @@ namespace CarCareTracker.Logic
return result.Id != 0; return result.Id != 0;
} }
} }
public OperationResponse UpdateUserDetails(int userId, LoginModel credentials)
{
//get current user details
var existingUser = _userData.GetUserRecordById(userId);
if (existingUser.Id == default)
{
return new OperationResponse { Success = false, Message = "Invalid user" };
}
//validate user token
var existingToken = _tokenData.GetTokenRecordByBody(credentials.Token);
if (existingToken.Id == default || existingToken.EmailAddress != existingUser.EmailAddress)
{
return new OperationResponse { Success = false, Message = "Invalid Token" };
}
if (!string.IsNullOrWhiteSpace(credentials.UserName) && existingUser.UserName != credentials.UserName)
{
//check if new username is already taken.
var existingUserWithUserName = _userData.GetUserRecordByUserName(credentials.UserName);
if (existingUserWithUserName.Id != default)
{
return new OperationResponse { Success = false, Message = "Username already taken" };
}
existingUser.UserName = credentials.UserName;
}
if (!string.IsNullOrWhiteSpace(credentials.EmailAddress) && existingUser.EmailAddress != credentials.EmailAddress)
{
//check if email address already exists
var existingUserWithEmailAddress = _userData.GetUserRecordByEmailAddress(credentials.EmailAddress);
if (existingUserWithEmailAddress.Id != default)
{
return new OperationResponse { Success = false, Message = "A user with that email already exists" };
}
existingUser.EmailAddress = credentials.EmailAddress;
}
if (!string.IsNullOrWhiteSpace(credentials.Password))
{
//update password
existingUser.Password = GetHash(credentials.Password);
}
//delete token
_tokenData.DeleteToken(existingToken.Id);
var result = _userData.SaveUserRecord(existingUser);
return new OperationResponse { Success = result, Message = result ? "User Updated" : StaticHelper.GenericErrorMessage };
}
public OperationResponse RegisterOpenIdUser(LoginModel credentials)
{
//validate their token.
var existingToken = _tokenData.GetTokenRecordByBody(credentials.Token);
if (existingToken.Id == default || existingToken.EmailAddress != credentials.EmailAddress)
{
return new OperationResponse { Success = false, Message = "Invalid Token" };
}
if (string.IsNullOrWhiteSpace(credentials.EmailAddress) || string.IsNullOrWhiteSpace(credentials.UserName))
{
return new OperationResponse { Success = false, Message = "Username cannot be blank" };
}
var existingUser = _userData.GetUserRecordByUserName(credentials.UserName);
if (existingUser.Id != default)
{
return new OperationResponse { Success = false, Message = "Username already taken" };
}
var existingUserWithEmail = _userData.GetUserRecordByEmailAddress(credentials.EmailAddress);
if (existingUserWithEmail.Id != default)
{
return new OperationResponse { Success = false, Message = "A user with that email already exists" };
}
_tokenData.DeleteToken(existingToken.Id);
var newUser = new UserData()
{
UserName = credentials.UserName,
Password = GetHash(NewToken()), //generate a password for OpenID User
EmailAddress = credentials.EmailAddress
};
var result = _userData.SaveUserRecord(newUser);
if (result)
{
return new OperationResponse { Success = true, Message = "You will be logged in briefly." };
}
else
{
return new OperationResponse { Success = false, Message = "Something went wrong, please try again later." };
}
}
//handles user registration //handles user registration
public OperationResponse RegisterNewUser(LoginModel credentials) public OperationResponse RegisterNewUser(LoginModel credentials)
{ {
@@ -112,21 +200,7 @@ namespace CarCareTracker.Logic
if (existingUser.Id != default) if (existingUser.Id != default)
{ {
//user exists, generate a token and send email. //user exists, generate a token and send email.
//check to see if there is an existing token sent to the user. GenerateTokenForEmailAddress(existingUser.EmailAddress, true);
var existingToken = _tokenData.GetTokenRecordByEmailAddress(existingUser.EmailAddress);
if (existingToken.Id == default)
{
var token = new Token()
{
Body = NewToken(),
EmailAddress = existingUser.EmailAddress
};
var result = _tokenData.CreateNewToken(token);
if (result)
{
result = _mailHelper.NotifyUserForPasswordReset(existingUser.EmailAddress, token.Body).Success;
}
}
} }
//for security purposes we want to always return true for this method. //for security purposes we want to always return true for this method.
//otherwise someone can spam the reset password method to sniff out users. //otherwise someone can spam the reset password method to sniff out users.
@@ -175,7 +249,8 @@ namespace CarCareTracker.Logic
Id = -1, Id = -1,
UserName = credentials.UserName, UserName = credentials.UserName,
IsAdmin = true, IsAdmin = true,
IsRootUser = true IsRootUser = true,
EmailAddress = string.Empty
}; };
} }
else else
@@ -193,6 +268,19 @@ namespace CarCareTracker.Logic
} }
} }
} }
public UserData ValidateOpenIDUser(LoginModel credentials)
{
var result = _userData.GetUserRecordByEmailAddress(credentials.EmailAddress);
if (result.Id != default)
{
result.Password = string.Empty;
return result;
}
else
{
return new UserData();
}
}
#region "Admin Functions" #region "Admin Functions"
public bool MakeUserAdmin(int userId, bool isAdmin) public bool MakeUserAdmin(int userId, bool isAdmin)
{ {
@@ -280,19 +368,32 @@ namespace CarCareTracker.Logic
#region "Root User" #region "Root User"
public bool CreateRootUserCredentials(LoginModel credentials) public bool CreateRootUserCredentials(LoginModel credentials)
{ {
var configFileContents = File.ReadAllText(StaticHelper.UserConfigPath); //check if file exists
var existingUserConfig = JsonSerializer.Deserialize<UserConfig>(configFileContents); if (File.Exists(StaticHelper.UserConfigPath))
if (existingUserConfig is not null)
{ {
//create hashes of the login credentials. var configFileContents = File.ReadAllText(StaticHelper.UserConfigPath);
var hashedUserName = GetHash(credentials.UserName); var existingUserConfig = JsonSerializer.Deserialize<UserConfig>(configFileContents);
var hashedPassword = GetHash(credentials.Password); if (existingUserConfig is not null)
//copy over settings that are off limits on the settings page. {
existingUserConfig.EnableAuth = true; //create hashes of the login credentials.
existingUserConfig.UserNameHash = hashedUserName; var hashedUserName = GetHash(credentials.UserName);
existingUserConfig.UserPasswordHash = hashedPassword; var hashedPassword = GetHash(credentials.Password);
//copy over settings that are off limits on the settings page.
existingUserConfig.EnableAuth = true;
existingUserConfig.UserNameHash = hashedUserName;
existingUserConfig.UserPasswordHash = hashedPassword;
}
File.WriteAllText(StaticHelper.UserConfigPath, JsonSerializer.Serialize(existingUserConfig));
} else
{
var newUserConfig = new UserConfig()
{
EnableAuth = true,
UserNameHash = GetHash(credentials.UserName),
UserPasswordHash = GetHash(credentials.Password)
};
File.WriteAllText(StaticHelper.UserConfigPath, JsonSerializer.Serialize(newUserConfig));
} }
File.WriteAllText(StaticHelper.UserConfigPath, JsonSerializer.Serialize(existingUserConfig));
_cache.Remove("userConfig_-1"); _cache.Remove("userConfig_-1");
return true; return true;
} }
@@ -314,21 +415,9 @@ namespace CarCareTracker.Logic
} }
private bool UserIsRoot(LoginModel credentials) private bool UserIsRoot(LoginModel credentials)
{ {
var configFileContents = File.ReadAllText(StaticHelper.UserConfigPath); var hashedUserName = GetHash(credentials.UserName);
var existingUserConfig = JsonSerializer.Deserialize<UserConfig>(configFileContents); var hashedPassword = GetHash(credentials.Password);
if (existingUserConfig is not null) return _configHelper.AuthenticateRootUser(hashedUserName, hashedPassword);
{
//create hashes of the login credentials.
var hashedUserName = GetHash(credentials.UserName);
var hashedPassword = GetHash(credentials.Password);
//compare against stored hash.
if (hashedUserName == existingUserConfig.UserNameHash &&
hashedPassword == existingUserConfig.UserPasswordHash)
{
return true;
}
}
return false;
} }
#endregion #endregion
private static string GetHash(string value) private static string GetHash(string value)
@@ -350,5 +439,30 @@ namespace CarCareTracker.Logic
{ {
return Guid.NewGuid().ToString().Substring(0, 8); return Guid.NewGuid().ToString().Substring(0, 8);
} }
public bool GenerateTokenForEmailAddress(string emailAddress, bool isPasswordReset)
{
bool result = false;
//check if there is already a token tied to this email address.
var existingToken = _tokenData.GetTokenRecordByEmailAddress(emailAddress);
if (existingToken.Id == default)
{
//no token, generate one and send.
var token = new Token()
{
Body = NewToken(),
EmailAddress = emailAddress
};
result = _tokenData.CreateNewToken(token);
if (result)
{
result = isPasswordReset ? _mailHelper.NotifyUserForPasswordReset(emailAddress, token.Body).Success : _mailHelper.NotifyUserForAccountUpdate(emailAddress, token.Body).Success;
}
} else
{
//token exists, send it again.
result = isPasswordReset ? _mailHelper.NotifyUserForPasswordReset(emailAddress, existingToken.Body).Success : _mailHelper.NotifyUserForAccountUpdate(emailAddress, existingToken.Body).Success;
}
return result;
}
} }
} }

67
Logic/OdometerLogic.cs Normal file
View File

@@ -0,0 +1,67 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
namespace CarCareTracker.Logic
{
public interface IOdometerLogic
{
int GetLastOdometerRecordMileage(int vehicleId, List<OdometerRecord> odometerRecords);
bool AutoInsertOdometerRecord(OdometerRecord odometer);
List<OdometerRecord> AutoConvertOdometerRecord(List<OdometerRecord> odometerRecords);
}
public class OdometerLogic: IOdometerLogic
{
private readonly IOdometerRecordDataAccess _odometerRecordDataAccess;
private readonly ILogger<IOdometerLogic> _logger;
public OdometerLogic(IOdometerRecordDataAccess odometerRecordDataAccess, ILogger<IOdometerLogic> logger)
{
_odometerRecordDataAccess = odometerRecordDataAccess;
_logger = logger;
}
public int GetLastOdometerRecordMileage(int vehicleId, List<OdometerRecord> odometerRecords)
{
if (!odometerRecords.Any())
{
odometerRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
}
if (!odometerRecords.Any())
{
//no existing odometer records for this vehicle.
return 0;
}
return odometerRecords.Max(x => x.Mileage);
}
public bool AutoInsertOdometerRecord(OdometerRecord odometer)
{
var lastReportedMileage = GetLastOdometerRecordMileage(odometer.VehicleId, new List<OdometerRecord>());
odometer.InitialMileage = lastReportedMileage != default ? lastReportedMileage : odometer.Mileage;
var result = _odometerRecordDataAccess.SaveOdometerRecordToVehicle(odometer);
return result;
}
public List<OdometerRecord> AutoConvertOdometerRecord(List<OdometerRecord> odometerRecords)
{
//perform ordering
odometerRecords = odometerRecords.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList();
int previousMileage = 0;
for (int i = 0; i < odometerRecords.Count; i++)
{
var currentObject = odometerRecords[i];
if (previousMileage == default)
{
//first record
currentObject.InitialMileage = currentObject.Mileage;
}
else
{
//subsequent records
currentObject.InitialMileage = previousMileage;
}
//save to db.
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(currentObject);
previousMileage = currentObject.Mileage;
}
return odometerRecords;
}
}
}

View File

@@ -1,7 +1,6 @@
using CarCareTracker.External.Interfaces; using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper; using CarCareTracker.Helper;
using CarCareTracker.Models; using CarCareTracker.Models;
using Microsoft.AspNetCore.Mvc.Formatters;
namespace CarCareTracker.Logic namespace CarCareTracker.Logic
{ {
@@ -48,6 +47,12 @@ namespace CarCareTracker.Logic
if (existingUser.Id != default) if (existingUser.Id != default)
{ {
//user exists. //user exists.
//check if user is already a collaborator
var userAccess = _userAccess.GetUserAccessByVehicleAndUserId(existingUser.Id, vehicleId);
if (userAccess != null)
{
return new OperationResponse { Success = false, Message = "User is already a collaborator" };
}
var result = AddUserAccessToVehicle(existingUser.Id, vehicleId); var result = AddUserAccessToVehicle(existingUser.Id, vehicleId);
if (result) if (result)
{ {

107
Logic/VehicleLogic.cs Normal file
View File

@@ -0,0 +1,107 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
namespace CarCareTracker.Logic
{
public interface IVehicleLogic
{
int GetMaxMileage(int vehicleId);
int GetMinMileage(int vehicleId);
bool GetVehicleHasUrgentOrPastDueReminders(int vehicleId);
}
public class VehicleLogic: IVehicleLogic
{
private readonly IServiceRecordDataAccess _serviceRecordDataAccess;
private readonly IGasRecordDataAccess _gasRecordDataAccess;
private readonly ICollisionRecordDataAccess _collisionRecordDataAccess;
private readonly IUpgradeRecordDataAccess _upgradeRecordDataAccess;
private readonly IOdometerRecordDataAccess _odometerRecordDataAccess;
private readonly IReminderRecordDataAccess _reminderRecordDataAccess;
private readonly IReminderHelper _reminderHelper;
public VehicleLogic(
IServiceRecordDataAccess serviceRecordDataAccess,
IGasRecordDataAccess gasRecordDataAccess,
ICollisionRecordDataAccess collisionRecordDataAccess,
IUpgradeRecordDataAccess upgradeRecordDataAccess,
IOdometerRecordDataAccess odometerRecordDataAccess,
IReminderRecordDataAccess reminderRecordDataAccess,
IReminderHelper reminderHelper
) {
_serviceRecordDataAccess = serviceRecordDataAccess;
_gasRecordDataAccess = gasRecordDataAccess;
_collisionRecordDataAccess = collisionRecordDataAccess;
_upgradeRecordDataAccess = upgradeRecordDataAccess;
_odometerRecordDataAccess = odometerRecordDataAccess;
_reminderRecordDataAccess = reminderRecordDataAccess;
_reminderHelper = reminderHelper;
}
public int GetMaxMileage(int vehicleId)
{
var numbersArray = new List<int>();
var serviceRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId);
if (serviceRecords.Any())
{
numbersArray.Add(serviceRecords.Max(x => x.Mileage));
}
var repairRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId);
if (repairRecords.Any())
{
numbersArray.Add(repairRecords.Max(x => x.Mileage));
}
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
if (gasRecords.Any())
{
numbersArray.Add(gasRecords.Max(x => x.Mileage));
}
var upgradeRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
if (upgradeRecords.Any())
{
numbersArray.Add(upgradeRecords.Max(x => x.Mileage));
}
var odometerRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
if (odometerRecords.Any())
{
numbersArray.Add(odometerRecords.Max(x => x.Mileage));
}
return numbersArray.Any() ? numbersArray.Max() : 0;
}
public int GetMinMileage(int vehicleId)
{
var numbersArray = new List<int>();
var serviceRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId).Where(x => x.Mileage != default);
if (serviceRecords.Any())
{
numbersArray.Add(serviceRecords.Min(x => x.Mileage));
}
var repairRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId).Where(x => x.Mileage != default);
if (repairRecords.Any())
{
numbersArray.Add(repairRecords.Min(x => x.Mileage));
}
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId).Where(x => x.Mileage != default);
if (gasRecords.Any())
{
numbersArray.Add(gasRecords.Min(x => x.Mileage));
}
var upgradeRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId).Where(x => x.Mileage != default);
if (upgradeRecords.Any())
{
numbersArray.Add(upgradeRecords.Min(x => x.Mileage));
}
var odometerRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId).Where(x => x.Mileage != default);
if (odometerRecords.Any())
{
numbersArray.Add(odometerRecords.Min(x => x.Mileage));
}
return numbersArray.Any() ? numbersArray.Min() : 0;
}
public bool GetVehicleHasUrgentOrPastDueReminders(int vehicleId)
{
var currentMileage = GetMaxMileage(vehicleId);
var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId);
var results = _reminderHelper.GetReminderRecordViewModels(reminders, currentMileage, DateTime.Now);
return results.Any(x => x.Urgency == ReminderUrgency.VeryUrgent || x.Urgency == ReminderUrgency.PastDue);
}
}
}

View File

@@ -10,6 +10,7 @@ namespace CarCareTracker.MapProfile
Map(m => m.Date).Name(["date", "fuelup_date"]); Map(m => m.Date).Name(["date", "fuelup_date"]);
Map(m => m.DateCreated).Name(["datecreated"]); Map(m => m.DateCreated).Name(["datecreated"]);
Map(m => m.DateModified).Name(["datemodified"]); Map(m => m.DateModified).Name(["datemodified"]);
Map(m => m.InitialOdometer).Name(["initialodometer"]);
Map(m => m.Odometer).Name(["odometer"]); Map(m => m.Odometer).Name(["odometer"]);
Map(m => m.FuelConsumed).Name(["gallons", "liters", "litres", "consumption", "quantity", "fuelconsumed"]); Map(m => m.FuelConsumed).Name(["gallons", "liters", "litres", "consumption", "quantity", "fuelconsumed"]);
Map(m => m.Cost).Name(["cost", "total cost", "totalcost", "total price"]); Map(m => m.Cost).Name(["cost", "total cost", "totalcost", "total price"]);

View File

@@ -1,9 +1,7 @@
using CarCareTracker.Logic; using CarCareTracker.Logic;
using CarCareTracker.Models; using CarCareTracker.Models;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System.Security.Claims; using System.Security.Claims;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
@@ -123,6 +121,7 @@ namespace CarCareTracker.Middleware
{ {
new(ClaimTypes.Name, authCookie.UserData.UserName), new(ClaimTypes.Name, authCookie.UserData.UserName),
new(ClaimTypes.NameIdentifier, authCookie.UserData.Id.ToString()), new(ClaimTypes.NameIdentifier, authCookie.UserData.Id.ToString()),
new(ClaimTypes.Email, authCookie.UserData.EmailAddress),
new(ClaimTypes.Role, "CookieAuth") new(ClaimTypes.Role, "CookieAuth")
}; };
if (authCookie.UserData.IsAdmin) if (authCookie.UserData.IsAdmin)
@@ -157,7 +156,13 @@ namespace CarCareTracker.Middleware
return Task.CompletedTask; return Task.CompletedTask;
} }
} }
Response.Redirect("/Login/Index"); if (Request.Path.Value == "/Vehicle/Index" && Request.QueryString.HasValue)
{
Response.Redirect($"/Login/Index?redirectURL={Request.Path.Value}{Request.QueryString.Value}");
} else
{
Response.Redirect("/Login/Index");
}
return Task.CompletedTask; return Task.CompletedTask;
} }
protected override Task HandleForbiddenAsync(AuthenticationProperties properties) protected override Task HandleForbiddenAsync(AuthenticationProperties properties)
@@ -170,7 +175,7 @@ namespace CarCareTracker.Middleware
return Task.CompletedTask; return Task.CompletedTask;
} }
} }
Response.Redirect("/Error/401"); Response.Redirect("/Error/Unauthorized");
return Task.CompletedTask; return Task.CompletedTask;
} }
} }

View File

@@ -4,6 +4,7 @@
{ {
public int Id { get; set; } public int Id { get; set; }
public int VehicleId { get; set; } public int VehicleId { get; set; }
public List<int> ReminderRecordId { get; set; } = new List<int>();
public string Date { get; set; } = DateTime.Now.ToShortDateString(); public string Date { get; set; } = DateTime.Now.ToShortDateString();
public int Mileage { get; set; } public int Mileage { get; set; }
public string Description { get; set; } public string Description { get; set; }
@@ -12,6 +13,22 @@
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>(); public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
public List<SupplyUsage> Supplies { get; set; } = new List<SupplyUsage>(); public List<SupplyUsage> Supplies { get; set; } = new List<SupplyUsage>();
public List<string> Tags { get; set; } = new List<string>(); public List<string> Tags { get; set; } = new List<string>();
public CollisionRecord ToCollisionRecord() { return new CollisionRecord { Id = Id, VehicleId = VehicleId, Date = DateTime.Parse(Date), Cost = Cost, Mileage = Mileage, Description = Description, Notes = Notes, Files = Files, Tags = Tags }; } public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
public List<SupplyUsageHistory> RequisitionHistory { get; set; } = new List<SupplyUsageHistory>();
public bool CopySuppliesAttachment { get; set; } = false;
public CollisionRecord ToCollisionRecord() { return new CollisionRecord {
Id = Id,
VehicleId = VehicleId,
Date = DateTime.Parse(Date),
Cost = Cost,
Mileage = Mileage,
Description = Description,
Notes = Notes,
Files = Files,
Tags = Tags,
ExtraFields = ExtraFields,
RequisitionHistory = RequisitionHistory
};
}
} }
} }

View File

@@ -19,5 +19,6 @@
public string Notes { get; set; } public string Notes { get; set; }
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>(); public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
public List<string> Tags { get; set; } = new List<string>(); public List<string> Tags { get; set; } = new List<string>();
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
} }
} }

View File

@@ -0,0 +1,8 @@
namespace CarCareTracker.Models
{
public class GasRecordEditModel
{
public List<int> RecordIds { get; set; } = new List<int>();
public GasRecord EditRecord { get; set; } = new GasRecord();
}
}

View File

@@ -19,6 +19,7 @@
public string Notes { get; set; } public string Notes { get; set; }
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>(); public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
public List<string> Tags { get; set; } = new List<string>(); public List<string> Tags { get; set; } = new List<string>();
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
public GasRecord ToGasRecord() { return new GasRecord { public GasRecord ToGasRecord() { return new GasRecord {
Id = Id, Id = Id,
Cost = Cost, Cost = Cost,
@@ -30,7 +31,8 @@
IsFillToFull = IsFillToFull, IsFillToFull = IsFillToFull,
MissedFuelUp = MissedFuelUp, MissedFuelUp = MissedFuelUp,
Notes = Notes, Notes = Notes,
Tags = Tags Tags = Tags,
ExtraFields = ExtraFields
}; } }; }
} }
} }

View File

@@ -22,6 +22,7 @@
public bool MissedFuelUp { get; set; } public bool MissedFuelUp { get; set; }
public string Notes { get; set; } public string Notes { get; set; }
public List<string> Tags { get; set; } = new List<string>(); public List<string> Tags { get; set; } = new List<string>();
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
public bool IncludeInAverage { get { return MilesPerGallon > 0 || (!IsFillToFull && !MissedFuelUp); } } public bool IncludeInAverage { get { return MilesPerGallon > 0 || (!IsFillToFull && !MissedFuelUp); } }
} }
} }

View File

@@ -0,0 +1,9 @@
namespace CarCareTracker.Models
{
public class GenericRecordEditModel
{
public ImportMode DataType { get; set; }
public List<int> RecordIds { get; set; } = new List<int>();
public GenericRecord EditRecord { get; set; } = new GenericRecord();
}
}

View File

@@ -8,5 +8,6 @@
public string NoteText { get; set; } public string NoteText { get; set; }
public bool Pinned { get; set; } public bool Pinned { get; set; }
public List<string> Tags { get; set; } = new List<string>(); public List<string> Tags { get; set; } = new List<string>();
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
} }
} }

View File

@@ -0,0 +1,18 @@
namespace CarCareTracker.Models
{
public class OpenIDConfig
{
public string Name { get; set; }
public string ClientId { get; set; }
public string ClientSecret { get; set; }
public string AuthURL { get; set; }
public string TokenURL { get; set; }
public string RedirectURL { get; set; }
public string Scope { get; set; }
public string State { get; set; }
public bool ValidateState { get; set; } = false;
public bool DisableRegularLogin { get; set; } = false;
public string LogOutURL { get; set; } = "";
public string RemoteAuthURL { get { return $"{AuthURL}?client_id={ClientId}&response_type=code&redirect_uri={RedirectURL}&scope={Scope}&state={State}"; } }
}
}

View File

@@ -0,0 +1,7 @@
namespace CarCareTracker.Models
{
public class OpenIDResult
{
public string id_token { get; set; }
}
}

View File

@@ -5,9 +5,12 @@
public int Id { get; set; } public int Id { get; set; }
public int VehicleId { get; set; } public int VehicleId { get; set; }
public DateTime Date { get; set; } public DateTime Date { get; set; }
public int InitialMileage { get; set; }
public int Mileage { get; set; } public int Mileage { get; set; }
public int DistanceTraveled { get { return Mileage - InitialMileage; } }
public string Notes { get; set; } public string Notes { get; set; }
public List<string> Tags { get; set; } = new List<string>(); public List<string> Tags { get; set; } = new List<string>();
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>(); public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
} }
} }

View File

@@ -0,0 +1,8 @@
namespace CarCareTracker.Models
{
public class OdometerRecordEditModel
{
public List<int> RecordIds { get; set; } = new List<int>();
public OdometerRecord EditRecord { get; set; } = new OdometerRecord();
}
}

View File

@@ -5,10 +5,12 @@
public int Id { get; set; } public int Id { get; set; }
public int VehicleId { get; set; } public int VehicleId { get; set; }
public string Date { get; set; } = DateTime.Now.ToShortDateString(); public string Date { get; set; } = DateTime.Now.ToShortDateString();
public int InitialMileage { get; set; }
public int Mileage { get; set; } public int Mileage { get; set; }
public string Notes { get; set; } public string Notes { get; set; }
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>(); public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
public List<string> Tags { get; set; } = new List<string>(); public List<string> Tags { get; set; } = new List<string>();
public OdometerRecord ToOdometerRecord() { return new OdometerRecord { Id = Id, VehicleId = VehicleId, Date = DateTime.Parse(Date), Mileage = Mileage, Notes = Notes, Files = Files, Tags = Tags }; } public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
public OdometerRecord ToOdometerRecord() { return new OdometerRecord { Id = Id, VehicleId = VehicleId, Date = DateTime.Parse(Date), Mileage = Mileage, Notes = Notes, Files = Files, Tags = Tags, ExtraFields = ExtraFields, InitialMileage = InitialMileage }; }
} }
} }

View File

@@ -1,8 +0,0 @@
namespace CarCareTracker.Models
{
public class PlanCostItem
{
public string CostName { get; set; }
public decimal CostAmount { get; set; }
}
}

View File

@@ -4,6 +4,7 @@
{ {
public int Id { get; set; } public int Id { get; set; }
public int VehicleId { get; set; } public int VehicleId { get; set; }
public int ReminderRecordId { get; set; }
public DateTime DateCreated { get; set; } public DateTime DateCreated { get; set; }
public DateTime DateModified { get; set; } public DateTime DateModified { get; set; }
public string Description { get; set; } public string Description { get; set; }
@@ -13,5 +14,7 @@
public PlanPriority Priority { get; set; } public PlanPriority Priority { get; set; }
public PlanProgress Progress { get; set; } public PlanProgress Progress { get; set; }
public decimal Cost { get; set; } public decimal Cost { get; set; }
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
public List<SupplyUsageHistory> RequisitionHistory { get; set; } = new List<SupplyUsageHistory>();
} }
} }

View File

@@ -4,6 +4,7 @@
{ {
public int Id { get; set; } public int Id { get; set; }
public int VehicleId { get; set; } public int VehicleId { get; set; }
public int ReminderRecordId { get; set; }
public string DateCreated { get; set; } = DateTime.Now.ToShortDateString(); public string DateCreated { get; set; } = DateTime.Now.ToShortDateString();
public string DateModified { get; set; } = DateTime.Now.ToShortDateString(); public string DateModified { get; set; } = DateTime.Now.ToShortDateString();
public string Description { get; set; } public string Description { get; set; }
@@ -14,9 +15,13 @@
public PlanPriority Priority { get; set; } public PlanPriority Priority { get; set; }
public PlanProgress Progress { get; set; } public PlanProgress Progress { get; set; }
public decimal Cost { get; set; } public decimal Cost { get; set; }
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
public List<SupplyUsageHistory> RequisitionHistory { get; set; } = new List<SupplyUsageHistory>();
public bool CopySuppliesAttachment { get; set; } = false;
public PlanRecord ToPlanRecord() { return new PlanRecord { public PlanRecord ToPlanRecord() { return new PlanRecord {
Id = Id, Id = Id,
VehicleId = VehicleId, VehicleId = VehicleId,
ReminderRecordId = ReminderRecordId,
DateCreated = DateTime.Parse(DateCreated), DateCreated = DateTime.Parse(DateCreated),
DateModified = DateTime.Parse(DateModified), DateModified = DateTime.Parse(DateModified),
Description = Description, Description = Description,
@@ -25,7 +30,13 @@
ImportMode = ImportMode, ImportMode = ImportMode,
Cost = Cost, Cost = Cost,
Priority = Priority, Priority = Priority,
Progress = Progress Progress = Progress,
ExtraFields = ExtraFields,
RequisitionHistory = RequisitionHistory
}; } }; }
/// <summary>
/// only used to hide view template button on plan create modal.
/// </summary>
public bool CreatedFromReminder { get; set; }
} }
} }

View File

@@ -0,0 +1,10 @@
namespace CarCareTracker.Models
{
public class ReminderUrgencyConfig
{
public int UrgentDays { get; set; } = 30;
public int VeryUrgentDays { get; set; } = 7;
public int UrgentDistance { get; set; } = 100;
public int VeryUrgentDistance { get; set; } = 50;
}
}

View File

@@ -10,8 +10,10 @@
public string Notes { get; set; } public string Notes { get; set; }
public bool IsRecurring { get; set; } = false; public bool IsRecurring { get; set; } = false;
public int CustomMileageInterval { get; set; } = 0; public int CustomMileageInterval { get; set; } = 0;
public int CustomMonthInterval { get; set; } = 0;
public ReminderMileageInterval ReminderMileageInterval { get; set; } = ReminderMileageInterval.FiveThousandMiles; public ReminderMileageInterval ReminderMileageInterval { get; set; } = ReminderMileageInterval.FiveThousandMiles;
public ReminderMonthInterval ReminderMonthInterval { get; set; } = ReminderMonthInterval.OneYear; public ReminderMonthInterval ReminderMonthInterval { get; set; } = ReminderMonthInterval.OneYear;
public ReminderMetric Metric { get; set; } = ReminderMetric.Date; public ReminderMetric Metric { get; set; } = ReminderMetric.Date;
public List<string> Tags { get; set; } = new List<string>();
} }
} }

Some files were not shown because too many files have changed in this diff Show More