Compare commits
79 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -8,3 +8,6 @@ wwwroot/documents/
|
||||
wwwroot/temp/
|
||||
wwwroot/imports/
|
||||
wwwroot/translations/
|
||||
config/userConfig.json
|
||||
CarCareTracker.csproj.user
|
||||
Properties/launchSettings.json
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
||||
<PackageReference Include="LiteDB" Version="5.0.17" />
|
||||
<PackageReference Include="Npgsql" Version="8.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<View_SelectedScaffolderID>RazorViewEmptyScaffolder</View_SelectedScaffolderID>
|
||||
<View_SelectedScaffolderCategoryPath>root/Common/MVC/View</View_SelectedScaffolderCategoryPath>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -29,6 +29,7 @@ namespace CarCareTracker.Controllers
|
||||
private readonly IUserLogic _userLogic;
|
||||
private readonly IFileHelper _fileHelper;
|
||||
private readonly IMailHelper _mailHelper;
|
||||
private readonly IConfigHelper _config;
|
||||
public APIController(IVehicleDataAccess dataAccess,
|
||||
IGasHelper gasHelper,
|
||||
IReminderHelper reminderHelper,
|
||||
@@ -44,6 +45,7 @@ namespace CarCareTracker.Controllers
|
||||
IUserRecordDataAccess userRecordDataAccess,
|
||||
IMailHelper mailHelper,
|
||||
IFileHelper fileHelper,
|
||||
IConfigHelper config,
|
||||
IUserLogic userLogic)
|
||||
{
|
||||
_dataAccess = dataAccess;
|
||||
@@ -62,6 +64,7 @@ namespace CarCareTracker.Controllers
|
||||
_reminderHelper = reminderHelper;
|
||||
_userLogic = userLogic;
|
||||
_fileHelper = fileHelper;
|
||||
_config = config;
|
||||
}
|
||||
public IActionResult Index()
|
||||
{
|
||||
@@ -126,6 +129,17 @@ namespace CarCareTracker.Controllers
|
||||
Cost = decimal.Parse(input.Cost)
|
||||
};
|
||||
_serviceRecordDataAccess.SaveServiceRecordToVehicle(serviceRecord);
|
||||
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
{
|
||||
var odometerRecord = new OdometerRecord()
|
||||
{
|
||||
VehicleId = vehicleId,
|
||||
Date = DateTime.Parse(input.Date),
|
||||
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
|
||||
Mileage = int.Parse(input.Odometer)
|
||||
};
|
||||
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(odometerRecord);
|
||||
}
|
||||
response.Success = true;
|
||||
response.Message = "Service Record Added";
|
||||
return Json(response);
|
||||
@@ -182,6 +196,17 @@ namespace CarCareTracker.Controllers
|
||||
Cost = decimal.Parse(input.Cost)
|
||||
};
|
||||
_collisionRecordDataAccess.SaveCollisionRecordToVehicle(repairRecord);
|
||||
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
{
|
||||
var odometerRecord = new OdometerRecord()
|
||||
{
|
||||
VehicleId = vehicleId,
|
||||
Date = DateTime.Parse(input.Date),
|
||||
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
|
||||
Mileage = int.Parse(input.Odometer)
|
||||
};
|
||||
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(odometerRecord);
|
||||
}
|
||||
response.Success = true;
|
||||
response.Message = "Repair Record Added";
|
||||
return Json(response);
|
||||
@@ -238,6 +263,17 @@ namespace CarCareTracker.Controllers
|
||||
Cost = decimal.Parse(input.Cost)
|
||||
};
|
||||
_upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(upgradeRecord);
|
||||
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
{
|
||||
var odometerRecord = new OdometerRecord()
|
||||
{
|
||||
VehicleId = vehicleId,
|
||||
Date = DateTime.Parse(input.Date),
|
||||
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
|
||||
Mileage = int.Parse(input.Odometer)
|
||||
};
|
||||
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(odometerRecord);
|
||||
}
|
||||
response.Success = true;
|
||||
response.Message = "Upgrade Record Added";
|
||||
return Json(response);
|
||||
@@ -413,6 +449,17 @@ namespace CarCareTracker.Controllers
|
||||
Cost = decimal.Parse(input.Cost)
|
||||
};
|
||||
_gasRecordDataAccess.SaveGasRecordToVehicle(gasRecord);
|
||||
if (_config.GetUserConfig(User).EnableAutoOdometerInsert)
|
||||
{
|
||||
var odometerRecord = new OdometerRecord()
|
||||
{
|
||||
VehicleId = vehicleId,
|
||||
Date = DateTime.Parse(input.Date),
|
||||
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
|
||||
Mileage = int.Parse(input.Odometer)
|
||||
};
|
||||
_odometerRecordDataAccess.SaveOdometerRecordToVehicle(odometerRecord);
|
||||
}
|
||||
response.Success = true;
|
||||
response.Message = "Gas Record Added";
|
||||
return Json(response);
|
||||
|
||||
@@ -26,9 +26,9 @@ namespace CarCareTracker.Controllers
|
||||
_logger = logger;
|
||||
_loginLogic = loginLogic;
|
||||
}
|
||||
public IActionResult Index()
|
||||
public IActionResult Index(string redirectURL = "")
|
||||
{
|
||||
return View();
|
||||
return View(model: redirectURL);
|
||||
}
|
||||
public IActionResult Registration()
|
||||
{
|
||||
|
||||
716
Controllers/MigrationController.cs
Normal file
716
Controllers/MigrationController.cs
Normal file
@@ -0,0 +1,716 @@
|
||||
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))"
|
||||
};
|
||||
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>();
|
||||
#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
|
||||
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>();
|
||||
#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
|
||||
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 ISupplyRecordDataAccess _supplyRecordDataAccess;
|
||||
private readonly IPlanRecordDataAccess _planRecordDataAccess;
|
||||
private readonly IPlanRecordTemplateDataAccess _planRecordTemplateDataAccess;
|
||||
private readonly IOdometerRecordDataAccess _odometerRecordDataAccess;
|
||||
private readonly IWebHostEnvironment _webEnv;
|
||||
private readonly IConfigHelper _config;
|
||||
@@ -51,6 +52,7 @@ namespace CarCareTracker.Controllers
|
||||
IUpgradeRecordDataAccess upgradeRecordDataAccess,
|
||||
ISupplyRecordDataAccess supplyRecordDataAccess,
|
||||
IPlanRecordDataAccess planRecordDataAccess,
|
||||
IPlanRecordTemplateDataAccess planRecordTemplateDataAccess,
|
||||
IOdometerRecordDataAccess odometerRecordDataAccess,
|
||||
IUserLogic userLogic,
|
||||
IWebHostEnvironment webEnv,
|
||||
@@ -71,6 +73,7 @@ namespace CarCareTracker.Controllers
|
||||
_upgradeRecordDataAccess = upgradeRecordDataAccess;
|
||||
_supplyRecordDataAccess = supplyRecordDataAccess;
|
||||
_planRecordDataAccess = planRecordDataAccess;
|
||||
_planRecordTemplateDataAccess = planRecordTemplateDataAccess;
|
||||
_odometerRecordDataAccess = odometerRecordDataAccess;
|
||||
_userLogic = userLogic;
|
||||
_webEnv = webEnv;
|
||||
@@ -142,6 +145,7 @@ namespace CarCareTracker.Controllers
|
||||
_reminderRecordDataAccess.DeleteAllReminderRecordsByVehicleId(vehicleId) &&
|
||||
_upgradeRecordDataAccess.DeleteAllUpgradeRecordsByVehicleId(vehicleId) &&
|
||||
_planRecordDataAccess.DeleteAllPlanRecordsByVehicleId(vehicleId) &&
|
||||
_planRecordTemplateDataAccess.DeleteAllPlanRecordTemplatesByVehicleId(vehicleId) &&
|
||||
_supplyRecordDataAccess.DeleteAllSupplyRecordsByVehicleId(vehicleId) &&
|
||||
_userLogic.DeleteAllAccessToVehicle(vehicleId) &&
|
||||
_dataAccess.DeleteVehicle(vehicleId);
|
||||
@@ -157,7 +161,7 @@ namespace CarCareTracker.Controllers
|
||||
[HttpGet]
|
||||
public IActionResult ExportFromVehicleToCsv(int vehicleId, ImportMode mode)
|
||||
{
|
||||
if (vehicleId == default)
|
||||
if (vehicleId == default && mode != ImportMode.SupplyRecord)
|
||||
{
|
||||
return Json(false);
|
||||
}
|
||||
@@ -345,7 +349,11 @@ namespace CarCareTracker.Controllers
|
||||
[HttpPost]
|
||||
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);
|
||||
}
|
||||
@@ -791,7 +799,14 @@ namespace CarCareTracker.Controllers
|
||||
{
|
||||
foreach(TaxRecord recurringFee in recurringFees)
|
||||
{
|
||||
var newDate = recurringFee.Date.AddMonths((int)recurringFee.RecurringInterval);
|
||||
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()
|
||||
@@ -803,6 +818,7 @@ namespace CarCareTracker.Controllers
|
||||
IsRecurring = true,
|
||||
Notes = recurringFee.Notes,
|
||||
RecurringInterval = recurringFee.RecurringInterval,
|
||||
CustomMonthInterval = recurringFee.CustomMonthInterval,
|
||||
Files = recurringFee.Files,
|
||||
Tags = recurringFee.Tags
|
||||
};
|
||||
@@ -840,6 +856,7 @@ namespace CarCareTracker.Controllers
|
||||
VehicleId = result.VehicleId,
|
||||
IsRecurring = result.IsRecurring,
|
||||
RecurringInterval = result.RecurringInterval,
|
||||
CustomMonthInterval = result.CustomMonthInterval,
|
||||
Files = result.Files,
|
||||
Tags = result.Tags
|
||||
};
|
||||
@@ -1344,7 +1361,8 @@ namespace CarCareTracker.Controllers
|
||||
IsRecurring = result.IsRecurring,
|
||||
ReminderMileageInterval = result.ReminderMileageInterval,
|
||||
ReminderMonthInterval = result.ReminderMonthInterval,
|
||||
CustomMileageInterval = result.CustomMileageInterval
|
||||
CustomMileageInterval = result.CustomMileageInterval,
|
||||
CustomMonthInterval = result.CustomMonthInterval
|
||||
};
|
||||
return PartialView("_ReminderRecordModal", convertedResult);
|
||||
}
|
||||
@@ -1467,6 +1485,21 @@ namespace CarCareTracker.Controllers
|
||||
}
|
||||
#endregion
|
||||
#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 (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)
|
||||
{
|
||||
foreach(SupplyUsage supply in supplyUsage)
|
||||
@@ -1503,6 +1536,10 @@ namespace CarCareTracker.Controllers
|
||||
public IActionResult GetSupplyRecordsForRecordsByVehicleId(int vehicleId)
|
||||
{
|
||||
var result = _supplyRecordDataAccess.GetSupplyRecordsByVehicleId(vehicleId);
|
||||
if (_config.GetServerEnableShopSupplies())
|
||||
{
|
||||
result.AddRange(_supplyRecordDataAccess.GetSupplyRecordsByVehicleId(0)); // add shop supplies
|
||||
}
|
||||
result.RemoveAll(x => x.Quantity <= 0);
|
||||
bool _useDescending = _config.GetUserConfig(User).UseDescending;
|
||||
if (_useDescending)
|
||||
@@ -1581,6 +1618,60 @@ namespace CarCareTracker.Controllers
|
||||
}
|
||||
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]
|
||||
public IActionResult GetAddPlanRecordPartialView()
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
{
|
||||
public enum ReminderMonthInterval
|
||||
{
|
||||
Other = 0,
|
||||
OneMonth = 1,
|
||||
ThreeMonths = 3,
|
||||
SixMonths = 6,
|
||||
|
||||
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.Models;
|
||||
using LiteDB;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
@@ -9,18 +10,36 @@ namespace CarCareTracker.Filter
|
||||
public class CollaboratorFilter: ActionFilterAttribute
|
||||
{
|
||||
private readonly IUserLogic _userLogic;
|
||||
public CollaboratorFilter(IUserLogic userLogic) {
|
||||
private readonly IConfigHelper _config;
|
||||
public CollaboratorFilter(IUserLogic userLogic, IConfigHelper config) {
|
||||
_userLogic = userLogic;
|
||||
_config = config;
|
||||
}
|
||||
public override void OnActionExecuting(ActionExecutingContext filterContext)
|
||||
{
|
||||
if (!filterContext.HttpContext.User.IsInRole(nameof(UserData.IsRootUser)))
|
||||
{
|
||||
var vehicleId = int.Parse(filterContext.ActionArguments["vehicleId"].ToString());
|
||||
var userId = int.Parse(filterContext.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier));
|
||||
if (!_userLogic.UserCanEditVehicle(userId, vehicleId))
|
||||
if (vehicleId != default)
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@ namespace CarCareTracker.Helper
|
||||
UserConfig GetUserConfig(ClaimsPrincipal user);
|
||||
bool SaveUserConfig(ClaimsPrincipal user, UserConfig configData);
|
||||
string GetLogoUrl();
|
||||
string GetServerLanguage();
|
||||
bool GetServerEnableShopSupplies();
|
||||
string GetServerPostgresConnection();
|
||||
public bool DeleteUserConfig(int userId);
|
||||
}
|
||||
public class ConfigHelper : IConfigHelper
|
||||
@@ -34,6 +37,25 @@ namespace CarCareTracker.Helper
|
||||
}
|
||||
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)
|
||||
{
|
||||
var storedUserId = user.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
@@ -111,6 +133,7 @@ namespace CarCareTracker.Helper
|
||||
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>>(),
|
||||
DefaultTab = (ImportMode)int.Parse(_config[nameof(UserConfig.DefaultTab)])
|
||||
};
|
||||
|
||||
@@ -13,11 +13,14 @@ namespace CarCareTracker.Helper
|
||||
public class MailHelper : IMailHelper
|
||||
{
|
||||
private readonly MailConfig mailConfig;
|
||||
private readonly IFileHelper _fileHelper;
|
||||
public MailHelper(
|
||||
IConfiguration config
|
||||
IConfiguration config,
|
||||
IFileHelper fileHelper
|
||||
) {
|
||||
//load mailConfig from Configuration
|
||||
mailConfig = config.GetSection("MailConfig").Get<MailConfig>();
|
||||
_fileHelper = fileHelper;
|
||||
}
|
||||
public OperationResponse NotifyUserForRegistration(string emailAddress, string token)
|
||||
{
|
||||
@@ -75,14 +78,19 @@ namespace CarCareTracker.Helper
|
||||
{
|
||||
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 = $"<h4>{vehicle.Year} {vehicle.Make} {vehicle.Model} #{vehicle.LicensePlate}</h4><br /><table style='width:100%'><tr><th style='padding:8px;'>Urgency</th><th style='padding:8px;'>Description</th></tr>";
|
||||
string emailBody = File.ReadAllText(emailTemplatePath);
|
||||
emailBody = emailBody.Replace("{VehicleInformation}", $"{vehicle.Year} {vehicle.Make} {vehicle.Model} #{vehicle.LicensePlate}");
|
||||
string tableBody = "";
|
||||
foreach(ReminderRecordViewModel reminder in reminders)
|
||||
{
|
||||
emailBody += $"<tr><td style='padding:8px; text-align:center;'>{reminder.Urgency}</td><td style='padding:8px; text-align:center;'>{reminder.Description}</td></tr>";
|
||||
var dueOn = reminder.Metric == ReminderMetric.Both ? $"{reminder.Date} or {reminder.Mileage}" : reminder.Metric == ReminderMetric.Date ? $"{reminder.Date.ToShortDateString()}" : $"{reminder.Mileage}";
|
||||
tableBody += $"<tr class='{reminder.Urgency}'><td>{StaticHelper.GetTitleCaseReminderUrgency(reminder.Urgency)}</td><td>{reminder.Description}</td><td>{dueOn}</td></tr>";
|
||||
}
|
||||
emailBody += "</table>";
|
||||
emailBody = emailBody.Replace("{TableBody}", tableBody);
|
||||
try
|
||||
{
|
||||
foreach (string emailAddress in emailAddresses)
|
||||
|
||||
@@ -13,7 +13,14 @@ namespace CarCareTracker.Helper
|
||||
{
|
||||
if (existingReminder.Metric == ReminderMetric.Both)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
if (existingReminder.ReminderMileageInterval != ReminderMileageInterval.Other)
|
||||
{
|
||||
existingReminder.Mileage += (int)existingReminder.ReminderMileageInterval;
|
||||
@@ -35,7 +42,14 @@ namespace CarCareTracker.Helper
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,22 @@ namespace CarCareTracker.Helper
|
||||
public static string DbName = "data/cartracker.db";
|
||||
public static string UserConfigPath = "config/userConfig.json";
|
||||
public static string GenericErrorMessage = "An error occurred, please try again later";
|
||||
public static string ReminderEmailTemplate = "defaults/reminderemailtemplate.txt";
|
||||
|
||||
public static string 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)
|
||||
{
|
||||
|
||||
@@ -48,6 +48,12 @@ namespace CarCareTracker.Logic
|
||||
if (existingUser.Id != default)
|
||||
{
|
||||
//user exists.
|
||||
//check if user is already a collaborator
|
||||
var userAccess = _userAccess.GetUserAccessByVehicleAndUserId(existingUser.Id, vehicleId);
|
||||
if (userAccess != null)
|
||||
{
|
||||
return new OperationResponse { Success = false, Message = "User is already a collaborator" };
|
||||
}
|
||||
var result = AddUserAccessToVehicle(existingUser.Id, vehicleId);
|
||||
if (result)
|
||||
{
|
||||
|
||||
@@ -157,7 +157,13 @@ namespace CarCareTracker.Middleware
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
Response.Redirect("/Login/Index");
|
||||
if (Request.Path.Value == "/Vehicle/Index" && Request.QueryString.HasValue)
|
||||
{
|
||||
Response.Redirect($"/Login/Index?redirectURL={Request.Path.Value}{Request.QueryString.Value}");
|
||||
} else
|
||||
{
|
||||
Response.Redirect("/Login/Index");
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
protected override Task HandleForbiddenAsync(AuthenticationProperties properties)
|
||||
@@ -170,7 +176,7 @@ namespace CarCareTracker.Middleware
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
Response.Redirect("/Error/401");
|
||||
Response.Redirect("/Error/Unauthorized");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,5 +8,6 @@
|
||||
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>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
public string Notes { get; set; }
|
||||
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 ReminderMonthInterval ReminderMonthInterval { get; set; } = ReminderMonthInterval.OneYear;
|
||||
public ReminderMetric Metric { get; set; } = ReminderMetric.Date;
|
||||
|
||||
@@ -10,20 +10,27 @@
|
||||
public string Notes { get; set; }
|
||||
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 ReminderMonthInterval ReminderMonthInterval { get; set; } = ReminderMonthInterval.OneYear;
|
||||
public ReminderMetric Metric { get; set; } = ReminderMetric.Date;
|
||||
public ReminderRecord ToReminderRecord() { return new ReminderRecord {
|
||||
Id = Id,
|
||||
VehicleId = VehicleId,
|
||||
Date = DateTime.Parse(string.IsNullOrWhiteSpace(Date) ? DateTime.Now.AddDays(1).ToShortDateString() : Date),
|
||||
Mileage = Mileage,
|
||||
Description = Description,
|
||||
Metric = Metric,
|
||||
IsRecurring = IsRecurring,
|
||||
ReminderMileageInterval = ReminderMileageInterval,
|
||||
ReminderMonthInterval = ReminderMonthInterval,
|
||||
CustomMileageInterval = CustomMileageInterval,
|
||||
Notes = Notes }; }
|
||||
public ReminderRecord ToReminderRecord()
|
||||
{
|
||||
return new ReminderRecord
|
||||
{
|
||||
Id = Id,
|
||||
VehicleId = VehicleId,
|
||||
Date = DateTime.Parse(string.IsNullOrWhiteSpace(Date) ? DateTime.Now.AddDays(1).ToShortDateString() : Date),
|
||||
Mileage = Mileage,
|
||||
Description = Description,
|
||||
Metric = Metric,
|
||||
IsRecurring = IsRecurring,
|
||||
ReminderMileageInterval = ReminderMileageInterval,
|
||||
ReminderMonthInterval = ReminderMonthInterval,
|
||||
CustomMileageInterval = CustomMileageInterval,
|
||||
CustomMonthInterval = CustomMonthInterval,
|
||||
Notes = Notes
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
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<string> Tags { get; set; } = new List<string>();
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
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<string> Tags { get; set; } = new List<string>();
|
||||
public TaxRecord ToTaxRecord() { return new TaxRecord {
|
||||
@@ -21,6 +22,7 @@
|
||||
Notes = Notes,
|
||||
IsRecurring = IsRecurring,
|
||||
RecurringInterval = RecurringInterval,
|
||||
CustomMonthInterval = CustomMonthInterval,
|
||||
Files = Files,
|
||||
Tags = Tags
|
||||
}; }
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
public bool UseMarkDownOnSavedNotes { get; set; }
|
||||
public bool EnableAutoReminderRefresh { 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; }
|
||||
|
||||
71
Program.cs
71
Program.cs
@@ -5,26 +5,52 @@ using CarCareTracker.Logic;
|
||||
using CarCareTracker.Middleware;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddControllersWithViews();
|
||||
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<IUserRecordDataAccess, UserRecordDataAccess>();
|
||||
builder.Services.AddSingleton<ITokenRecordDataAccess, TokenRecordDataAccess>();
|
||||
builder.Services.AddSingleton<IUserAccessDataAccess, UserAccessDataAccess>();
|
||||
builder.Services.AddSingleton<IUserConfigDataAccess, UserConfigDataAccess>();
|
||||
builder.Services.AddSingleton<ISupplyRecordDataAccess, SupplyRecordDataAccess>();
|
||||
builder.Services.AddSingleton<IPlanRecordDataAccess, PlanRecordDataAccess>();
|
||||
builder.Services.AddSingleton<IOdometerRecordDataAccess, OdometerRecordDataAccess>();
|
||||
|
||||
//data access method
|
||||
if (!string.IsNullOrWhiteSpace(builder.Configuration["POSTGRES_CONNECTION"])){
|
||||
builder.Services.AddSingleton<IVehicleDataAccess, PGVehicleDataAccess>();
|
||||
builder.Services.AddSingleton<INoteDataAccess, PGNoteDataAccess>();
|
||||
builder.Services.AddSingleton<IServiceRecordDataAccess, PGServiceRecordDataAccess>();
|
||||
builder.Services.AddSingleton<IGasRecordDataAccess, PGGasRecordDataAccess>();
|
||||
builder.Services.AddSingleton<ICollisionRecordDataAccess, PGCollisionRecordDataAccess>();
|
||||
builder.Services.AddSingleton<ITaxRecordDataAccess, PGTaxRecordDataAccess>();
|
||||
builder.Services.AddSingleton<IReminderRecordDataAccess, PGReminderRecordDataAccess>();
|
||||
builder.Services.AddSingleton<IUpgradeRecordDataAccess, PGUpgradeRecordDataAccess>();
|
||||
builder.Services.AddSingleton<IOdometerRecordDataAccess, PGOdometerRecordDataAccess>();
|
||||
builder.Services.AddSingleton<ISupplyRecordDataAccess, PGSupplyRecordDataAccess>();
|
||||
builder.Services.AddSingleton<IPlanRecordDataAccess, PGPlanRecordDataAccess>();
|
||||
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>();
|
||||
}
|
||||
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>();
|
||||
}
|
||||
|
||||
//configure helpers
|
||||
builder.Services.AddSingleton<IFileHelper, FileHelper>();
|
||||
@@ -43,6 +69,10 @@ if (!Directory.Exists("data"))
|
||||
{
|
||||
Directory.CreateDirectory("data");
|
||||
}
|
||||
if (!Directory.Exists("config"))
|
||||
{
|
||||
Directory.CreateDirectory("config");
|
||||
}
|
||||
|
||||
//Additional JsonFile
|
||||
builder.Configuration.AddJsonFile(StaticHelper.UserConfigPath, optional: true, reloadOnChange: true);
|
||||
@@ -55,6 +85,17 @@ builder.Services.AddAuthorization(options =>
|
||||
{
|
||||
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();
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,20 @@
|
||||
}
|
||||
@section Scripts {
|
||||
<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()">
|
||||
<ul class="navbar-nav" id="homeTab" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<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 @(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>
|
||||
@@ -50,6 +58,12 @@
|
||||
<li class="nav-item" role="presentation">
|
||||
<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 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>@translator.Translate(userLanguage,"Settings")</button>
|
||||
</li>
|
||||
@@ -77,6 +91,8 @@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="supply-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>
|
||||
</div>
|
||||
@@ -88,6 +104,12 @@
|
||||
</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>
|
||||
loadGarage();
|
||||
bindWindowResize();
|
||||
|
||||
@@ -53,6 +53,10 @@
|
||||
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="enableAutoOdometerInsert" checked="@Model.UserConfig.EnableAutoOdometerInsert">
|
||||
<label class="form-check-label" for="enableAutoOdometerInsert">@translator.Translate(userLanguage, "Auto Insert Odometer Records")<br /><small class="text-body-secondary">@translator.Translate(userLanguage, "Only when Adding Service/Repair/Upgrade/Fuel Record or Completing a Plan")</small></label>
|
||||
</div>
|
||||
<div class="form-check form-switch @(User.IsInRole(nameof(UserData.IsRootUser)) ? "" : "d-none")">
|
||||
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="enableShopSupplies" checked="@Model.UserConfig.EnableShopSupplies">
|
||||
<label class="form-check-label" for="enableShopSupplies">@translator.Translate(userLanguage, "Shop Supplies")</label>
|
||||
</div>
|
||||
@if (User.IsInRole(nameof(UserData.IsRootUser)))
|
||||
{
|
||||
<div class="form-check form-switch">
|
||||
@@ -153,7 +157,7 @@
|
||||
<span class="lead">@translator.Translate(userLanguage, "Backups")</span>
|
||||
<div class="row">
|
||||
<div class="col-6 d-grid">
|
||||
<button onclick="makeBackup()" class="btn btn-primary btn-md">@translator.Translate(userLanguage, "Make")</button>
|
||||
<button onclick="makeBackup()" class="btn btn-primary btn-md">@translator.Translate(userLanguage, "Create")</button>
|
||||
</div>
|
||||
<div class="col-6 d-grid">
|
||||
<input onChange="restoreBackup(this)" type="file" accept=".zip" class="d-none" id="inputBackup">
|
||||
@@ -187,7 +191,7 @@
|
||||
<img src="/defaults/lubelogger_logo.png" />
|
||||
</div>
|
||||
<div class="d-flex justify-content-center">
|
||||
<small class="text-body-secondary">Version 1.1.1</small>
|
||||
<small class="text-body-secondary">Version 1.1.5</small>
|
||||
</div>
|
||||
<p class="lead">
|
||||
Proudly developed in the rural town of Price, Utah by Hargata Softworks.
|
||||
@@ -217,6 +221,7 @@
|
||||
<li class="list-group-item">Bootstrap</li>
|
||||
<li class="list-group-item">Bootstrap-DatePicker</li>
|
||||
<li class="list-group-item">LiteDB</li>
|
||||
<li class="list-group-item">Npgsql</li>
|
||||
<li class="list-group-item">SweetAlert2</li>
|
||||
<li class="list-group-item">CsvHelper</li>
|
||||
<li class="list-group-item">Chart.js</li>
|
||||
@@ -256,6 +261,7 @@
|
||||
useMarkDownOnSavedNotes: $("#useMarkDownOnSavedNotes").is(":checked"),
|
||||
enableAutoReminderRefresh: $("#enableAutoReminderRefresh").is(":checked"),
|
||||
enableAutoOdometerInsert: $("#enableAutoOdometerInsert").is(":checked"),
|
||||
enableShopSupplies: $("#enableShopSupplies").is(":checked"),
|
||||
preferredGasUnit: $("#preferredGasUnit").val(),
|
||||
preferredGasMileageUnit: $("#preferredFuelMileageUnit").val(),
|
||||
userLanguage: $("#defaultLanguage").val(),
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
@using CarCareTracker.Helper
|
||||
@inject IConfigHelper config
|
||||
@inject ITranslationHelper translator
|
||||
@{
|
||||
var logoUrl = config.GetLogoUrl();
|
||||
var userLanguage = config.GetServerLanguage();
|
||||
}
|
||||
@{
|
||||
ViewData["Title"] = "LubeLogger - Login";
|
||||
@@ -14,17 +16,17 @@
|
||||
<div class="col-12">
|
||||
<img src="@logoUrl" />
|
||||
<div class="form-group">
|
||||
<label for="inputUserName">Username</label>
|
||||
<label for="inputUserName">@translator.Translate(userLanguage, "Username")</label>
|
||||
<input type="text" id="inputUserName" class="form-control">
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="button" class="btn btn-warning mt-2" onclick="requestPasswordReset()"><i class="bi bi-box-arrow-in-right me-2"></i>Request</button>
|
||||
<button type="button" class="btn btn-warning mt-2" onclick="requestPasswordReset()"><i class="bi bi-box-arrow-in-right me-2"></i>@translator.Translate(userLanguage, "Request")</button>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<a href="/Login/ResetPassword" class="btn btn-link mt-2">I Have a Token</a>
|
||||
<a href="/Login/ResetPassword" class="btn btn-link mt-2">@translator.Translate(userLanguage, "I Have a Token")</a>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<a href="/Login/Index" class="btn btn-link mt-2">Back to Login</a>
|
||||
<a href="/Login/Index" class="btn btn-link mt-2">@translator.Translate(userLanguage, "Back to Login")</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
@using CarCareTracker.Helper
|
||||
@inject IConfigHelper config
|
||||
@inject ITranslationHelper translator
|
||||
@model string
|
||||
@{
|
||||
var logoUrl = config.GetLogoUrl();
|
||||
var userLanguage = config.GetServerLanguage();
|
||||
}
|
||||
@{
|
||||
ViewData["Title"] = "LubeLogger - Login";
|
||||
@@ -14,26 +17,31 @@
|
||||
<div class="col-12">
|
||||
<img src="@logoUrl" />
|
||||
<div class="form-group">
|
||||
<label for="inputUserName">Username</label>
|
||||
<label for="inputUserName">@translator.Translate(userLanguage, "Username")</label>
|
||||
<input type="text" id="inputUserName" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="inputUserPassword">Password</label>
|
||||
<label for="inputUserPassword">@translator.Translate(userLanguage, "Password")</label>
|
||||
<input type="password" id="inputUserPassword" onkeyup="handlePasswordKeyPress(event)" class="form-control">
|
||||
</div>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="inputPersistent">
|
||||
<label class="form-check-label" for="inputPersistent">Remember Me</label>
|
||||
<label class="form-check-label" for="inputPersistent">@translator.Translate(userLanguage, "Remember Me")</label>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="button" class="btn btn-warning mt-2" onclick="performLogin()"><i class="bi bi-box-arrow-in-right me-2"></i>Login</button>
|
||||
<button type="button" class="btn btn-warning mt-2" onclick="performLogin()"><i class="bi bi-box-arrow-in-right me-2"></i>@translator.Translate(userLanguage, "Login")</button>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<a href="/Login/ForgotPassword" class="btn btn-link mt-2">Forgot Password</a>
|
||||
<a href="/Login/ForgotPassword" class="btn btn-link mt-2">@translator.Translate(userLanguage, "Forgot Password")</a>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<a href="/Login/Registration" class="btn btn-link mt-2">Register</a>
|
||||
<a href="/Login/Registration" class="btn btn-link mt-2">@translator.Translate(userLanguage, "Register")</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function getRedirectURL(){
|
||||
return { url: decodeHTMLEntities('@Model') };
|
||||
}
|
||||
</script>
|
||||
@@ -1,7 +1,9 @@
|
||||
@using CarCareTracker.Helper
|
||||
@inject IConfigHelper config
|
||||
@inject ITranslationHelper translator
|
||||
@{
|
||||
var logoUrl = config.GetLogoUrl();
|
||||
var userLanguage = config.GetServerLanguage();
|
||||
}
|
||||
@{
|
||||
ViewData["Title"] = "LubeLogger - Register";
|
||||
@@ -14,26 +16,26 @@
|
||||
<div class="col-12">
|
||||
<img src="@logoUrl" />
|
||||
<div class="form-group">
|
||||
<label for="inputToken">Token</label>
|
||||
<label for="inputToken">@translator.Translate(userLanguage, "Token")</label>
|
||||
<input type="text" id="inputToken" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="inputUserName">Email Address</label>
|
||||
<label for="inputUserName">@translator.Translate(userLanguage, "Email Address")</label>
|
||||
<input type="text" id="inputEmail" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="inputUserName">Username</label>
|
||||
<label for="inputUserName">@translator.Translate(userLanguage, "Username")</label>
|
||||
<input type="text" id="inputUserName" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="inputUserPassword">Password</label>
|
||||
<label for="inputUserPassword">@translator.Translate(userLanguage, "Password")</label>
|
||||
<input type="password" id="inputUserPassword" class="form-control">
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="button" class="btn btn-warning mt-2" onclick="performRegistration()"><i class="bi bi-box-arrow-in-right me-2"></i>Register</button>
|
||||
<button type="button" class="btn btn-warning mt-2" onclick="performRegistration()"><i class="bi bi-box-arrow-in-right me-2"></i>@translator.Translate(userLanguage, "Register")</button>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<a href="/Login/Index" class="btn btn-link mt-2">Back to Login</a>
|
||||
<a href="/Login/Index" class="btn btn-link mt-2">@translator.Translate(userLanguage, "Back to Login")</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
@using CarCareTracker.Helper
|
||||
@inject IConfigHelper config
|
||||
@inject ITranslationHelper translator
|
||||
@{
|
||||
var logoUrl = config.GetLogoUrl();
|
||||
var userLanguage = config.GetServerLanguage();
|
||||
}
|
||||
@{
|
||||
ViewData["Title"] = "LubeLogger - Register";
|
||||
@@ -14,22 +16,22 @@
|
||||
<div class="col-12">
|
||||
<img src="@logoUrl" />
|
||||
<div class="form-group">
|
||||
<label for="inputToken">Token</label>
|
||||
<label for="inputToken">@translator.Translate(userLanguage, "Token")</label>
|
||||
<input type="text" id="inputToken" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="inputUserName">Email Address</label>
|
||||
<label for="inputUserName">@translator.Translate(userLanguage, "Email Address")</label>
|
||||
<input type="text" id="inputEmail" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="inputUserPassword">New Password</label>
|
||||
<label for="inputUserPassword">@translator.Translate(userLanguage, "New Password")</label>
|
||||
<input type="password" id="inputUserPassword" class="form-control">
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="button" class="btn btn-warning mt-2" onclick="performPasswordReset()"><i class="bi bi-box-arrow-in-right me-2"></i>Reset Password</button>
|
||||
<button type="button" class="btn btn-warning mt-2" onclick="performPasswordReset()"><i class="bi bi-box-arrow-in-right me-2"></i>@translator.Translate(userLanguage, "Reset Password")</button>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<a href="/Login/Index" class="btn btn-link mt-2">Back to Login</a>
|
||||
<a href="/Login/Index" class="btn btn-link mt-2">@translator.Translate(userLanguage, "Back to Login")</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
88
Views/Migration/Index.cshtml
Normal file
88
Views/Migration/Index.cshtml
Normal file
@@ -0,0 +1,88 @@
|
||||
@using CarCareTracker.Helper
|
||||
@{
|
||||
ViewData["Title"] = "Admin";
|
||||
}
|
||||
@inject IConfiguration config;
|
||||
@inject ITranslationHelper translator
|
||||
@{
|
||||
var userLanguage = config[nameof(UserConfig.UserLanguage)] ?? "en_US";
|
||||
}
|
||||
@model AdminViewModel
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-1">
|
||||
<a href="/Home" class="btn btn-secondary btn-md mt-1 mb-1"><i class="bi bi-arrow-left-square"></i></a>
|
||||
</div>
|
||||
<div class="col-11">
|
||||
<span class="display-6">@translator.Translate(userLanguage, "Database Migration")</span>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item">Instructions</li>
|
||||
<li class="list-group-item">Use this tool to migrate data between LiteDB and Postgres</li>
|
||||
<li class="list-group-item">Note that it is recommended that the Postgres DB is empty when importing from LiteDB to prevent primary key errors.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="row d-flex justify-content-center">
|
||||
<div class="col-3">
|
||||
<div class="d-grid">
|
||||
<input onChange="importPostgresData(this)" type="file" accept=".db" class="d-none" id="inputImport">
|
||||
<button type="button" class="btn btn-warning mt-2" onclick="importToPostgres()"><i class="bi bi-upload me-2"></i>@translator.Translate(userLanguage, "Import To Postgres")</button>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="button" class="btn btn-warning mt-2" onclick="exportFromPostgres()"><i class="bi bi-download me-2"></i>@translator.Translate(userLanguage, "Export From Postgres")</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function exportFromPostgres(){
|
||||
sloader.show();
|
||||
$.get('/Migration/Export', function (data) {
|
||||
sloader.hide();
|
||||
if (data.success) {
|
||||
window.location.href = data.message;
|
||||
} else {
|
||||
errorToast(genericErrorMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
function importPostgresData(event) {
|
||||
let formData = new FormData();
|
||||
formData.append("file", event.files[0]);
|
||||
sloader.show();
|
||||
$.ajax({
|
||||
url: "/Files/HandleFileUpload",
|
||||
data: formData,
|
||||
cache: false,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
type: 'POST',
|
||||
success: function (response) {
|
||||
if (response.trim() != '') {
|
||||
$.post('/Migration/Import', { fileName: response }, function (data) {
|
||||
sloader.hide();
|
||||
if (data.success) {
|
||||
successToast(data.message);
|
||||
setTimeout(function () { window.location.href = '/Home/Index' }, 500);
|
||||
} else {
|
||||
errorToast(genericErrorMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
sloader.hide();
|
||||
errorToast("An error has occurred, please check the file size and try again later.");
|
||||
}
|
||||
});
|
||||
}
|
||||
function importToPostgres() {
|
||||
$("#inputImport").click();
|
||||
}
|
||||
</script>
|
||||
@@ -1 +1,8 @@
|
||||
<h1>Access Denied</h1>
|
||||
<div class="row">
|
||||
<div class="col-1">
|
||||
<a href="/Home" class="btn btn-secondary btn-md mt-1 mb-1"><i class="bi bi-arrow-left-square"></i></a>
|
||||
</div>
|
||||
<div class="col-11">
|
||||
<h1>Access Denied</h1>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,6 +1,7 @@
|
||||
@using CarCareTracker.Helper
|
||||
<!DOCTYPE html>
|
||||
@inject IConfigHelper config
|
||||
@inject ITranslationHelper translator
|
||||
@{
|
||||
var userConfig = config.GetUserConfig(User);
|
||||
var useDarkMode = userConfig.UseDarkMode;
|
||||
@@ -10,6 +11,7 @@
|
||||
var useThreeDecimals = userConfig.UseThreeDecimalGasCost;
|
||||
var shortDatePattern = System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern;
|
||||
var numberFormat = System.Globalization.CultureInfo.CurrentCulture.NumberFormat;
|
||||
var userLanguage = userConfig.UserLanguage;
|
||||
shortDatePattern = shortDatePattern.ToLower();
|
||||
if (!shortDatePattern.Contains("dd"))
|
||||
{
|
||||
@@ -86,7 +88,7 @@
|
||||
return input;
|
||||
}
|
||||
function genericErrorMessage(){
|
||||
return "An error has occurred, please try again later";
|
||||
return decodeHTMLEntities('@translator.Translate(userLanguage, "An error has occurred, please try again later")');
|
||||
}
|
||||
</script>
|
||||
@await RenderSectionAsync("Scripts", required: false)
|
||||
|
||||
@@ -101,9 +101,10 @@
|
||||
<thead class="sticky-top">
|
||||
<tr class="d-flex">
|
||||
<th scope="col" class="col-2">@translator.Translate(userLanguage,"Date Refueled")</th>
|
||||
<th scope="col" class="col-2">@($"{translator.Translate(userLanguage,"Odometer")}({distanceUnit})")</th>
|
||||
<th scope="col" class="col-2">@($"{translator.Translate(userLanguage, "Odometer")}({distanceUnit})")</th>
|
||||
<th scope="col" class="col-1" style="cursor:pointer;" onclick="toggleSort('gas-tab-pane', this)">@($"Δ({distanceUnit})")</th>
|
||||
<th scope="col" class="col-2" data-gas="consumption" data-unit="@consumptionUnit" onclick="toggleSort('gas-tab-pane', this)" oncontextmenu="toggleUnits(this)" style="cursor:pointer;">@($"{translator.Translate(userLanguage,"Consumption")}({consumptionUnit})")</th>
|
||||
<th scope="col" class="col-4" data-gas="fueleconomy" data-unit="@fuelEconomyUnit" onclick="toggleSort('gas-tab-pane', this)" oncontextmenu="toggleUnits(this)" style="cursor:pointer;">@($"{@translator.Translate(userLanguage,"Fuel Economy")}({fuelEconomyUnit})")</th>
|
||||
<th scope="col" class="col-3" data-gas="fueleconomy" data-unit="@fuelEconomyUnit" onclick="toggleSort('gas-tab-pane', this)" oncontextmenu="toggleUnits(this)" style="cursor:pointer;">@($"{@translator.Translate(userLanguage,"Fuel Economy")}({fuelEconomyUnit})")</th>
|
||||
<th scope="col" class="col-1" onclick="toggleSort('gas-tab-pane', this)" style="cursor:pointer;">@translator.Translate(userLanguage,"Cost")</th>
|
||||
<th scope="col" class="col-1" onclick="toggleSort('gas-tab-pane', this)" style="cursor:pointer;">@translator.Translate(userLanguage,"Unit Cost")</th>
|
||||
</tr>
|
||||
@@ -113,9 +114,10 @@
|
||||
{
|
||||
<tr class="d-flex" style="cursor:pointer;" onclick="showEditGasRecordModal(@gasRecord.Id)" data-tags='@string.Join(" ", gasRecord.Tags)'>
|
||||
<td class="col-2">@gasRecord.Date</td>
|
||||
<td class="col-2" data-gas-type="mileage" data-gas-aggregate="@gasRecord.DeltaMileage">@gasRecord.Mileage</td>
|
||||
<td class="col-2" data-gas-type="mileage" data-gas-aggregate="@gasRecord.DeltaMileage" data-gas-original="@gasRecord.Mileage">@gasRecord.Mileage</td>
|
||||
<td class="col-1">@(gasRecord.DeltaMileage == default ? "---" : gasRecord.DeltaMileage)</td>
|
||||
<td class="col-2" data-gas-type="consumption" data-gas-aggregate="@gasRecord.Gallons">@gasRecord.Gallons.ToString("F")</td>
|
||||
<td class="col-4" data-gas-type="fueleconomy" data-aggregated='@(gasRecord.IncludeInAverage.ToString().ToLower())'>@(gasRecord.MilesPerGallon == 0 ? "---" : gasRecord.MilesPerGallon.ToString("F"))</td>
|
||||
<td class="col-3" data-gas-type="fueleconomy" data-aggregated='@(gasRecord.IncludeInAverage.ToString().ToLower())'>@(gasRecord.MilesPerGallon == 0 ? "---" : gasRecord.MilesPerGallon.ToString("F"))</td>
|
||||
<td class="col-1" data-record-type="cost">@((hideZero && gasRecord.Cost == default) ? "---" : gasRecord.Cost.ToString(gasCostFormat))</td>
|
||||
<td class="col-1" data-gas-type="unitcost">@((hideZero && gasRecord.CostPerGallon == default) ? "---" : gasRecord.CostPerGallon.ToString(gasCostFormat))</td>
|
||||
</tr>
|
||||
|
||||
@@ -28,6 +28,24 @@
|
||||
<label for="noteTextArea">@translator.Translate(userLanguage,"Notes")<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label>
|
||||
<textarea class="form-control vehicleNoteContainer" id="noteTextArea">@Model.NoteText</textarea>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
@if (Model.Files.Any())
|
||||
{
|
||||
<div>
|
||||
@await Html.PartialAsync("_UploadedFiles", Model.Files)
|
||||
<label for="serviceRecordFiles">@translator.Translate(userLanguage, "Upload more documents")</label>
|
||||
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="noteFiles">
|
||||
<br /><small class="text-body-secondary">@translator.Translate(userLanguage, "Max File Size: 28.6MB")</small>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<label for="serviceRecordFiles">@translator.Translate(userLanguage, "Upload documents(optional)")</label>
|
||||
<input onChange="uploadVehicleFilesAsync(this)" type="file" multiple accept=".png,.jpg,.jpeg,.pdf,.xls,.xlsx,.docx" class="form-control-file" id="noteFiles">
|
||||
<br />
|
||||
<small class="text-body-secondary">@translator.Translate(userLanguage, "Max File Size: 28.6MB")</small>
|
||||
}
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label for="noteRecordTag">@translator.Translate(userLanguage,"Tags(optional)")</label>
|
||||
<select multiple class="form-select" id="noteRecordTag">
|
||||
@@ -57,6 +75,14 @@
|
||||
}
|
||||
</div>
|
||||
<script>
|
||||
var uploadedFiles = [];
|
||||
getUploadedFilesFromModel();
|
||||
function getUploadedFilesFromModel() {
|
||||
@foreach (UploadedFiles filesUploaded in Model.Files)
|
||||
{
|
||||
@:uploadedFiles.push({ name: "@filesUploaded.Name", location: "@filesUploaded.Location" });
|
||||
}
|
||||
}
|
||||
function getNoteModelData(){
|
||||
return { id: @Model.Id}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,16 @@
|
||||
<button type="button" class="btn btn-secondary" onclick="hideAddPlanRecordModal()">@translator.Translate(userLanguage, "Cancel")</button>
|
||||
@if (isNew)
|
||||
{
|
||||
<button type="button" class="btn btn-primary" onclick="savePlanRecordToVehicle()">@translator.Translate(userLanguage, "Add New Plan Record")</button>
|
||||
<div class="btn-group">
|
||||
<button onclick="savePlanRecordToVehicle()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage, "Add New Plan Record")</button>
|
||||
<button type="button" class="btn btn-md btn-primary btn-md mt-1 mb-1 dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<span class="visually-hidden">Toggle Dropdown</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="#" onclick="savePlanRecordTemplate()">@translator.Translate(userLanguage, "Save as Template")</a></li>
|
||||
<li><a class="dropdown-item" href="#" onclick="showPlanRecordTemplatesModal()">@translator.Translate(userLanguage, "View Templates")</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
else if (!isNew)
|
||||
{
|
||||
|
||||
87
Views/Vehicle/_PlanRecordTemplateModal.cshtml
Normal file
87
Views/Vehicle/_PlanRecordTemplateModal.cshtml
Normal file
@@ -0,0 +1,87 @@
|
||||
@using CarCareTracker.Helper
|
||||
@inject IConfigHelper config
|
||||
@inject ITranslationHelper translator
|
||||
@{
|
||||
var userConfig = config.GetUserConfig(User);
|
||||
var userLanguage = userConfig.UserLanguage;
|
||||
}
|
||||
@model List<PlanRecordInput>
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">@translator.Translate(userLanguage,"Select Template")</h5>
|
||||
<button type="button" class="btn-close" onclick="hidePlanRecordTemplatesModal()" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
@if (Model.Any())
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-12" style="max-height:50vh; overflow-y:auto;">
|
||||
<table class="table table-hover">
|
||||
<thead class="sticky-top">
|
||||
<tr class="d-flex">
|
||||
<th scope="col" class="col-8">@translator.Translate(userLanguage,"Description")</th>
|
||||
<th scope="col" class="col-2">@translator.Translate(userLanguage, "Use")</th>
|
||||
<th scope="col" class="col-2">@translator.Translate(userLanguage, "Delete")</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (PlanRecordInput planRecordTemplate in Model)
|
||||
{
|
||||
<tr class="d-flex" id="supplyRows">
|
||||
<td class="col-8 text-truncate">
|
||||
@StaticHelper.TruncateStrings(planRecordTemplate.Description)
|
||||
@if (planRecordTemplate.Files.Any())
|
||||
{
|
||||
<i class="bi bi-paperclip ms-2"></i>
|
||||
}
|
||||
@if (planRecordTemplate.Supplies.Any())
|
||||
{
|
||||
<i class="bi bi-shop ms-2"></i>
|
||||
}
|
||||
@if (planRecordTemplate.ImportMode == ImportMode.ServiceRecord)
|
||||
{
|
||||
<i class="bi bi-card-checklist ms-2"></i>
|
||||
}
|
||||
else if (planRecordTemplate.ImportMode == ImportMode.UpgradeRecord)
|
||||
{
|
||||
<i class="bi bi-wrench-adjustable ms-2"></i>
|
||||
}
|
||||
else if (planRecordTemplate.ImportMode == ImportMode.RepairRecord)
|
||||
{
|
||||
<i class="bi bi-exclamation-octagon ms-2"></i>
|
||||
}
|
||||
@if (planRecordTemplate.Priority == PlanPriority.Critical)
|
||||
{
|
||||
<i class="bi bi-fire ms-2"></i>
|
||||
}
|
||||
else if (planRecordTemplate.Priority == PlanPriority.Normal)
|
||||
{
|
||||
<i class="bi bi-water ms-2"></i>
|
||||
}
|
||||
else if (planRecordTemplate.Priority == PlanPriority.Low)
|
||||
{
|
||||
<i class="bi bi-snow ms-2"></i>
|
||||
}
|
||||
</td>
|
||||
<td class="col-2"><button type="button" class="btn btn-primary" onclick="usePlannerRecordTemplate(@planRecordTemplate.Id)"><i class="bi bi-plus-square"></i></button></td>
|
||||
<td class="col-2"><button type="button" class="btn btn-danger" onclick="deletePlannerRecordTemplate(@planRecordTemplate.Id)"><i class="bi bi-trash"></i></button></td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="text-center">
|
||||
<h4>@translator.Translate(userLanguage, "No templates are found.")</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" onclick="hidePlanRecordTemplatesModal()">@translator.Translate(userLanguage, "Cancel")</button>
|
||||
</div>
|
||||
@@ -100,4 +100,11 @@
|
||||
<div class="modal-content" id="planRecordModalContent">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" data-bs-focus="false" id="planRecordTemplateModal" tabindex="-1" role="dialog" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content" id="planRecordTemplateModalContent">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -16,10 +16,15 @@
|
||||
new Chart($("#donut-chart"), {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: ['@translator.Translate(userLanguage,"Not Urgent")', '@translator.Translate(userLanguage,"Urgent")', '@translator.Translate(userLanguage,"Very Urgent")', '@translator.Translate(userLanguage,"Past Due")'],
|
||||
labels: [
|
||||
decodeHTMLEntities('@translator.Translate(userLanguage, "Not Urgent")'),
|
||||
decodeHTMLEntities('@translator.Translate(userLanguage, "Urgent")'),
|
||||
decodeHTMLEntities('@translator.Translate(userLanguage, "Very Urgent")'),
|
||||
decodeHTMLEntities('@translator.Translate(userLanguage, "Past Due")')
|
||||
],
|
||||
datasets: [
|
||||
{
|
||||
label: '@translator.Translate(userLanguage,"Reminders by Category")',
|
||||
label: decodeHTMLEntities('@translator.Translate(userLanguage, "Reminders by Category")'),
|
||||
backgroundColor: ["#488f31", "#ffa600", "#de425b", "#cccccc"],
|
||||
data: [
|
||||
@Model.NotUrgentCount,
|
||||
@@ -40,7 +45,7 @@
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: '@translator.Translate(userLanguage,"Reminders by Urgency")',
|
||||
text: decodeHTMLEntities('@translator.Translate(userLanguage, "Reminders by Urgency")'),
|
||||
color: useDarkMode ? "#fff" : "#000"
|
||||
},
|
||||
}
|
||||
|
||||
@@ -72,7 +72,9 @@
|
||||
<!option value="OneHundredFiftyThousandMiles" @(Model.ReminderMileageInterval == ReminderMileageInterval.OneHundredFiftyThousandMiles ? "selected" : "")>150000 mi. / Km</!option>
|
||||
</select>
|
||||
<label for="reminderRecurringMonth">Month</label>
|
||||
<select class="form-select" id="reminderRecurringMonth" @(Model.IsRecurring ? "" : "disabled")>
|
||||
<select class="form-select" onchange="checkCustomMonthInterval()" id="reminderRecurringMonth" @(Model.IsRecurring ? "" : "disabled")>
|
||||
<!option value="Other" @(Model.ReminderMonthInterval == ReminderMonthInterval.Other ? "selected" : "")>@(Model.ReminderMonthInterval == ReminderMonthInterval.Other && Model.CustomMonthInterval > 0 ? $"{translator.Translate(userLanguage, "Other")}: {Model.CustomMonthInterval}" : $"{translator.Translate(userLanguage, "Other")}") </!option>
|
||||
<!option value="OneMonth" @(Model.ReminderMonthInterval == ReminderMonthInterval.OneMonth ? "selected" : "")>@translator.Translate(userLanguage, "1 Month")</!option>
|
||||
<!option value="ThreeMonths" @(Model.ReminderMonthInterval == ReminderMonthInterval.ThreeMonths || isNew ? "selected" : "")>@translator.Translate(userLanguage,"3 Months")</!option>
|
||||
<!option value="SixMonths" @(Model.ReminderMonthInterval == ReminderMonthInterval.SixMonths ? "selected" : "")>@translator.Translate(userLanguage,"6 Months")</!option>
|
||||
<!option value="OneYear" @(Model.ReminderMonthInterval == ReminderMonthInterval.OneYear ? "selected" : "")>@translator.Translate(userLanguage, "1 Year")</!option>
|
||||
@@ -102,7 +104,8 @@
|
||||
</div>
|
||||
<script>
|
||||
var customMileageInterval = @Model.CustomMileageInterval;
|
||||
var customMonthInterval = @Model.CustomMonthInterval;
|
||||
function getReminderRecordModelData() {
|
||||
return { id: @Model.Id, mileageInterval: '@Model.ReminderMileageInterval.ToString()'}
|
||||
return { id: @Model.Id, mileageInterval: decodeHTMLEntities('@Model.ReminderMileageInterval.ToString()'), monthInterval: decodeHTMLEntities('@Model.ReminderMonthInterval.ToString()')}
|
||||
}
|
||||
</script>
|
||||
@@ -24,7 +24,8 @@
|
||||
<th scope="col" class="col-1"></th>
|
||||
<th scope="col" class="col-2">@translator.Translate(userLanguage,"Quantity")</th>
|
||||
<th scope="col" class="col-2">@translator.Translate(userLanguage, "In Stock")</th>
|
||||
<th scope="col" class="col-5">@translator.Translate(userLanguage, "Description")</th>
|
||||
<th scope="col" class="col-2">@translator.Translate(userLanguage, "Part Number")</th>
|
||||
<th scope="col" class="col-3">@translator.Translate(userLanguage, "Description")</th>
|
||||
<th scope="col" class="col-2">@translator.Translate(userLanguage, "Unit Cost")</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -35,7 +36,8 @@
|
||||
<td class="col-1"><input class="form-check-input" type="checkbox" onchange="toggleQuantityFieldDisabled(this)" value="@supplyRecord.Id"></td>
|
||||
<td class="col-2"><input type="text" disabled onchange="recalculateTotal()" class="form-control"></td>
|
||||
<td class="col-2 supplyquantity">@supplyRecord.Quantity</td>
|
||||
<td class="col-5">@supplyRecord.Description</td>
|
||||
<td class="col-2 text-truncate">@StaticHelper.TruncateStrings(supplyRecord.PartNumber)</td>
|
||||
<td class="col-3 text-truncate">@StaticHelper.TruncateStrings(supplyRecord.Description)</td>
|
||||
<td class="col-2 supplyprice">@((supplyRecord.Quantity > 0 ? supplyRecord.Cost / supplyRecord.Quantity : 0).ToString("F"))</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
@@ -42,7 +42,8 @@
|
||||
<label class="form-check-label" for="taxIsRecurring">@translator.Translate(userLanguage,"Is Recurring")</label>
|
||||
</div>
|
||||
<label for="taxRecurringMonth">@translator.Translate(userLanguage,"Month")</label>
|
||||
<select class="form-select" id="taxRecurringMonth" @(Model.IsRecurring ? "" : "disabled")>
|
||||
<select class="form-select" onchange="checkCustomMonthIntervalForTax()" id="taxRecurringMonth" @(Model.IsRecurring ? "" : "disabled")>
|
||||
<!option value="Other" @(Model.RecurringInterval == ReminderMonthInterval.Other ? "selected" : "")>@(Model.RecurringInterval == ReminderMonthInterval.Other && Model.CustomMonthInterval > 0 ? $"{translator.Translate(userLanguage, "Other")}: {Model.CustomMonthInterval}" : $"{translator.Translate(userLanguage, "Other")}") </!option>
|
||||
<!option value="OneMonth" @(Model.RecurringInterval == ReminderMonthInterval.OneMonth ? "selected" : "")>@translator.Translate(userLanguage,"1 Month")</!option>
|
||||
<!option value="ThreeMonths" @(Model.RecurringInterval == ReminderMonthInterval.ThreeMonths || isNew ? "selected" : "")>@translator.Translate(userLanguage, "3 Months")</!option>
|
||||
<!option value="SixMonths" @(Model.RecurringInterval == ReminderMonthInterval.SixMonths ? "selected" : "")>@translator.Translate(userLanguage, "6 Months")</!option>
|
||||
@@ -97,6 +98,7 @@
|
||||
</div>
|
||||
<script>
|
||||
var uploadedFiles = [];
|
||||
var customMonthInterval = @Model.CustomMonthInterval;
|
||||
getUploadedFilesFromModel();
|
||||
function getUploadedFilesFromModel() {
|
||||
@foreach (UploadedFiles filesUploaded in Model.Files)
|
||||
@@ -105,6 +107,6 @@
|
||||
}
|
||||
}
|
||||
function getTaxRecordModelData() {
|
||||
return { id: @Model.Id}
|
||||
return { id: @Model.Id, monthInterval: decodeHTMLEntities('@Model.RecurringInterval.ToString()') }
|
||||
}
|
||||
</script>
|
||||
@@ -14,6 +14,7 @@
|
||||
"HideZero": false,
|
||||
"EnableAutoReminderRefresh": false,
|
||||
"EnableAutoOdometerInsert": false,
|
||||
"EnableShopSupplies": false,
|
||||
"UseUKMPG": false,
|
||||
"UseThreeDecimalGasCost": true,
|
||||
"UseMarkDownOnSavedNotes": false,
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"UseDarkMode":true,"EnableCsvImports":false,"UseMPG":true,"UseDescending":false,"EnableAuth":false,"UserNameHash":"","UserPasswordHash":""}
|
||||
File diff suppressed because one or more lines are too long
49
wwwroot/defaults/reminderemailtemplate.txt
Normal file
49
wwwroot/defaults/reminderemailtemplate.txt
Normal file
@@ -0,0 +1,49 @@
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-family: arial, sans-serif;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
td, th {
|
||||
border: 1px solid #dddddd;
|
||||
text-align: left;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.VeryUrgent {
|
||||
background-color: #EA9999;
|
||||
}
|
||||
.Urgent {
|
||||
background-color: #FFE599;
|
||||
}
|
||||
.NotUrgent {
|
||||
background-color: #B6D7A8;
|
||||
}
|
||||
.PastDue {
|
||||
background-color: #CCCCCC;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>{VehicleInformation}</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<th>
|
||||
Urgency
|
||||
</th>
|
||||
<th>
|
||||
Description
|
||||
</th>
|
||||
<th>
|
||||
Due
|
||||
</th>
|
||||
</tr>
|
||||
{TableBody}
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -16,6 +16,7 @@ function loadGarage() {
|
||||
$.get('/Home/Garage', function (data) {
|
||||
$("#garageContainer").html(data);
|
||||
loadSettings();
|
||||
bindTabEvent();
|
||||
});
|
||||
}
|
||||
function loadSettings() {
|
||||
@@ -23,6 +24,31 @@ function loadSettings() {
|
||||
$("#settings-tab-pane").html(data);
|
||||
});
|
||||
}
|
||||
function getVehicleSupplyRecords() {
|
||||
$.get(`/Vehicle/GetSupplyRecordsByVehicleId?vehicleId=0`, function (data) {
|
||||
if (data) {
|
||||
$("#supply-tab-pane").html(data);
|
||||
restoreScrollPosition();
|
||||
}
|
||||
});
|
||||
}
|
||||
function GetVehicleId() {
|
||||
return { vehicleId: 0 };
|
||||
}
|
||||
function bindTabEvent() {
|
||||
$('button[data-bs-toggle="tab"]').on('show.bs.tab', function (e) {
|
||||
switch (e.target.id) {
|
||||
case "supply-tab":
|
||||
getVehicleSupplyRecords();
|
||||
break;
|
||||
}
|
||||
switch (e.relatedTarget.id) { //clear out previous tabs with grids in them to help with performance
|
||||
case "supply-tab":
|
||||
$("#supply-tab-pane").html("");
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
function performLogOut() {
|
||||
$.post('/Login/LogOut', function (data) {
|
||||
if (data) {
|
||||
|
||||
@@ -257,28 +257,28 @@ function convertFuelMileageUnits(currentUnit, destinationUnit, save) {
|
||||
convertedAmount = 100 / convertedAmount;
|
||||
elem.innerText = convertedAmount.toFixed(2);
|
||||
}
|
||||
//update labels up top.
|
||||
var newAverage = globalParseFloat($("#averageFuelMileageLabel").text().split(":")[1].trim());
|
||||
if (newAverage > 0) {
|
||||
newAverage = 100 / newAverage;
|
||||
var averageLabel = $("#averageFuelMileageLabel");
|
||||
averageLabel.text(`${averageLabel.text().split(':')[0]}: ${newAverage.toFixed(2)}`);
|
||||
}
|
||||
var newMin = globalParseFloat($("#minFuelMileageLabel").text().split(":")[1].trim());
|
||||
if (newMin > 0) {
|
||||
newMin = 100 / newMin;
|
||||
var minLabel = $("#minFuelMileageLabel");
|
||||
minLabel.text(`${minLabel.text().split(':')[0]}: ${newMin.toFixed(2)}`);
|
||||
}
|
||||
var newMax = globalParseFloat($("#maxFuelMileageLabel").text().split(":")[1].trim());
|
||||
if (newMax > 0) {
|
||||
newMax = 100 / newMax;
|
||||
var maxLabel = $("#maxFuelMileageLabel");
|
||||
maxLabel.text(`${maxLabel.text().split(':')[0]}: ${newMax.toFixed(2)}`);
|
||||
}
|
||||
sender.text(sender.text().replace(sender.attr("data-unit"), "km/l"));
|
||||
sender.attr("data-unit", "km/l");
|
||||
});
|
||||
//update labels up top.
|
||||
var newAverage = globalParseFloat($("#averageFuelMileageLabel").text().split(":")[1].trim());
|
||||
if (newAverage > 0) {
|
||||
newAverage = 100 / newAverage;
|
||||
var averageLabel = $("#averageFuelMileageLabel");
|
||||
averageLabel.text(`${averageLabel.text().split(':')[0]}: ${newAverage.toFixed(2)}`);
|
||||
}
|
||||
var newMin = globalParseFloat($("#minFuelMileageLabel").text().split(":")[1].trim());
|
||||
if (newMin > 0) {
|
||||
newMin = 100 / newMin;
|
||||
var minLabel = $("#minFuelMileageLabel");
|
||||
minLabel.text(`${minLabel.text().split(':')[0]}: ${newMin.toFixed(2)}`);
|
||||
}
|
||||
var newMax = globalParseFloat($("#maxFuelMileageLabel").text().split(":")[1].trim());
|
||||
if (newMax > 0) {
|
||||
newMax = 100 / newMax;
|
||||
var maxLabel = $("#maxFuelMileageLabel");
|
||||
maxLabel.text(`${maxLabel.text().split(':')[0]}: ${newMax.toFixed(2)}`);
|
||||
}
|
||||
sender.text(sender.text().replace(sender.attr("data-unit"), "km/l"));
|
||||
sender.attr("data-unit", "km/l");
|
||||
if (save) { setDebounce(saveUserGasTabPreferences); }
|
||||
break;
|
||||
}
|
||||
@@ -291,27 +291,28 @@ function convertFuelMileageUnits(currentUnit, destinationUnit, save) {
|
||||
convertedAmount = 100 / convertedAmount;
|
||||
elem.innerText = convertedAmount.toFixed(2);
|
||||
}
|
||||
var newAverage = globalParseFloat($("#averageFuelMileageLabel").text().split(":")[1].trim());
|
||||
if (newAverage > 0) {
|
||||
newAverage = 100 / newAverage;
|
||||
var averageLabel = $("#averageFuelMileageLabel");
|
||||
averageLabel.text(`${averageLabel.text().split(':')[0]}: ${newAverage.toFixed(2)}`);
|
||||
}
|
||||
var newMin = globalParseFloat($("#minFuelMileageLabel").text().split(":")[1].trim());
|
||||
if (newMin > 0) {
|
||||
newMin = 100 / newMin;
|
||||
var minLabel = $("#minFuelMileageLabel");
|
||||
minLabel.text(`${minLabel.text().split(':')[0]}: ${newMin.toFixed(2)}`);
|
||||
}
|
||||
var newMax = globalParseFloat($("#maxFuelMileageLabel").text().split(":")[1].trim());
|
||||
if (newMax > 0) {
|
||||
newMax = 100 / newMax;
|
||||
var maxLabel = $("#maxFuelMileageLabel");
|
||||
maxLabel.text(`${maxLabel.text().split(':')[0]}: ${newMax.toFixed(2)}`);
|
||||
}
|
||||
sender.text(sender.text().replace(sender.attr("data-unit"), "l/100km"));
|
||||
sender.attr("data-unit", "l/100km");
|
||||
});
|
||||
var newAverage = globalParseFloat($("#averageFuelMileageLabel").text().split(":")[1].trim());
|
||||
if (newAverage > 0) {
|
||||
newAverage = 100 / newAverage;
|
||||
|
||||
var averageLabel = $("#averageFuelMileageLabel");
|
||||
averageLabel.text(`${averageLabel.text().split(':')[0]}: ${newAverage.toFixed(2)}`);
|
||||
}
|
||||
var newMin = globalParseFloat($("#minFuelMileageLabel").text().split(":")[1].trim());
|
||||
if (newMin > 0) {
|
||||
newMin = 100 / newMin;
|
||||
var minLabel = $("#minFuelMileageLabel");
|
||||
minLabel.text(`${minLabel.text().split(':')[0]}: ${newMin.toFixed(2)}`);
|
||||
}
|
||||
var newMax = globalParseFloat($("#maxFuelMileageLabel").text().split(":")[1].trim());
|
||||
if (newMax > 0) {
|
||||
newMax = 100 / newMax;
|
||||
var maxLabel = $("#maxFuelMileageLabel");
|
||||
maxLabel.text(`${maxLabel.text().split(':')[0]}: ${newMax.toFixed(2)}`);
|
||||
}
|
||||
sender.text(sender.text().replace(sender.attr("data-unit"), "l/100km"));
|
||||
sender.attr("data-unit", "l/100km");
|
||||
if (save) { setDebounce(saveUserGasTabPreferences); }
|
||||
break;
|
||||
}
|
||||
@@ -341,8 +342,14 @@ function updateMPGLabels() {
|
||||
} else {
|
||||
averageLabel.text(`${averageLabel.text().split(':')[0]}: 0.00`);
|
||||
}
|
||||
minLabel.text(`${minLabel.text().split(':')[0]}: ${minMPG.toFixed(2)}`);
|
||||
maxLabel.text(`${maxLabel.text().split(':')[0]}: ${maxMPG.toFixed(2)}`);
|
||||
if (!getGlobalConfig().useMPG && $("[data-gas='fueleconomy']").attr("data-unit") != 'km/l') {
|
||||
maxLabel.text(`${maxLabel.text().split(':')[0]}: ${minMPG.toFixed(2)}`);
|
||||
minLabel.text(`${minLabel.text().split(':')[0]}: ${maxMPG.toFixed(2)}`);
|
||||
}
|
||||
else {
|
||||
minLabel.text(`${minLabel.text().split(':')[0]}: ${minMPG.toFixed(2)}`);
|
||||
maxLabel.text(`${maxLabel.text().split(':')[0]}: ${maxMPG.toFixed(2)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,13 @@
|
||||
var isPersistent = $("#inputPersistent").is(":checked");
|
||||
$.post('/Login/Login', {userName: userName, password: userPassword, isPersistent: isPersistent}, function (data) {
|
||||
if (data) {
|
||||
window.location.href = '/Home';
|
||||
//check for redirectURL
|
||||
var redirectURL = getRedirectURL().url;
|
||||
if (redirectURL.trim() != "") {
|
||||
window.location.href = redirectURL;
|
||||
} else {
|
||||
window.location.href = '/Home';
|
||||
}
|
||||
} else {
|
||||
errorToast("Invalid Login Credentials, please try again.");
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ function getAndValidateNoteValues() {
|
||||
vehicleId: vehicleId,
|
||||
description: noteDescription,
|
||||
noteText: noteText,
|
||||
files: uploadedFiles,
|
||||
pinned: noteIsPinned,
|
||||
tags: noteTags
|
||||
}
|
||||
|
||||
@@ -74,6 +74,79 @@ function savePlanRecordToVehicle(isEdit) {
|
||||
}
|
||||
})
|
||||
}
|
||||
function showPlanRecordTemplatesModal() {
|
||||
var vehicleId = GetVehicleId().vehicleId;
|
||||
$.get(`/Vehicle/GetPlanRecordTemplatesForVehicleId?vehicleId=${vehicleId}`, function (data) {
|
||||
if (data) {
|
||||
$("#planRecordTemplateModalContent").html(data);
|
||||
hideAddPlanRecordModal();
|
||||
$('#planRecordTemplateModal').modal('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
function hidePlanRecordTemplatesModal() {
|
||||
$('#planRecordTemplateModal').modal('hide');
|
||||
$('#planRecordModal').modal('show');
|
||||
}
|
||||
function usePlannerRecordTemplate(planRecordTemplateId) {
|
||||
$.post(`/Vehicle/ConvertPlanRecordTemplateToPlanRecord?planRecordTemplateId=${planRecordTemplateId}`, function (data) {
|
||||
if (data.success) {
|
||||
var vehicleId = GetVehicleId().vehicleId;
|
||||
successToast(data.message);
|
||||
$('#planRecordTemplateModal').modal('hide');
|
||||
hideAddPlanRecordModal();
|
||||
saveScrollPosition();
|
||||
getVehiclePlanRecords(vehicleId);
|
||||
} else {
|
||||
errorToast(data.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deletePlannerRecordTemplate(planRecordTemplateId) {
|
||||
$("#workAroundInput").show();
|
||||
Swal.fire({
|
||||
title: "Confirm Deletion?",
|
||||
text: "Deleted Plan Templates cannot be restored.",
|
||||
showCancelButton: true,
|
||||
confirmButtonText: "Delete",
|
||||
confirmButtonColor: "#dc3545"
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
$.post(`/Vehicle/DeletePlanRecordTemplateById?planRecordTemplateId=${planRecordTemplateId}`, function (data) {
|
||||
$("#workAroundInput").hide();
|
||||
if (data) {
|
||||
successToast("Template Deleted");
|
||||
hidePlanRecordTemplatesModal();
|
||||
} else {
|
||||
errorToast(genericErrorMessage());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$("#workAroundInput").hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
function savePlanRecordTemplate() {
|
||||
//get values
|
||||
var formValues = getAndValidatePlanRecordValues();
|
||||
//validate
|
||||
if (formValues.hasError) {
|
||||
errorToast("Please check the form data");
|
||||
return;
|
||||
}
|
||||
//save to db.
|
||||
$.post('/Vehicle/SavePlanRecordTemplateToVehicleId', { planRecord: formValues }, function (data) {
|
||||
if (data.success) {
|
||||
successToast(data.message);
|
||||
hideAddPlanRecordModal();
|
||||
saveScrollPosition();
|
||||
getVehiclePlanRecords(formValues.vehicleId);
|
||||
} else {
|
||||
errorToast(data.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
function getAndValidatePlanRecordValues() {
|
||||
var planDescription = $("#planRecordDescription").val();
|
||||
var planCost = $("#planRecordCost").val();
|
||||
|
||||
@@ -15,6 +15,35 @@
|
||||
function hideAddReminderRecordModal() {
|
||||
$('#reminderRecordModal').modal('hide');
|
||||
}
|
||||
function checkCustomMonthInterval() {
|
||||
var selectedValue = $("#reminderRecurringMonth").val();
|
||||
if (selectedValue == "Other") {
|
||||
$("#workAroundInput").show();
|
||||
Swal.fire({
|
||||
title: 'Specify Custom Month Interval',
|
||||
html: `
|
||||
<input type="text" id="inputCustomMileage" class="swal2-input" placeholder="Months">
|
||||
`,
|
||||
confirmButtonText: 'Set',
|
||||
focusConfirm: false,
|
||||
preConfirm: () => {
|
||||
const customMonth = $("#inputCustomMileage").val();
|
||||
if (!customMonth || isNaN(parseInt(customMonth)) || parseInt(customMonth) <= 0) {
|
||||
Swal.showValidationMessage(`Please enter a valid number`);
|
||||
}
|
||||
return { customMonth }
|
||||
},
|
||||
}).then(function (result) {
|
||||
if (result.isConfirmed) {
|
||||
customMonthInterval = result.value.customMonth;
|
||||
$("#reminderRecurringMonth > option[value='Other']").text(`Other: ${result.value.customMonth}`);
|
||||
} else {
|
||||
$("#reminderRecurringMonth").val(getReminderRecordModelData().monthInterval);
|
||||
}
|
||||
$("#workAroundInput").hide();
|
||||
});
|
||||
}
|
||||
}
|
||||
function checkCustomMileageInterval() {
|
||||
var selectedValue = $("#reminderRecurringMileage").val();
|
||||
if (selectedValue == "Other") {
|
||||
@@ -36,7 +65,7 @@ function checkCustomMileageInterval() {
|
||||
}).then(function (result) {
|
||||
if (result.isConfirmed) {
|
||||
customMileageInterval = result.value.customMileage;
|
||||
$("option[value='Other']").text(`Other: ${result.value.customMileage}`);
|
||||
$("#reminderRecurringMileage > option[value='Other']").text(`Other: ${result.value.customMileage}`);
|
||||
} else {
|
||||
$("#reminderRecurringMileage").val(getReminderRecordModelData().mileageInterval);
|
||||
}
|
||||
@@ -185,6 +214,7 @@ function getAndValidateReminderRecordValues() {
|
||||
isRecurring: reminderIsRecurring,
|
||||
reminderMileageInterval: reminderRecurringMileage,
|
||||
reminderMonthInterval: reminderRecurringMonth,
|
||||
customMileageInterval: customMileageInterval
|
||||
customMileageInterval: customMileageInterval,
|
||||
customMonthInterval: customMonthInterval
|
||||
}
|
||||
}
|
||||
@@ -276,4 +276,114 @@ function updateAggregateLabels() {
|
||||
var newCount = $("[data-record-type='cost']").parent(":not('.override-hide')").length;
|
||||
var countLabel = $("[data-aggregate-type='count']");
|
||||
countLabel.text(`${countLabel.text().split(':')[0]}: ${newCount}`)
|
||||
}
|
||||
|
||||
function uploadVehicleFilesAsync(event) {
|
||||
let formData = new FormData();
|
||||
var files = event.files;
|
||||
for (var x = 0; x < files.length; x++) {
|
||||
formData.append("file", files[x]);
|
||||
}
|
||||
sloader.show();
|
||||
$.ajax({
|
||||
url: "/Files/HandleMultipleFileUpload",
|
||||
data: formData,
|
||||
cache: false,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
type: 'POST',
|
||||
success: function (response) {
|
||||
sloader.hide();
|
||||
if (response.length > 0) {
|
||||
uploadedFiles.push.apply(uploadedFiles, response);
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
sloader.hide();
|
||||
errorToast("An error has occurred, please check the file size and try again later.")
|
||||
}
|
||||
});
|
||||
}
|
||||
function deleteFileFromUploadedFiles(fileLocation, event) {
|
||||
event.parentElement.parentElement.parentElement.remove();
|
||||
uploadedFiles = uploadedFiles.filter(x => x.location != fileLocation);
|
||||
}
|
||||
function editFileName(fileLocation, event) {
|
||||
Swal.fire({
|
||||
title: 'Rename File',
|
||||
html: `
|
||||
<input type="text" id="newFileName" class="swal2-input" placeholder="New File Name">
|
||||
`,
|
||||
confirmButtonText: 'Rename',
|
||||
focusConfirm: false,
|
||||
preConfirm: () => {
|
||||
const newFileName = $("#newFileName").val();
|
||||
if (!newFileName) {
|
||||
Swal.showValidationMessage(`Please enter a valid file name`)
|
||||
}
|
||||
return { newFileName }
|
||||
},
|
||||
}).then(function (result) {
|
||||
if (result.isConfirmed) {
|
||||
var linkDisplayObject = $(event.parentElement.parentElement).find('a')[0];
|
||||
linkDisplayObject.text = result.value.newFileName;
|
||||
var editFileIndex = uploadedFiles.findIndex(x => x.location == fileLocation);
|
||||
uploadedFiles[editFileIndex].name = result.value.newFileName;
|
||||
}
|
||||
});
|
||||
}
|
||||
var scrollPosition = 0;
|
||||
function saveScrollPosition() {
|
||||
scrollPosition = $(".vehicleDetailTabContainer").scrollTop();
|
||||
}
|
||||
function restoreScrollPosition() {
|
||||
$(".vehicleDetailTabContainer").scrollTop(scrollPosition);
|
||||
scrollPosition = 0;
|
||||
}
|
||||
function toggleMarkDownOverlay(textAreaName) {
|
||||
var textArea = $(`#${textAreaName}`);
|
||||
if ($(".markdown-overlay").length > 0) {
|
||||
$(".markdown-overlay").remove();
|
||||
return;
|
||||
}
|
||||
var text = textArea.val();
|
||||
if (text == undefined) {
|
||||
return;
|
||||
}
|
||||
if (text.length > 0) {
|
||||
var formatted = markdown(text);
|
||||
//var overlay div
|
||||
var overlayDiv = `<div class='markdown-overlay' style="z-index: 1060; position:absolute; top:${textArea.css('top')}; left:${textArea.css('left')}; width:${textArea.css('width')}; height:${textArea.css('height')}; padding:${textArea.css('padding')}; overflow-y:auto; background-color:var(--bs-modal-bg);">${formatted}</div>`;
|
||||
textArea.parent().children(`label[for=${textAreaName}]`).append(overlayDiv);
|
||||
}
|
||||
}
|
||||
function showLinks(e) {
|
||||
var textAreaName = $(e.parentElement).attr("for");
|
||||
toggleMarkDownOverlay(textAreaName);
|
||||
}
|
||||
function printTab() {
|
||||
setTimeout(function () {
|
||||
window.print();
|
||||
}, 500);
|
||||
}
|
||||
function exportVehicleData(mode) {
|
||||
var vehicleId = GetVehicleId().vehicleId;
|
||||
$.get('/Vehicle/ExportFromVehicleToCsv', { vehicleId: vehicleId, mode: mode }, function (data) {
|
||||
if (!data) {
|
||||
errorToast(genericErrorMessage());
|
||||
} else {
|
||||
window.location.href = data;
|
||||
}
|
||||
});
|
||||
}
|
||||
function showBulkImportModal(mode) {
|
||||
$.get(`/Vehicle/GetBulkImportModalPartialView?mode=${mode}`, function (data) {
|
||||
if (data) {
|
||||
$("#bulkImportModalContent").html(data);
|
||||
$("#bulkImportModal").modal('show');
|
||||
}
|
||||
})
|
||||
}
|
||||
function hideBulkImportModal() {
|
||||
$("#bulkImportModal").modal('hide');
|
||||
}
|
||||
@@ -84,6 +84,35 @@ function saveTaxRecordToVehicle(isEdit) {
|
||||
}
|
||||
})
|
||||
}
|
||||
function checkCustomMonthIntervalForTax() {
|
||||
var selectedValue = $("#taxRecurringMonth").val();
|
||||
if (selectedValue == "Other") {
|
||||
$("#workAroundInput").show();
|
||||
Swal.fire({
|
||||
title: 'Specify Custom Month Interval',
|
||||
html: `
|
||||
<input type="text" id="inputCustomMileage" class="swal2-input" placeholder="Months">
|
||||
`,
|
||||
confirmButtonText: 'Set',
|
||||
focusConfirm: false,
|
||||
preConfirm: () => {
|
||||
const customMonth = $("#inputCustomMileage").val();
|
||||
if (!customMonth || isNaN(parseInt(customMonth)) || parseInt(customMonth) <= 0) {
|
||||
Swal.showValidationMessage(`Please enter a valid number`);
|
||||
}
|
||||
return { customMonth }
|
||||
},
|
||||
}).then(function (result) {
|
||||
if (result.isConfirmed) {
|
||||
customMonthInterval = result.value.customMonth;
|
||||
$("#taxRecurringMonth > option[value='Other']").text(`Other: ${result.value.customMonth}`);
|
||||
} else {
|
||||
$("#taxRecurringMonth").val(getTaxRecordModelData().monthInterval);
|
||||
}
|
||||
$("#workAroundInput").hide();
|
||||
});
|
||||
}
|
||||
}
|
||||
function getAndValidateTaxRecordValues() {
|
||||
var taxDate = $("#taxRecordDate").val();
|
||||
var taxDescription = $("#taxRecordDescription").val();
|
||||
@@ -125,6 +154,7 @@ function getAndValidateTaxRecordValues() {
|
||||
notes: taxNotes,
|
||||
isRecurring: taxIsRecurring,
|
||||
recurringInterval: taxRecurringMonth,
|
||||
customMonthInterval: customMonthInterval,
|
||||
tags: taxTags,
|
||||
files: uploadedFiles,
|
||||
addReminderRecord: addReminderRecord
|
||||
|
||||
@@ -222,27 +222,6 @@ function editVehicle(vehicleId) {
|
||||
function hideEditVehicleModal() {
|
||||
$('#editVehicleModal').modal('hide');
|
||||
}
|
||||
function exportVehicleData(mode) {
|
||||
var vehicleId = GetVehicleId().vehicleId;
|
||||
$.get('/Vehicle/ExportFromVehicleToCsv', { vehicleId: vehicleId, mode: mode }, function (data) {
|
||||
if (!data) {
|
||||
errorToast(genericErrorMessage());
|
||||
} else {
|
||||
window.location.href = data;
|
||||
}
|
||||
});
|
||||
}
|
||||
function showBulkImportModal(mode) {
|
||||
$.get(`/Vehicle/GetBulkImportModalPartialView?mode=${mode}`, function (data) {
|
||||
if (data) {
|
||||
$("#bulkImportModalContent").html(data);
|
||||
$("#bulkImportModal").modal('show');
|
||||
}
|
||||
})
|
||||
}
|
||||
function hideBulkImportModal(){
|
||||
$("#bulkImportModal").modal('hide');
|
||||
}
|
||||
function deleteVehicle(vehicleId) {
|
||||
Swal.fire({
|
||||
title: "Confirm Deletion?",
|
||||
@@ -260,32 +239,6 @@ function deleteVehicle(vehicleId) {
|
||||
}
|
||||
});
|
||||
}
|
||||
function uploadVehicleFilesAsync(event) {
|
||||
let formData = new FormData();
|
||||
var files = event.files;
|
||||
for (var x = 0; x < files.length; x++) {
|
||||
formData.append("file", files[x]);
|
||||
}
|
||||
sloader.show();
|
||||
$.ajax({
|
||||
url: "/Files/HandleMultipleFileUpload",
|
||||
data: formData,
|
||||
cache: false,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
type: 'POST',
|
||||
success: function (response) {
|
||||
sloader.hide();
|
||||
if (response.length > 0) {
|
||||
uploadedFiles.push.apply(uploadedFiles, response);
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
sloader.hide();
|
||||
errorToast("An error has occurred, please check the file size and try again later.")
|
||||
}
|
||||
});
|
||||
}
|
||||
function showAddReminderModal(reminderModalInput) {
|
||||
if (reminderModalInput != undefined) {
|
||||
$.post('/Vehicle/GetAddReminderRecordPartialView', {reminderModel: reminderModalInput}, function (data) {
|
||||
@@ -318,47 +271,6 @@ function getVehicleHaveImportantReminders(vehicleId) {
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
function printTab() {
|
||||
setTimeout(function () {
|
||||
window.print();
|
||||
}, 500);
|
||||
}
|
||||
function deleteFileFromUploadedFiles(fileLocation, event) {
|
||||
event.parentElement.parentElement.parentElement.remove();
|
||||
uploadedFiles = uploadedFiles.filter(x => x.location != fileLocation);
|
||||
}
|
||||
function editFileName(fileLocation, event) {
|
||||
Swal.fire({
|
||||
title: 'Rename File',
|
||||
html: `
|
||||
<input type="text" id="newFileName" class="swal2-input" placeholder="New File Name">
|
||||
`,
|
||||
confirmButtonText: 'Rename',
|
||||
focusConfirm: false,
|
||||
preConfirm: () => {
|
||||
const newFileName = $("#newFileName").val();
|
||||
if (!newFileName) {
|
||||
Swal.showValidationMessage(`Please enter a valid file name`)
|
||||
}
|
||||
return { newFileName }
|
||||
},
|
||||
}).then(function (result) {
|
||||
if (result.isConfirmed) {
|
||||
var linkDisplayObject = $(event.parentElement.parentElement).find('a')[0];
|
||||
linkDisplayObject.text = result.value.newFileName;
|
||||
var editFileIndex = uploadedFiles.findIndex(x => x.location == fileLocation);
|
||||
uploadedFiles[editFileIndex].name = result.value.newFileName;
|
||||
}
|
||||
});
|
||||
}
|
||||
var scrollPosition = 0;
|
||||
function saveScrollPosition() {
|
||||
scrollPosition = $(".vehicleDetailTabContainer").scrollTop();
|
||||
}
|
||||
function restoreScrollPosition() {
|
||||
$(".vehicleDetailTabContainer").scrollTop(scrollPosition);
|
||||
scrollPosition = 0;
|
||||
}
|
||||
function moveRecord(recordId, source, dest) {
|
||||
$("#workAroundInput").show();
|
||||
var friendlySource = "";
|
||||
@@ -415,25 +327,4 @@ function moveRecord(recordId, source, dest) {
|
||||
$("#workAroundInput").hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
function toggleMarkDownOverlay(textAreaName) {
|
||||
var textArea = $(`#${textAreaName}`);
|
||||
if ($(".markdown-overlay").length > 0) {
|
||||
$(".markdown-overlay").remove();
|
||||
return;
|
||||
}
|
||||
var text = textArea.val();
|
||||
if (text == undefined) {
|
||||
return;
|
||||
}
|
||||
if (text.length > 0) {
|
||||
var formatted = markdown(text);
|
||||
//var overlay div
|
||||
var overlayDiv = `<div class='markdown-overlay' style="z-index: 1060; position:absolute; top:${textArea.css('top')}; left:${textArea.css('left')}; width:${textArea.css('width')}; height:${textArea.css('height')}; padding:${textArea.css('padding')}; overflow-y:auto; background-color:var(--bs-modal-bg);">${formatted}</div>`;
|
||||
textArea.parent().children(`label[for=${textAreaName}]`).append(overlayDiv);
|
||||
}
|
||||
}
|
||||
function showLinks(e) {
|
||||
var textAreaName = $(e.parentElement).attr("for");
|
||||
toggleMarkDownOverlay(textAreaName);
|
||||
}
|
||||
@@ -273,81 +273,6 @@
|
||||
makeOptionItemFunction(self.options, 'itemText');
|
||||
makeOptionFunction(self.options, 'tagClass');
|
||||
|
||||
// Typeahead Bootstrap version 2.3.2
|
||||
if (self.options.typeahead) {
|
||||
var typeahead = self.options.typeahead || {};
|
||||
|
||||
makeOptionFunction(typeahead, 'source');
|
||||
|
||||
self.$input.typeahead($.extend({}, typeahead, {
|
||||
source: function (query, process) {
|
||||
function processItems(items) {
|
||||
var texts = [];
|
||||
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var text = self.options.itemText(items[i]);
|
||||
map[text] = items[i];
|
||||
texts.push(text);
|
||||
}
|
||||
process(texts);
|
||||
}
|
||||
|
||||
this.map = {};
|
||||
var map = this.map,
|
||||
data = typeahead.source(query);
|
||||
|
||||
if ($.isFunction(data.success)) {
|
||||
// support for Angular callbacks
|
||||
data.success(processItems);
|
||||
} else if ($.isFunction(data.then)) {
|
||||
// support for Angular promises
|
||||
data.then(processItems);
|
||||
} else {
|
||||
// support for functions and jquery promises
|
||||
$.when(data)
|
||||
.then(processItems);
|
||||
}
|
||||
},
|
||||
updater: function (text) {
|
||||
self.add(this.map[text]);
|
||||
return this.map[text];
|
||||
},
|
||||
matcher: function (text) {
|
||||
return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
|
||||
},
|
||||
sorter: function (texts) {
|
||||
return texts.sort();
|
||||
},
|
||||
highlighter: function (text) {
|
||||
var regex = new RegExp( '(' + this.query + ')', 'gi' );
|
||||
return text.replace( regex, "<strong>$1</strong>" );
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
// typeahead.js
|
||||
if (self.options.typeaheadjs) {
|
||||
var typeaheadConfig = null;
|
||||
var typeaheadDatasets = {};
|
||||
|
||||
// Determine if main configurations were passed or simply a dataset
|
||||
var typeaheadjs = self.options.typeaheadjs;
|
||||
if ($.isArray(typeaheadjs)) {
|
||||
typeaheadConfig = typeaheadjs[0];
|
||||
typeaheadDatasets = typeaheadjs[1];
|
||||
} else {
|
||||
typeaheadDatasets = typeaheadjs;
|
||||
}
|
||||
|
||||
self.$input.typeahead(typeaheadConfig, typeaheadDatasets).on('typeahead:selected', $.proxy(function (obj, datum) {
|
||||
if (typeaheadDatasets.valueKey)
|
||||
self.add(datum[typeaheadDatasets.valueKey]);
|
||||
else
|
||||
self.add(datum);
|
||||
self.$input.typeahead('val', '');
|
||||
}, self));
|
||||
}
|
||||
|
||||
self.$container.on('click', $.proxy(function(event) {
|
||||
if (! self.$element.attr('disabled')) {
|
||||
self.$input.removeAttr('disabled');
|
||||
@@ -423,7 +348,7 @@
|
||||
var textLength = $input.val().length,
|
||||
wordSpace = Math.ceil(textLength / 5),
|
||||
size = textLength + wordSpace + 1;
|
||||
$input.attr('size', Math.max(this.inputSize, $input.val().length));
|
||||
$input.attr('size', Math.max(this.inputSize, size));
|
||||
}, self));
|
||||
|
||||
self.$container.on('input', 'input', $.proxy(function (event) {
|
||||
@@ -448,7 +373,7 @@
|
||||
var textLength = $input.val().length,
|
||||
wordSpace = Math.ceil(textLength / 5),
|
||||
size = textLength + wordSpace + 1;
|
||||
$input.attr('size', Math.max(this.inputSize, $input.val().length));
|
||||
$input.attr('size', Math.max(this.inputSize, size));
|
||||
};
|
||||
}));
|
||||
|
||||
@@ -480,7 +405,7 @@
|
||||
var textLength = $input.val().length,
|
||||
wordSpace = Math.ceil(textLength / 5),
|
||||
size = textLength + wordSpace + 1;
|
||||
$input.attr('size', Math.max(this.inputSize, $input.val().length));
|
||||
$input.attr('size', Math.max(this.inputSize, size));
|
||||
}, self));
|
||||
|
||||
// Remove icon clicked
|
||||
|
||||
Reference in New Issue
Block a user