Compare commits
296 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b6a6787bb | ||
|
|
7302982366 | ||
|
|
19b7dfc90a | ||
|
|
29825a6ad6 | ||
|
|
f6493f0496 | ||
|
|
c2d61eecc0 | ||
|
|
2a4354c52e | ||
|
|
e7dc4f67f5 | ||
|
|
8584d2cf9c | ||
|
|
92b9c6953c | ||
|
|
ac1c2ca7fe | ||
|
|
f05ca7f1f8 | ||
|
|
ecef1c8640 | ||
|
|
43d58a4b7e | ||
|
|
8293b376a2 | ||
|
|
c243cdd54c | ||
|
|
0383257356 | ||
|
|
73e8731bd4 | ||
|
|
b0e82889e0 | ||
|
|
8e28116371 | ||
|
|
ed717af91c | ||
|
|
7ae5a982e9 | ||
|
|
2e3f1e6763 | ||
|
|
4a2e02afc8 | ||
|
|
9c53850faa | ||
|
|
695b15faed | ||
|
|
33aeaf9825 | ||
|
|
dc3608524a | ||
|
|
6996814888 | ||
|
|
9bbaf49ade | ||
|
|
db737df712 | ||
|
|
bae1839c06 | ||
|
|
7e70f5108f | ||
|
|
c5c0a6900b | ||
|
|
50b88dd7a1 | ||
|
|
e44eb991f5 | ||
|
|
39d0d346ad | ||
|
|
142865f1ce | ||
|
|
2c18755a0f | ||
|
|
d3be77bf09 | ||
|
|
bcafd9e97e | ||
|
|
f581e55842 | ||
|
|
dfe4e4f1ab | ||
|
|
080e2a1667 | ||
|
|
01cbee00fd | ||
|
|
f0869c741f | ||
|
|
6dc690011d | ||
|
|
65891c7c11 | ||
|
|
d306152d38 | ||
|
|
b372f64e11 | ||
|
|
baff93bd96 | ||
|
|
abbe13b269 | ||
|
|
fb43932e0d | ||
|
|
c10aa73e5e | ||
|
|
be09f3e9dd | ||
|
|
d3f94337ae | ||
|
|
46a227453e | ||
|
|
8981d69844 | ||
|
|
09fbc37472 | ||
|
|
5cee1ea7cf | ||
|
|
cd9a673e62 | ||
|
|
dd9f754e85 | ||
|
|
7d22d1ddc4 | ||
|
|
d5f562b48f | ||
|
|
bb64ee4012 | ||
|
|
a60430b4b2 | ||
|
|
117a172bc2 | ||
|
|
b93b7f321e | ||
|
|
f34f3da587 | ||
|
|
8104f852d8 | ||
|
|
32e58e6280 | ||
|
|
c4dc81e4bc | ||
|
|
9fe0396abe | ||
|
|
ad2b58697a | ||
|
|
4845b02fc8 | ||
|
|
1ed53d5e4b | ||
|
|
00622126d7 | ||
|
|
b5cdd66248 | ||
|
|
78408427b8 | ||
|
|
baf9e8e833 | ||
|
|
bde00a26d5 | ||
|
|
6be6a2196e | ||
|
|
b8dab3d4a4 | ||
|
|
447c929386 | ||
|
|
9e37c01a83 | ||
|
|
3d39dc8ed8 | ||
|
|
08ace8b08d | ||
|
|
cbf95b1e04 | ||
|
|
fd8f93ee5f | ||
|
|
4f146f9427 | ||
|
|
19ace06c08 | ||
|
|
4bfe947ce1 | ||
|
|
4850b38e7f | ||
|
|
e5f19c5f20 | ||
|
|
8c4212678f | ||
|
|
573e80728c | ||
|
|
c88fa690f6 | ||
|
|
1feb89acf5 | ||
|
|
8be252e949 | ||
|
|
3aaf230a60 | ||
|
|
27126638be | ||
|
|
8c3a001930 | ||
|
|
2b2f181888 | ||
|
|
66557fa126 | ||
|
|
7c00951d74 | ||
|
|
1087ed56ce | ||
|
|
dd2cfd90b1 | ||
|
|
e45339f75c | ||
|
|
9c225ff7a0 | ||
|
|
6cdfba420f | ||
|
|
cc43d45c9c | ||
|
|
dba51f171d | ||
|
|
0bbf9f783f | ||
|
|
a52ac6a41b | ||
|
|
a542c91dc3 | ||
|
|
6bcbb0cc86 | ||
|
|
7a78d51c79 | ||
|
|
3c2715840e | ||
|
|
dfbd90aaf4 | ||
|
|
2b3a4ce8ce | ||
|
|
135292f2b4 | ||
|
|
499c697b0b | ||
|
|
fb74f01609 | ||
|
|
6ab2216742 | ||
|
|
7c97aa70a0 | ||
|
|
ff255e8293 | ||
|
|
57dc976a9f | ||
|
|
13361241e8 | ||
|
|
332af9a04a | ||
|
|
961c60f936 | ||
|
|
34483886be | ||
|
|
548989f9ae | ||
|
|
83a59aff37 | ||
|
|
60f28b16e7 | ||
|
|
9cb8bbd5b7 | ||
|
|
f7c95e9b36 | ||
|
|
cd37eedd15 | ||
|
|
7d11c4003f | ||
|
|
7d9b67a04d | ||
|
|
aba178a324 | ||
|
|
4ecdaf5225 | ||
|
|
c0bc9f7a14 | ||
|
|
094d96d880 | ||
|
|
a8fad6f160 | ||
|
|
6befd5ca76 | ||
|
|
046812ff27 | ||
|
|
db1778a749 | ||
|
|
f27fa1625c | ||
|
|
39a9d5f95b | ||
|
|
234d7163fc | ||
|
|
6f64cc9996 | ||
|
|
58e3b49bdf | ||
|
|
ca2dc1e1e0 | ||
|
|
c65dca4c58 | ||
|
|
82c2351b00 | ||
|
|
f31ca163e5 | ||
|
|
351db5de95 | ||
|
|
41164516f7 | ||
|
|
29a3c815fc | ||
|
|
1768063e57 | ||
|
|
35ce5603e5 | ||
|
|
19e38f9885 | ||
|
|
c55528b8a0 | ||
|
|
1c00f31312 | ||
|
|
8e66530544 | ||
|
|
7bdd3d902b | ||
|
|
abb44608fe | ||
|
|
0b1e3f4be8 | ||
|
|
156eb8ec27 | ||
|
|
472dcac590 | ||
|
|
b4d86f415c | ||
|
|
812e768f93 | ||
|
|
a08d4798e1 | ||
|
|
7bc08c9950 | ||
|
|
20107e3f05 | ||
|
|
ed678c36a5 | ||
|
|
f7574a9a60 | ||
|
|
e506b543e6 | ||
|
|
019a549b64 | ||
|
|
8dbc883a8c | ||
|
|
5fd918115c | ||
|
|
a11f8377fe | ||
|
|
7be19f8603 | ||
|
|
5407ebecb1 | ||
|
|
b75a1b4e6c | ||
|
|
1c28039aaf | ||
|
|
3a1836ef84 | ||
|
|
c747889f85 | ||
|
|
338a8426b2 | ||
|
|
4b1701d158 | ||
|
|
5d64a9a422 | ||
|
|
c2315db127 | ||
|
|
e40129f701 | ||
|
|
d198ad9a6b | ||
|
|
abffc5ab60 | ||
|
|
24ff9db32d | ||
|
|
07fa560344 | ||
|
|
28615d9038 | ||
|
|
d8f53e4b65 | ||
|
|
1f0cef4161 | ||
|
|
af5d72e0d0 | ||
|
|
1397e92709 | ||
|
|
a49121b1d9 | ||
|
|
ca65a6fb71 | ||
|
|
a54857c6bf | ||
|
|
2eadd05289 | ||
|
|
6eafa5e036 | ||
|
|
40f01ad100 | ||
|
|
161b36325e | ||
|
|
f9a6ddd513 | ||
|
|
e85110f8b6 | ||
|
|
76d3dba574 | ||
|
|
178b50a033 | ||
|
|
fb45aefde3 | ||
|
|
05bbc8a95b | ||
|
|
f123299dd6 | ||
|
|
7174413e2a | ||
|
|
d816f73598 | ||
|
|
b249ccdd6c | ||
|
|
4a007530a6 | ||
|
|
04ce448b23 | ||
|
|
ccd446f299 | ||
|
|
c49c8a5301 | ||
|
|
55cc2819d0 | ||
|
|
f8de7de0d6 | ||
|
|
2ea1bc2c20 | ||
|
|
90d095ea51 | ||
|
|
e1d12d0918 | ||
|
|
d9d0957040 | ||
|
|
9d73db3c51 | ||
|
|
c0f0786fd4 | ||
|
|
357eff116f | ||
|
|
32a047c522 | ||
|
|
8a237bb7ec | ||
|
|
f5b9072cc6 | ||
|
|
4e3eaa53ff | ||
|
|
4779d3f161 | ||
|
|
b0173fae94 | ||
|
|
c6ee8830a3 | ||
|
|
c2eeab5025 | ||
|
|
43fd40347f | ||
|
|
53139f9bb2 | ||
|
|
0b6033cc00 | ||
|
|
6f0115e5c5 | ||
|
|
2403adf537 | ||
|
|
f00ab897b5 | ||
|
|
093631bf6f | ||
|
|
5c2835ab76 | ||
|
|
03029981fd | ||
|
|
69b1838038 | ||
|
|
1c2f83026c | ||
|
|
d36f2c59e3 | ||
|
|
53ebec3f03 | ||
|
|
f2cbbaeb12 | ||
|
|
31c1202649 | ||
|
|
331499461a | ||
|
|
8c6dd5e343 | ||
|
|
01b1e8228d | ||
|
|
43979d6115 | ||
|
|
6a9860e202 | ||
|
|
39338e8028 | ||
|
|
d1d5351a01 | ||
|
|
c9385c7fdd | ||
|
|
afaae89af6 | ||
|
|
b9d799cd49 | ||
|
|
e47c541e08 | ||
|
|
51ff01d2cd | ||
|
|
618399cb09 | ||
|
|
b837a2e528 | ||
|
|
a1e8b8f9cc | ||
|
|
787c5da72a | ||
|
|
260703be8e | ||
|
|
053801b046 | ||
|
|
db9b1970c5 | ||
|
|
b153ef5ea5 | ||
|
|
b54809f399 | ||
|
|
f7f47c54ff | ||
|
|
92564ae527 | ||
|
|
52ada8574d | ||
|
|
013fb67943 | ||
|
|
d86298f502 | ||
|
|
5891b78be0 | ||
|
|
a9e3e44f2c | ||
|
|
0d1c7234e8 | ||
|
|
e3abe5f209 | ||
|
|
b453bfce5b | ||
|
|
147a1b03a7 | ||
|
|
3017db5f86 | ||
|
|
399d0d8058 | ||
|
|
b8c0d4ef67 | ||
|
|
918d086705 | ||
|
|
ac05acf96b | ||
|
|
e7449806c0 | ||
|
|
baab3213b5 | ||
|
|
d68e9e9589 | ||
|
|
dbb139dfad |
3
.env
3
.env
@@ -5,4 +5,5 @@ MailConfig__EmailFrom=""
|
|||||||
MailConfig__UseSSL="false"
|
MailConfig__UseSSL="false"
|
||||||
MailConfig__Port=587
|
MailConfig__Port=587
|
||||||
MailConfig__Username=""
|
MailConfig__Username=""
|
||||||
MailConfig__Password=""
|
MailConfig__Password=""
|
||||||
|
LOGGING__LOGLEVEL__DEFAULT=Error
|
||||||
51
.github/workflows/build-and-push-image.yml
vendored
Normal file
51
.github/workflows/build-and-push-image.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
name: Build and Push Image to Dockerhub and GHCR
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
release:
|
||||||
|
types: ["published"]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: "${{ secrets.DH_USER }}"
|
||||||
|
password: "${{ secrets.DH_PASS }}"
|
||||||
|
|
||||||
|
- name: Login to GitHub Container Registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: "hargata"
|
||||||
|
password: "${{ secrets.GHCR_PAT }}"
|
||||||
|
|
||||||
|
- name: Docker Metadata
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v5
|
||||||
|
with:
|
||||||
|
context: workflow
|
||||||
|
images: |
|
||||||
|
hargata/lubelogger
|
||||||
|
ghcr.io/hargata/lubelogger
|
||||||
|
tags: |
|
||||||
|
type=edge,branch=main
|
||||||
|
type=ref,event=tag
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
30
.github/workflows/dockerhub-docker-image.yml
vendored
30
.github/workflows/dockerhub-docker-image.yml
vendored
@@ -1,30 +0,0 @@
|
|||||||
name: Docker Image To Docker Hub
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "main" ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
build:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: "${{ secrets.DH_USER }}"
|
|
||||||
password: "${{ secrets.DH_PASS }}"
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
tags: |
|
|
||||||
hargata/lubelogger:latest
|
|
||||||
31
.github/workflows/ghcr-docker-image.yml
vendored
31
.github/workflows/ghcr-docker-image.yml
vendored
@@ -1,31 +0,0 @@
|
|||||||
name: Docker Image To GHCR
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "main" ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
build:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: "hargata"
|
|
||||||
password: "${{ secrets.GHCR_PAT }}"
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
tags: |
|
|
||||||
ghcr.io/hargata/lubelogger:latest
|
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -7,3 +7,7 @@ data/cartracker.db
|
|||||||
wwwroot/documents/
|
wwwroot/documents/
|
||||||
wwwroot/temp/
|
wwwroot/temp/
|
||||||
wwwroot/imports/
|
wwwroot/imports/
|
||||||
|
wwwroot/translations/
|
||||||
|
config/userConfig.json
|
||||||
|
CarCareTracker.csproj.user
|
||||||
|
Properties/launchSettings.json
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
<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="Npgsql" Version="8.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<View_SelectedScaffolderID>RazorViewEmptyScaffolder</View_SelectedScaffolderID>
|
|
||||||
<View_SelectedScaffolderCategoryPath>root/Common/MVC/View</View_SelectedScaffolderCategoryPath>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -22,10 +22,14 @@ namespace CarCareTracker.Controllers
|
|||||||
private readonly IReminderRecordDataAccess _reminderRecordDataAccess;
|
private readonly IReminderRecordDataAccess _reminderRecordDataAccess;
|
||||||
private readonly IUpgradeRecordDataAccess _upgradeRecordDataAccess;
|
private readonly IUpgradeRecordDataAccess _upgradeRecordDataAccess;
|
||||||
private readonly IOdometerRecordDataAccess _odometerRecordDataAccess;
|
private readonly IOdometerRecordDataAccess _odometerRecordDataAccess;
|
||||||
|
private readonly IUserAccessDataAccess _userAccessDataAccess;
|
||||||
|
private readonly IUserRecordDataAccess _userRecordDataAccess;
|
||||||
private readonly IReminderHelper _reminderHelper;
|
private readonly IReminderHelper _reminderHelper;
|
||||||
private readonly IGasHelper _gasHelper;
|
private readonly IGasHelper _gasHelper;
|
||||||
private readonly IUserLogic _userLogic;
|
private readonly IUserLogic _userLogic;
|
||||||
private readonly IFileHelper _fileHelper;
|
private readonly IFileHelper _fileHelper;
|
||||||
|
private readonly IMailHelper _mailHelper;
|
||||||
|
private readonly IConfigHelper _config;
|
||||||
public APIController(IVehicleDataAccess dataAccess,
|
public APIController(IVehicleDataAccess dataAccess,
|
||||||
IGasHelper gasHelper,
|
IGasHelper gasHelper,
|
||||||
IReminderHelper reminderHelper,
|
IReminderHelper reminderHelper,
|
||||||
@@ -37,7 +41,11 @@ namespace CarCareTracker.Controllers
|
|||||||
IReminderRecordDataAccess reminderRecordDataAccess,
|
IReminderRecordDataAccess reminderRecordDataAccess,
|
||||||
IUpgradeRecordDataAccess upgradeRecordDataAccess,
|
IUpgradeRecordDataAccess upgradeRecordDataAccess,
|
||||||
IOdometerRecordDataAccess odometerRecordDataAccess,
|
IOdometerRecordDataAccess odometerRecordDataAccess,
|
||||||
|
IUserAccessDataAccess userAccessDataAccess,
|
||||||
|
IUserRecordDataAccess userRecordDataAccess,
|
||||||
|
IMailHelper mailHelper,
|
||||||
IFileHelper fileHelper,
|
IFileHelper fileHelper,
|
||||||
|
IConfigHelper config,
|
||||||
IUserLogic userLogic)
|
IUserLogic userLogic)
|
||||||
{
|
{
|
||||||
_dataAccess = dataAccess;
|
_dataAccess = dataAccess;
|
||||||
@@ -49,10 +57,14 @@ namespace CarCareTracker.Controllers
|
|||||||
_reminderRecordDataAccess = reminderRecordDataAccess;
|
_reminderRecordDataAccess = reminderRecordDataAccess;
|
||||||
_upgradeRecordDataAccess = upgradeRecordDataAccess;
|
_upgradeRecordDataAccess = upgradeRecordDataAccess;
|
||||||
_odometerRecordDataAccess = odometerRecordDataAccess;
|
_odometerRecordDataAccess = odometerRecordDataAccess;
|
||||||
|
_userAccessDataAccess = userAccessDataAccess;
|
||||||
|
_userRecordDataAccess = userRecordDataAccess;
|
||||||
|
_mailHelper = mailHelper;
|
||||||
_gasHelper = gasHelper;
|
_gasHelper = gasHelper;
|
||||||
_reminderHelper = reminderHelper;
|
_reminderHelper = reminderHelper;
|
||||||
_userLogic = userLogic;
|
_userLogic = userLogic;
|
||||||
_fileHelper = fileHelper;
|
_fileHelper = fileHelper;
|
||||||
|
_config = config;
|
||||||
}
|
}
|
||||||
public IActionResult Index()
|
public IActionResult Index()
|
||||||
{
|
{
|
||||||
@@ -117,6 +129,17 @@ 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)
|
||||||
|
};
|
||||||
|
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(odometerRecord);
|
||||||
|
}
|
||||||
response.Success = true;
|
response.Success = true;
|
||||||
response.Message = "Service Record Added";
|
response.Message = "Service Record Added";
|
||||||
return Json(response);
|
return Json(response);
|
||||||
@@ -173,6 +196,17 @@ 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)
|
||||||
|
};
|
||||||
|
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(odometerRecord);
|
||||||
|
}
|
||||||
response.Success = true;
|
response.Success = true;
|
||||||
response.Message = "Repair Record Added";
|
response.Message = "Repair Record Added";
|
||||||
return Json(response);
|
return Json(response);
|
||||||
@@ -229,6 +263,17 @@ 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)
|
||||||
|
};
|
||||||
|
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(odometerRecord);
|
||||||
|
}
|
||||||
response.Success = true;
|
response.Success = true;
|
||||||
response.Message = "Upgrade Record Added";
|
response.Message = "Upgrade Record Added";
|
||||||
return Json(response);
|
return Json(response);
|
||||||
@@ -404,6 +449,17 @@ 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)
|
||||||
|
};
|
||||||
|
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(odometerRecord);
|
||||||
|
}
|
||||||
response.Success = true;
|
response.Success = true;
|
||||||
response.Message = "Gas Record Added";
|
response.Message = "Gas Record Added";
|
||||||
return Json(response);
|
return Json(response);
|
||||||
@@ -428,12 +484,65 @@ namespace CarCareTracker.Controllers
|
|||||||
}
|
}
|
||||||
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
[Route("/api/vehicle/reminders/send")]
|
||||||
|
public IActionResult SendReminders(List<ReminderUrgency> urgencies)
|
||||||
|
{
|
||||||
|
var vehicles = _dataAccess.GetVehicles();
|
||||||
|
List<OperationResponse> operationResponses = new List<OperationResponse>();
|
||||||
|
foreach(Vehicle vehicle in vehicles)
|
||||||
|
{
|
||||||
|
var vehicleId = vehicle.Id;
|
||||||
|
//get reminders
|
||||||
|
var currentMileage = GetMaxMileage(vehicleId);
|
||||||
|
var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId);
|
||||||
|
var results = _reminderHelper.GetReminderRecordViewModels(reminders, currentMileage, DateTime.Now).OrderByDescending(x => x.Urgency).ToList();
|
||||||
|
results.RemoveAll(x => !urgencies.Contains(x.Urgency));
|
||||||
|
if (!results.Any())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//get list of recipients.
|
||||||
|
var userIds = _userAccessDataAccess.GetUserAccessByVehicleId(vehicleId).Select(x => x.Id.UserId);
|
||||||
|
List<string> emailRecipients = new List<string>();
|
||||||
|
foreach (int userId in userIds)
|
||||||
|
{
|
||||||
|
var userData = _userRecordDataAccess.GetUserRecordById(userId);
|
||||||
|
emailRecipients.Add(userData.EmailAddress);
|
||||||
|
};
|
||||||
|
if (!emailRecipients.Any())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var result = _mailHelper.NotifyUserForReminders(vehicle, emailRecipients, results);
|
||||||
|
operationResponses.Add(result);
|
||||||
|
}
|
||||||
|
if (operationResponses.All(x => x.Success))
|
||||||
|
{
|
||||||
|
return Json(new OperationResponse { Success = true, Message = "Emails sent" });
|
||||||
|
} else if (operationResponses.All(x => !x.Success))
|
||||||
|
{
|
||||||
|
return Json(new OperationResponse { Success = false, Message = "All emails failed, check SMTP settings" });
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return Json(new OperationResponse { Success = true, Message = "Some emails sent, some failed, check recipient settings" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||||
|
[HttpGet]
|
||||||
[Route("/api/makebackup")]
|
[Route("/api/makebackup")]
|
||||||
public IActionResult MakeBackup()
|
public IActionResult MakeBackup()
|
||||||
{
|
{
|
||||||
var result = _fileHelper.MakeBackup();
|
var result = _fileHelper.MakeBackup();
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
|
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||||
|
[HttpGet]
|
||||||
|
[Route("/api/demo/restore")]
|
||||||
|
public IActionResult RestoreDemo()
|
||||||
|
{
|
||||||
|
var result = _fileHelper.RestoreBackup("/defaults/demo_default.zip", true);
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
private int GetMaxMileage(int vehicleId)
|
private int GetMaxMileage(int vehicleId)
|
||||||
{
|
{
|
||||||
var numbersArray = new List<int>();
|
var numbersArray = new List<int>();
|
||||||
|
|||||||
@@ -33,6 +33,26 @@ namespace CarCareTracker.Controllers
|
|||||||
return Json(fileName);
|
return Json(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult HandleTranslationFileUpload(IFormFile file)
|
||||||
|
{
|
||||||
|
var originalFileName = Path.GetFileNameWithoutExtension(file.FileName);
|
||||||
|
if (originalFileName == "en_US")
|
||||||
|
{
|
||||||
|
return Json(new OperationResponse { Success = false, Message = "The translation file name en_US is reserved." });
|
||||||
|
}
|
||||||
|
var fileName = UploadFile(file);
|
||||||
|
//move file from temp to translation folder.
|
||||||
|
var uploadedFilePath = _fileHelper.MoveFileFromTemp(fileName, "translations/");
|
||||||
|
//rename uploaded file so that it preserves original name.
|
||||||
|
if (!string.IsNullOrWhiteSpace(uploadedFilePath))
|
||||||
|
{
|
||||||
|
var result = _fileHelper.RenameFile(uploadedFilePath, originalFileName);
|
||||||
|
return Json(new OperationResponse { Success = result, Message = string.Empty });
|
||||||
|
}
|
||||||
|
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage });
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult HandleMultipleFileUpload(List<IFormFile> file)
|
public IActionResult HandleMultipleFileUpload(List<IFormFile> file)
|
||||||
{
|
{
|
||||||
@@ -44,7 +64,7 @@ namespace CarCareTracker.Controllers
|
|||||||
}
|
}
|
||||||
return Json(uploadedFiles);
|
return Json(uploadedFiles);
|
||||||
}
|
}
|
||||||
|
[Authorize(Roles = nameof(UserData.IsRootUser))]
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult DeleteFiles(string fileLocation)
|
public IActionResult DeleteFiles(string fileLocation)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,17 +15,28 @@ 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 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,
|
||||||
IConfigHelper configuration)
|
IConfigHelper configuration,
|
||||||
|
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;
|
||||||
|
_extraFieldDataAccess = extraFieldDataAccess;
|
||||||
|
_reminderRecordDataAccess = reminderRecordDataAccess;
|
||||||
|
_reminderHelper = reminderHelper;
|
||||||
}
|
}
|
||||||
private int GetUserID()
|
private int GetUserID()
|
||||||
{
|
{
|
||||||
@@ -44,10 +55,45 @@ namespace CarCareTracker.Controllers
|
|||||||
}
|
}
|
||||||
return PartialView("_GarageDisplay", vehiclesStored);
|
return PartialView("_GarageDisplay", vehiclesStored);
|
||||||
}
|
}
|
||||||
|
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 maxMileage = vehicleReminders.Max(x => x.Mileage) + 1000;
|
||||||
|
var reminderUrgency = _reminderHelper.GetReminderRecordViewModels(vehicleReminders, maxMileage, 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 }, reminder.Mileage + 1000, DateTime.Now).FirstOrDefault();
|
||||||
|
return PartialView("_ReminderRecordCalendarModal", reminderUrgency);
|
||||||
|
}
|
||||||
public IActionResult Settings()
|
public IActionResult Settings()
|
||||||
{
|
{
|
||||||
var userConfig = _config.GetUserConfig(User);
|
var userConfig = _config.GetUserConfig(User);
|
||||||
return PartialView("_Settings", userConfig);
|
var languages = _fileHelper.GetLanguages();
|
||||||
|
var viewModel = new SettingsViewModel
|
||||||
|
{
|
||||||
|
UserConfig = userConfig,
|
||||||
|
UILanguages = languages
|
||||||
|
};
|
||||||
|
return PartialView("_Settings", viewModel);
|
||||||
}
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult WriteToSettings(UserConfig userConfig)
|
public IActionResult WriteToSettings(UserConfig userConfig)
|
||||||
@@ -59,7 +105,30 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
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);
|
||||||
|
}
|
||||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||||
public IActionResult Error()
|
public IActionResult Error()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ namespace CarCareTracker.Controllers
|
|||||||
_logger = logger;
|
_logger = logger;
|
||||||
_loginLogic = loginLogic;
|
_loginLogic = loginLogic;
|
||||||
}
|
}
|
||||||
public IActionResult Index()
|
public IActionResult Index(string redirectURL = "")
|
||||||
{
|
{
|
||||||
return View();
|
return View(model: redirectURL);
|
||||||
}
|
}
|
||||||
public IActionResult Registration()
|
public IActionResult Registration()
|
||||||
{
|
{
|
||||||
|
|||||||
757
Controllers/MigrationController.cs
Normal file
757
Controllers/MigrationController.cs
Normal file
@@ -0,0 +1,757 @@
|
|||||||
|
using CarCareTracker.External.Implementations;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using LiteDB;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ namespace CarCareTracker.Controllers
|
|||||||
private readonly IUpgradeRecordDataAccess _upgradeRecordDataAccess;
|
private readonly IUpgradeRecordDataAccess _upgradeRecordDataAccess;
|
||||||
private readonly ISupplyRecordDataAccess _supplyRecordDataAccess;
|
private readonly ISupplyRecordDataAccess _supplyRecordDataAccess;
|
||||||
private readonly IPlanRecordDataAccess _planRecordDataAccess;
|
private readonly IPlanRecordDataAccess _planRecordDataAccess;
|
||||||
|
private readonly IPlanRecordTemplateDataAccess _planRecordTemplateDataAccess;
|
||||||
private readonly IOdometerRecordDataAccess _odometerRecordDataAccess;
|
private readonly IOdometerRecordDataAccess _odometerRecordDataAccess;
|
||||||
private readonly IWebHostEnvironment _webEnv;
|
private readonly IWebHostEnvironment _webEnv;
|
||||||
private readonly IConfigHelper _config;
|
private readonly IConfigHelper _config;
|
||||||
@@ -35,6 +36,7 @@ namespace CarCareTracker.Controllers
|
|||||||
private readonly IReminderHelper _reminderHelper;
|
private readonly IReminderHelper _reminderHelper;
|
||||||
private readonly IReportHelper _reportHelper;
|
private readonly IReportHelper _reportHelper;
|
||||||
private readonly IUserLogic _userLogic;
|
private readonly IUserLogic _userLogic;
|
||||||
|
private readonly IExtraFieldDataAccess _extraFieldDataAccess;
|
||||||
|
|
||||||
public VehicleController(ILogger<VehicleController> logger,
|
public VehicleController(ILogger<VehicleController> logger,
|
||||||
IFileHelper fileHelper,
|
IFileHelper fileHelper,
|
||||||
@@ -51,7 +53,9 @@ namespace CarCareTracker.Controllers
|
|||||||
IUpgradeRecordDataAccess upgradeRecordDataAccess,
|
IUpgradeRecordDataAccess upgradeRecordDataAccess,
|
||||||
ISupplyRecordDataAccess supplyRecordDataAccess,
|
ISupplyRecordDataAccess supplyRecordDataAccess,
|
||||||
IPlanRecordDataAccess planRecordDataAccess,
|
IPlanRecordDataAccess planRecordDataAccess,
|
||||||
|
IPlanRecordTemplateDataAccess planRecordTemplateDataAccess,
|
||||||
IOdometerRecordDataAccess odometerRecordDataAccess,
|
IOdometerRecordDataAccess odometerRecordDataAccess,
|
||||||
|
IExtraFieldDataAccess extraFieldDataAccess,
|
||||||
IUserLogic userLogic,
|
IUserLogic userLogic,
|
||||||
IWebHostEnvironment webEnv,
|
IWebHostEnvironment webEnv,
|
||||||
IConfigHelper config)
|
IConfigHelper config)
|
||||||
@@ -71,7 +75,9 @@ namespace CarCareTracker.Controllers
|
|||||||
_upgradeRecordDataAccess = upgradeRecordDataAccess;
|
_upgradeRecordDataAccess = upgradeRecordDataAccess;
|
||||||
_supplyRecordDataAccess = supplyRecordDataAccess;
|
_supplyRecordDataAccess = supplyRecordDataAccess;
|
||||||
_planRecordDataAccess = planRecordDataAccess;
|
_planRecordDataAccess = planRecordDataAccess;
|
||||||
|
_planRecordTemplateDataAccess = planRecordTemplateDataAccess;
|
||||||
_odometerRecordDataAccess = odometerRecordDataAccess;
|
_odometerRecordDataAccess = odometerRecordDataAccess;
|
||||||
|
_extraFieldDataAccess = extraFieldDataAccess;
|
||||||
_userLogic = userLogic;
|
_userLogic = userLogic;
|
||||||
_webEnv = webEnv;
|
_webEnv = webEnv;
|
||||||
_config = config;
|
_config = config;
|
||||||
@@ -85,6 +91,7 @@ namespace CarCareTracker.Controllers
|
|||||||
public IActionResult Index(int vehicleId)
|
public IActionResult Index(int vehicleId)
|
||||||
{
|
{
|
||||||
var data = _dataAccess.GetVehicleById(vehicleId);
|
var data = _dataAccess.GetVehicleById(vehicleId);
|
||||||
|
UpdateRecurringTaxes(vehicleId);
|
||||||
return View(data);
|
return View(data);
|
||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -141,6 +148,7 @@ namespace CarCareTracker.Controllers
|
|||||||
_reminderRecordDataAccess.DeleteAllReminderRecordsByVehicleId(vehicleId) &&
|
_reminderRecordDataAccess.DeleteAllReminderRecordsByVehicleId(vehicleId) &&
|
||||||
_upgradeRecordDataAccess.DeleteAllUpgradeRecordsByVehicleId(vehicleId) &&
|
_upgradeRecordDataAccess.DeleteAllUpgradeRecordsByVehicleId(vehicleId) &&
|
||||||
_planRecordDataAccess.DeleteAllPlanRecordsByVehicleId(vehicleId) &&
|
_planRecordDataAccess.DeleteAllPlanRecordsByVehicleId(vehicleId) &&
|
||||||
|
_planRecordTemplateDataAccess.DeleteAllPlanRecordTemplatesByVehicleId(vehicleId) &&
|
||||||
_supplyRecordDataAccess.DeleteAllSupplyRecordsByVehicleId(vehicleId) &&
|
_supplyRecordDataAccess.DeleteAllSupplyRecordsByVehicleId(vehicleId) &&
|
||||||
_userLogic.DeleteAllAccessToVehicle(vehicleId) &&
|
_userLogic.DeleteAllAccessToVehicle(vehicleId) &&
|
||||||
_dataAccess.DeleteVehicle(vehicleId);
|
_dataAccess.DeleteVehicle(vehicleId);
|
||||||
@@ -156,7 +164,7 @@ namespace CarCareTracker.Controllers
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult ExportFromVehicleToCsv(int vehicleId, ImportMode mode)
|
public IActionResult ExportFromVehicleToCsv(int vehicleId, ImportMode mode)
|
||||||
{
|
{
|
||||||
if (vehicleId == default)
|
if (vehicleId == default && mode != ImportMode.SupplyRecord)
|
||||||
{
|
{
|
||||||
return Json(false);
|
return Json(false);
|
||||||
}
|
}
|
||||||
@@ -171,7 +179,7 @@ namespace CarCareTracker.Controllers
|
|||||||
var vehicleRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId);
|
var vehicleRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId);
|
||||||
if (vehicleRecords.Any())
|
if (vehicleRecords.Any())
|
||||||
{
|
{
|
||||||
var exportData = vehicleRecords.Select(x => new ServiceRecordExportModel { Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString("C"), Notes = x.Notes, Odometer = x.Mileage.ToString() });
|
var exportData = vehicleRecords.Select(x => new ServiceRecordExportModel { Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString("C"), Notes = x.Notes, Odometer = x.Mileage.ToString(), Tags = string.Join(" ", x.Tags) });
|
||||||
using (var writer = new StreamWriter(fullExportFilePath))
|
using (var writer = new StreamWriter(fullExportFilePath))
|
||||||
{
|
{
|
||||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||||
@@ -189,7 +197,7 @@ namespace CarCareTracker.Controllers
|
|||||||
var vehicleRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId);
|
var vehicleRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId);
|
||||||
if (vehicleRecords.Any())
|
if (vehicleRecords.Any())
|
||||||
{
|
{
|
||||||
var exportData = vehicleRecords.Select(x => new ServiceRecordExportModel { Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString("C"), Notes = x.Notes, Odometer = x.Mileage.ToString() });
|
var exportData = vehicleRecords.Select(x => new ServiceRecordExportModel { Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString("C"), Notes = x.Notes, Odometer = x.Mileage.ToString(), Tags = string.Join(" ", x.Tags) });
|
||||||
using (var writer = new StreamWriter(fullExportFilePath))
|
using (var writer = new StreamWriter(fullExportFilePath))
|
||||||
{
|
{
|
||||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||||
@@ -207,7 +215,7 @@ namespace CarCareTracker.Controllers
|
|||||||
var vehicleRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
|
var vehicleRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
|
||||||
if (vehicleRecords.Any())
|
if (vehicleRecords.Any())
|
||||||
{
|
{
|
||||||
var exportData = vehicleRecords.Select(x => new ServiceRecordExportModel { Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString("C"), Notes = x.Notes, Odometer = x.Mileage.ToString() });
|
var exportData = vehicleRecords.Select(x => new ServiceRecordExportModel { Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString("C"), Notes = x.Notes, Odometer = x.Mileage.ToString(), Tags = string.Join(" ", x.Tags) });
|
||||||
using (var writer = new StreamWriter(fullExportFilePath))
|
using (var writer = new StreamWriter(fullExportFilePath))
|
||||||
{
|
{
|
||||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||||
@@ -225,7 +233,7 @@ namespace CarCareTracker.Controllers
|
|||||||
var vehicleRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
|
var vehicleRecords = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId);
|
||||||
if (vehicleRecords.Any())
|
if (vehicleRecords.Any())
|
||||||
{
|
{
|
||||||
var exportData = vehicleRecords.Select(x => new OdometerRecordExportModel { Date = x.Date.ToShortDateString(), Notes = x.Notes, Odometer = x.Mileage.ToString() });
|
var exportData = vehicleRecords.Select(x => new OdometerRecordExportModel { Date = x.Date.ToShortDateString(), Notes = x.Notes, Odometer = x.Mileage.ToString(), Tags = string.Join(" ", x.Tags) });
|
||||||
using (var writer = new StreamWriter(fullExportFilePath))
|
using (var writer = new StreamWriter(fullExportFilePath))
|
||||||
{
|
{
|
||||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||||
@@ -251,7 +259,8 @@ namespace CarCareTracker.Controllers
|
|||||||
PartNumber = x.PartNumber,
|
PartNumber = x.PartNumber,
|
||||||
PartQuantity = x.Quantity.ToString(),
|
PartQuantity = x.Quantity.ToString(),
|
||||||
PartSupplier = x.PartSupplier,
|
PartSupplier = x.PartSupplier,
|
||||||
Notes = x.Notes
|
Notes = x.Notes,
|
||||||
|
Tags = string.Join(" ", x.Tags)
|
||||||
});
|
});
|
||||||
using (var writer = new StreamWriter(fullExportFilePath))
|
using (var writer = new StreamWriter(fullExportFilePath))
|
||||||
{
|
{
|
||||||
@@ -270,7 +279,7 @@ namespace CarCareTracker.Controllers
|
|||||||
var vehicleRecords = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId);
|
var vehicleRecords = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId);
|
||||||
if (vehicleRecords.Any())
|
if (vehicleRecords.Any())
|
||||||
{
|
{
|
||||||
var exportData = vehicleRecords.Select(x => new TaxRecordExportModel { Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString("C"), Notes = x.Notes });
|
var exportData = vehicleRecords.Select(x => new TaxRecordExportModel { Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString("C"), Notes = x.Notes, Tags = string.Join(" ", x.Tags) });
|
||||||
using (var writer = new StreamWriter(fullExportFilePath))
|
using (var writer = new StreamWriter(fullExportFilePath))
|
||||||
{
|
{
|
||||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||||
@@ -316,7 +325,6 @@ namespace CarCareTracker.Controllers
|
|||||||
var vehicleRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
var vehicleRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
||||||
bool useMPG = _config.GetUserConfig(User).UseMPG;
|
bool useMPG = _config.GetUserConfig(User).UseMPG;
|
||||||
bool useUKMPG = _config.GetUserConfig(User).UseUKMPG;
|
bool useUKMPG = _config.GetUserConfig(User).UseUKMPG;
|
||||||
vehicleRecords = vehicleRecords.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList();
|
|
||||||
var convertedRecords = _gasHelper.GetGasRecordViewModels(vehicleRecords, useMPG, useUKMPG);
|
var convertedRecords = _gasHelper.GetGasRecordViewModels(vehicleRecords, useMPG, useUKMPG);
|
||||||
var exportData = convertedRecords.Select(x => new GasRecordExportModel
|
var exportData = convertedRecords.Select(x => new GasRecordExportModel
|
||||||
{
|
{
|
||||||
@@ -327,7 +335,8 @@ namespace CarCareTracker.Controllers
|
|||||||
Odometer = x.Mileage.ToString(),
|
Odometer = x.Mileage.ToString(),
|
||||||
IsFillToFull = x.IsFillToFull.ToString(),
|
IsFillToFull = x.IsFillToFull.ToString(),
|
||||||
MissedFuelUp = x.MissedFuelUp.ToString(),
|
MissedFuelUp = x.MissedFuelUp.ToString(),
|
||||||
Notes = x.Notes
|
Notes = x.Notes,
|
||||||
|
Tags = string.Join(" ", x.Tags)
|
||||||
});
|
});
|
||||||
using (var writer = new StreamWriter(fullExportFilePath))
|
using (var writer = new StreamWriter(fullExportFilePath))
|
||||||
{
|
{
|
||||||
@@ -344,7 +353,11 @@ namespace CarCareTracker.Controllers
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult ImportToVehicleIdFromCsv(int vehicleId, ImportMode mode, string fileName)
|
public IActionResult ImportToVehicleIdFromCsv(int vehicleId, ImportMode mode, string fileName)
|
||||||
{
|
{
|
||||||
if (vehicleId == default || string.IsNullOrWhiteSpace(fileName))
|
if (vehicleId == default && mode != ImportMode.SupplyRecord)
|
||||||
|
{
|
||||||
|
return Json(false);
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(fileName))
|
||||||
{
|
{
|
||||||
return Json(false);
|
return Json(false);
|
||||||
}
|
}
|
||||||
@@ -376,9 +389,10 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
VehicleId = vehicleId,
|
VehicleId = vehicleId,
|
||||||
Date = DateTime.Parse(importModel.Date),
|
Date = DateTime.Parse(importModel.Date),
|
||||||
Mileage = int.Parse(importModel.Odometer, NumberStyles.Any),
|
Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)),
|
||||||
Gallons = decimal.Parse(importModel.FuelConsumed, NumberStyles.Any),
|
Gallons = decimal.Parse(importModel.FuelConsumed, NumberStyles.Any),
|
||||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes
|
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||||
|
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||||
};
|
};
|
||||||
if (string.IsNullOrWhiteSpace(importModel.Cost) && !string.IsNullOrWhiteSpace(importModel.Price))
|
if (string.IsNullOrWhiteSpace(importModel.Cost) && !string.IsNullOrWhiteSpace(importModel.Price))
|
||||||
{
|
{
|
||||||
@@ -420,10 +434,11 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
VehicleId = vehicleId,
|
VehicleId = vehicleId,
|
||||||
Date = DateTime.Parse(importModel.Date),
|
Date = DateTime.Parse(importModel.Date),
|
||||||
Mileage = int.Parse(importModel.Odometer, NumberStyles.Any),
|
Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)),
|
||||||
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Service Record on {importModel.Date}" : importModel.Description,
|
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Service Record on {importModel.Date}" : importModel.Description,
|
||||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any)
|
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||||
|
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||||
};
|
};
|
||||||
_serviceRecordDataAccess.SaveServiceRecordToVehicle(convertedRecord);
|
_serviceRecordDataAccess.SaveServiceRecordToVehicle(convertedRecord);
|
||||||
}
|
}
|
||||||
@@ -433,8 +448,9 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
VehicleId = vehicleId,
|
VehicleId = vehicleId,
|
||||||
Date = DateTime.Parse(importModel.Date),
|
Date = DateTime.Parse(importModel.Date),
|
||||||
Mileage = int.Parse(importModel.Odometer, NumberStyles.Any),
|
Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)),
|
||||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes
|
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||||
|
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||||
};
|
};
|
||||||
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(convertedRecord);
|
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(convertedRecord);
|
||||||
}
|
}
|
||||||
@@ -463,10 +479,11 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
VehicleId = vehicleId,
|
VehicleId = vehicleId,
|
||||||
Date = DateTime.Parse(importModel.Date),
|
Date = DateTime.Parse(importModel.Date),
|
||||||
Mileage = int.Parse(importModel.Odometer, NumberStyles.Any),
|
Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)),
|
||||||
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Repair Record on {importModel.Date}" : importModel.Description,
|
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Repair Record on {importModel.Date}" : importModel.Description,
|
||||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any)
|
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||||
|
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||||
};
|
};
|
||||||
_collisionRecordDataAccess.SaveCollisionRecordToVehicle(convertedRecord);
|
_collisionRecordDataAccess.SaveCollisionRecordToVehicle(convertedRecord);
|
||||||
}
|
}
|
||||||
@@ -476,10 +493,11 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
VehicleId = vehicleId,
|
VehicleId = vehicleId,
|
||||||
Date = DateTime.Parse(importModel.Date),
|
Date = DateTime.Parse(importModel.Date),
|
||||||
Mileage = int.Parse(importModel.Odometer, NumberStyles.Any),
|
Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)),
|
||||||
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Upgrade Record on {importModel.Date}" : importModel.Description,
|
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Upgrade Record on {importModel.Date}" : importModel.Description,
|
||||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any)
|
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||||
|
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||||
};
|
};
|
||||||
_upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(convertedRecord);
|
_upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(convertedRecord);
|
||||||
}
|
}
|
||||||
@@ -494,7 +512,8 @@ namespace CarCareTracker.Controllers
|
|||||||
Quantity = decimal.Parse(importModel.PartQuantity, NumberStyles.Any),
|
Quantity = decimal.Parse(importModel.PartQuantity, NumberStyles.Any),
|
||||||
Description = importModel.Description,
|
Description = importModel.Description,
|
||||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||||
Notes = importModel.Notes
|
Notes = importModel.Notes,
|
||||||
|
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||||
};
|
};
|
||||||
_supplyRecordDataAccess.SaveSupplyRecordToVehicle(convertedRecord);
|
_supplyRecordDataAccess.SaveSupplyRecordToVehicle(convertedRecord);
|
||||||
}
|
}
|
||||||
@@ -506,7 +525,8 @@ namespace CarCareTracker.Controllers
|
|||||||
Date = DateTime.Parse(importModel.Date),
|
Date = DateTime.Parse(importModel.Date),
|
||||||
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Tax Record on {importModel.Date}" : importModel.Description,
|
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Tax Record on {importModel.Date}" : importModel.Description,
|
||||||
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
|
||||||
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any)
|
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any),
|
||||||
|
Tags = string.IsNullOrWhiteSpace(importModel.Tags) ? [] : importModel.Tags.Split(" ").ToList()
|
||||||
};
|
};
|
||||||
_taxRecordDataAccess.SaveTaxRecordToVehicle(convertedRecord);
|
_taxRecordDataAccess.SaveTaxRecordToVehicle(convertedRecord);
|
||||||
}
|
}
|
||||||
@@ -529,8 +549,6 @@ namespace CarCareTracker.Controllers
|
|||||||
public IActionResult GetGasRecordsByVehicleId(int vehicleId)
|
public IActionResult GetGasRecordsByVehicleId(int vehicleId)
|
||||||
{
|
{
|
||||||
var result = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
var result = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
||||||
//need it in ascending order to perform computation.
|
|
||||||
result = result.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList();
|
|
||||||
//check if the user uses MPG or Liters per 100km.
|
//check if the user uses MPG or Liters per 100km.
|
||||||
var userConfig = _config.GetUserConfig(User);
|
var userConfig = _config.GetUserConfig(User);
|
||||||
bool useMPG = userConfig.UseMPG;
|
bool useMPG = userConfig.UseMPG;
|
||||||
@@ -540,10 +558,13 @@ namespace CarCareTracker.Controllers
|
|||||||
{
|
{
|
||||||
computedResults = computedResults.OrderByDescending(x => DateTime.Parse(x.Date)).ThenByDescending(x => x.Mileage).ToList();
|
computedResults = computedResults.OrderByDescending(x => DateTime.Parse(x.Date)).ThenByDescending(x => x.Mileage).ToList();
|
||||||
}
|
}
|
||||||
var vehicleIsElectric = _dataAccess.GetVehicleById(vehicleId).IsElectric;
|
var vehicleData = _dataAccess.GetVehicleById(vehicleId);
|
||||||
|
var vehicleIsElectric = vehicleData.IsElectric;
|
||||||
|
var vehicleUseHours = vehicleData.UseHours;
|
||||||
var viewModel = new GasRecordViewModelContainer()
|
var viewModel = new GasRecordViewModelContainer()
|
||||||
{
|
{
|
||||||
UseKwh = vehicleIsElectric,
|
UseKwh = vehicleIsElectric,
|
||||||
|
UseHours = vehicleUseHours,
|
||||||
GasRecords = computedResults
|
GasRecords = computedResults
|
||||||
};
|
};
|
||||||
return PartialView("_Gas", viewModel);
|
return PartialView("_Gas", viewModel);
|
||||||
@@ -566,9 +587,12 @@ namespace CarCareTracker.Controllers
|
|||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetAddGasRecordPartialView()
|
public IActionResult GetAddGasRecordPartialView(int vehicleId)
|
||||||
{
|
{
|
||||||
return PartialView("_GasModal", new GasRecordInputContainer() { GasRecord = new GasRecordInput() });
|
var vehicleData = _dataAccess.GetVehicleById(vehicleId);
|
||||||
|
var vehicleIsElectric = vehicleData.IsElectric;
|
||||||
|
var vehicleUseHours = vehicleData.UseHours;
|
||||||
|
return PartialView("_GasModal", new GasRecordInputContainer() { UseKwh = vehicleIsElectric, UseHours = vehicleUseHours, GasRecord = new GasRecordInput() { ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.GasRecord).ExtraFields } });
|
||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetGasRecordForEditById(int gasRecordId)
|
public IActionResult GetGasRecordForEditById(int gasRecordId)
|
||||||
@@ -585,12 +609,17 @@ namespace CarCareTracker.Controllers
|
|||||||
Gallons = result.Gallons,
|
Gallons = result.Gallons,
|
||||||
IsFillToFull = result.IsFillToFull,
|
IsFillToFull = result.IsFillToFull,
|
||||||
MissedFuelUp = result.MissedFuelUp,
|
MissedFuelUp = result.MissedFuelUp,
|
||||||
Notes = result.Notes
|
Notes = result.Notes,
|
||||||
|
Tags = result.Tags,
|
||||||
|
ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.GasRecord).ExtraFields)
|
||||||
};
|
};
|
||||||
var vehicleIsElectric = _dataAccess.GetVehicleById(convertedResult.VehicleId).IsElectric;
|
var vehicleData = _dataAccess.GetVehicleById(convertedResult.VehicleId);
|
||||||
|
var vehicleIsElectric = vehicleData.IsElectric;
|
||||||
|
var vehicleUseHours = vehicleData.UseHours;
|
||||||
var viewModel = new GasRecordInputContainer()
|
var viewModel = new GasRecordInputContainer()
|
||||||
{
|
{
|
||||||
UseKwh = vehicleIsElectric,
|
UseKwh = vehicleIsElectric,
|
||||||
|
UseHours = vehicleUseHours,
|
||||||
GasRecord = convertedResult
|
GasRecord = convertedResult
|
||||||
};
|
};
|
||||||
return PartialView("_GasModal", viewModel);
|
return PartialView("_GasModal", viewModel);
|
||||||
@@ -601,6 +630,15 @@ namespace CarCareTracker.Controllers
|
|||||||
var result = _gasRecordDataAccess.DeleteGasRecordById(gasRecordId);
|
var result = _gasRecordDataAccess.DeleteGasRecordById(gasRecordId);
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult SaveUserGasTabPreferences(string gasUnit, string fuelMileageUnit)
|
||||||
|
{
|
||||||
|
var currentConfig = _config.GetUserConfig(User);
|
||||||
|
currentConfig.PreferredGasUnit = gasUnit;
|
||||||
|
currentConfig.PreferredGasMileageUnit = fuelMileageUnit;
|
||||||
|
var result = _config.SaveUserConfig(User, currentConfig);
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
#region "Service Records"
|
#region "Service Records"
|
||||||
[TypeFilter(typeof(CollaboratorFilter))]
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
@@ -644,7 +682,7 @@ namespace CarCareTracker.Controllers
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetAddServiceRecordPartialView()
|
public IActionResult GetAddServiceRecordPartialView()
|
||||||
{
|
{
|
||||||
return PartialView("_ServiceRecordModal", new ServiceRecordInput());
|
return PartialView("_ServiceRecordModal", new ServiceRecordInput() { ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.ServiceRecord).ExtraFields });
|
||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetServiceRecordForEditById(int serviceRecordId)
|
public IActionResult GetServiceRecordForEditById(int serviceRecordId)
|
||||||
@@ -660,7 +698,9 @@ namespace CarCareTracker.Controllers
|
|||||||
Mileage = result.Mileage,
|
Mileage = result.Mileage,
|
||||||
Notes = result.Notes,
|
Notes = result.Notes,
|
||||||
VehicleId = result.VehicleId,
|
VehicleId = result.VehicleId,
|
||||||
Files = result.Files
|
Files = result.Files,
|
||||||
|
Tags = result.Tags,
|
||||||
|
ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.ServiceRecord).ExtraFields)
|
||||||
};
|
};
|
||||||
return PartialView("_ServiceRecordModal", convertedResult);
|
return PartialView("_ServiceRecordModal", convertedResult);
|
||||||
}
|
}
|
||||||
@@ -713,7 +753,7 @@ namespace CarCareTracker.Controllers
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetAddCollisionRecordPartialView()
|
public IActionResult GetAddCollisionRecordPartialView()
|
||||||
{
|
{
|
||||||
return PartialView("_CollisionRecordModal", new CollisionRecordInput());
|
return PartialView("_CollisionRecordModal", new CollisionRecordInput() { ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.RepairRecord).ExtraFields });
|
||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetCollisionRecordForEditById(int collisionRecordId)
|
public IActionResult GetCollisionRecordForEditById(int collisionRecordId)
|
||||||
@@ -729,7 +769,9 @@ namespace CarCareTracker.Controllers
|
|||||||
Mileage = result.Mileage,
|
Mileage = result.Mileage,
|
||||||
Notes = result.Notes,
|
Notes = result.Notes,
|
||||||
VehicleId = result.VehicleId,
|
VehicleId = result.VehicleId,
|
||||||
Files = result.Files
|
Files = result.Files,
|
||||||
|
Tags = result.Tags,
|
||||||
|
ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.RepairRecord).ExtraFields)
|
||||||
};
|
};
|
||||||
return PartialView("_CollisionRecordModal", convertedResult);
|
return PartialView("_CollisionRecordModal", convertedResult);
|
||||||
}
|
}
|
||||||
@@ -757,6 +799,44 @@ namespace CarCareTracker.Controllers
|
|||||||
}
|
}
|
||||||
return PartialView("_TaxRecords", result);
|
return PartialView("_TaxRecords", result);
|
||||||
}
|
}
|
||||||
|
private void UpdateRecurringTaxes(int vehicleId)
|
||||||
|
{
|
||||||
|
var result = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId);
|
||||||
|
var recurringFees = result.Where(x => x.IsRecurring);
|
||||||
|
if (recurringFees.Any())
|
||||||
|
{
|
||||||
|
foreach(TaxRecord recurringFee in recurringFees)
|
||||||
|
{
|
||||||
|
var newDate = new DateTime();
|
||||||
|
if (recurringFee.RecurringInterval != ReminderMonthInterval.Other)
|
||||||
|
{
|
||||||
|
newDate = recurringFee.Date.AddMonths((int)recurringFee.RecurringInterval);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
newDate = recurringFee.Date.AddMonths(recurringFee.CustomMonthInterval);
|
||||||
|
}
|
||||||
|
if (DateTime.Now > newDate){
|
||||||
|
recurringFee.IsRecurring = false;
|
||||||
|
var newRecurringFee = new TaxRecord()
|
||||||
|
{
|
||||||
|
VehicleId = recurringFee.VehicleId,
|
||||||
|
Date = newDate,
|
||||||
|
Description = recurringFee.Description,
|
||||||
|
Cost = recurringFee.Cost,
|
||||||
|
IsRecurring = true,
|
||||||
|
Notes = recurringFee.Notes,
|
||||||
|
RecurringInterval = recurringFee.RecurringInterval,
|
||||||
|
CustomMonthInterval = recurringFee.CustomMonthInterval,
|
||||||
|
Files = recurringFee.Files,
|
||||||
|
Tags = recurringFee.Tags,
|
||||||
|
ExtraFields = recurringFee.ExtraFields
|
||||||
|
};
|
||||||
|
_taxRecordDataAccess.SaveTaxRecordToVehicle(recurringFee);
|
||||||
|
_taxRecordDataAccess.SaveTaxRecordToVehicle(newRecurringFee);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult SaveTaxRecordToVehicleId(TaxRecordInput taxRecord)
|
public IActionResult SaveTaxRecordToVehicleId(TaxRecordInput taxRecord)
|
||||||
{
|
{
|
||||||
@@ -768,7 +848,7 @@ namespace CarCareTracker.Controllers
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetAddTaxRecordPartialView()
|
public IActionResult GetAddTaxRecordPartialView()
|
||||||
{
|
{
|
||||||
return PartialView("_TaxRecordModal", new TaxRecordInput());
|
return PartialView("_TaxRecordModal", new TaxRecordInput() { ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.TaxRecord).ExtraFields });
|
||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetTaxRecordForEditById(int taxRecordId)
|
public IActionResult GetTaxRecordForEditById(int taxRecordId)
|
||||||
@@ -783,7 +863,12 @@ namespace CarCareTracker.Controllers
|
|||||||
Description = result.Description,
|
Description = result.Description,
|
||||||
Notes = result.Notes,
|
Notes = result.Notes,
|
||||||
VehicleId = result.VehicleId,
|
VehicleId = result.VehicleId,
|
||||||
Files = result.Files
|
IsRecurring = result.IsRecurring,
|
||||||
|
RecurringInterval = result.RecurringInterval,
|
||||||
|
CustomMonthInterval = result.CustomMonthInterval,
|
||||||
|
Files = result.Files,
|
||||||
|
Tags = result.Tags,
|
||||||
|
ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.TaxRecord).ExtraFields)
|
||||||
};
|
};
|
||||||
return PartialView("_TaxRecordModal", convertedResult);
|
return PartialView("_TaxRecordModal", convertedResult);
|
||||||
}
|
}
|
||||||
@@ -816,7 +901,7 @@ namespace CarCareTracker.Controllers
|
|||||||
UpgradeRecordSum = upgradeRecords.Sum(x => x.Cost)
|
UpgradeRecordSum = upgradeRecords.Sum(x => x.Cost)
|
||||||
};
|
};
|
||||||
//get costbymonth
|
//get costbymonth
|
||||||
List<CostForVehicleByMonth> allCosts = new List<CostForVehicleByMonth>();
|
List<CostForVehicleByMonth> allCosts = StaticHelper.GetBaseLineCosts();
|
||||||
allCosts.AddRange(_reportHelper.GetServiceRecordSum(serviceRecords, 0));
|
allCosts.AddRange(_reportHelper.GetServiceRecordSum(serviceRecords, 0));
|
||||||
allCosts.AddRange(_reportHelper.GetRepairRecordSum(collisionRecords, 0));
|
allCosts.AddRange(_reportHelper.GetRepairRecordSum(collisionRecords, 0));
|
||||||
allCosts.AddRange(_reportHelper.GetUpgradeRecordSum(upgradeRecords, 0));
|
allCosts.AddRange(_reportHelper.GetUpgradeRecordSum(upgradeRecords, 0));
|
||||||
@@ -867,10 +952,17 @@ namespace CarCareTracker.Controllers
|
|||||||
var userConfig = _config.GetUserConfig(User);
|
var userConfig = _config.GetUserConfig(User);
|
||||||
var mileageData = _gasHelper.GetGasRecordViewModels(gasRecords, userConfig.UseMPG, userConfig.UseUKMPG);
|
var mileageData = _gasHelper.GetGasRecordViewModels(gasRecords, userConfig.UseMPG, userConfig.UseUKMPG);
|
||||||
mileageData.RemoveAll(x => x.MilesPerGallon == default);
|
mileageData.RemoveAll(x => x.MilesPerGallon == default);
|
||||||
var monthlyMileageData = mileageData.GroupBy(x => x.MonthId).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
var monthlyMileageData = StaticHelper.GetBaseLineCostsNoMonthName();
|
||||||
|
monthlyMileageData.AddRange(mileageData.GroupBy(x => x.MonthId).Select(x => new CostForVehicleByMonth
|
||||||
{
|
{
|
||||||
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
MonthId = x.Key,
|
||||||
Cost = x.Average(y => y.MilesPerGallon)
|
Cost = x.Average(y => y.MilesPerGallon)
|
||||||
|
}));
|
||||||
|
monthlyMileageData = monthlyMileageData.GroupBy(x => x.MonthId).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
||||||
|
{
|
||||||
|
MonthId = x.Key,
|
||||||
|
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
||||||
|
Cost = x.Sum(y=>y.Cost)
|
||||||
}).ToList();
|
}).ToList();
|
||||||
viewModel.FuelMileageForVehicleByMonth = monthlyMileageData;
|
viewModel.FuelMileageForVehicleByMonth = monthlyMileageData;
|
||||||
return PartialView("_Report", viewModel);
|
return PartialView("_Report", viewModel);
|
||||||
@@ -937,6 +1029,84 @@ namespace CarCareTracker.Controllers
|
|||||||
return PartialView("_ReminderMakeUpReport", viewModel);
|
return PartialView("_ReminderMakeUpReport", viewModel);
|
||||||
}
|
}
|
||||||
[TypeFilter(typeof(CollaboratorFilter))]
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult GetVehicleAttachments(int vehicleId, List<ImportMode> exportTabs)
|
||||||
|
{
|
||||||
|
List<GenericReportModel> attachmentData = new List<GenericReportModel>();
|
||||||
|
if (exportTabs.Contains(ImportMode.ServiceRecord)){
|
||||||
|
var records = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId).Where(x=>x.Files.Any());
|
||||||
|
attachmentData.AddRange(records.Select(x => new GenericReportModel
|
||||||
|
{
|
||||||
|
Date = x.Date,
|
||||||
|
Odometer = x.Mileage,
|
||||||
|
Files = x.Files
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (exportTabs.Contains(ImportMode.RepairRecord))
|
||||||
|
{
|
||||||
|
var records = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId).Where(x => x.Files.Any());
|
||||||
|
attachmentData.AddRange(records.Select(x => new GenericReportModel
|
||||||
|
{
|
||||||
|
Date = x.Date,
|
||||||
|
Odometer = x.Mileage,
|
||||||
|
Files = x.Files
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (exportTabs.Contains(ImportMode.UpgradeRecord))
|
||||||
|
{
|
||||||
|
var records = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId).Where(x => x.Files.Any());
|
||||||
|
attachmentData.AddRange(records.Select(x => new GenericReportModel
|
||||||
|
{
|
||||||
|
Date = x.Date,
|
||||||
|
Odometer = x.Mileage,
|
||||||
|
Files = x.Files
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (exportTabs.Contains(ImportMode.GasRecord))
|
||||||
|
{
|
||||||
|
var records = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId).Where(x => x.Files.Any());
|
||||||
|
attachmentData.AddRange(records.Select(x => new GenericReportModel
|
||||||
|
{
|
||||||
|
Date = x.Date,
|
||||||
|
Odometer = x.Mileage,
|
||||||
|
Files = x.Files
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (exportTabs.Contains(ImportMode.TaxRecord))
|
||||||
|
{
|
||||||
|
var records = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId).Where(x => x.Files.Any());
|
||||||
|
attachmentData.AddRange(records.Select(x => new GenericReportModel
|
||||||
|
{
|
||||||
|
Date = x.Date,
|
||||||
|
Odometer = 0,
|
||||||
|
Files = x.Files
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (exportTabs.Contains(ImportMode.OdometerRecord))
|
||||||
|
{
|
||||||
|
var records = _odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId).Where(x => x.Files.Any());
|
||||||
|
attachmentData.AddRange(records.Select(x => new GenericReportModel
|
||||||
|
{
|
||||||
|
Date = x.Date,
|
||||||
|
Odometer = x.Mileage,
|
||||||
|
Files = x.Files
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (attachmentData.Any())
|
||||||
|
{
|
||||||
|
attachmentData = attachmentData.OrderBy(x => x.Date).ThenBy(x => x.Odometer).ToList();
|
||||||
|
var result = _fileHelper.MakeAttachmentsExport(attachmentData);
|
||||||
|
if (string.IsNullOrWhiteSpace(result))
|
||||||
|
{
|
||||||
|
return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage });
|
||||||
|
}
|
||||||
|
return Json(new OperationResponse { Success = true, Message = result });
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return Json(new OperationResponse { Success = false, Message = "No Attachments Found" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
public IActionResult GetVehicleHistory(int vehicleId)
|
public IActionResult GetVehicleHistory(int vehicleId)
|
||||||
{
|
{
|
||||||
var vehicleHistory = new VehicleHistoryViewModel();
|
var vehicleHistory = new VehicleHistoryViewModel();
|
||||||
@@ -950,15 +1120,28 @@ namespace CarCareTracker.Controllers
|
|||||||
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
|
||||||
bool useMPG = _config.GetUserConfig(User).UseMPG;
|
bool useMPG = _config.GetUserConfig(User).UseMPG;
|
||||||
bool useUKMPG = _config.GetUserConfig(User).UseUKMPG;
|
bool useUKMPG = _config.GetUserConfig(User).UseUKMPG;
|
||||||
|
string preferredFuelMileageUnit = _config.GetUserConfig(User).PreferredGasMileageUnit;
|
||||||
vehicleHistory.TotalGasCost = gasRecords.Sum(x => x.Cost);
|
vehicleHistory.TotalGasCost = gasRecords.Sum(x => x.Cost);
|
||||||
vehicleHistory.TotalCost = serviceRecords.Sum(x => x.Cost) + repairRecords.Sum(x => x.Cost) + upgradeRecords.Sum(x => x.Cost) + taxRecords.Sum(x => x.Cost);
|
vehicleHistory.TotalCost = serviceRecords.Sum(x => x.Cost) + repairRecords.Sum(x => x.Cost) + upgradeRecords.Sum(x => x.Cost) + taxRecords.Sum(x => x.Cost);
|
||||||
var averageMPG = "0";
|
var averageMPG = "0";
|
||||||
var gasViewModels = _gasHelper.GetGasRecordViewModels(gasRecords, useMPG, useUKMPG);
|
var gasViewModels = _gasHelper.GetGasRecordViewModels(gasRecords, useMPG, useUKMPG);
|
||||||
if (gasViewModels.Any())
|
if (gasViewModels.Any())
|
||||||
{
|
{
|
||||||
averageMPG = _gasHelper.GetAverageGasMileage(gasViewModels);
|
averageMPG = _gasHelper.GetAverageGasMileage(gasViewModels, useMPG);
|
||||||
}
|
}
|
||||||
vehicleHistory.MPG = averageMPG;
|
var fuelEconomyMileageUnit = StaticHelper.GetFuelEconomyUnit(vehicleHistory.VehicleData.IsElectric, vehicleHistory.VehicleData.UseHours, useMPG, useUKMPG);
|
||||||
|
if (fuelEconomyMileageUnit == "l/100km" && preferredFuelMileageUnit == "km/l")
|
||||||
|
{
|
||||||
|
//conversion needed.
|
||||||
|
var newAverageMPG = decimal.Parse(averageMPG, NumberStyles.Any);
|
||||||
|
if (newAverageMPG != 0)
|
||||||
|
{
|
||||||
|
newAverageMPG = 100 / newAverageMPG;
|
||||||
|
}
|
||||||
|
averageMPG = newAverageMPG.ToString("F");
|
||||||
|
fuelEconomyMileageUnit = preferredFuelMileageUnit;
|
||||||
|
}
|
||||||
|
vehicleHistory.MPG = $"{averageMPG} {fuelEconomyMileageUnit}";
|
||||||
//insert servicerecords
|
//insert servicerecords
|
||||||
reportData.AddRange(serviceRecords.Select(x => new GenericReportModel
|
reportData.AddRange(serviceRecords.Select(x => new GenericReportModel
|
||||||
{
|
{
|
||||||
@@ -1012,10 +1195,17 @@ namespace CarCareTracker.Controllers
|
|||||||
mileageData.RemoveAll(x => DateTime.Parse(x.Date).Year != year);
|
mileageData.RemoveAll(x => DateTime.Parse(x.Date).Year != year);
|
||||||
}
|
}
|
||||||
mileageData.RemoveAll(x => x.MilesPerGallon == default);
|
mileageData.RemoveAll(x => x.MilesPerGallon == default);
|
||||||
var monthlyMileageData = mileageData.GroupBy(x => x.MonthId).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
var monthlyMileageData = StaticHelper.GetBaseLineCostsNoMonthName();
|
||||||
|
monthlyMileageData.AddRange(mileageData.GroupBy(x => x.MonthId).Select(x => new CostForVehicleByMonth
|
||||||
{
|
{
|
||||||
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
MonthId = x.Key,
|
||||||
Cost = x.Average(y => y.MilesPerGallon)
|
Cost = x.Average(y => y.MilesPerGallon)
|
||||||
|
}));
|
||||||
|
monthlyMileageData = monthlyMileageData.GroupBy(x => x.MonthId).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth
|
||||||
|
{
|
||||||
|
MonthId = x.Key,
|
||||||
|
MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key),
|
||||||
|
Cost = x.Sum(y => y.Cost)
|
||||||
}).ToList();
|
}).ToList();
|
||||||
return PartialView("_MPGByMonthReport", monthlyMileageData);
|
return PartialView("_MPGByMonthReport", monthlyMileageData);
|
||||||
}
|
}
|
||||||
@@ -1023,7 +1213,7 @@ namespace CarCareTracker.Controllers
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult GetCostByMonthByVehicle(int vehicleId, List<ImportMode> selectedMetrics, int year = 0)
|
public IActionResult GetCostByMonthByVehicle(int vehicleId, List<ImportMode> selectedMetrics, int year = 0)
|
||||||
{
|
{
|
||||||
List<CostForVehicleByMonth> allCosts = new List<CostForVehicleByMonth>();
|
List<CostForVehicleByMonth> allCosts = StaticHelper.GetBaseLineCosts();
|
||||||
if (selectedMetrics.Contains(ImportMode.ServiceRecord))
|
if (selectedMetrics.Contains(ImportMode.ServiceRecord))
|
||||||
{
|
{
|
||||||
var serviceRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId);
|
var serviceRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId);
|
||||||
@@ -1180,7 +1370,9 @@ namespace CarCareTracker.Controllers
|
|||||||
Metric = result.Metric,
|
Metric = result.Metric,
|
||||||
IsRecurring = result.IsRecurring,
|
IsRecurring = result.IsRecurring,
|
||||||
ReminderMileageInterval = result.ReminderMileageInterval,
|
ReminderMileageInterval = result.ReminderMileageInterval,
|
||||||
ReminderMonthInterval = result.ReminderMonthInterval
|
ReminderMonthInterval = result.ReminderMonthInterval,
|
||||||
|
CustomMileageInterval = result.CustomMileageInterval,
|
||||||
|
CustomMonthInterval = result.CustomMonthInterval
|
||||||
};
|
};
|
||||||
return PartialView("_ReminderRecordModal", convertedResult);
|
return PartialView("_ReminderRecordModal", convertedResult);
|
||||||
}
|
}
|
||||||
@@ -1233,7 +1425,7 @@ namespace CarCareTracker.Controllers
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetAddUpgradeRecordPartialView()
|
public IActionResult GetAddUpgradeRecordPartialView()
|
||||||
{
|
{
|
||||||
return PartialView("_UpgradeRecordModal", new UpgradeRecordInput());
|
return PartialView("_UpgradeRecordModal", new UpgradeRecordInput() { ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.UpgradeRecord).ExtraFields });
|
||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetUpgradeRecordForEditById(int upgradeRecordId)
|
public IActionResult GetUpgradeRecordForEditById(int upgradeRecordId)
|
||||||
@@ -1249,7 +1441,9 @@ namespace CarCareTracker.Controllers
|
|||||||
Mileage = result.Mileage,
|
Mileage = result.Mileage,
|
||||||
Notes = result.Notes,
|
Notes = result.Notes,
|
||||||
VehicleId = result.VehicleId,
|
VehicleId = result.VehicleId,
|
||||||
Files = result.Files
|
Files = result.Files,
|
||||||
|
Tags = result.Tags,
|
||||||
|
ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.UpgradeRecord).ExtraFields)
|
||||||
};
|
};
|
||||||
return PartialView("_UpgradeRecordModal", convertedResult);
|
return PartialView("_UpgradeRecordModal", convertedResult);
|
||||||
}
|
}
|
||||||
@@ -1266,8 +1460,17 @@ namespace CarCareTracker.Controllers
|
|||||||
public IActionResult GetNotesByVehicleId(int vehicleId)
|
public IActionResult GetNotesByVehicleId(int vehicleId)
|
||||||
{
|
{
|
||||||
var result = _noteDataAccess.GetNotesByVehicleId(vehicleId);
|
var result = _noteDataAccess.GetNotesByVehicleId(vehicleId);
|
||||||
|
result = result.OrderByDescending(x => x.Pinned).ToList();
|
||||||
return PartialView("_Notes", result);
|
return PartialView("_Notes", result);
|
||||||
}
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetPinnedNotesByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var result = _noteDataAccess.GetNotesByVehicleId(vehicleId);
|
||||||
|
result = result.Where(x=>x.Pinned).ToList();
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult SaveNoteToVehicleId(Note note)
|
public IActionResult SaveNoteToVehicleId(Note note)
|
||||||
{
|
{
|
||||||
@@ -1293,6 +1496,25 @@ namespace CarCareTracker.Controllers
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
#region "Supply Records"
|
#region "Supply Records"
|
||||||
|
private List<string> CheckSupplyRecordsAvailability(List<SupplyUsage> supplyUsage)
|
||||||
|
{
|
||||||
|
//returns empty string if all supplies are available
|
||||||
|
var result = new List<string>();
|
||||||
|
foreach (SupplyUsage supply in supplyUsage)
|
||||||
|
{
|
||||||
|
//get supply record.
|
||||||
|
var supplyData = _supplyRecordDataAccess.GetSupplyRecordById(supply.SupplyId);
|
||||||
|
if (supplyData == null)
|
||||||
|
{
|
||||||
|
result.Add("Missing Supplies, Please Delete This Template and Recreate It.");
|
||||||
|
}
|
||||||
|
else if (supply.Quantity > supplyData.Quantity)
|
||||||
|
{
|
||||||
|
result.Add($"Insufficient Quantity for {supplyData.Description}, need: {supply.Quantity}, available: {supplyData.Quantity}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
private void RequisitionSupplyRecordsByUsage(List<SupplyUsage> supplyUsage)
|
private void RequisitionSupplyRecordsByUsage(List<SupplyUsage> supplyUsage)
|
||||||
{
|
{
|
||||||
foreach(SupplyUsage supply in supplyUsage)
|
foreach(SupplyUsage supply in supplyUsage)
|
||||||
@@ -1329,6 +1551,10 @@ namespace CarCareTracker.Controllers
|
|||||||
public IActionResult GetSupplyRecordsForRecordsByVehicleId(int vehicleId)
|
public IActionResult GetSupplyRecordsForRecordsByVehicleId(int vehicleId)
|
||||||
{
|
{
|
||||||
var result = _supplyRecordDataAccess.GetSupplyRecordsByVehicleId(vehicleId);
|
var result = _supplyRecordDataAccess.GetSupplyRecordsByVehicleId(vehicleId);
|
||||||
|
if (_config.GetServerEnableShopSupplies())
|
||||||
|
{
|
||||||
|
result.AddRange(_supplyRecordDataAccess.GetSupplyRecordsByVehicleId(0)); // add shop supplies
|
||||||
|
}
|
||||||
result.RemoveAll(x => x.Quantity <= 0);
|
result.RemoveAll(x => x.Quantity <= 0);
|
||||||
bool _useDescending = _config.GetUserConfig(User).UseDescending;
|
bool _useDescending = _config.GetUserConfig(User).UseDescending;
|
||||||
if (_useDescending)
|
if (_useDescending)
|
||||||
@@ -1352,7 +1578,7 @@ namespace CarCareTracker.Controllers
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetAddSupplyRecordPartialView()
|
public IActionResult GetAddSupplyRecordPartialView()
|
||||||
{
|
{
|
||||||
return PartialView("_SupplyRecordModal", new SupplyRecordInput());
|
return PartialView("_SupplyRecordModal", new SupplyRecordInput() { ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.SupplyRecord).ExtraFields });
|
||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetSupplyRecordForEditById(int supplyRecordId)
|
public IActionResult GetSupplyRecordForEditById(int supplyRecordId)
|
||||||
@@ -1370,7 +1596,9 @@ namespace CarCareTracker.Controllers
|
|||||||
PartSupplier = result.PartSupplier,
|
PartSupplier = result.PartSupplier,
|
||||||
Notes = result.Notes,
|
Notes = result.Notes,
|
||||||
VehicleId = result.VehicleId,
|
VehicleId = result.VehicleId,
|
||||||
Files = result.Files
|
Files = result.Files,
|
||||||
|
Tags = result.Tags,
|
||||||
|
ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.SupplyRecord).ExtraFields)
|
||||||
};
|
};
|
||||||
return PartialView("_SupplyRecordModal", convertedResult);
|
return PartialView("_SupplyRecordModal", convertedResult);
|
||||||
}
|
}
|
||||||
@@ -1407,10 +1635,64 @@ namespace CarCareTracker.Controllers
|
|||||||
}
|
}
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult SavePlanRecordTemplateToVehicleId(PlanRecordInput planRecord)
|
||||||
|
{
|
||||||
|
//check if template name already taken.
|
||||||
|
var existingRecord = _planRecordTemplateDataAccess.GetPlanRecordTemplatesByVehicleId(planRecord.VehicleId).Where(x=>x.Description == planRecord.Description).Any();
|
||||||
|
if (existingRecord)
|
||||||
|
{
|
||||||
|
return Json(new OperationResponse { Success = false, Message = "A template with that description already exists for this vehicle"});
|
||||||
|
}
|
||||||
|
planRecord.Files = planRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
|
||||||
|
var result = _planRecordTemplateDataAccess.SavePlanRecordTemplateToVehicle(planRecord);
|
||||||
|
return Json(new OperationResponse { Success = result, Message = result ? "Template Added" : StaticHelper.GenericErrorMessage });
|
||||||
|
}
|
||||||
|
[TypeFilter(typeof(CollaboratorFilter))]
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetPlanRecordTemplatesForVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
var result = _planRecordTemplateDataAccess.GetPlanRecordTemplatesByVehicleId(vehicleId);
|
||||||
|
return PartialView("_PlanRecordTemplateModal", result);
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult DeletePlanRecordTemplateById(int planRecordTemplateId)
|
||||||
|
{
|
||||||
|
var result = _planRecordTemplateDataAccess.DeletePlanRecordTemplateById(planRecordTemplateId);
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult ConvertPlanRecordTemplateToPlanRecord(int planRecordTemplateId)
|
||||||
|
{
|
||||||
|
var existingRecord = _planRecordTemplateDataAccess.GetPlanRecordTemplateById(planRecordTemplateId);
|
||||||
|
if (existingRecord.Id == default)
|
||||||
|
{
|
||||||
|
return Json(new OperationResponse { Success = false, Message = "Unable to find template" });
|
||||||
|
}
|
||||||
|
if (existingRecord.Supplies.Any())
|
||||||
|
{
|
||||||
|
//check if all supplies are available
|
||||||
|
var supplyAvailability = CheckSupplyRecordsAvailability(existingRecord.Supplies);
|
||||||
|
if (supplyAvailability.Any())
|
||||||
|
{
|
||||||
|
return Json(new OperationResponse { Success = false, Message = string.Join("<br>", supplyAvailability) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//populate createdDate
|
||||||
|
existingRecord.DateCreated = DateTime.Now.ToString("G");
|
||||||
|
existingRecord.DateModified = DateTime.Now.ToString("G");
|
||||||
|
existingRecord.Id = default;
|
||||||
|
var result = _planRecordDataAccess.SavePlanRecordToVehicle(existingRecord.ToPlanRecord());
|
||||||
|
if (result && existingRecord.Supplies.Any())
|
||||||
|
{
|
||||||
|
RequisitionSupplyRecordsByUsage(existingRecord.Supplies);
|
||||||
|
}
|
||||||
|
return Json(new OperationResponse { Success = result, Message = result ? "Plan Record Added" : StaticHelper.GenericErrorMessage });
|
||||||
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetAddPlanRecordPartialView()
|
public IActionResult GetAddPlanRecordPartialView()
|
||||||
{
|
{
|
||||||
return PartialView("_PlanRecordModal", new PlanRecordInput());
|
return PartialView("_PlanRecordModal", new PlanRecordInput() { ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.PlanRecord).ExtraFields });
|
||||||
}
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult UpdatePlanRecordProgress(int planRecordId, PlanProgress planProgress, int odometer = 0)
|
public IActionResult UpdatePlanRecordProgress(int planRecordId, PlanProgress planProgress, int odometer = 0)
|
||||||
@@ -1428,7 +1710,8 @@ namespace CarCareTracker.Controllers
|
|||||||
Date = DateTime.Now,
|
Date = DateTime.Now,
|
||||||
VehicleId = existingRecord.VehicleId,
|
VehicleId = existingRecord.VehicleId,
|
||||||
Mileage = odometer,
|
Mileage = odometer,
|
||||||
Notes = $"Auto Insert From Plan Record: {existingRecord.Description}"
|
Notes = $"Auto Insert From Plan Record: {existingRecord.Description}",
|
||||||
|
ExtraFields = existingRecord.ExtraFields
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//convert plan record to service/upgrade/repair record.
|
//convert plan record to service/upgrade/repair record.
|
||||||
@@ -1442,7 +1725,8 @@ namespace CarCareTracker.Controllers
|
|||||||
Description = existingRecord.Description,
|
Description = existingRecord.Description,
|
||||||
Cost = existingRecord.Cost,
|
Cost = existingRecord.Cost,
|
||||||
Notes = existingRecord.Notes,
|
Notes = existingRecord.Notes,
|
||||||
Files = existingRecord.Files
|
Files = existingRecord.Files,
|
||||||
|
ExtraFields = existingRecord.ExtraFields
|
||||||
};
|
};
|
||||||
_serviceRecordDataAccess.SaveServiceRecordToVehicle(newRecord);
|
_serviceRecordDataAccess.SaveServiceRecordToVehicle(newRecord);
|
||||||
}
|
}
|
||||||
@@ -1456,7 +1740,8 @@ namespace CarCareTracker.Controllers
|
|||||||
Description = existingRecord.Description,
|
Description = existingRecord.Description,
|
||||||
Cost = existingRecord.Cost,
|
Cost = existingRecord.Cost,
|
||||||
Notes = existingRecord.Notes,
|
Notes = existingRecord.Notes,
|
||||||
Files = existingRecord.Files
|
Files = existingRecord.Files,
|
||||||
|
ExtraFields = existingRecord.ExtraFields
|
||||||
};
|
};
|
||||||
_collisionRecordDataAccess.SaveCollisionRecordToVehicle(newRecord);
|
_collisionRecordDataAccess.SaveCollisionRecordToVehicle(newRecord);
|
||||||
}
|
}
|
||||||
@@ -1470,7 +1755,8 @@ namespace CarCareTracker.Controllers
|
|||||||
Description = existingRecord.Description,
|
Description = existingRecord.Description,
|
||||||
Cost = existingRecord.Cost,
|
Cost = existingRecord.Cost,
|
||||||
Notes = existingRecord.Notes,
|
Notes = existingRecord.Notes,
|
||||||
Files = existingRecord.Files
|
Files = existingRecord.Files,
|
||||||
|
ExtraFields = existingRecord.ExtraFields
|
||||||
};
|
};
|
||||||
_upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(newRecord);
|
_upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(newRecord);
|
||||||
}
|
}
|
||||||
@@ -1494,7 +1780,8 @@ namespace CarCareTracker.Controllers
|
|||||||
Cost = result.Cost,
|
Cost = result.Cost,
|
||||||
Notes = result.Notes,
|
Notes = result.Notes,
|
||||||
VehicleId = result.VehicleId,
|
VehicleId = result.VehicleId,
|
||||||
Files = result.Files
|
Files = result.Files,
|
||||||
|
ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.PlanRecord).ExtraFields)
|
||||||
};
|
};
|
||||||
return PartialView("_PlanRecordModal", convertedResult);
|
return PartialView("_PlanRecordModal", convertedResult);
|
||||||
}
|
}
|
||||||
@@ -1533,7 +1820,7 @@ namespace CarCareTracker.Controllers
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetAddOdometerRecordPartialView()
|
public IActionResult GetAddOdometerRecordPartialView()
|
||||||
{
|
{
|
||||||
return PartialView("_OdometerRecordModal", new OdometerRecordInput());
|
return PartialView("_OdometerRecordModal", new OdometerRecordInput() { ExtraFields = _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.OdometerRecord).ExtraFields });
|
||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetOdometerRecordForEditById(int odometerRecordId)
|
public IActionResult GetOdometerRecordForEditById(int odometerRecordId)
|
||||||
@@ -1547,7 +1834,9 @@ namespace CarCareTracker.Controllers
|
|||||||
Mileage = result.Mileage,
|
Mileage = result.Mileage,
|
||||||
Notes = result.Notes,
|
Notes = result.Notes,
|
||||||
VehicleId = result.VehicleId,
|
VehicleId = result.VehicleId,
|
||||||
Files = result.Files
|
Files = result.Files,
|
||||||
|
Tags = result.Tags,
|
||||||
|
ExtraFields = StaticHelper.AddExtraFields(result.ExtraFields, _extraFieldDataAccess.GetExtraFieldsById((int)ImportMode.OdometerRecord).ExtraFields)
|
||||||
};
|
};
|
||||||
return PartialView("_OdometerRecordModal", convertedResult);
|
return PartialView("_OdometerRecordModal", convertedResult);
|
||||||
}
|
}
|
||||||
@@ -1558,5 +1847,55 @@ namespace CarCareTracker.Controllers
|
|||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
#region "Shared Methods"
|
||||||
|
public IActionResult MoveRecord(int recordId, ImportMode source, ImportMode destination)
|
||||||
|
{
|
||||||
|
var genericRecord = new GenericRecord();
|
||||||
|
bool result = false;
|
||||||
|
//get
|
||||||
|
switch (source)
|
||||||
|
{
|
||||||
|
case ImportMode.ServiceRecord:
|
||||||
|
genericRecord = _serviceRecordDataAccess.GetServiceRecordById(recordId);
|
||||||
|
break;
|
||||||
|
case ImportMode.RepairRecord:
|
||||||
|
genericRecord = _collisionRecordDataAccess.GetCollisionRecordById(recordId);
|
||||||
|
break;
|
||||||
|
case ImportMode.UpgradeRecord:
|
||||||
|
genericRecord = _upgradeRecordDataAccess.GetUpgradeRecordById(recordId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//save
|
||||||
|
switch (destination)
|
||||||
|
{
|
||||||
|
case ImportMode.ServiceRecord:
|
||||||
|
result = _serviceRecordDataAccess.SaveServiceRecordToVehicle(StaticHelper.GenericToServiceRecord(genericRecord));
|
||||||
|
break;
|
||||||
|
case ImportMode.RepairRecord:
|
||||||
|
result = _collisionRecordDataAccess.SaveCollisionRecordToVehicle(StaticHelper.GenericToRepairRecord(genericRecord));
|
||||||
|
break;
|
||||||
|
case ImportMode.UpgradeRecord:
|
||||||
|
result = _upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(StaticHelper.GenericToUpgradeRecord(genericRecord));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//delete
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
switch (source)
|
||||||
|
{
|
||||||
|
case ImportMode.ServiceRecord:
|
||||||
|
_serviceRecordDataAccess.DeleteServiceRecordById(recordId);
|
||||||
|
break;
|
||||||
|
case ImportMode.RepairRecord:
|
||||||
|
_collisionRecordDataAccess.DeleteCollisionRecordById(recordId);
|
||||||
|
break;
|
||||||
|
case ImportMode.UpgradeRecord:
|
||||||
|
_upgradeRecordDataAccess.DeleteUpgradeRecordById(recordId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Json(result);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
{
|
{
|
||||||
public enum ReminderMileageInterval
|
public enum ReminderMileageInterval
|
||||||
{
|
{
|
||||||
|
Other = 0,
|
||||||
FiftyMiles = 50,
|
FiftyMiles = 50,
|
||||||
OneHundredMiles = 100,
|
OneHundredMiles = 100,
|
||||||
FiveHundredMiles = 500,
|
FiveHundredMiles = 500,
|
||||||
@@ -14,7 +15,9 @@
|
|||||||
FifteenThousandMiles = 15000,
|
FifteenThousandMiles = 15000,
|
||||||
TwentyThousandMiles = 20000,
|
TwentyThousandMiles = 20000,
|
||||||
ThirtyThousandMiles = 30000,
|
ThirtyThousandMiles = 30000,
|
||||||
|
FortyThousandMiles = 40000,
|
||||||
FiftyThousandMiles = 50000,
|
FiftyThousandMiles = 50000,
|
||||||
|
SixtyThousandMiles = 60000,
|
||||||
OneHundredThousandMiles = 100000,
|
OneHundredThousandMiles = 100000,
|
||||||
OneHundredFiftyThousandMiles = 150000
|
OneHundredFiftyThousandMiles = 150000
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
{
|
{
|
||||||
public enum ReminderMonthInterval
|
public enum ReminderMonthInterval
|
||||||
{
|
{
|
||||||
|
Other = 0,
|
||||||
|
OneMonth = 1,
|
||||||
ThreeMonths = 3,
|
ThreeMonths = 3,
|
||||||
SixMonths = 6,
|
SixMonths = 6,
|
||||||
OneYear = 12,
|
OneYear = 12,
|
||||||
|
|||||||
30
External/Implementations/Litedb/ExtraFieldDataAccess.cs
vendored
Normal file
30
External/Implementations/Litedb/ExtraFieldDataAccess.cs
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class ExtraFieldDataAccess: IExtraFieldDataAccess
|
||||||
|
{
|
||||||
|
private static string dbName = StaticHelper.DbName;
|
||||||
|
private static string tableName = "extrafields";
|
||||||
|
public RecordExtraField GetExtraFieldsById(int importMode)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(dbName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<RecordExtraField>(tableName);
|
||||||
|
return table.FindById(importMode) ?? new RecordExtraField();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public bool SaveExtraFields(RecordExtraField record)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(dbName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<RecordExtraField>(tableName);
|
||||||
|
table.Upsert(record);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
External/Implementations/Litedb/PlanRecordTemplateDataAccess.cs
vendored
Normal file
57
External/Implementations/Litedb/PlanRecordTemplateDataAccess.cs
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Helper;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PlanRecordTemplateDataAccess : IPlanRecordTemplateDataAccess
|
||||||
|
{
|
||||||
|
private static string dbName = StaticHelper.DbName;
|
||||||
|
private static string tableName = "planrecordtemplates";
|
||||||
|
public List<PlanRecordInput> GetPlanRecordTemplatesByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(dbName))
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(dbName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<PlanRecordInput>(tableName);
|
||||||
|
return table.FindById(planRecordId);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public bool DeletePlanRecordTemplateById(int planRecordId)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(dbName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<PlanRecordInput>(tableName);
|
||||||
|
table.Delete(planRecordId);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public bool SavePlanRecordTemplateToVehicle(PlanRecordInput planRecord)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(dbName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<PlanRecordInput>(tableName);
|
||||||
|
table.Upsert(planRecord);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public bool DeleteAllPlanRecordTemplatesByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
using (var db = new LiteDatabase(dbName))
|
||||||
|
{
|
||||||
|
var table = db.GetCollection<PlanRecord>(tableName);
|
||||||
|
var planRecords = table.DeleteMany(Query.EQ(nameof(PlanRecordInput.VehicleId), vehicleId));
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
using CarCareTracker.Helper;
|
using CarCareTracker.Helper;
|
||||||
using CarCareTracker.Models;
|
using CarCareTracker.Models;
|
||||||
using LiteDB;
|
using LiteDB;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
||||||
|
|
||||||
namespace CarCareTracker.External.Implementations
|
namespace CarCareTracker.External.Implementations
|
||||||
{
|
{
|
||||||
160
External/Implementations/Postgres/CollisionRecordDataAccess.cs
vendored
Normal file
160
External/Implementations/Postgres/CollisionRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGCollisionRecordDataAccess : ICollisionRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGCollisionRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "collisionrecords";
|
||||||
|
public PGCollisionRecordDataAccess(IConfiguration config, ILogger<PGCollisionRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<CollisionRecord> GetCollisionRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<CollisionRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
CollisionRecord collisionRecord = JsonSerializer.Deserialize<CollisionRecord>(reader["data"] as string);
|
||||||
|
results.Add(collisionRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<CollisionRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public CollisionRecord GetCollisionRecordById(int collisionRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new CollisionRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", collisionRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
CollisionRecord collisionRecord = JsonSerializer.Deserialize<CollisionRecord>(reader["data"] as string);
|
||||||
|
result = collisionRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new CollisionRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteCollisionRecordById(int collisionRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", collisionRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveCollisionRecordToVehicle(CollisionRecord collisionRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (collisionRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", collisionRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
collisionRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (collisionRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(collisionRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", collisionRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collisionRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(collisionRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", collisionRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllCollisionRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
80
External/Implementations/Postgres/ExtraFieldDataAccess.cs
vendored
Normal file
80
External/Implementations/Postgres/ExtraFieldDataAccess.cs
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
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))";
|
||||||
|
if (existingRecord.ExtraFields != null)
|
||||||
|
{
|
||||||
|
cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
}
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", record.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", JsonSerializer.Serialize(record));
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/GasRecordDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/GasRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGGasRecordDataAccess: IGasRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGGasRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "gasrecords";
|
||||||
|
public PGGasRecordDataAccess(IConfiguration config, ILogger<PGGasRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<GasRecord> GetGasRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<GasRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
GasRecord gasRecord = JsonSerializer.Deserialize<GasRecord>(reader["data"] as string);
|
||||||
|
results.Add(gasRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<GasRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public GasRecord GetGasRecordById(int gasRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new GasRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", gasRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
GasRecord gasRecord = JsonSerializer.Deserialize<GasRecord>(reader["data"] as string);
|
||||||
|
result = gasRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new GasRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteGasRecordById(int gasRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", gasRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveGasRecordToVehicle(GasRecord gasRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (gasRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", gasRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
gasRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (gasRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(gasRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", gasRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gasRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(gasRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", gasRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllGasRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
153
External/Implementations/Postgres/NoteDataAccess.cs
vendored
Normal file
153
External/Implementations/Postgres/NoteDataAccess.cs
vendored
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGNoteDataAccess: INoteDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGNoteDataAccess> _logger;
|
||||||
|
private static string tableName = "notes";
|
||||||
|
public PGNoteDataAccess(IConfiguration config, ILogger<PGNoteDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<Note> GetNotesByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<Note>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
Note note = JsonSerializer.Deserialize<Note>(reader["data"] as string);
|
||||||
|
results.Add(note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<Note>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Note GetNoteById(int noteId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new Note();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", noteId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
Note note = JsonSerializer.Deserialize<Note>(reader["data"] as string);
|
||||||
|
result = note;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new Note();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveNoteToVehicle(Note note)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (note.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", note.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
note.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (note.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(note);
|
||||||
|
ctextU.Parameters.AddWithValue("id", note.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return note.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(note);
|
||||||
|
ctext.Parameters.AddWithValue("id", note.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteNoteById(int noteId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", noteId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllNotesByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/OdometerRecordDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/OdometerRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGOdometerRecordDataAccess : IOdometerRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGOdometerRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "odometerrecords";
|
||||||
|
public PGOdometerRecordDataAccess(IConfiguration config, ILogger<PGOdometerRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<OdometerRecord> GetOdometerRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<OdometerRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
OdometerRecord odometerRecord = JsonSerializer.Deserialize<OdometerRecord>(reader["data"] as string);
|
||||||
|
results.Add(odometerRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<OdometerRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public OdometerRecord GetOdometerRecordById(int odometerRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new OdometerRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", odometerRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
OdometerRecord odometerRecord = JsonSerializer.Deserialize<OdometerRecord>(reader["data"] as string);
|
||||||
|
result = odometerRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new OdometerRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteOdometerRecordById(int odometerRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", odometerRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveOdometerRecordToVehicle(OdometerRecord odometerRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (odometerRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", odometerRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
odometerRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (odometerRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(odometerRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", odometerRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return odometerRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(odometerRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", odometerRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllOdometerRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/PlanRecordDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/PlanRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGPlanRecordDataAccess : IPlanRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGPlanRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "planrecords";
|
||||||
|
public PGPlanRecordDataAccess(IConfiguration config, ILogger<PGPlanRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<PlanRecord> GetPlanRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<PlanRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
PlanRecord planRecord = JsonSerializer.Deserialize<PlanRecord>(reader["data"] as string);
|
||||||
|
results.Add(planRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<PlanRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public PlanRecord GetPlanRecordById(int planRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new PlanRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", planRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
PlanRecord planRecord = JsonSerializer.Deserialize<PlanRecord>(reader["data"] as string);
|
||||||
|
result = planRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new PlanRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeletePlanRecordById(int planRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", planRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SavePlanRecordToVehicle(PlanRecord planRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (planRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", planRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
planRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (planRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(planRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", planRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return planRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(planRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", planRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllPlanRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/PlanRecordTemplateDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/PlanRecordTemplateDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGPlanRecordTemplateDataAccess : IPlanRecordTemplateDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGPlanRecordTemplateDataAccess> _logger;
|
||||||
|
private static string tableName = "planrecordtemplates";
|
||||||
|
public PGPlanRecordTemplateDataAccess(IConfiguration config, ILogger<PGPlanRecordTemplateDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<PlanRecordInput> GetPlanRecordTemplatesByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<PlanRecordInput>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
PlanRecordInput planRecord = JsonSerializer.Deserialize<PlanRecordInput>(reader["data"] as string);
|
||||||
|
results.Add(planRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<PlanRecordInput>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public PlanRecordInput GetPlanRecordTemplateById(int planRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new PlanRecordInput();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", planRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
PlanRecordInput planRecord = JsonSerializer.Deserialize<PlanRecordInput>(reader["data"] as string);
|
||||||
|
result = planRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new PlanRecordInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeletePlanRecordTemplateById(int planRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", planRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SavePlanRecordTemplateToVehicle(PlanRecordInput planRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (planRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", planRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
planRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (planRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(planRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", planRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return planRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(planRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", planRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllPlanRecordTemplatesByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/ReminderRecordDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/ReminderRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGReminderRecordDataAccess : IReminderRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGReminderRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "reminderrecords";
|
||||||
|
public PGReminderRecordDataAccess(IConfiguration config, ILogger<PGReminderRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<ReminderRecord> GetReminderRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<ReminderRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
ReminderRecord reminderRecord = JsonSerializer.Deserialize<ReminderRecord>(reader["data"] as string);
|
||||||
|
results.Add(reminderRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<ReminderRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public ReminderRecord GetReminderRecordById(int reminderRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new ReminderRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", reminderRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
ReminderRecord reminderRecord = JsonSerializer.Deserialize<ReminderRecord>(reader["data"] as string);
|
||||||
|
result = reminderRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new ReminderRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteReminderRecordById(int reminderRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", reminderRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveReminderRecordToVehicle(ReminderRecord reminderRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (reminderRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", reminderRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
reminderRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (reminderRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(reminderRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", reminderRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reminderRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(reminderRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", reminderRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllReminderRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/ServiceRecordDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/ServiceRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGServiceRecordDataAccess: IServiceRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGServiceRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "servicerecords";
|
||||||
|
public PGServiceRecordDataAccess(IConfiguration config, ILogger<PGServiceRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<ServiceRecord> GetServiceRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<ServiceRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
ServiceRecord serviceRecord = JsonSerializer.Deserialize<ServiceRecord>(reader["data"] as string);
|
||||||
|
results.Add(serviceRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<ServiceRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public ServiceRecord GetServiceRecordById(int serviceRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new ServiceRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", serviceRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
ServiceRecord serviceRecord = JsonSerializer.Deserialize<ServiceRecord>(reader["data"] as string);
|
||||||
|
result = serviceRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new ServiceRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteServiceRecordById(int serviceRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", serviceRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveServiceRecordToVehicle(ServiceRecord serviceRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (serviceRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", serviceRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
serviceRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (serviceRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(serviceRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", serviceRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return serviceRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(serviceRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", serviceRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllServiceRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/SupplyRecordDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/SupplyRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGSupplyRecordDataAccess : ISupplyRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGSupplyRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "supplyrecords";
|
||||||
|
public PGSupplyRecordDataAccess(IConfiguration config, ILogger<PGSupplyRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<SupplyRecord> GetSupplyRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<SupplyRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
SupplyRecord supplyRecord = JsonSerializer.Deserialize<SupplyRecord>(reader["data"] as string);
|
||||||
|
results.Add(supplyRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<SupplyRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public SupplyRecord GetSupplyRecordById(int supplyRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new SupplyRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", supplyRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
SupplyRecord supplyRecord = JsonSerializer.Deserialize<SupplyRecord>(reader["data"] as string);
|
||||||
|
result = supplyRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new SupplyRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteSupplyRecordById(int supplyRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", supplyRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveSupplyRecordToVehicle(SupplyRecord supplyRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (supplyRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", supplyRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
supplyRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (supplyRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(supplyRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", supplyRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return supplyRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(supplyRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", supplyRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllSupplyRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/TaxRecordDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/TaxRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGTaxRecordDataAccess : ITaxRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGTaxRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "taxrecords";
|
||||||
|
public PGTaxRecordDataAccess(IConfiguration config, ILogger<PGTaxRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<TaxRecord> GetTaxRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<TaxRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
TaxRecord taxRecord = JsonSerializer.Deserialize<TaxRecord>(reader["data"] as string);
|
||||||
|
results.Add(taxRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<TaxRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public TaxRecord GetTaxRecordById(int taxRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new TaxRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", taxRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
TaxRecord taxRecord = JsonSerializer.Deserialize<TaxRecord>(reader["data"] as string);
|
||||||
|
result = taxRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new TaxRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteTaxRecordById(int taxRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", taxRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveTaxRecordToVehicle(TaxRecord taxRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (taxRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", taxRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
taxRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (taxRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(taxRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", taxRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return taxRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(taxRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", taxRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllTaxRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
143
External/Implementations/Postgres/TokenRecordDataAccess.cs
vendored
Normal file
143
External/Implementations/Postgres/TokenRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGTokenRecordDataAccess : ITokenRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGTokenRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "tokenrecords";
|
||||||
|
public PGTokenRecordDataAccess(IConfiguration config, ILogger<PGTokenRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, body TEXT not null, emailaddress TEXT not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<Token> GetTokens()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, emailaddress, body FROM app.{tableName}";
|
||||||
|
var results = new List<Token>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
Token result = new Token();
|
||||||
|
result.Id = int.Parse(reader["id"].ToString());
|
||||||
|
result.EmailAddress = reader["emailaddress"].ToString();
|
||||||
|
result.Body = reader["body"].ToString();
|
||||||
|
results.Add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<Token>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Token GetTokenRecordByBody(string tokenBody)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, emailaddress, body FROM app.{tableName} WHERE body = @body";
|
||||||
|
var result = new Token();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("body", tokenBody);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
result.Id = int.Parse(reader["id"].ToString());
|
||||||
|
result.EmailAddress = reader["emailaddress"].ToString();
|
||||||
|
result.Body = reader["body"].ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new Token();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Token GetTokenRecordByEmailAddress(string emailAddress)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, emailaddress, body FROM app.{tableName} WHERE emailaddress = @emailaddress";
|
||||||
|
var result = new Token();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("emailaddress", emailAddress);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
result.Id = int.Parse(reader["id"].ToString());
|
||||||
|
result.EmailAddress = reader["emailaddress"].ToString();
|
||||||
|
result.Body = reader["body"].ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new Token();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool CreateNewToken(Token token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (emailaddress, body) VALUES(@emailaddress, @body) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("emailaddress", token.EmailAddress);
|
||||||
|
ctext.Parameters.AddWithValue("body", token.Body);
|
||||||
|
token.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
return token.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteToken(int tokenId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", tokenId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
External/Implementations/Postgres/UpgradeRecordDataAccess.cs
vendored
Normal file
159
External/Implementations/Postgres/UpgradeRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGUpgradeRecordDataAccess : IUpgradeRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGUpgradeRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "upgraderecords";
|
||||||
|
public PGUpgradeRecordDataAccess(IConfiguration config, ILogger<PGUpgradeRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<UpgradeRecord> GetUpgradeRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<UpgradeRecord>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
UpgradeRecord upgradeRecord = JsonSerializer.Deserialize<UpgradeRecord>(reader["data"] as string);
|
||||||
|
results.Add(upgradeRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<UpgradeRecord>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public UpgradeRecord GetUpgradeRecordById(int upgradeRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new UpgradeRecord();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", upgradeRecordId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
UpgradeRecord upgradeRecord = JsonSerializer.Deserialize<UpgradeRecord>(reader["data"] as string);
|
||||||
|
result = upgradeRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new UpgradeRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteUpgradeRecordById(int upgradeRecordId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", upgradeRecordId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveUpgradeRecordToVehicle(UpgradeRecord upgradeRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (upgradeRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (vehicleId, data) VALUES(@vehicleId, CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", upgradeRecord.VehicleId);
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
upgradeRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (upgradeRecord.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(upgradeRecord);
|
||||||
|
ctextU.Parameters.AddWithValue("id", upgradeRecord.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return upgradeRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(upgradeRecord);
|
||||||
|
ctext.Parameters.AddWithValue("id", upgradeRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteAllUpgradeRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
211
External/Implementations/Postgres/UserAccessDataAcces.cs
vendored
Normal file
211
External/Implementations/Postgres/UserAccessDataAcces.cs
vendored
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Net.Mail;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGUserAccessDataAccess : IUserAccessDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGUserAccessDataAccess> _logger;
|
||||||
|
private static string tableName = "useraccessrecords";
|
||||||
|
public PGUserAccessDataAccess(IConfiguration config, ILogger<PGUserAccessDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (userId INT, vehicleId INT, PRIMARY KEY(userId, vehicleId))";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of vehicles user have access to.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public List<UserAccess> GetUserAccessByUserId(int userId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT userId, vehicleId FROM app.{tableName} WHERE userId = @userId";
|
||||||
|
var results = new List<UserAccess>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("userId", userId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
UserAccess result = new UserAccess()
|
||||||
|
{
|
||||||
|
Id = new UserVehicle
|
||||||
|
{
|
||||||
|
UserId = int.Parse(reader["userId"].ToString()),
|
||||||
|
VehicleId = int.Parse(reader["vehicleId"].ToString())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
results.Add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<UserAccess>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public UserAccess GetUserAccessByVehicleAndUserId(int userId, int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT userId, vehicleId FROM app.{tableName} WHERE userId = @userId AND vehicleId = @vehicleId";
|
||||||
|
UserAccess result = null;
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("userId", userId);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
result = new UserAccess()
|
||||||
|
{
|
||||||
|
Id = new UserVehicle
|
||||||
|
{
|
||||||
|
UserId = int.Parse(reader["userId"].ToString()),
|
||||||
|
VehicleId = int.Parse(reader["vehicleId"].ToString())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new UserAccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<UserAccess> GetUserAccessByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT userId, vehicleId FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
var results = new List<UserAccess>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
UserAccess result = new UserAccess()
|
||||||
|
{
|
||||||
|
Id = new UserVehicle
|
||||||
|
{
|
||||||
|
UserId = int.Parse(reader["userId"].ToString()),
|
||||||
|
VehicleId = int.Parse(reader["vehicleId"].ToString())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
results.Add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<UserAccess>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveUserAccess(UserAccess userAccess)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (userId, vehicleId) VALUES(@userId, @vehicleId)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("userId", userAccess.Id.UserId);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", userAccess.Id.VehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteUserAccess(int userId, int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE userId = @userId AND vehicleId = @vehicleId";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("userId", userId);
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Delete all access records when a vehicle is deleted.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vehicleId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool DeleteAllAccessRecordsByVehicleId(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE vehicleId = @vehicleId";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("vehicleId", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Delee all access records when a user is deleted.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool DeleteAllAccessRecordsByUserId(int userId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE userId = @userId";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("userId", userId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
107
External/Implementations/Postgres/UserConfigDataAccess.cs
vendored
Normal file
107
External/Implementations/Postgres/UserConfigDataAccess.cs
vendored
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGUserConfigDataAccess: IUserConfigDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGUserConfigDataAccess> _logger;
|
||||||
|
private static string tableName = "userconfigrecords";
|
||||||
|
public PGUserConfigDataAccess(IConfiguration config, ILogger<PGUserConfigDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT primary key, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public UserConfigData GetUserConfig(int userId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT data FROM app.{tableName} WHERE id = @id";
|
||||||
|
UserConfigData result = null;
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", userId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
UserConfigData userConfig = JsonSerializer.Deserialize<UserConfigData>(reader["data"] as string);
|
||||||
|
result = userConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new UserConfigData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveUserConfig(UserConfigData userConfigData)
|
||||||
|
{
|
||||||
|
var existingRecord = GetUserConfig(userConfigData.Id);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (existingRecord == null)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (id, data) VALUES(@id, CAST(@data AS jsonb))";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(userConfigData);
|
||||||
|
ctext.Parameters.AddWithValue("id", userConfigData.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(userConfigData);
|
||||||
|
ctext.Parameters.AddWithValue("id", userConfigData.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteUserConfig(int userId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", userId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
194
External/Implementations/Postgres/UserRecordDataAccess.cs
vendored
Normal file
194
External/Implementations/Postgres/UserRecordDataAccess.cs
vendored
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGUserRecordDataAccess : IUserRecordDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGUserRecordDataAccess> _logger;
|
||||||
|
private static string tableName = "userrecords";
|
||||||
|
public PGUserRecordDataAccess(IConfiguration config, ILogger<PGUserRecordDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, username TEXT not null, emailaddress TEXT not null, password TEXT not null, isadmin BOOLEAN)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<UserData> GetUsers()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, username, emailaddress, password, isadmin FROM app.{tableName}";
|
||||||
|
var results = new List<UserData>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
UserData result = new UserData();
|
||||||
|
result.Id = int.Parse(reader["id"].ToString());
|
||||||
|
result.UserName = reader["username"].ToString();
|
||||||
|
result.EmailAddress = reader["emailaddress"].ToString();
|
||||||
|
result.Password = reader["password"].ToString();
|
||||||
|
result.IsAdmin = bool.Parse(reader["isadmin"].ToString());
|
||||||
|
results.Add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<UserData>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public UserData GetUserRecordByUserName(string userName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, username, emailaddress, password, isadmin FROM app.{tableName} WHERE username = @username";
|
||||||
|
var result = new UserData();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("username", userName);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
result.Id = int.Parse(reader["id"].ToString());
|
||||||
|
result.UserName = reader["username"].ToString();
|
||||||
|
result.EmailAddress = reader["emailaddress"].ToString();
|
||||||
|
result.Password = reader["password"].ToString();
|
||||||
|
result.IsAdmin = bool.Parse(reader["isadmin"].ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new UserData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public UserData GetUserRecordByEmailAddress(string emailAddress)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, username, emailaddress, password, isadmin FROM app.{tableName} WHERE emailaddress = @emailaddress";
|
||||||
|
var result = new UserData();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("emailaddress", emailAddress);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
result.Id = int.Parse(reader["id"].ToString());
|
||||||
|
result.UserName = reader["username"].ToString();
|
||||||
|
result.EmailAddress = reader["emailaddress"].ToString();
|
||||||
|
result.Password = reader["password"].ToString();
|
||||||
|
result.IsAdmin = bool.Parse(reader["isadmin"].ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new UserData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public UserData GetUserRecordById(int userId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, username, emailaddress, password, isadmin FROM app.{tableName} WHERE id = @id";
|
||||||
|
var result = new UserData();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", userId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
result.Id = int.Parse(reader["id"].ToString());
|
||||||
|
result.UserName = reader["username"].ToString();
|
||||||
|
result.EmailAddress = reader["emailaddress"].ToString();
|
||||||
|
result.Password = reader["password"].ToString();
|
||||||
|
result.IsAdmin = bool.Parse(reader["isadmin"].ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new UserData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveUserRecord(UserData userRecord)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (userRecord.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (username, emailaddress, password, isadmin) VALUES(@username, @emailaddress, @password, @isadmin) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("username", userRecord.UserName);
|
||||||
|
ctext.Parameters.AddWithValue("emailaddress", userRecord.EmailAddress);
|
||||||
|
ctext.Parameters.AddWithValue("password", userRecord.Password);
|
||||||
|
ctext.Parameters.AddWithValue("isadmin", userRecord.IsAdmin);
|
||||||
|
userRecord.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
return userRecord.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET username = @username, emailaddress = @emailaddress, password = @password, isadmin = @isadmin WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", userRecord.Id);
|
||||||
|
ctext.Parameters.AddWithValue("username", userRecord.UserName);
|
||||||
|
ctext.Parameters.AddWithValue("emailaddress", userRecord.EmailAddress);
|
||||||
|
ctext.Parameters.AddWithValue("password", userRecord.Password);
|
||||||
|
ctext.Parameters.AddWithValue("isadmin", userRecord.IsAdmin);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool DeleteUserRecord(int userId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", userId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
138
External/Implementations/Postgres/VehicleDataAccess.cs
vendored
Normal file
138
External/Implementations/Postgres/VehicleDataAccess.cs
vendored
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
using CarCareTracker.External.Interfaces;
|
||||||
|
using CarCareTracker.Models;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Implementations
|
||||||
|
{
|
||||||
|
public class PGVehicleDataAccess: IVehicleDataAccess
|
||||||
|
{
|
||||||
|
private NpgsqlDataSource pgDataSource;
|
||||||
|
private readonly ILogger<PGVehicleDataAccess> _logger;
|
||||||
|
private static string tableName = "vehicles";
|
||||||
|
public PGVehicleDataAccess(IConfiguration config, ILogger<PGVehicleDataAccess> logger)
|
||||||
|
{
|
||||||
|
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
|
||||||
|
_logger = logger;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//create table if not exist.
|
||||||
|
string initCMD = $"CREATE TABLE IF NOT EXISTS app.{tableName} (id INT GENERATED BY DEFAULT AS IDENTITY primary key, data jsonb not null)";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(initCMD))
|
||||||
|
{
|
||||||
|
ctext.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool SaveVehicle(Vehicle vehicle)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(vehicle.ImageLocation))
|
||||||
|
{
|
||||||
|
vehicle.ImageLocation = "/defaults/noimage.png";
|
||||||
|
}
|
||||||
|
if (vehicle.Id == default)
|
||||||
|
{
|
||||||
|
string cmd = $"INSERT INTO app.{tableName} (data) VALUES(CAST(@data AS jsonb)) RETURNING id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("data", "{}");
|
||||||
|
vehicle.Id = Convert.ToInt32(ctext.ExecuteScalar());
|
||||||
|
//update json data
|
||||||
|
if (vehicle.Id != default)
|
||||||
|
{
|
||||||
|
string cmdU = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctextU = pgDataSource.CreateCommand(cmdU))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(vehicle);
|
||||||
|
ctextU.Parameters.AddWithValue("id", vehicle.Id);
|
||||||
|
ctextU.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctextU.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vehicle.Id != default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string cmd = $"UPDATE app.{tableName} SET data = CAST(@data AS jsonb) WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
var serializedData = JsonSerializer.Serialize(vehicle);
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicle.Id);
|
||||||
|
ctext.Parameters.AddWithValue("data", serializedData);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public bool DeleteVehicle(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"DELETE FROM app.{tableName} WHERE id = @id";
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
return ctext.ExecuteNonQuery() > 0;
|
||||||
|
}
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<Vehicle> GetVehicles()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, data FROM app.{tableName} ORDER BY id ASC";
|
||||||
|
var results = new List<Vehicle>();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
Vehicle vehicle = JsonSerializer.Deserialize<Vehicle>(reader["data"] as string);
|
||||||
|
results.Add(vehicle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new List<Vehicle>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Vehicle GetVehicleById(int vehicleId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cmd = $"SELECT id, data FROM app.{tableName} WHERE id = @id";
|
||||||
|
Vehicle vehicle = new Vehicle();
|
||||||
|
using (var ctext = pgDataSource.CreateCommand(cmd))
|
||||||
|
{
|
||||||
|
ctext.Parameters.AddWithValue("id", vehicleId);
|
||||||
|
using (NpgsqlDataReader reader = ctext.ExecuteReader())
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
vehicle = JsonSerializer.Deserialize<Vehicle>(reader["data"] as string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vehicle;
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return new Vehicle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
External/Interfaces/IExtraFieldDataAccess.cs
vendored
Normal file
10
External/Interfaces/IExtraFieldDataAccess.cs
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using CarCareTracker.Models;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Interfaces
|
||||||
|
{
|
||||||
|
public interface IExtraFieldDataAccess
|
||||||
|
{
|
||||||
|
public RecordExtraField GetExtraFieldsById(int importMode);
|
||||||
|
public bool SaveExtraFields(RecordExtraField record);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
External/Interfaces/IPlanRecordTemplateDataAccess.cs
vendored
Normal file
13
External/Interfaces/IPlanRecordTemplateDataAccess.cs
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using CarCareTracker.Models;
|
||||||
|
|
||||||
|
namespace CarCareTracker.External.Interfaces
|
||||||
|
{
|
||||||
|
public interface IPlanRecordTemplateDataAccess
|
||||||
|
{
|
||||||
|
public List<PlanRecordInput> GetPlanRecordTemplatesByVehicleId(int vehicleId);
|
||||||
|
public PlanRecordInput GetPlanRecordTemplateById(int planRecordId);
|
||||||
|
public bool DeletePlanRecordTemplateById(int planRecordId);
|
||||||
|
public bool SavePlanRecordTemplateToVehicle(PlanRecordInput planRecord);
|
||||||
|
public bool DeleteAllPlanRecordTemplatesByVehicleId(int vehicleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ namespace CarCareTracker.Helper
|
|||||||
{
|
{
|
||||||
UserConfig GetUserConfig(ClaimsPrincipal user);
|
UserConfig GetUserConfig(ClaimsPrincipal user);
|
||||||
bool SaveUserConfig(ClaimsPrincipal user, UserConfig configData);
|
bool SaveUserConfig(ClaimsPrincipal user, UserConfig configData);
|
||||||
|
string GetLogoUrl();
|
||||||
|
string GetServerLanguage();
|
||||||
|
bool GetServerEnableShopSupplies();
|
||||||
|
string GetServerPostgresConnection();
|
||||||
public bool DeleteUserConfig(int userId);
|
public bool DeleteUserConfig(int userId);
|
||||||
}
|
}
|
||||||
public class ConfigHelper : IConfigHelper
|
public class ConfigHelper : IConfigHelper
|
||||||
@@ -24,6 +28,34 @@ namespace CarCareTracker.Helper
|
|||||||
_userConfig = userConfig;
|
_userConfig = userConfig;
|
||||||
_cache = memoryCache;
|
_cache = memoryCache;
|
||||||
}
|
}
|
||||||
|
public string GetLogoUrl()
|
||||||
|
{
|
||||||
|
var logoUrl = _config["LUBELOGGER_LOGO_URL"];
|
||||||
|
if (string.IsNullOrWhiteSpace(logoUrl))
|
||||||
|
{
|
||||||
|
logoUrl = "/defaults/lubelogger_logo.png";
|
||||||
|
}
|
||||||
|
return logoUrl;
|
||||||
|
}
|
||||||
|
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);
|
||||||
@@ -94,9 +126,14 @@ namespace CarCareTracker.Helper
|
|||||||
EnableAuth = bool.Parse(_config[nameof(UserConfig.EnableAuth)]),
|
EnableAuth = bool.Parse(_config[nameof(UserConfig.EnableAuth)]),
|
||||||
HideZero = bool.Parse(_config[nameof(UserConfig.HideZero)]),
|
HideZero = bool.Parse(_config[nameof(UserConfig.HideZero)]),
|
||||||
UseUKMPG = bool.Parse(_config[nameof(UserConfig.UseUKMPG)]),
|
UseUKMPG = bool.Parse(_config[nameof(UserConfig.UseUKMPG)]),
|
||||||
|
UseMarkDownOnSavedNotes = bool.Parse(_config[nameof(UserConfig.UseMarkDownOnSavedNotes)]),
|
||||||
UseThreeDecimalGasCost = bool.Parse(_config[nameof(UserConfig.UseThreeDecimalGasCost)]),
|
UseThreeDecimalGasCost = bool.Parse(_config[nameof(UserConfig.UseThreeDecimalGasCost)]),
|
||||||
EnableAutoReminderRefresh = bool.Parse(_config[nameof(UserConfig.EnableAutoReminderRefresh)]),
|
EnableAutoReminderRefresh = bool.Parse(_config[nameof(UserConfig.EnableAutoReminderRefresh)]),
|
||||||
EnableAutoOdometerInsert = bool.Parse(_config[nameof(UserConfig.EnableAutoOdometerInsert)]),
|
EnableAutoOdometerInsert = bool.Parse(_config[nameof(UserConfig.EnableAutoOdometerInsert)]),
|
||||||
|
PreferredGasMileageUnit = _config[nameof(UserConfig.PreferredGasMileageUnit)],
|
||||||
|
PreferredGasUnit = _config[nameof(UserConfig.PreferredGasUnit)],
|
||||||
|
UserLanguage = _config[nameof(UserConfig.UserLanguage)],
|
||||||
|
EnableShopSupplies = bool.Parse(_config[nameof(UserConfig.EnableShopSupplies)]),
|
||||||
VisibleTabs = _config.GetSection("VisibleTabs").Get<List<ImportMode>>(),
|
VisibleTabs = _config.GetSection("VisibleTabs").Get<List<ImportMode>>(),
|
||||||
DefaultTab = (ImportMode)int.Parse(_config[nameof(UserConfig.DefaultTab)])
|
DefaultTab = (ImportMode)int.Parse(_config[nameof(UserConfig.DefaultTab)])
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.IO.Compression;
|
using CarCareTracker.Models;
|
||||||
|
using System.IO.Compression;
|
||||||
|
|
||||||
namespace CarCareTracker.Helper
|
namespace CarCareTracker.Helper
|
||||||
{
|
{
|
||||||
@@ -6,9 +7,12 @@ namespace CarCareTracker.Helper
|
|||||||
{
|
{
|
||||||
string GetFullFilePath(string currentFilePath, bool mustExist = true);
|
string GetFullFilePath(string currentFilePath, bool mustExist = true);
|
||||||
string MoveFileFromTemp(string currentFilePath, string newFolder);
|
string MoveFileFromTemp(string currentFilePath, string newFolder);
|
||||||
|
bool RenameFile(string currentFilePath, string newName);
|
||||||
bool DeleteFile(string currentFilePath);
|
bool DeleteFile(string currentFilePath);
|
||||||
string MakeBackup();
|
string MakeBackup();
|
||||||
bool RestoreBackup(string fileName);
|
bool RestoreBackup(string fileName, bool clearExisting = false);
|
||||||
|
string MakeAttachmentsExport(List<GenericReportModel> exportData);
|
||||||
|
List<string> GetLanguages();
|
||||||
}
|
}
|
||||||
public class FileHelper : IFileHelper
|
public class FileHelper : IFileHelper
|
||||||
{
|
{
|
||||||
@@ -19,6 +23,40 @@ namespace CarCareTracker.Helper
|
|||||||
_webEnv = webEnv;
|
_webEnv = webEnv;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
public List<string> GetLanguages()
|
||||||
|
{
|
||||||
|
var languagePath = Path.Combine(_webEnv.WebRootPath, "translations");
|
||||||
|
var defaultList = new List<string>() { "en_US" };
|
||||||
|
if (Directory.Exists(languagePath))
|
||||||
|
{
|
||||||
|
var listOfLanguages = Directory.GetFiles(languagePath);
|
||||||
|
if (listOfLanguages.Any())
|
||||||
|
{
|
||||||
|
defaultList.AddRange(listOfLanguages.Select(x => Path.GetFileNameWithoutExtension(x)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultList;
|
||||||
|
}
|
||||||
|
public bool RenameFile(string currentFilePath, string newName)
|
||||||
|
{
|
||||||
|
var fullFilePath = GetFullFilePath(currentFilePath);
|
||||||
|
if (!string.IsNullOrWhiteSpace(fullFilePath))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var originalFileName = Path.GetFileNameWithoutExtension(fullFilePath);
|
||||||
|
var newFilePath = fullFilePath.Replace(originalFileName, newName);
|
||||||
|
File.Move(fullFilePath, newFilePath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
public string GetFullFilePath(string currentFilePath, bool mustExist = true)
|
public string GetFullFilePath(string currentFilePath, bool mustExist = true)
|
||||||
{
|
{
|
||||||
if (currentFilePath.StartsWith("/"))
|
if (currentFilePath.StartsWith("/"))
|
||||||
@@ -38,7 +76,7 @@ namespace CarCareTracker.Helper
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public bool RestoreBackup(string fileName)
|
public bool RestoreBackup(string fileName, bool clearExisting = false)
|
||||||
{
|
{
|
||||||
var fullFilePath = GetFullFilePath(fileName);
|
var fullFilePath = GetFullFilePath(fileName);
|
||||||
if (string.IsNullOrWhiteSpace(fullFilePath))
|
if (string.IsNullOrWhiteSpace(fullFilePath))
|
||||||
@@ -64,9 +102,17 @@ namespace CarCareTracker.Helper
|
|||||||
{
|
{
|
||||||
Directory.CreateDirectory(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
|
//copy each files from temp folder to newPath
|
||||||
var filesToUpload = Directory.GetFiles(imagePath);
|
var filesToUpload = Directory.GetFiles(imagePath);
|
||||||
foreach(string file in filesToUpload)
|
foreach (string file in filesToUpload)
|
||||||
{
|
{
|
||||||
File.Copy(file, $"{existingPath}/{Path.GetFileName(file)}", true);
|
File.Copy(file, $"{existingPath}/{Path.GetFileName(file)}", true);
|
||||||
}
|
}
|
||||||
@@ -78,6 +124,14 @@ namespace CarCareTracker.Helper
|
|||||||
{
|
{
|
||||||
Directory.CreateDirectory(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
|
//copy each files from temp folder to newPath
|
||||||
var filesToUpload = Directory.GetFiles(documentPath);
|
var filesToUpload = Directory.GetFiles(documentPath);
|
||||||
foreach (string file in filesToUpload)
|
foreach (string file in filesToUpload)
|
||||||
@@ -100,12 +154,37 @@ namespace CarCareTracker.Helper
|
|||||||
File.Move(configPath, StaticHelper.UserConfigPath, true);
|
File.Move(configPath, StaticHelper.UserConfigPath, true);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception ex)
|
}
|
||||||
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, $"Error Restoring Database Backup: {ex.Message}");
|
_logger.LogError(ex, $"Error Restoring Database Backup: {ex.Message}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public string MakeAttachmentsExport(List<GenericReportModel> exportData)
|
||||||
|
{
|
||||||
|
var folderName = Guid.NewGuid();
|
||||||
|
var tempPath = Path.Combine(_webEnv.WebRootPath, $"temp/{folderName}");
|
||||||
|
if (!Directory.Exists(tempPath))
|
||||||
|
Directory.CreateDirectory(tempPath);
|
||||||
|
int fileIndex = 0;
|
||||||
|
foreach (GenericReportModel reportModel in exportData)
|
||||||
|
{
|
||||||
|
foreach (UploadedFiles file in reportModel.Files)
|
||||||
|
{
|
||||||
|
var fileToCopy = GetFullFilePath(file.Location);
|
||||||
|
var destFileName = $"{tempPath}/{fileIndex}{Path.GetExtension(file.Location)}";
|
||||||
|
File.Copy(fileToCopy, destFileName);
|
||||||
|
fileIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var destFilePath = $"{tempPath}.zip";
|
||||||
|
ZipFile.CreateFromDirectory(tempPath, destFilePath);
|
||||||
|
//delete temp directory
|
||||||
|
Directory.Delete(tempPath, true);
|
||||||
|
var zipFileName = $"/temp/{folderName}.zip";
|
||||||
|
return zipFileName;
|
||||||
|
}
|
||||||
public string MakeBackup()
|
public string MakeBackup()
|
||||||
{
|
{
|
||||||
var folderName = $"db_backup_{DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss")}";
|
var folderName = $"db_backup_{DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss")}";
|
||||||
|
|||||||
@@ -5,26 +5,36 @@ namespace CarCareTracker.Helper
|
|||||||
public interface IGasHelper
|
public interface IGasHelper
|
||||||
{
|
{
|
||||||
List<GasRecordViewModel> GetGasRecordViewModels(List<GasRecord> result, bool useMPG, bool useUKMPG);
|
List<GasRecordViewModel> GetGasRecordViewModels(List<GasRecord> result, bool useMPG, bool useUKMPG);
|
||||||
string GetAverageGasMileage(List<GasRecordViewModel> results);
|
string GetAverageGasMileage(List<GasRecordViewModel> results, bool useMPG);
|
||||||
}
|
}
|
||||||
public class GasHelper : IGasHelper
|
public class GasHelper : IGasHelper
|
||||||
{
|
{
|
||||||
public string GetAverageGasMileage(List<GasRecordViewModel> results)
|
public string GetAverageGasMileage(List<GasRecordViewModel> results, bool useMPG)
|
||||||
{
|
{
|
||||||
var recordWithCalculatedMPG = results.Where(x => x.MilesPerGallon > 0);
|
var recordsToCalculate = results.Where(x => x.IncludeInAverage);
|
||||||
var minMileage = results.Min(x => x.Mileage);
|
if (recordsToCalculate.Any())
|
||||||
if (recordWithCalculatedMPG.Any())
|
|
||||||
{
|
{
|
||||||
var maxMileage = recordWithCalculatedMPG.Max(x => x.Mileage);
|
try
|
||||||
var totalGallonsConsumed = recordWithCalculatedMPG.Sum(x => x.Gallons);
|
{
|
||||||
var deltaMileage = maxMileage - minMileage;
|
var totalMileage = recordsToCalculate.Sum(x => x.DeltaMileage);
|
||||||
var averageGasMileage = (maxMileage - minMileage) / totalGallonsConsumed;
|
var totalGallons = recordsToCalculate.Sum(x => x.Gallons);
|
||||||
return averageGasMileage.ToString("F");
|
var averageGasMileage = totalMileage / totalGallons;
|
||||||
|
if (!useMPG && averageGasMileage > 0)
|
||||||
|
{
|
||||||
|
averageGasMileage = 100 / averageGasMileage;
|
||||||
|
}
|
||||||
|
return averageGasMileage.ToString("F");
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return "0";
|
return "0";
|
||||||
}
|
}
|
||||||
public List<GasRecordViewModel> GetGasRecordViewModels(List<GasRecord> result, bool useMPG, bool useUKMPG)
|
public List<GasRecordViewModel> GetGasRecordViewModels(List<GasRecord> result, bool useMPG, bool useUKMPG)
|
||||||
{
|
{
|
||||||
|
//need to order by to get correct results
|
||||||
|
result = result.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList();
|
||||||
var computedResults = new List<GasRecordViewModel>();
|
var computedResults = new List<GasRecordViewModel>();
|
||||||
int previousMileage = 0;
|
int previousMileage = 0;
|
||||||
decimal unFactoredConsumption = 0.00M;
|
decimal unFactoredConsumption = 0.00M;
|
||||||
@@ -60,7 +70,8 @@ namespace CarCareTracker.Helper
|
|||||||
CostPerGallon = convertedConsumption > 0.00M ? currentObject.Cost / convertedConsumption : 0,
|
CostPerGallon = convertedConsumption > 0.00M ? currentObject.Cost / convertedConsumption : 0,
|
||||||
IsFillToFull = currentObject.IsFillToFull,
|
IsFillToFull = currentObject.IsFillToFull,
|
||||||
MissedFuelUp = currentObject.MissedFuelUp,
|
MissedFuelUp = currentObject.MissedFuelUp,
|
||||||
Notes = currentObject.Notes
|
Notes = currentObject.Notes,
|
||||||
|
Tags = currentObject.Tags
|
||||||
};
|
};
|
||||||
if (currentObject.MissedFuelUp)
|
if (currentObject.MissedFuelUp)
|
||||||
{
|
{
|
||||||
@@ -73,9 +84,16 @@ namespace CarCareTracker.Helper
|
|||||||
else if (currentObject.IsFillToFull)
|
else if (currentObject.IsFillToFull)
|
||||||
{
|
{
|
||||||
//if user filled to full.
|
//if user filled to full.
|
||||||
if (convertedConsumption > 0.00M)
|
if (convertedConsumption > 0.00M && deltaMileage > 0)
|
||||||
{
|
{
|
||||||
gasRecordViewModel.MilesPerGallon = useMPG ? (unFactoredMileage + deltaMileage) / (unFactoredConsumption + convertedConsumption) : 100 / ((unFactoredMileage + deltaMileage) / (unFactoredConsumption + convertedConsumption));
|
try
|
||||||
|
{
|
||||||
|
gasRecordViewModel.MilesPerGallon = useMPG ? (unFactoredMileage + deltaMileage) / (unFactoredConsumption + convertedConsumption) : 100 / ((unFactoredMileage + deltaMileage) / (unFactoredConsumption + convertedConsumption));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
gasRecordViewModel.MilesPerGallon = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//reset unFactored vars
|
//reset unFactored vars
|
||||||
unFactoredConsumption = 0;
|
unFactoredConsumption = 0;
|
||||||
@@ -105,7 +123,8 @@ namespace CarCareTracker.Helper
|
|||||||
CostPerGallon = convertedConsumption > 0.00M ? currentObject.Cost / convertedConsumption : 0,
|
CostPerGallon = convertedConsumption > 0.00M ? currentObject.Cost / convertedConsumption : 0,
|
||||||
IsFillToFull = currentObject.IsFillToFull,
|
IsFillToFull = currentObject.IsFillToFull,
|
||||||
MissedFuelUp = currentObject.MissedFuelUp,
|
MissedFuelUp = currentObject.MissedFuelUp,
|
||||||
Notes = currentObject.Notes
|
Notes = currentObject.Notes,
|
||||||
|
Tags = currentObject.Tags
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
previousMileage = currentObject.Mileage;
|
previousMileage = currentObject.Mileage;
|
||||||
|
|||||||
@@ -8,15 +8,19 @@ 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 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;
|
||||||
public MailHelper(
|
public MailHelper(
|
||||||
IConfiguration config
|
IConfiguration config,
|
||||||
|
IFileHelper fileHelper
|
||||||
) {
|
) {
|
||||||
//load mailConfig from Configuration
|
//load mailConfig from Configuration
|
||||||
mailConfig = config.GetSection("MailConfig").Get<MailConfig>();
|
mailConfig = config.GetSection("MailConfig").Get<MailConfig>();
|
||||||
|
_fileHelper = fileHelper;
|
||||||
}
|
}
|
||||||
public OperationResponse NotifyUserForRegistration(string emailAddress, string token)
|
public OperationResponse NotifyUserForRegistration(string emailAddress, string token)
|
||||||
{
|
{
|
||||||
@@ -60,20 +64,67 @@ namespace CarCareTracker.Helper
|
|||||||
return new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage };
|
return new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private bool SendEmail(string emailTo, string emailSubject, string emailBody) {
|
public OperationResponse NotifyUserForReminders(Vehicle vehicle, List<string> emailAddresses, List<ReminderRecordViewModel> reminders)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(mailConfig.EmailServer))
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "SMTP Server Not Setup" };
|
||||||
|
}
|
||||||
|
if (!emailAddresses.Any())
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "No recipients could be found" };
|
||||||
|
}
|
||||||
|
if (!reminders.Any())
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = "No reminders could be found" };
|
||||||
|
}
|
||||||
|
//get email template, this file has to exist since it's a static file.
|
||||||
|
var emailTemplatePath = _fileHelper.GetFullFilePath(StaticHelper.ReminderEmailTemplate);
|
||||||
|
string emailSubject = $"Vehicle Reminders From LubeLogger - {DateTime.Now.ToShortDateString()}";
|
||||||
|
//construct html table.
|
||||||
|
string emailBody = File.ReadAllText(emailTemplatePath);
|
||||||
|
emailBody = emailBody.Replace("{VehicleInformation}", $"{vehicle.Year} {vehicle.Make} {vehicle.Model} #{vehicle.LicensePlate}");
|
||||||
|
string tableBody = "";
|
||||||
|
foreach(ReminderRecordViewModel reminder in reminders)
|
||||||
|
{
|
||||||
|
var dueOn = reminder.Metric == ReminderMetric.Both ? $"{reminder.Date} or {reminder.Mileage}" : reminder.Metric == ReminderMetric.Date ? $"{reminder.Date.ToShortDateString()}" : $"{reminder.Mileage}";
|
||||||
|
tableBody += $"<tr class='{reminder.Urgency}'><td>{StaticHelper.GetTitleCaseReminderUrgency(reminder.Urgency)}</td><td>{reminder.Description}</td><td>{dueOn}</td></tr>";
|
||||||
|
}
|
||||||
|
emailBody = emailBody.Replace("{TableBody}", tableBody);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (string emailAddress in emailAddresses)
|
||||||
|
{
|
||||||
|
SendEmail(emailAddress, emailSubject, emailBody, true, true);
|
||||||
|
}
|
||||||
|
return new OperationResponse { Success = true, Message = "Email Sent!" };
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
return new OperationResponse { Success = false, Message = ex.Message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private bool SendEmail(string emailTo, string emailSubject, string emailBody, bool isBodyHtml = false, bool useAsync = false) {
|
||||||
string to = emailTo;
|
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);
|
MailMessage message = new MailMessage(from, to);
|
||||||
message.Subject = emailSubject;
|
message.Subject = emailSubject;
|
||||||
message.Body = emailBody;
|
message.Body = emailBody;
|
||||||
|
message.IsBodyHtml = isBodyHtml;
|
||||||
SmtpClient client = new SmtpClient(server);
|
SmtpClient client = new SmtpClient(server);
|
||||||
client.EnableSsl = mailConfig.UseSSL;
|
client.EnableSsl = mailConfig.UseSSL;
|
||||||
client.Port = mailConfig.Port;
|
client.Port = mailConfig.Port;
|
||||||
client.Credentials = new NetworkCredential(mailConfig.Username, mailConfig.Password);
|
client.Credentials = new NetworkCredential(mailConfig.Username, mailConfig.Password);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
client.Send(message);
|
if (useAsync)
|
||||||
|
{
|
||||||
|
client.SendMailAsync(message, new CancellationToken());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
client.Send(message);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -13,16 +13,43 @@ namespace CarCareTracker.Helper
|
|||||||
{
|
{
|
||||||
if (existingReminder.Metric == ReminderMetric.Both)
|
if (existingReminder.Metric == ReminderMetric.Both)
|
||||||
{
|
{
|
||||||
existingReminder.Date = existingReminder.Date.AddMonths((int)existingReminder.ReminderMonthInterval);
|
if (existingReminder.ReminderMonthInterval != ReminderMonthInterval.Other)
|
||||||
existingReminder.Mileage += (int)existingReminder.ReminderMileageInterval;
|
{
|
||||||
|
existingReminder.Date = existingReminder.Date.AddMonths((int)existingReminder.ReminderMonthInterval);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
existingReminder.Date = existingReminder.Date.AddMonths(existingReminder.CustomMonthInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingReminder.ReminderMileageInterval != ReminderMileageInterval.Other)
|
||||||
|
{
|
||||||
|
existingReminder.Mileage += (int)existingReminder.ReminderMileageInterval;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
existingReminder.Mileage += existingReminder.CustomMileageInterval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (existingReminder.Metric == ReminderMetric.Odometer)
|
else if (existingReminder.Metric == ReminderMetric.Odometer)
|
||||||
{
|
{
|
||||||
existingReminder.Mileage += (int)existingReminder.ReminderMileageInterval;
|
if (existingReminder.ReminderMileageInterval != ReminderMileageInterval.Other)
|
||||||
|
{
|
||||||
|
existingReminder.Mileage += (int)existingReminder.ReminderMileageInterval;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
existingReminder.Mileage += 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 = existingReminder.Date.AddMonths((int)existingReminder.ReminderMonthInterval);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
existingReminder.Date = existingReminder.Date.AddMonths(existingReminder.CustomMonthInterval);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return existingReminder;
|
return existingReminder;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using CarCareTracker.Models;
|
using CarCareTracker.Models;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace CarCareTracker.Helper
|
namespace CarCareTracker.Helper
|
||||||
{
|
{
|
||||||
@@ -10,6 +12,22 @@ namespace CarCareTracker.Helper
|
|||||||
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 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)
|
||||||
{
|
{
|
||||||
@@ -63,5 +81,138 @@ namespace CarCareTracker.Helper
|
|||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
public static List<CostForVehicleByMonth> GetBaseLineCosts()
|
||||||
|
{
|
||||||
|
return new List<CostForVehicleByMonth>()
|
||||||
|
{
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(1), MonthId = 1, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(2), MonthId = 2, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(3), MonthId = 3, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(4), MonthId = 4, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(5), MonthId = 5, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(6), MonthId = 6, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(7), MonthId = 7, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(8), MonthId = 8, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(9), MonthId = 9, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(10), MonthId = 10, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(11), MonthId = 11, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(12), MonthId = 12, Cost = 0M}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static List<CostForVehicleByMonth> GetBaseLineCostsNoMonthName()
|
||||||
|
{
|
||||||
|
return new List<CostForVehicleByMonth>()
|
||||||
|
{
|
||||||
|
new CostForVehicleByMonth { MonthId = 1, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthId = 2, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthId = 3, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthId = 4, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthId = 5, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthId = 6, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthId = 7, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthId = 8, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth {MonthId = 9, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth { MonthId = 10, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth { MonthId = 11, Cost = 0M},
|
||||||
|
new CostForVehicleByMonth { MonthId = 12, Cost = 0M}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServiceRecord GenericToServiceRecord(GenericRecord input)
|
||||||
|
{
|
||||||
|
return new ServiceRecord
|
||||||
|
{
|
||||||
|
VehicleId = input.VehicleId,
|
||||||
|
Date = input.Date,
|
||||||
|
Description = input.Description,
|
||||||
|
Cost = input.Cost,
|
||||||
|
Mileage = input.Mileage,
|
||||||
|
Files = input.Files,
|
||||||
|
Notes = input.Notes,
|
||||||
|
Tags = input.Tags,
|
||||||
|
ExtraFields = input.ExtraFields
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static CollisionRecord GenericToRepairRecord(GenericRecord input)
|
||||||
|
{
|
||||||
|
return new CollisionRecord
|
||||||
|
{
|
||||||
|
VehicleId = input.VehicleId,
|
||||||
|
Date = input.Date,
|
||||||
|
Description = input.Description,
|
||||||
|
Cost = input.Cost,
|
||||||
|
Mileage = input.Mileage,
|
||||||
|
Files = input.Files,
|
||||||
|
Notes = input.Notes,
|
||||||
|
Tags = input.Tags,
|
||||||
|
ExtraFields = input.ExtraFields
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static UpgradeRecord GenericToUpgradeRecord(GenericRecord input)
|
||||||
|
{
|
||||||
|
return new UpgradeRecord
|
||||||
|
{
|
||||||
|
VehicleId = input.VehicleId,
|
||||||
|
Date = input.Date,
|
||||||
|
Description = input.Description,
|
||||||
|
Cost = input.Cost,
|
||||||
|
Mileage = input.Mileage,
|
||||||
|
Files = input.Files,
|
||||||
|
Notes = input.Notes,
|
||||||
|
Tags = input.Tags,
|
||||||
|
ExtraFields = input.ExtraFields
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
//append the fields.
|
||||||
|
foreach (ExtraField extraField in recordExtraFields)
|
||||||
|
{
|
||||||
|
extraField.IsRequired = templateExtraFields.Where(x => x.Name == extraField.Name).First().IsRequired;
|
||||||
|
}
|
||||||
|
return recordExtraFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetFuelEconomyUnit(bool useKwh, bool useHours, bool useMPG, bool useUKMPG)
|
||||||
|
{
|
||||||
|
string fuelEconomyUnit;
|
||||||
|
if (useKwh)
|
||||||
|
{
|
||||||
|
var distanceUnit = useHours ? "h" : (useMPG ? "mi." : "km");
|
||||||
|
fuelEconomyUnit = useMPG ? $"{distanceUnit}/kWh" : $"kWh/100{distanceUnit}";
|
||||||
|
}
|
||||||
|
else if (useMPG && useUKMPG)
|
||||||
|
{
|
||||||
|
fuelEconomyUnit = useHours ? "h/g" : "mpg";
|
||||||
|
}
|
||||||
|
else if (useUKMPG)
|
||||||
|
{
|
||||||
|
fuelEconomyUnit = useHours ? "l/100h" : "l/100mi.";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fuelEconomyUnit = useHours ? (useMPG ? "h/g" : "l/100h") : (useMPG ? "mpg" : "l/100km");
|
||||||
|
}
|
||||||
|
return fuelEconomyUnit;
|
||||||
|
}
|
||||||
|
public static long GetEpochFromDateTime(DateTime date)
|
||||||
|
{
|
||||||
|
return new DateTimeOffset(date).ToUnixTimeMilliseconds();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
62
Helper/TranslationHelper.cs
Normal file
62
Helper/TranslationHelper.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using CarCareTracker.Models;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Helper
|
||||||
|
{
|
||||||
|
public interface ITranslationHelper
|
||||||
|
{
|
||||||
|
string Translate(string userLanguage, string text);
|
||||||
|
}
|
||||||
|
public class TranslationHelper : ITranslationHelper
|
||||||
|
{
|
||||||
|
private readonly IFileHelper _fileHelper;
|
||||||
|
private readonly IConfiguration _config;
|
||||||
|
private IMemoryCache _cache;
|
||||||
|
public TranslationHelper(IFileHelper fileHelper, IConfiguration config, IMemoryCache memoryCache)
|
||||||
|
{
|
||||||
|
_fileHelper = fileHelper;
|
||||||
|
_config = config;
|
||||||
|
_cache = memoryCache;
|
||||||
|
}
|
||||||
|
public string Translate(string userLanguage, string text)
|
||||||
|
{
|
||||||
|
bool create = bool.Parse(_config["LUBELOGGER_TRANSLATOR"] ?? "false");
|
||||||
|
//transform input text into key.
|
||||||
|
string translationKey = text.Replace(" ", "_");
|
||||||
|
var translationFilePath = userLanguage == "en_US" ? _fileHelper.GetFullFilePath($"/defaults/en_US.json") : _fileHelper.GetFullFilePath($"/translations/{userLanguage}.json", false);
|
||||||
|
var dictionary = _cache.GetOrCreate<Dictionary<string, string>>($"lang_{userLanguage}", entry =>
|
||||||
|
{
|
||||||
|
entry.SlidingExpiration = TimeSpan.FromHours(1);
|
||||||
|
if (File.Exists(translationFilePath))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var translationFile = File.ReadAllText(translationFilePath);
|
||||||
|
var translationDictionary = JsonSerializer.Deserialize<Dictionary<string, string>>(translationFile);
|
||||||
|
return translationDictionary ?? new Dictionary<string, string>();
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
return new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (dictionary != null && dictionary.ContainsKey(translationKey))
|
||||||
|
{
|
||||||
|
return dictionary[translationKey];
|
||||||
|
}
|
||||||
|
else if (create && File.Exists(translationFilePath))
|
||||||
|
{
|
||||||
|
//create entry
|
||||||
|
dictionary.Add(translationKey, text);
|
||||||
|
File.WriteAllText(translationFilePath, JsonSerializer.Serialize(dictionary));
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -280,19 +280,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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ namespace CarCareTracker.MapProfile
|
|||||||
Map(m => m.Progress).Name(["progress"]);
|
Map(m => m.Progress).Name(["progress"]);
|
||||||
Map(m => m.Type).Name(["type"]);
|
Map(m => m.Type).Name(["type"]);
|
||||||
Map(m => m.Priority).Name(["priority"]);
|
Map(m => m.Priority).Name(["priority"]);
|
||||||
|
Map(m => m.Tags).Name(["tags"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,7 +157,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 +176,7 @@ namespace CarCareTracker.Middleware
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Response.Redirect("/Error/401");
|
Response.Redirect("/Error/Unauthorized");
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
namespace CarCareTracker.Models
|
namespace CarCareTracker.Models
|
||||||
{
|
{
|
||||||
public class CollisionRecord
|
public class CollisionRecord: GenericRecord
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
|
||||||
public int VehicleId { get; set; }
|
|
||||||
public DateTime Date { get; set; }
|
|
||||||
public int Mileage { get; set; }
|
|
||||||
public string Description { get; set; }
|
|
||||||
public decimal Cost { get; set; }
|
|
||||||
public string Notes { get; set; }
|
|
||||||
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
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<SupplyUsage> Supplies { get; set; } = new List<SupplyUsage>();
|
public List<SupplyUsage> Supplies { get; set; } = new List<SupplyUsage>();
|
||||||
public CollisionRecord ToCollisionRecord() { return new CollisionRecord { Id = Id, VehicleId = VehicleId, Date = DateTime.Parse(Date), Cost = Cost, Mileage = Mileage, Description = Description, Notes = Notes, Files = Files }; }
|
public List<string> Tags { get; set; } = new List<string>();
|
||||||
|
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
|
||||||
|
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 }; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
9
Models/ExtraField.cs
Normal file
9
Models/ExtraField.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public class ExtraField
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Value { get; set; }
|
||||||
|
public bool IsRequired { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,5 +18,7 @@
|
|||||||
public bool MissedFuelUp { get; set; } = false;
|
public bool MissedFuelUp { get; set; } = false;
|
||||||
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<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
public bool MissedFuelUp { get; set; } = false;
|
public bool MissedFuelUp { get; set; } = false;
|
||||||
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<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,
|
||||||
@@ -28,7 +30,9 @@
|
|||||||
Files = Files,
|
Files = Files,
|
||||||
IsFillToFull = IsFillToFull,
|
IsFillToFull = IsFillToFull,
|
||||||
MissedFuelUp = MissedFuelUp,
|
MissedFuelUp = MissedFuelUp,
|
||||||
Notes = Notes
|
Notes = Notes,
|
||||||
|
Tags = Tags,
|
||||||
|
ExtraFields = ExtraFields
|
||||||
}; }
|
}; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
{
|
{
|
||||||
public class GasRecordInputContainer
|
public class GasRecordInputContainer
|
||||||
{
|
{
|
||||||
public bool UseKwh { get; set; }
|
public bool UseKwh { get; set; }
|
||||||
public GasRecordInput GasRecord { get; set; }
|
public bool UseHours { get; set; }
|
||||||
|
public GasRecordInput GasRecord { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,5 +21,7 @@
|
|||||||
public bool IsFillToFull { get; set; }
|
public bool IsFillToFull { get; set; }
|
||||||
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 bool IncludeInAverage { get { return MilesPerGallon > 0 || (!IsFillToFull && !MissedFuelUp); } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
{
|
{
|
||||||
public class GasRecordViewModelContainer
|
public class GasRecordViewModelContainer
|
||||||
{
|
{
|
||||||
public bool UseKwh { get; set; }
|
public bool UseKwh { get; set; }
|
||||||
public List<GasRecordViewModel> GasRecords { get; set; } = new List<GasRecordViewModel>();
|
public bool UseHours { get; set; }
|
||||||
|
public List<GasRecordViewModel> GasRecords { get; set; } = new List<GasRecordViewModel>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
Models/GenericRecord.cs
Normal file
16
Models/GenericRecord.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public class GenericRecord
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int VehicleId { get; set; }
|
||||||
|
public DateTime Date { get; set; }
|
||||||
|
public int Mileage { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public decimal Cost { get; set; }
|
||||||
|
public string Notes { get; set; }
|
||||||
|
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||||
|
public List<string> Tags { get; set;} = new List<string>();
|
||||||
|
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
public string PartNumber { get; set; }
|
public string PartNumber { get; set; }
|
||||||
public string PartSupplier { get; set; }
|
public string PartSupplier { get; set; }
|
||||||
public string PartQuantity { get; set; }
|
public string PartQuantity { get; set; }
|
||||||
|
public string Tags { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SupplyRecordExportModel
|
public class SupplyRecordExportModel
|
||||||
@@ -34,6 +35,7 @@
|
|||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public string Cost { get; set; }
|
public string Cost { get; set; }
|
||||||
public string Notes { get; set; }
|
public string Notes { get; set; }
|
||||||
|
public string Tags { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ServiceRecordExportModel
|
public class ServiceRecordExportModel
|
||||||
@@ -43,12 +45,14 @@
|
|||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public string Notes { get; set; }
|
public string Notes { get; set; }
|
||||||
public string Cost { get; set; }
|
public string Cost { get; set; }
|
||||||
|
public string Tags { get; set; }
|
||||||
}
|
}
|
||||||
public class OdometerRecordExportModel
|
public class OdometerRecordExportModel
|
||||||
{
|
{
|
||||||
public string Date { get; set; }
|
public string Date { get; set; }
|
||||||
public string Odometer { get; set; }
|
public string Odometer { get; set; }
|
||||||
public string Notes { get; set; }
|
public string Notes { get; set; }
|
||||||
|
public string Tags { get; set; }
|
||||||
}
|
}
|
||||||
public class TaxRecordExportModel
|
public class TaxRecordExportModel
|
||||||
{
|
{
|
||||||
@@ -56,6 +60,7 @@
|
|||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public string Notes { get; set; }
|
public string Notes { get; set; }
|
||||||
public string Cost { get; set; }
|
public string Cost { get; set; }
|
||||||
|
public string Tags { get; set; }
|
||||||
}
|
}
|
||||||
public class GasRecordExportModel
|
public class GasRecordExportModel
|
||||||
{
|
{
|
||||||
@@ -67,6 +72,7 @@
|
|||||||
public string IsFillToFull { get; set; }
|
public string IsFillToFull { get; set; }
|
||||||
public string MissedFuelUp { get; set; }
|
public string MissedFuelUp { get; set; }
|
||||||
public string Notes { get; set; }
|
public string Notes { get; set; }
|
||||||
|
public string Tags { get; set; }
|
||||||
}
|
}
|
||||||
public class ReminderExportModel
|
public class ReminderExportModel
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,5 +6,8 @@
|
|||||||
public int VehicleId { get; set; }
|
public int VehicleId { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public string NoteText { get; set; }
|
public string NoteText { get; set; }
|
||||||
|
public bool Pinned { get; set; }
|
||||||
|
public List<string> Tags { get; set; } = new List<string>();
|
||||||
|
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
public DateTime Date { get; set; }
|
public DateTime Date { get; set; }
|
||||||
public int Mileage { get; set; }
|
public int Mileage { get; set; }
|
||||||
public string Notes { get; set; }
|
public string Notes { get; set; }
|
||||||
|
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>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
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 OdometerRecord ToOdometerRecord() { return new OdometerRecord { Id = Id, VehicleId = VehicleId, Date = DateTime.Parse(Date), Mileage = Mileage, Notes = Notes, Files = Files }; }
|
public List<string> Tags { get; set; } = new List<string>();
|
||||||
|
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 }; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,5 +13,6 @@
|
|||||||
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>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +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 PlanRecord ToPlanRecord() { return new PlanRecord {
|
public PlanRecord ToPlanRecord() { return new PlanRecord {
|
||||||
Id = Id,
|
Id = Id,
|
||||||
VehicleId = VehicleId,
|
VehicleId = VehicleId,
|
||||||
@@ -25,7 +26,8 @@
|
|||||||
ImportMode = ImportMode,
|
ImportMode = ImportMode,
|
||||||
Cost = Cost,
|
Cost = Cost,
|
||||||
Priority = Priority,
|
Priority = Priority,
|
||||||
Progress = Progress
|
Progress = Progress,
|
||||||
|
ExtraFields = ExtraFields
|
||||||
}; }
|
}; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
Models/RecordExtraField.cs
Normal file
14
Models/RecordExtraField.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public class RecordExtraField
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Corresponds to int value of ImportMode enum
|
||||||
|
/// </summary>
|
||||||
|
[BsonId(false)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
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 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;
|
||||||
|
|||||||
@@ -9,19 +9,28 @@
|
|||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
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 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 ReminderRecord ToReminderRecord() { return new ReminderRecord {
|
public ReminderRecord ToReminderRecord()
|
||||||
Id = Id,
|
{
|
||||||
VehicleId = VehicleId,
|
return new ReminderRecord
|
||||||
Date = DateTime.Parse(string.IsNullOrWhiteSpace(Date) ? DateTime.Now.AddDays(1).ToShortDateString() : Date),
|
{
|
||||||
Mileage = Mileage,
|
Id = Id,
|
||||||
Description = Description,
|
VehicleId = VehicleId,
|
||||||
Metric = Metric,
|
Date = DateTime.Parse(string.IsNullOrWhiteSpace(Date) ? DateTime.Now.AddDays(1).ToShortDateString() : Date),
|
||||||
IsRecurring = IsRecurring,
|
Mileage = Mileage,
|
||||||
ReminderMileageInterval = ReminderMileageInterval,
|
Description = Description,
|
||||||
ReminderMonthInterval = ReminderMonthInterval,
|
Metric = Metric,
|
||||||
Notes = Notes }; }
|
IsRecurring = IsRecurring,
|
||||||
|
ReminderMileageInterval = ReminderMileageInterval,
|
||||||
|
ReminderMonthInterval = ReminderMonthInterval,
|
||||||
|
CustomMileageInterval = CustomMileageInterval,
|
||||||
|
CustomMonthInterval = CustomMonthInterval,
|
||||||
|
Notes = Notes
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,5 +11,6 @@
|
|||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public string Notes { get; set; }
|
public string Notes { get; set; }
|
||||||
public decimal Cost { get; set; }
|
public decimal Cost { get; set; }
|
||||||
|
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
namespace CarCareTracker.Models
|
namespace CarCareTracker.Models
|
||||||
{
|
{
|
||||||
public class ServiceRecord
|
public class ServiceRecord: GenericRecord
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
|
||||||
public int VehicleId { get; set; }
|
|
||||||
public DateTime Date { get; set; }
|
|
||||||
public int Mileage { get; set; }
|
|
||||||
public string Description { get; set; }
|
|
||||||
public decimal Cost { get; set; }
|
|
||||||
public string Notes { get; set; }
|
|
||||||
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
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<SupplyUsage> Supplies { get; set; } = new List<SupplyUsage>();
|
public List<SupplyUsage> Supplies { get; set; } = new List<SupplyUsage>();
|
||||||
public ServiceRecord ToServiceRecord() { return new ServiceRecord { Id = Id, VehicleId = VehicleId, Date = DateTime.Parse(Date), Cost = Cost, Mileage = Mileage, Description = Description, Notes = Notes, Files = Files }; }
|
public List<string> Tags { get; set; } = new List<string>();
|
||||||
|
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
|
||||||
|
public ServiceRecord ToServiceRecord() { return new ServiceRecord { Id = Id, VehicleId = VehicleId, Date = DateTime.Parse(Date), Cost = Cost, Mileage = Mileage, Description = Description, Notes = Notes, Files = Files, Tags = Tags, ExtraFields = ExtraFields }; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
Models/Settings/SettingsViewModel.cs
Normal file
8
Models/Settings/SettingsViewModel.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public class SettingsViewModel
|
||||||
|
{
|
||||||
|
public UserConfig UserConfig { get; set; }
|
||||||
|
public List<string> UILanguages { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,5 +33,7 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
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<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
public decimal Cost { get; set; }
|
public decimal Cost { get; set; }
|
||||||
public string Notes { get; set; }
|
public string Notes { get; set; }
|
||||||
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||||
|
public List<string> Tags { get; set; } = new List<string>();
|
||||||
|
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
|
||||||
public SupplyRecord ToSupplyRecord() { return new SupplyRecord {
|
public SupplyRecord ToSupplyRecord() { return new SupplyRecord {
|
||||||
Id = Id,
|
Id = Id,
|
||||||
VehicleId = VehicleId,
|
VehicleId = VehicleId,
|
||||||
@@ -22,6 +24,9 @@
|
|||||||
Quantity = Quantity,
|
Quantity = Quantity,
|
||||||
Description = Description,
|
Description = Description,
|
||||||
Notes = Notes,
|
Notes = Notes,
|
||||||
Files = Files }; }
|
Files = Files,
|
||||||
|
Tags = Tags,
|
||||||
|
ExtraFields = ExtraFields
|
||||||
|
}; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,11 @@
|
|||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public decimal Cost { get; set; }
|
public decimal Cost { get; set; }
|
||||||
public string Notes { get; set; }
|
public string Notes { get; set; }
|
||||||
|
public bool IsRecurring { get; set; } = false;
|
||||||
|
public ReminderMonthInterval RecurringInterval { get; set; } = ReminderMonthInterval.OneYear;
|
||||||
|
public int CustomMonthInterval { get; set; } = 0;
|
||||||
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||||
|
public List<string> Tags { get; set; } = new List<string>();
|
||||||
|
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,25 @@
|
|||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public decimal Cost { get; set; }
|
public decimal Cost { get; set; }
|
||||||
public string Notes { get; set; }
|
public string Notes { get; set; }
|
||||||
|
public bool IsRecurring { get; set; } = false;
|
||||||
|
public ReminderMonthInterval RecurringInterval { get; set; } = ReminderMonthInterval.ThreeMonths;
|
||||||
|
public int CustomMonthInterval { get; set; } = 0;
|
||||||
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
||||||
public TaxRecord ToTaxRecord() { return new TaxRecord { Id = Id, VehicleId = VehicleId, Date = DateTime.Parse(Date), Cost = Cost, Description = Description, Notes = Notes, Files = Files }; }
|
public List<string> Tags { get; set; } = new List<string>();
|
||||||
|
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
|
||||||
|
public TaxRecord ToTaxRecord() { return new TaxRecord {
|
||||||
|
Id = Id,
|
||||||
|
VehicleId = VehicleId,
|
||||||
|
Date = DateTime.Parse(Date),
|
||||||
|
Cost = Cost,
|
||||||
|
Description = Description,
|
||||||
|
Notes = Notes,
|
||||||
|
IsRecurring = IsRecurring,
|
||||||
|
RecurringInterval = RecurringInterval,
|
||||||
|
CustomMonthInterval = CustomMonthInterval,
|
||||||
|
Files = Files,
|
||||||
|
Tags = Tags,
|
||||||
|
ExtraFields = ExtraFields
|
||||||
|
}; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
namespace CarCareTracker.Models
|
namespace CarCareTracker.Models
|
||||||
{
|
{
|
||||||
public class UpgradeRecord
|
public class UpgradeRecord: GenericRecord
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
|
||||||
public int VehicleId { get; set; }
|
|
||||||
public DateTime Date { get; set; }
|
|
||||||
public int Mileage { get; set; }
|
|
||||||
public string Description { get; set; }
|
|
||||||
public decimal Cost { get; set; }
|
|
||||||
public string Notes { get; set; }
|
|
||||||
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
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<SupplyUsage> Supplies { get; set; } = new List<SupplyUsage>();
|
public List<SupplyUsage> Supplies { get; set; } = new List<SupplyUsage>();
|
||||||
public UpgradeRecord ToUpgradeRecord() { return new UpgradeRecord { Id = Id, VehicleId = VehicleId, Date = DateTime.Parse(Date), Cost = Cost, Mileage = Mileage, Description = Description, Notes = Notes, Files = Files }; }
|
public List<string> Tags { get; set; } = new List<string>();
|
||||||
|
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
|
||||||
|
public UpgradeRecord ToUpgradeRecord() { return new UpgradeRecord { Id = Id, VehicleId = VehicleId, Date = DateTime.Parse(Date), Cost = Cost, Mileage = Mileage, Description = Description, Notes = Notes, Files = Files, Tags = Tags, ExtraFields = ExtraFields }; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,15 @@
|
|||||||
public bool HideZero { get; set; }
|
public bool HideZero { get; set; }
|
||||||
public bool UseUKMPG {get;set;}
|
public bool UseUKMPG {get;set;}
|
||||||
public bool UseThreeDecimalGasCost { get; set; }
|
public bool UseThreeDecimalGasCost { get; set; }
|
||||||
|
public bool UseMarkDownOnSavedNotes { get; set; }
|
||||||
public bool EnableAutoReminderRefresh { get; set; }
|
public bool EnableAutoReminderRefresh { get; set; }
|
||||||
public bool EnableAutoOdometerInsert { get; set; }
|
public bool EnableAutoOdometerInsert { get; set; }
|
||||||
|
public bool EnableShopSupplies { get; set; }
|
||||||
|
public string PreferredGasUnit { get; set; } = string.Empty;
|
||||||
|
public string PreferredGasMileageUnit { get; set; } = string.Empty;
|
||||||
public string UserNameHash { get; set; }
|
public string UserNameHash { get; set; }
|
||||||
public string UserPasswordHash { get; set;}
|
public string UserPasswordHash { get; set;}
|
||||||
|
public string UserLanguage { get; set; } = "en_US";
|
||||||
public List<ImportMode> VisibleTabs { get; set; } = new List<ImportMode>() {
|
public List<ImportMode> VisibleTabs { get; set; } = new List<ImportMode>() {
|
||||||
ImportMode.Dashboard,
|
ImportMode.Dashboard,
|
||||||
ImportMode.ServiceRecord,
|
ImportMode.ServiceRecord,
|
||||||
|
|||||||
@@ -9,5 +9,7 @@
|
|||||||
public string Model { get; set; }
|
public string Model { get; set; }
|
||||||
public string LicensePlate { get; set; }
|
public string LicensePlate { get; set; }
|
||||||
public bool IsElectric { get; set; } = false;
|
public bool IsElectric { get; set; } = false;
|
||||||
|
public bool UseHours { get; set; } = false;
|
||||||
|
public List<string> Tags { get; set; } = new List<string>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
74
Program.cs
74
Program.cs
@@ -5,26 +5,54 @@ using CarCareTracker.Logic;
|
|||||||
using CarCareTracker.Middleware;
|
using CarCareTracker.Middleware;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
builder.Services.AddControllersWithViews();
|
builder.Services.AddControllersWithViews();
|
||||||
builder.Services.AddSingleton<IVehicleDataAccess, VehicleDataAccess>();
|
|
||||||
builder.Services.AddSingleton<INoteDataAccess, NoteDataAccess>();
|
//data access method
|
||||||
builder.Services.AddSingleton<IServiceRecordDataAccess, ServiceRecordDataAccess>();
|
if (!string.IsNullOrWhiteSpace(builder.Configuration["POSTGRES_CONNECTION"])){
|
||||||
builder.Services.AddSingleton<IGasRecordDataAccess, GasRecordDataAccess>();
|
builder.Services.AddSingleton<IVehicleDataAccess, PGVehicleDataAccess>();
|
||||||
builder.Services.AddSingleton<ICollisionRecordDataAccess, CollisionRecordDataAccess>();
|
builder.Services.AddSingleton<INoteDataAccess, PGNoteDataAccess>();
|
||||||
builder.Services.AddSingleton<ITaxRecordDataAccess, TaxRecordDataAccess>();
|
builder.Services.AddSingleton<IServiceRecordDataAccess, PGServiceRecordDataAccess>();
|
||||||
builder.Services.AddSingleton<IReminderRecordDataAccess, ReminderRecordDataAccess>();
|
builder.Services.AddSingleton<IGasRecordDataAccess, PGGasRecordDataAccess>();
|
||||||
builder.Services.AddSingleton<IUpgradeRecordDataAccess, UpgradeRecordDataAccess>();
|
builder.Services.AddSingleton<ICollisionRecordDataAccess, PGCollisionRecordDataAccess>();
|
||||||
builder.Services.AddSingleton<IUserRecordDataAccess, UserRecordDataAccess>();
|
builder.Services.AddSingleton<ITaxRecordDataAccess, PGTaxRecordDataAccess>();
|
||||||
builder.Services.AddSingleton<ITokenRecordDataAccess, TokenRecordDataAccess>();
|
builder.Services.AddSingleton<IReminderRecordDataAccess, PGReminderRecordDataAccess>();
|
||||||
builder.Services.AddSingleton<IUserAccessDataAccess, UserAccessDataAccess>();
|
builder.Services.AddSingleton<IUpgradeRecordDataAccess, PGUpgradeRecordDataAccess>();
|
||||||
builder.Services.AddSingleton<IUserConfigDataAccess, UserConfigDataAccess>();
|
builder.Services.AddSingleton<IOdometerRecordDataAccess, PGOdometerRecordDataAccess>();
|
||||||
builder.Services.AddSingleton<ISupplyRecordDataAccess, SupplyRecordDataAccess>();
|
builder.Services.AddSingleton<ISupplyRecordDataAccess, PGSupplyRecordDataAccess>();
|
||||||
builder.Services.AddSingleton<IPlanRecordDataAccess, PlanRecordDataAccess>();
|
builder.Services.AddSingleton<IPlanRecordDataAccess, PGPlanRecordDataAccess>();
|
||||||
builder.Services.AddSingleton<IOdometerRecordDataAccess, OdometerRecordDataAccess>();
|
builder.Services.AddSingleton<IPlanRecordTemplateDataAccess, PGPlanRecordTemplateDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IUserConfigDataAccess, PGUserConfigDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IUserRecordDataAccess, PGUserRecordDataAccess>();
|
||||||
|
builder.Services.AddSingleton<ITokenRecordDataAccess, PGTokenRecordDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IUserAccessDataAccess, PGUserAccessDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IExtraFieldDataAccess, PGExtraFieldDataAccess>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.Services.AddSingleton<IVehicleDataAccess, VehicleDataAccess>();
|
||||||
|
builder.Services.AddSingleton<INoteDataAccess, NoteDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IServiceRecordDataAccess, ServiceRecordDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IGasRecordDataAccess, GasRecordDataAccess>();
|
||||||
|
builder.Services.AddSingleton<ICollisionRecordDataAccess, CollisionRecordDataAccess>();
|
||||||
|
builder.Services.AddSingleton<ITaxRecordDataAccess, TaxRecordDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IReminderRecordDataAccess, ReminderRecordDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IUpgradeRecordDataAccess, UpgradeRecordDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IOdometerRecordDataAccess, OdometerRecordDataAccess>();
|
||||||
|
builder.Services.AddSingleton<ISupplyRecordDataAccess, SupplyRecordDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IPlanRecordDataAccess, PlanRecordDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IPlanRecordTemplateDataAccess, PlanRecordTemplateDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IUserConfigDataAccess, UserConfigDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IUserRecordDataAccess, UserRecordDataAccess>();
|
||||||
|
builder.Services.AddSingleton<ITokenRecordDataAccess, TokenRecordDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IUserAccessDataAccess, UserAccessDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IExtraFieldDataAccess, ExtraFieldDataAccess>();
|
||||||
|
}
|
||||||
|
|
||||||
//configure helpers
|
//configure helpers
|
||||||
builder.Services.AddSingleton<IFileHelper, FileHelper>();
|
builder.Services.AddSingleton<IFileHelper, FileHelper>();
|
||||||
@@ -33,6 +61,7 @@ builder.Services.AddSingleton<IReminderHelper, ReminderHelper>();
|
|||||||
builder.Services.AddSingleton<IReportHelper, ReportHelper>();
|
builder.Services.AddSingleton<IReportHelper, ReportHelper>();
|
||||||
builder.Services.AddSingleton<IMailHelper, MailHelper>();
|
builder.Services.AddSingleton<IMailHelper, MailHelper>();
|
||||||
builder.Services.AddSingleton<IConfigHelper, ConfigHelper>();
|
builder.Services.AddSingleton<IConfigHelper, ConfigHelper>();
|
||||||
|
builder.Services.AddSingleton<ITranslationHelper, TranslationHelper>();
|
||||||
|
|
||||||
//configure logic
|
//configure logic
|
||||||
builder.Services.AddSingleton<ILoginLogic, LoginLogic>();
|
builder.Services.AddSingleton<ILoginLogic, LoginLogic>();
|
||||||
@@ -42,6 +71,10 @@ if (!Directory.Exists("data"))
|
|||||||
{
|
{
|
||||||
Directory.CreateDirectory("data");
|
Directory.CreateDirectory("data");
|
||||||
}
|
}
|
||||||
|
if (!Directory.Exists("config"))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory("config");
|
||||||
|
}
|
||||||
|
|
||||||
//Additional JsonFile
|
//Additional JsonFile
|
||||||
builder.Configuration.AddJsonFile(StaticHelper.UserConfigPath, optional: true, reloadOnChange: true);
|
builder.Configuration.AddJsonFile(StaticHelper.UserConfigPath, optional: true, reloadOnChange: true);
|
||||||
@@ -54,6 +87,17 @@ builder.Services.AddAuthorization(options =>
|
|||||||
{
|
{
|
||||||
options.DefaultPolicy = new AuthorizationPolicyBuilder().AddAuthenticationSchemes("AuthN").RequireAuthenticatedUser().Build();
|
options.DefaultPolicy = new AuthorizationPolicyBuilder().AddAuthenticationSchemes("AuthN").RequireAuthenticatedUser().Build();
|
||||||
});
|
});
|
||||||
|
//Configure max file upload size
|
||||||
|
builder.Services.Configure<KestrelServerOptions>(options =>
|
||||||
|
{
|
||||||
|
options.Limits.MaxRequestBodySize = int.MaxValue; // if don't set default value is: 30 MB
|
||||||
|
});
|
||||||
|
builder.Services.Configure<FormOptions>(options =>
|
||||||
|
{
|
||||||
|
options.ValueLengthLimit = int.MaxValue;
|
||||||
|
options.MultipartBodyLengthLimit = int.MaxValue; // if don't set default value is: 128 MB
|
||||||
|
options.MultipartHeadersLengthLimit = int.MaxValue;
|
||||||
|
});
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"profiles": {
|
|
||||||
"http": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
},
|
|
||||||
"dotnetRunMessages": true,
|
|
||||||
"applicationUrl": "http://localhost:5011"
|
|
||||||
},
|
|
||||||
"IIS Express": {
|
|
||||||
"commandName": "IISExpress",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
|
||||||
"iisSettings": {
|
|
||||||
"windowsAuthentication": false,
|
|
||||||
"anonymousAuthentication": true,
|
|
||||||
"iisExpress": {
|
|
||||||
"applicationUrl": "http://localhost:11362",
|
|
||||||
"sslPort": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
14
README.md
14
README.md
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
A self-hosted, open-source vehicle service records and maintainence tracker.
|
A self-hosted, open-source vehicle service records and maintainence tracker.
|
||||||
|
|
||||||
Support this project on Patreon: https://patreon.com/LubeLogger
|
Visit our website: https://lubelogger.com
|
||||||
|
|
||||||
|
Support this project by [Subscribing on Patreon](https://patreon.com/LubeLogger) or [Making a Donation](https://buy.stripe.com/aEU9Egc8DdMc9bO144)
|
||||||
|
|
||||||
## Why
|
## Why
|
||||||
Because nobody should have to deal with a homemade spreadsheet or a shoebox full of receipts when it comes to vehicle maintainence.
|
Because nobody should have to deal with a homemade spreadsheet or a shoebox full of receipts when it comes to vehicle maintainence.
|
||||||
@@ -10,6 +12,11 @@ Because nobody should have to deal with a homemade spreadsheet or a shoebox full
|
|||||||
## Screenshots
|
## Screenshots
|
||||||
<a href="/docs/screenshots.md">Screenshots</a>
|
<a href="/docs/screenshots.md">Screenshots</a>
|
||||||
|
|
||||||
|
## Demo
|
||||||
|
Try it out before you download it! The live demo resets every 20 minutes.
|
||||||
|
|
||||||
|
[Live Demo](https://demo.lubelogger.com) Login using username "test" and password "1234"
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
- Bootstrap
|
- Bootstrap
|
||||||
- LiteDB
|
- LiteDB
|
||||||
@@ -17,12 +24,13 @@ Because nobody should have to deal with a homemade spreadsheet or a shoebox full
|
|||||||
- SweetAlert2
|
- SweetAlert2
|
||||||
- CsvHelper
|
- CsvHelper
|
||||||
- Chart.js
|
- Chart.js
|
||||||
|
- Drawdown
|
||||||
|
|
||||||
## Docker Setup (GHCR)
|
## Docker Setup (GHCR)
|
||||||
1. Install Docker
|
1. Install Docker
|
||||||
2. Run `docker pull ghcr.io/hargata/lubelogger:latest`
|
2. Run `docker pull ghcr.io/hargata/lubelogger:latest`
|
||||||
3. CHECK culture in .env file, default is en_US, this will change the currency and date formats. You can also setup SMTP Config here.
|
3. CHECK culture in .env file, default is en_US, this will change the currency and date formats. You can also setup SMTP Config here.
|
||||||
4. If not using traefik, use docker-compose-notraefik.yml
|
4. If using traefik, use docker-compose.traefik.yml
|
||||||
5. Run `docker-compose up`
|
5. Run `docker-compose up`
|
||||||
|
|
||||||
## Docker Setup (Manual Build)
|
## Docker Setup (Manual Build)
|
||||||
@@ -31,7 +39,7 @@ Because nobody should have to deal with a homemade spreadsheet or a shoebox full
|
|||||||
3. CHECK culture in .env file, default is en_US, also setup SMTP for user management if you want that.
|
3. CHECK culture in .env file, default is en_US, also setup SMTP for user management if you want that.
|
||||||
4. Run `docker build -t lubelogger -f Dockerfile .`
|
4. Run `docker build -t lubelogger -f Dockerfile .`
|
||||||
5. CHECK docker-compose.yml and make sure the mounting directories look correct.
|
5. CHECK docker-compose.yml and make sure the mounting directories look correct.
|
||||||
6. If not using traefik, use docker-compose-notraefik.yml
|
6. If using traefik, use docker-compose.traefik.yml
|
||||||
7. Run `docker-compose up`
|
7. Run `docker-compose up`
|
||||||
|
|
||||||
## Additional Docker Instructions
|
## Additional Docker Instructions
|
||||||
|
|||||||
@@ -241,6 +241,21 @@
|
|||||||
</div>
|
</div>
|
||||||
@if (User.IsInRole(nameof(UserData.IsRootUser)))
|
@if (User.IsInRole(nameof(UserData.IsRootUser)))
|
||||||
{
|
{
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-1">
|
||||||
|
GET
|
||||||
|
</div>
|
||||||
|
<div class="col-5">
|
||||||
|
<code>/api/vehicle/reminders/send</code>
|
||||||
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
|
Send reminder emails out to collaborators based on specified urgency.
|
||||||
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
|
(must be root user)<br />
|
||||||
|
urgencies[]=[NotUrgent,Urgent,VeryUrgent,PastDue]
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-1">
|
<div class="col-1">
|
||||||
GET
|
GET
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
@{
|
@using CarCareTracker.Helper
|
||||||
|
@{
|
||||||
ViewData["Title"] = "Admin";
|
ViewData["Title"] = "Admin";
|
||||||
}
|
}
|
||||||
@inject IConfiguration config;
|
@inject IConfiguration config;
|
||||||
|
@inject ITranslationHelper translator
|
||||||
@{
|
@{
|
||||||
bool emailServerIsSetup = true;
|
bool emailServerIsSetup = true;
|
||||||
var mailConfig = config.GetSection("MailConfig").Get<MailConfig>();
|
var mailConfig = config.GetSection("MailConfig").Get<MailConfig>();
|
||||||
|
var userLanguage = config[nameof(UserConfig.UserLanguage)] ?? "en_US";
|
||||||
if (mailConfig is null || string.IsNullOrWhiteSpace(mailConfig.EmailServer))
|
if (mailConfig is null || string.IsNullOrWhiteSpace(mailConfig.EmailServer))
|
||||||
{
|
{
|
||||||
emailServerIsSetup = false;
|
emailServerIsSetup = false;
|
||||||
@@ -17,31 +20,31 @@
|
|||||||
<a href="/Home" class="btn btn-secondary btn-md mt-1 mb-1"><i class="bi bi-arrow-left-square"></i></a>
|
<a href="/Home" class="btn btn-secondary btn-md mt-1 mb-1"><i class="bi bi-arrow-left-square"></i></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-11">
|
<div class="col-11">
|
||||||
<span class="display-6">Admin Panel</span>
|
<span class="display-6">@translator.Translate(userLanguage, "Admin Panel")</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-5 col-12">
|
<div class="col-md-5 col-12">
|
||||||
<span class="lead">Tokens</span>
|
<span class="lead">@translator.Translate(userLanguage, "Tokens")</span>
|
||||||
<hr />
|
<hr />
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<button onclick="generateNewToken()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Generate User Token</button>
|
<button onclick="generateNewToken()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage, "Generate User Token")</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 d-flex align-items-center">
|
<div class="col-6 d-flex align-items-center">
|
||||||
<div class="form-check form-switch">
|
<div class="form-check form-switch">
|
||||||
<input class="form-check-input" type="checkbox" role="switch" id="enableAutoNotify" @(emailServerIsSetup ? "checked" : "disabled")>
|
<input class="form-check-input" type="checkbox" role="switch" id="enableAutoNotify" @(emailServerIsSetup ? "checked" : "disabled")>
|
||||||
<label class="form-check-label" for="enableAutoNotify">Auto Notify(via Email)</label>
|
<label class="form-check-label" for="enableAutoNotify">@translator.Translate(userLanguage, "Auto Notify(via Email)")</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-hover">
|
<table class="table table-hover">
|
||||||
<thead class="sticky-top">
|
<thead class="sticky-top">
|
||||||
<tr class="d-flex">
|
<tr class="d-flex">
|
||||||
<th scope="col" class="col-4">Token</th>
|
<th scope="col" class="col-4">@translator.Translate(userLanguage, "Token")</th>
|
||||||
<th scope="col" class="col-6">Issued To</th>
|
<th scope="col" class="col-6">@translator.Translate(userLanguage, "Issued To")</th>
|
||||||
<th scope="col" class="col-2">Delete</th>
|
<th scope="col" class="col-2">@translator.Translate(userLanguage, "Delete")</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -59,15 +62,15 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-7">
|
<div class="col-12 col-md-7">
|
||||||
<span class="lead">Users</span>
|
<span class="lead">@translator.Translate(userLanguage, "Users")</span>
|
||||||
<hr />
|
<hr />
|
||||||
<table class="table table-hover">
|
<table class="table table-hover">
|
||||||
<thead class="sticky-top">
|
<thead class="sticky-top">
|
||||||
<tr class="d-flex">
|
<tr class="d-flex">
|
||||||
<th scope="col" class="col-4">Username</th>
|
<th scope="col" class="col-4">@translator.Translate(userLanguage, "Username")</th>
|
||||||
<th scope="col" class="col-4">Email</th>
|
<th scope="col" class="col-4">@translator.Translate(userLanguage, "Email")</th>
|
||||||
<th scope="col" class="col-2">Is Admin</th>
|
<th scope="col" class="col-2">@translator.Translate(userLanguage, "Is Admin")</th>
|
||||||
<th scope="col" class="col-2">Delete</th>
|
<th scope="col" class="col-2">@translator.Translate(userLanguage, "Delete")</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -92,7 +95,7 @@
|
|||||||
if (data){
|
if (data){
|
||||||
reloadPage();
|
reloadPage();
|
||||||
} else {
|
} else {
|
||||||
errorToast("An error has occurred, please try again later.");
|
errorToast(genericErrorMessage());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -104,7 +107,7 @@
|
|||||||
if (data) {
|
if (data) {
|
||||||
reloadPage();
|
reloadPage();
|
||||||
} else {
|
} else {
|
||||||
errorToast("An error has occurred, please try again later.");
|
errorToast(genericErrorMessage());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -113,7 +116,7 @@
|
|||||||
if (data) {
|
if (data) {
|
||||||
reloadPage();
|
reloadPage();
|
||||||
} else {
|
} else {
|
||||||
errorToast("An error has occurred, please try again later.");
|
errorToast(genericErrorMessage());
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,48 @@
|
|||||||
@using CarCareTracker.Helper
|
@using CarCareTracker.Helper
|
||||||
@inject IConfigHelper config
|
@inject IConfigHelper config
|
||||||
|
@inject ITranslationHelper translator
|
||||||
@{
|
@{
|
||||||
var enableAuth = config.GetUserConfig(User).EnableAuth;
|
var userConfig = config.GetUserConfig(User);
|
||||||
|
var enableAuth = userConfig.EnableAuth;
|
||||||
|
var userLanguage = userConfig.UserLanguage;
|
||||||
|
var logoUrl = config.GetLogoUrl();
|
||||||
}
|
}
|
||||||
@model string
|
@model string
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "LubeLogger";
|
ViewData["Title"] = "LubeLogger";
|
||||||
}
|
}
|
||||||
@section Scripts {
|
@section Scripts {
|
||||||
<script src="~/js/garage.js" asp-append-version="true"></script>
|
<script src="~/js/garage.js"></script>
|
||||||
|
<script src="~/js/supplyrecord.js"></script>
|
||||||
|
<script src="~/lib/drawdown/drawdown.js"></script>
|
||||||
}
|
}
|
||||||
<div class="lubelogger-mobile-nav" onclick="hideMobileNav()">
|
<div class="lubelogger-mobile-nav" onclick="hideMobileNav()">
|
||||||
<ul class="navbar-nav" id="homeTab" role="tablist">
|
<ul class="navbar-nav" id="homeTab" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link @(Model == "garage" ? "active" : "")" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-car-front me-2"></i>Garage</span></button>
|
<button class="nav-link user-select-none @(Model == "garage" ? "active" : "")" ontouchstart="detectLongTouch(this)" ontouchend="detectTouchEndPremature(this)" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-car-front me-2"></i>@translator.Translate(userLanguage,"Garage")</span></button>
|
||||||
|
</li>
|
||||||
|
@if(config.GetServerEnableShopSupplies())
|
||||||
|
{
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link" id="supply-tab" data-bs-toggle="tab" data-bs-target="#supply-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-shop me-2"></i>@translator.Translate(userLanguage, "Supplies")</button>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link" id="calendar-tab" data-bs-toggle="tab" data-bs-target="#calendar-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-calendar-week me-2"></i>@translator.Translate(userLanguage, "Calendar")</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link @(Model == "settings" ? "active" : "")" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-gear me-2"></i>Settings</span></button>
|
<button class="nav-link @(Model == "settings" ? "active" : "")" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-gear me-2"></i>@translator.Translate(userLanguage,"Settings")</span></button>
|
||||||
</li>
|
</li>
|
||||||
@if (User.IsInRole("CookieAuth"))
|
@if (User.IsInRole("CookieAuth"))
|
||||||
{
|
{
|
||||||
@if (User.IsInRole(nameof(UserData.IsAdmin)))
|
@if (User.IsInRole(nameof(UserData.IsAdmin)))
|
||||||
{
|
{
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="dropdown-item" href="/Admin"><span class="display-3 ms-2"><i class="bi bi-people me-2"></i>Admin Panel</span></a>
|
<a class="dropdown-item" href="/Admin"><span class="display-3 ms-2"><i class="bi bi-people me-2"></i>@translator.Translate(userLanguage,"Admin Panel")</span></a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link" onclick="performLogOut()"><span class="display-3 ms-2"><i class="bi bi-box-arrow-right me-2"></i>Logout</span></button>
|
<button class="nav-link" onclick="performLogOut()"><span class="display-3 ms-2"><i class="bi bi-box-arrow-right me-2"></i>@translator.Translate(userLanguage,"Logout")</span></button>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
@@ -35,7 +50,7 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mt-2">
|
<div class="row mt-2">
|
||||||
<div class="d-flex lubelogger-navbar">
|
<div class="d-flex lubelogger-navbar">
|
||||||
<img src="/defaults/lubelogger_logo.png" />
|
<img src="@logoUrl" />
|
||||||
<div class="lubelogger-navbar-button">
|
<div class="lubelogger-navbar-button">
|
||||||
<button type="button" class="btn btn-dark" onclick="showMobileNav()"><i class="bi bi-list lubelogger-menu-icon"></i></button>
|
<button type="button" class="btn btn-dark" onclick="showMobileNav()"><i class="bi bi-list lubelogger-menu-icon"></i></button>
|
||||||
</div>
|
</div>
|
||||||
@@ -44,10 +59,19 @@
|
|||||||
<hr />
|
<hr />
|
||||||
<ul class="nav nav-tabs lubelogger-tab" id="homeTab" role="tablist">
|
<ul class="nav nav-tabs lubelogger-tab" id="homeTab" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link @(Model == "garage" ? "active" : "")" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><i class="bi bi-car-front me-2"></i>Garage</button>
|
<button class="nav-link @(Model == "garage" ? "active" : "")" oncontextmenu="sortGarage(this)" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><i class="bi bi-car-front me-2"></i>@translator.Translate(userLanguage,"Garage")</button>
|
||||||
|
</li>
|
||||||
|
@if (config.GetServerEnableShopSupplies())
|
||||||
|
{
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link" id="supply-tab" data-bs-toggle="tab" data-bs-target="#supply-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-shop me-2"></i>@translator.Translate(userLanguage, "Supplies")</button>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link" id="calendar-tab" data-bs-toggle="tab" data-bs-target="#calendar-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-calendar-week me-2"></i>@translator.Translate(userLanguage, "Calendar")</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item ms-auto" role="presentation">
|
<li class="nav-item ms-auto" role="presentation">
|
||||||
<button class="nav-link @(Model == "settings" ? "active" : "")" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings-tab-pane" type="button" role="tab"><i class="bi bi-gear me-2"></i>Settings</button>
|
<button class="nav-link @(Model == "settings" ? "active" : "")" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings-tab-pane" type="button" role="tab"><i class="bi bi-gear me-2"></i>@translator.Translate(userLanguage,"Settings")</button>
|
||||||
</li>
|
</li>
|
||||||
@if (User.IsInRole("CookieAuth"))
|
@if (User.IsInRole("CookieAuth"))
|
||||||
{
|
{
|
||||||
@@ -57,11 +81,11 @@
|
|||||||
@if (User.IsInRole(nameof(UserData.IsAdmin)))
|
@if (User.IsInRole(nameof(UserData.IsAdmin)))
|
||||||
{
|
{
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item" href="/Admin"><i class="bi bi-people me-2"></i>Admin Panel</a>
|
<a class="dropdown-item" href="/Admin"><i class="bi bi-people me-2"></i>@translator.Translate(userLanguage,"Admin Panel")</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
<li>
|
<li>
|
||||||
<button class="dropdown-item" onclick="performLogOut()"><i class="bi bi-box-arrow-right me-2"></i>Logout</button>
|
<button class="dropdown-item" onclick="performLogOut()"><i class="bi bi-box-arrow-right me-2"></i>@translator.Translate(userLanguage,"Logout")</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
@@ -69,11 +93,14 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content" id="homeTab">
|
<div class="tab-content" id="homeTab">
|
||||||
<div class="tab-pane fade @(Model == "garage" ? "show active" : "")" id="garage-tab-pane" role="tabpanel" tabindex="0">
|
<div class="tab-pane fade @(Model == "garage" ? "show active" : "")" id="garage-tab-pane" role="tabpanel" tabindex="0">
|
||||||
<div class="row">
|
<div id="garageContainer">
|
||||||
<div id="garageContainer" class="row gy-3 align-items-stretch">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tab-pane fade" id="supply-tab-pane" role="tabpanel" tabindex="0">
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane fade" id="calendar-tab-pane" role="tabpanel" tabindex="0">
|
||||||
|
</div>
|
||||||
<div class="tab-pane fade @(Model == "settings" ? "show active" : "")" id="settings-tab-pane" role="tabpanel" tabindex="0">
|
<div class="tab-pane fade @(Model == "settings" ? "show active" : "")" id="settings-tab-pane" role="tabpanel" tabindex="0">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -85,6 +112,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="modal fade" id="bulkImportModal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content" id="bulkImportModalContent">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<script>
|
<script>
|
||||||
loadGarage();
|
loadGarage();
|
||||||
bindWindowResize();
|
bindWindowResize();
|
||||||
|
|||||||
25
Views/Home/_Calendar.cshtml
Normal file
25
Views/Home/_Calendar.cshtml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
@using CarCareTracker.Helper
|
||||||
|
@model List<ReminderRecordViewModel>
|
||||||
|
<script>
|
||||||
|
var eventDates = [];
|
||||||
|
var groupedDates = [];
|
||||||
|
@foreach(ReminderRecordViewModel reminderRecord in Model)
|
||||||
|
{
|
||||||
|
@:eventDates.push({ id: @reminderRecord.Id, date: decodeHTMLEntities('@StaticHelper.GetEpochFromDateTime(reminderRecord.Date)'), description: decodeHTMLEntities('@reminderRecord.Description'), urgency: decodeHTMLEntities('@reminderRecord.Urgency.ToString()') });
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<div class="row vehicleDetailTabContainer">
|
||||||
|
<div class="col-12 reminderCalendarView">
|
||||||
|
<div class="reminderCalendarViewContent" style="height:60vh;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal fade" data-bs-focus="false" id="reminderRecordCalendarModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
|
<div class="modal-content" id="reminderRecordCalendarModalContent">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
initCalendar();
|
||||||
|
</script>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user