Merge branch 'Hargata/user.config' into Hargata/users

# Conflicts:
#	Helper/ConfigHelper.cs
#	Views/Home/Index.cshtml
This commit is contained in:
DESKTOP-GENO133\IvanPlex
2024-01-14 11:20:02 -07:00
23 changed files with 355 additions and 121 deletions

View File

@@ -1,4 +1,5 @@
using CarCareTracker.Logic;
using CarCareTracker.Helper;
using CarCareTracker.Logic;
using CarCareTracker.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
@@ -12,10 +13,12 @@ namespace CarCareTracker.Controllers
{
private ILoginLogic _loginLogic;
private IUserLogic _userLogic;
public AdminController(ILoginLogic loginLogic, IUserLogic userLogic)
private IConfigHelper _configHelper;
public AdminController(ILoginLogic loginLogic, IUserLogic userLogic, IConfigHelper configHelper)
{
_loginLogic = loginLogic;
_userLogic = userLogic;
_configHelper = configHelper;
}
public IActionResult Index()
{
@@ -38,7 +41,7 @@ namespace CarCareTracker.Controllers
}
public IActionResult DeleteUser(int userId)
{
var result =_userLogic.DeleteAllAccessToUser(userId) && _loginLogic.DeleteUser(userId);
var result =_userLogic.DeleteAllAccessToUser(userId) && _configHelper.DeleteUserConfig(userId) && _loginLogic.DeleteUser(userId);
return Json(result);
}
}

View File

@@ -15,12 +15,12 @@ namespace CarCareTracker.Controllers
private readonly ILogger<HomeController> _logger;
private readonly IVehicleDataAccess _dataAccess;
private readonly IUserLogic _userLogic;
private readonly IConfiguration _config;
private readonly IConfigHelper _config;
public HomeController(ILogger<HomeController> logger,
IVehicleDataAccess dataAccess,
IUserLogic userLogic,
IConfiguration configuration)
IConfigHelper configuration)
{
_logger = logger;
_dataAccess = dataAccess;
@@ -46,49 +46,14 @@ namespace CarCareTracker.Controllers
}
public IActionResult Settings()
{
var userConfig = new UserConfig
{
EnableCsvImports = bool.Parse(_config[nameof(UserConfig.EnableCsvImports)]),
UseDarkMode = bool.Parse(_config[nameof(UserConfig.UseDarkMode)]),
UseMPG = bool.Parse(_config[nameof(UserConfig.UseMPG)]),
UseDescending = bool.Parse(_config[nameof(UserConfig.UseDescending)]),
EnableAuth = bool.Parse(_config[nameof(UserConfig.EnableAuth)]),
HideZero = bool.Parse(_config[nameof(UserConfig.HideZero)]),
UseUKMPG = bool.Parse(_config[nameof(UserConfig.UseUKMPG)])
};
var userConfig = _config.GetUserConfig(User);
return PartialView("_Settings", userConfig);
}
[HttpPost]
public IActionResult WriteToSettings(UserConfig userConfig)
{
try
{
if (!System.IO.File.Exists(StaticHelper.UserConfigPath))
{
//if file doesn't exist it might be because it's running on a mounted volume in docker.
System.IO.File.WriteAllText(StaticHelper.UserConfigPath, System.Text.Json.JsonSerializer.Serialize(new UserConfig()));
}
var configFileContents = System.IO.File.ReadAllText(StaticHelper.UserConfigPath);
var existingUserConfig = System.Text.Json.JsonSerializer.Deserialize<UserConfig>(configFileContents);
if (existingUserConfig is not null)
{
//copy over settings that are off limits on the settings page.
userConfig.EnableAuth = existingUserConfig.EnableAuth;
userConfig.UserNameHash = existingUserConfig.UserNameHash;
userConfig.UserPasswordHash = existingUserConfig.UserPasswordHash;
} else
{
userConfig.EnableAuth = false;
userConfig.UserNameHash = string.Empty;
userConfig.UserPasswordHash = string.Empty;
}
System.IO.File.WriteAllText(StaticHelper.UserConfigPath, System.Text.Json.JsonSerializer.Serialize(userConfig));
return Json(true);
} catch (Exception ex)
{
_logger.LogError(ex, "Error on saving config file.");
}
return Json(false);
var result = _config.SaveUserConfig(User, userConfig);
return Json(result);
}
public IActionResult Privacy()
{

View File

@@ -27,7 +27,7 @@ namespace CarCareTracker.Controllers
private readonly IUpgradeRecordDataAccess _upgradeRecordDataAccess;
private readonly IWebHostEnvironment _webEnv;
private readonly bool _useDescending;
private readonly IConfiguration _config;
private readonly IConfigHelper _config;
private readonly IFileHelper _fileHelper;
private readonly IGasHelper _gasHelper;
private readonly IReminderHelper _reminderHelper;
@@ -49,7 +49,7 @@ namespace CarCareTracker.Controllers
IUpgradeRecordDataAccess upgradeRecordDataAccess,
IUserLogic userLogic,
IWebHostEnvironment webEnv,
IConfiguration config)
IConfigHelper config)
{
_logger = logger;
_dataAccess = dataAccess;
@@ -67,7 +67,7 @@ namespace CarCareTracker.Controllers
_userLogic = userLogic;
_webEnv = webEnv;
_config = config;
_useDescending = bool.Parse(config[nameof(UserConfig.UseDescending)]);
_useDescending = config.GetUserConfig(User).UseDescending;
}
private int GetUserID()
{
@@ -231,8 +231,8 @@ namespace CarCareTracker.Controllers
var fileNameToExport = $"temp/{Guid.NewGuid()}.csv";
var fullExportFilePath = _fileHelper.GetFullFilePath(fileNameToExport, false);
var vehicleRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
bool useMPG = bool.Parse(_config[nameof(UserConfig.UseMPG)]);
bool useUKMPG = bool.Parse(_config[nameof(UserConfig.UseUKMPG)]);
bool useMPG = _config.GetUserConfig(User).UseMPG;
bool useUKMPG = _config.GetUserConfig(User).UseUKMPG;
vehicleRecords = vehicleRecords.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList();
var convertedRecords = _gasHelper.GetGasRecordViewModels(vehicleRecords, useMPG, useUKMPG);
var exportData = convertedRecords.Select(x => new GasRecordExportModel { Date = x.Date.ToString(), Cost = x.Cost.ToString(), FuelConsumed = x.Gallons.ToString(), FuelEconomy = x.MilesPerGallon.ToString(), Odometer = x.Mileage.ToString() });
@@ -389,8 +389,8 @@ namespace CarCareTracker.Controllers
//need it in ascending order to perform computation.
result = result.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList();
//check if the user uses MPG or Liters per 100km.
bool useMPG = bool.Parse(_config[nameof(UserConfig.UseMPG)]);
bool useUKMPG = bool.Parse(_config[nameof(UserConfig.UseUKMPG)]);
bool useMPG = _config.GetUserConfig(User).UseMPG;
bool useUKMPG = _config.GetUserConfig(User).UseUKMPG;
var computedResults = _gasHelper.GetGasRecordViewModels(result, useMPG, useUKMPG);
if (_useDescending)
{
@@ -753,8 +753,8 @@ namespace CarCareTracker.Controllers
var upgradeRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
var taxRecords = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId);
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
bool useMPG = bool.Parse(_config[nameof(UserConfig.UseMPG)]);
bool useUKMPG = bool.Parse(_config[nameof(UserConfig.UseUKMPG)]);
bool useMPG = _config.GetUserConfig(User).UseMPG;
bool useUKMPG = _config.GetUserConfig(User).UseUKMPG;
vehicleHistory.TotalGasCost = gasRecords.Sum(x => x.Cost);
vehicleHistory.TotalCost = serviceRecords.Sum(x => x.Cost) + repairRecords.Sum(x => x.Cost) + upgradeRecords.Sum(x => x.Cost) + taxRecords.Sum(x => x.Cost);
var averageMPG = 0.00M;

View File

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

View File

@@ -0,0 +1,11 @@
using CarCareTracker.Models;
namespace CarCareTracker.External.Interfaces
{
public interface IUserConfigDataAccess
{
public UserConfigData GetUserConfig(int userId);
public bool SaveUserConfig(UserConfigData userConfigData);
public bool DeleteUserConfig(int userId);
}
}

137
Helper/ConfigHelper.cs Normal file
View File

@@ -0,0 +1,137 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Microsoft.Extensions.Caching.Memory;
using System.Security.Claims;
namespace CarCareTracker.Helper
{
public interface IConfigHelper
{
UserConfig GetUserConfig(ClaimsPrincipal user);
bool SaveUserConfig(ClaimsPrincipal user, UserConfig configData);
public bool DeleteUserConfig(int userId);
}
public class ConfigHelper : IConfigHelper
{
private readonly IConfiguration _config;
private readonly IUserConfigDataAccess _userConfig;
private IMemoryCache _cache;
public ConfigHelper(IConfiguration serverConfig,
IUserConfigDataAccess userConfig,
IMemoryCache memoryCache)
{
_config = serverConfig;
_userConfig = userConfig;
_cache = memoryCache;
}
public bool SaveUserConfig(ClaimsPrincipal user, UserConfig configData)
{
var storedUserId = user.FindFirstValue(ClaimTypes.NameIdentifier);
int userId = 0;
if (storedUserId != null)
{
userId = int.Parse(storedUserId);
}
bool isRootUser = user.IsInRole(nameof(UserData.IsRootUser)) || userId == -1;
if (isRootUser)
{
try
{
if (!File.Exists(StaticHelper.UserConfigPath))
{
//if file doesn't exist it might be because it's running on a mounted volume in docker.
File.WriteAllText(StaticHelper.UserConfigPath, System.Text.Json.JsonSerializer.Serialize(new UserConfig()));
}
var configFileContents = File.ReadAllText(StaticHelper.UserConfigPath);
var existingUserConfig = System.Text.Json.JsonSerializer.Deserialize<UserConfig>(configFileContents);
if (existingUserConfig is not null)
{
//copy over settings that are off limits on the settings page.
configData.EnableAuth = existingUserConfig.EnableAuth;
configData.UserNameHash = existingUserConfig.UserNameHash;
configData.UserPasswordHash = existingUserConfig.UserPasswordHash;
}
else
{
configData.EnableAuth = false;
configData.UserNameHash = string.Empty;
configData.UserPasswordHash = string.Empty;
}
File.WriteAllText(StaticHelper.UserConfigPath, System.Text.Json.JsonSerializer.Serialize(configData));
_cache.Set<UserConfig>($"userConfig_{userId}", configData);
return true;
}
catch (Exception ex)
{
return false;
}
} else
{
var userConfig = new UserConfigData()
{
Id = userId,
UserConfig = configData
};
var result = _userConfig.SaveUserConfig(userConfig);
_cache.Set<UserConfig>($"userConfig_{userId}", configData);
return result;
}
}
public bool DeleteUserConfig(int userId)
{
_cache.Remove($"userConfig_{userId}");
var result = _userConfig.DeleteUserConfig(userId);
return result;
}
public UserConfig GetUserConfig(ClaimsPrincipal user)
{
var serverConfig = new UserConfig
{
EnableCsvImports = bool.Parse(_config[nameof(UserConfig.EnableCsvImports)]),
UseDarkMode = bool.Parse(_config[nameof(UserConfig.UseDarkMode)]),
UseMPG = bool.Parse(_config[nameof(UserConfig.UseMPG)]),
UseDescending = bool.Parse(_config[nameof(UserConfig.UseDescending)]),
EnableAuth = bool.Parse(_config[nameof(UserConfig.EnableAuth)]),
HideZero = bool.Parse(_config[nameof(UserConfig.HideZero)]),
UseUKMPG = bool.Parse(_config[nameof(UserConfig.UseUKMPG)])
};
int userId = 0;
if (user != null)
{
var storedUserId = user.FindFirstValue(ClaimTypes.NameIdentifier);
if (storedUserId != null)
{
userId = int.Parse(storedUserId);
}
} else
{
return serverConfig;
}
return _cache.GetOrCreate<UserConfig>($"userConfig_{userId}", entry =>
{
entry.SlidingExpiration = TimeSpan.FromHours(1);
if (!user.Identity.IsAuthenticated)
{
return serverConfig;
}
bool isRootUser = user.IsInRole(nameof(UserData.IsRootUser)) || userId == -1;
if (isRootUser)
{
return serverConfig;
}
else
{
var result = _userConfig.GetUserConfig(userId);
if (result == null)
{
return serverConfig;
}
else
{
return result.UserConfig;
}
}
});
}
}
}

View File

@@ -1,6 +1,7 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
using Microsoft.Extensions.Caching.Memory;
using System.Net;
using System.Net.Mail;
using System.Security.Cryptography;
@@ -19,6 +20,7 @@ namespace CarCareTracker.Logic
OperationResponse ResetPasswordByUser(LoginModel credentials);
OperationResponse ResetUserPassword(LoginModel credentials);
UserData ValidateUserCredentials(LoginModel credentials);
bool CheckIfUserIsValid(int userId);
bool CreateRootUserCredentials(LoginModel credentials);
bool DeleteRootUserCredentials();
List<UserData> GetAllUsers();
@@ -30,11 +32,31 @@ namespace CarCareTracker.Logic
private readonly IUserRecordDataAccess _userData;
private readonly ITokenRecordDataAccess _tokenData;
private readonly IMailHelper _mailHelper;
public LoginLogic(IUserRecordDataAccess userData, ITokenRecordDataAccess tokenData, IMailHelper mailHelper)
private IMemoryCache _cache;
public LoginLogic(IUserRecordDataAccess userData,
ITokenRecordDataAccess tokenData,
IMailHelper mailHelper,
IMemoryCache memoryCache)
{
_userData = userData;
_tokenData = tokenData;
_mailHelper = mailHelper;
_cache = memoryCache;
}
public bool CheckIfUserIsValid(int userId)
{
if (userId == -1)
{
return true;
}
var result = _userData.GetUserRecordById(userId);
if (result == null)
{
return false;
} else
{
return result.Id != 0;
}
}
//handles user registration
public OperationResponse RegisterNewUser(LoginModel credentials)
@@ -259,6 +281,7 @@ namespace CarCareTracker.Logic
existingUserConfig.UserPasswordHash = hashedPassword;
}
File.WriteAllText(StaticHelper.UserConfigPath, JsonSerializer.Serialize(existingUserConfig));
_cache.Remove("userConfig_-1");
return true;
}
public bool DeleteRootUserCredentials()
@@ -272,6 +295,8 @@ namespace CarCareTracker.Logic
existingUserConfig.UserNameHash = string.Empty;
existingUserConfig.UserPasswordHash = string.Empty;
}
//clear out the cached config for the root user.
_cache.Remove("userConfig_-1");
File.WriteAllText(StaticHelper.UserConfigPath, JsonSerializer.Serialize(existingUserConfig));
return true;
}

View File

@@ -113,11 +113,17 @@ namespace CarCareTracker.Middleware
}
else
{
if (!_loginLogic.CheckIfUserIsValid(authCookie.UserData.Id))
{
return AuthenticateResult.Fail("Cookie points to non-existant user.");
}
//validate if user is still valid
var appIdentity = new ClaimsIdentity("Custom");
var userIdentity = new List<Claim>
{
new(ClaimTypes.Name, authCookie.UserData.UserName),
new(ClaimTypes.NameIdentifier, authCookie.UserData.Id.ToString())
new(ClaimTypes.NameIdentifier, authCookie.UserData.Id.ToString()),
new(ClaimTypes.Role, "CookieAuth")
};
if (authCookie.UserData.IsAdmin)
{

View File

@@ -0,0 +1,11 @@
namespace CarCareTracker.Models
{
public class UserConfigData
{
/// <summary>
/// User ID
/// </summary>
public int Id { get; set; }
public UserConfig UserConfig { get; set; }
}
}

View File

@@ -21,6 +21,7 @@ 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>();
//configure helpers
builder.Services.AddSingleton<IFileHelper, FileHelper>();
@@ -28,6 +29,7 @@ builder.Services.AddSingleton<IGasHelper, GasHelper>();
builder.Services.AddSingleton<IReminderHelper, ReminderHelper>();
builder.Services.AddSingleton<IReportHelper, ReportHelper>();
builder.Services.AddSingleton<IMailHelper, MailHelper>();
builder.Services.AddSingleton<IConfigHelper, ConfigHelper>();
//configure logic
builder.Services.AddSingleton<ILoginLogic, LoginLogic>();

View File

@@ -4,13 +4,28 @@
@model AdminViewModel
<div class="container">
<div class="row">
<div class="col-5">
<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">Admin Panel</span>
</div>
</div>
<hr />
<div class="row">
<div class="col-md-5 col-12">
<span class="lead">Tokens</span>
<hr />
<div class="row">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="enableAutoNotify" checked>
<label class="form-check-label" for="enableAutoNotify">Auto Notify(via Email)</label>
<div class="col-6">
<button onclick="generateNewToken()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Generate User Token</button>
</div>
<div class="col-6 d-flex align-items-center">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="enableAutoNotify" checked>
<label class="form-check-label" for="enableAutoNotify">Auto Notify(via Email)</label>
</div>
</div>
<button onclick="generateNewToken()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Generate User Token</button>
</div>
<table class="table table-hover">
<thead>
@@ -34,11 +49,13 @@
</tbody>
</table>
</div>
<div class="col-7">
<div class="col-12 col-md-7">
<span class="lead">Users</span>
<hr />
<table class="table table-hover">
<thead>
<tr class="d-flex">
<th scope="col" class="col-4">UserName</th>
<th scope="col" class="col-4">Username</th>
<th scope="col" class="col-2">Is Admin</th>
<th scope="col" class="col-4">Reset Password</th>
<th scope="col" class="col-2">Delete</th>
@@ -70,9 +87,9 @@
}
});
}
function deleteUser(userId){
$.post(`/Admin/DeleteUser?userId=${userId}`, function(data){
if (data){
function deleteUser(userId) {
$.post(`/Admin/DeleteUser?userId=${userId}`, function (data) {
if (data) {
reloadPage();
}
})
@@ -82,12 +99,12 @@
navigator.clipboard.writeText(textToCopy);
successToast("Copied to Clipboard");
}
function generateNewToken(){
function generateNewToken() {
Swal.fire({
title: 'Generate Token',
html: `
<input type="text" id="inputEmail" class="swal2-input" placeholder="Email Address">
`,
<input type="text" id="inputEmail" class="swal2-input" placeholder="Email Address">
`,
confirmButtonText: 'Generate',
focusConfirm: false,
preConfirm: () => {
@@ -100,7 +117,7 @@
}).then(function (result) {
if (result.isConfirmed) {
var autoNotify = $("#enableAutoNotify").is(":checked");
$.get('/Admin/GenerateNewToken', {emailAddress: result.value.emailAddress, autoNotify: autoNotify}, function (data) {
$.get('/Admin/GenerateNewToken', { emailAddress: result.value.emailAddress, autoNotify: autoNotify }, function (data) {
if (data.success) {
reloadPage();
} else {

View File

@@ -1,6 +1,7 @@
@inject IConfiguration Configuration
@using CarCareTracker.Helper
@inject IConfigHelper config
@{
var enableAuth = bool.Parse(Configuration[nameof(UserConfig.EnableAuth)]);
var enableAuth = config.GetUserConfig(User).EnableAuth;
}
@model string
@{
@@ -14,13 +15,10 @@
<li class="nav-item" role="presentation">
<button class="nav-link active" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-car-front me-2"></i>Garage</span></button>
</li>
@if (User.IsInRole(nameof(UserData.IsRootUser)))
{
<li class="nav-item" role="presentation">
<button class="nav-link" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-gear me-2"></i>Settings</span></button>
</li>
}
@if (enableAuth)
<li class="nav-item" role="presentation">
<button class="nav-link" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings-tab-pane" type="button" role="tab"><span class="ms-2 display-3"><i class="bi bi-gear me-2"></i>Settings</span></button>
</li>
@if (User.IsInRole("CookieAuth"))
{
<li class="nav-item" role="presentation">
<button class="nav-link" onclick="performLogOut()"><span class="display-3 ms-2"><i class="bi bi-box-arrow-right me-2"></i>Logout</span></button>
@@ -42,16 +40,24 @@
<li class="nav-item" role="presentation">
<button class="nav-link @(Model == "garage" ? "active" : "")" id="garage-tab" data-bs-toggle="tab" data-bs-target="#garage-tab-pane" type="button" role="tab"><i class="bi bi-car-front me-2"></i>Garage</button>
</li>
@if (User.IsInRole(nameof(UserData.IsRootUser)))
<li class="nav-item ms-auto" role="presentation">
<button class="nav-link @(Model == "settings" ? "active" : "")" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings-tab-pane" type="button" role="tab"><i class="bi bi-gear me-2"></i>Settings</button>
</li>
@if (User.IsInRole("CookieAuth"))
{
<li class="nav-item ms-auto" role="presentation">
<button class="nav-link @(Model == "settings" ? "active" : "")" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings-tab-pane" type="button" role="tab"><i class="bi bi-gear me-2"></i>Settings</button>
</li>
}
@if (enableAuth)
{
<li class="nav-item @(!User.IsInRole(nameof(UserData.IsRootUser)) ? "ms-auto" : "")">
<button class="nav-link" onclick="performLogOut()"><i class="bi bi-box-arrow-right me-2"></i>Logout</button>
<li class="nav-item dropdown" role="presentation">
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false"><i class="bi bi-person me-2"></i>@User.Identity.Name</a>
<ul class="dropdown-menu">
@if (User.IsInRole(nameof(UserData.IsRootUser)))
{
<li>
<a class="dropdown-item" href="/Admin"><i class="bi bi-people me-2"></i>Admin Panel</a>
</li>
}
<li>
<button class="dropdown-item" onclick="performLogOut()"><i class="bi bi-box-arrow-right me-2"></i>Logout</button>
</li>
</ul>
</li>
}
</ul>
@@ -75,6 +81,5 @@
</div>
<script>
loadGarage();
loadSettings();
bindWindowResize();
</script>

View File

@@ -32,10 +32,13 @@
<input class="form-check-input" onChange="updateSettings()" type="checkbox" role="switch" id="hideZero" checked="@Model.HideZero">
<label class="form-check-label" for="hideZero">Replace @(0.ToString("C")) Costs with ---</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" onChange="enableAuthCheckChanged()" type="checkbox" role="switch" id="enableAuth" checked="@Model.EnableAuth">
<label class="form-check-label" for="enableAuth">Enable Authentication</label>
</div>
@if (User.IsInRole(nameof(UserData.IsRootUser)))
{
<div class="form-check form-switch">
<input class="form-check-input" onChange="enableAuthCheckChanged()" type="checkbox" role="switch" id="enableAuth" checked="@Model.EnableAuth">
<label class="form-check-label" for="enableAuth">Enable Authentication</label>
</div>
}
</div>
</div>
<div class="row">
@@ -120,7 +123,7 @@
if (result.isConfirmed) {
$.post('/Login/CreateLoginCreds', { userName: result.value.username, password: result.value.password }, function (data) {
if (data) {
window.location.href = '/Login';
setTimeout(function () { window.location.href = '/Login' }, 500);
} else {
errorToast("An error occurred, please try again later.");
}

View File

@@ -1,8 +1,10 @@
<!DOCTYPE html>
@inject IConfiguration Configuration
@using CarCareTracker.Helper
<!DOCTYPE html>
@inject IConfigHelper config
@{
var useDarkMode = bool.Parse(Configuration["UseDarkMode"]);
var enableCsvImports = bool.Parse(Configuration["EnableCsvImports"]);
var userConfig = config.GetUserConfig(User);
var useDarkMode = userConfig.UseDarkMode;
var enableCsvImports = userConfig.EnableCsvImports;
var shortDatePattern = System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern;
shortDatePattern = shortDatePattern.ToLower();
if (!shortDatePattern.Contains("dd"))

View File

@@ -42,7 +42,7 @@
<li class="nav-item" role="presentation">
<button class="nav-link" id="report-tab" data-bs-toggle="tab" data-bs-target="#report-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-file-bar-graph me-2"></i>Reports</span></button>
</li>
<li class="nav-item dropdown" role="presentation">
<li class="nav-item" role="presentation">
<button onclick="deleteVehicle(@Model.Id)" class="dropdown-item"><span class="display-3 ms-2"><i class="bi bi-trash me-2"></i>Delete Vehicle</span></button>
</li>
</ul>

View File

@@ -1,7 +1,8 @@
@inject IConfiguration Configuration
@using CarCareTracker.Helper
@inject IConfigHelper config
@{
var enableCsvImports = bool.Parse(Configuration[nameof(UserConfig.EnableCsvImports)]);
var hideZero = bool.Parse(Configuration[nameof(UserConfig.HideZero)]);
var enableCsvImports = config.GetUserConfig(User).EnableCsvImports;
var hideZero = config.GetUserConfig(User).HideZero;
}
@model List<CollisionRecord>
<div class="row">

View File

@@ -1,10 +1,11 @@
@inject IConfiguration Configuration
@using CarCareTracker.Helper
@inject IConfigHelper config
@model GasRecordViewModelContainer
@{
var enableCsvImports = bool.Parse(Configuration[nameof(UserConfig.EnableCsvImports)]);
var useMPG = bool.Parse(Configuration[nameof(UserConfig.UseMPG)]);
var useUKMPG = bool.Parse(Configuration[nameof(UserConfig.UseUKMPG)]);
var hideZero = bool.Parse(Configuration[nameof(UserConfig.HideZero)]);
var enableCsvImports = config.GetUserConfig(User).EnableCsvImports;
var useMPG = config.GetUserConfig(User).UseMPG;
var useUKMPG = config.GetUserConfig(User).UseUKMPG;
var hideZero = config.GetUserConfig(User).HideZero;
var useKwh = Model.UseKwh;
string consumptionUnit;
string fuelEconomyUnit;

View File

@@ -1,8 +1,9 @@
@inject IConfiguration Configuration
@using CarCareTracker.Helper
@inject IConfigHelper config
@model GasRecordInputContainer
@{
var useMPG = bool.Parse(Configuration[nameof(UserConfig.UseMPG)]);
var useUKMPG = bool.Parse(Configuration[nameof(UserConfig.UseUKMPG)]);
var useMPG = config.GetUserConfig(User).UseMPG;
var useUKMPG = config.GetUserConfig(User).UseUKMPG;
var useKwh = Model.UseKwh;
var isNew = Model.GasRecord.Id == 0;
string consumptionUnit;

View File

@@ -1,7 +1,8 @@
@inject IConfiguration Configuration
@using CarCareTracker.Helper
@inject IConfigHelper config
@{
var enableCsvImports = bool.Parse(Configuration[nameof(UserConfig.EnableCsvImports)]);
var hideZero = bool.Parse(Configuration[nameof(UserConfig.HideZero)]);
var enableCsvImports = config.GetUserConfig(User).EnableCsvImports;
var hideZero = config.GetUserConfig(User).HideZero;
}
@model List<ServiceRecord>
<div class="row">

View File

@@ -1,7 +1,8 @@
@inject IConfiguration Configuration
@using CarCareTracker.Helper
@inject IConfigHelper config
@{
var enableCsvImports = bool.Parse(Configuration[nameof(UserConfig.EnableCsvImports)]);
var hideZero = bool.Parse(Configuration[nameof(UserConfig.HideZero)]);
var enableCsvImports = config.GetUserConfig(User).EnableCsvImports;
var hideZero = config.GetUserConfig(User).HideZero;
}
@model List<TaxRecord>
<div class="row">

View File

@@ -1,7 +1,8 @@
@inject IConfiguration Configuration
@using CarCareTracker.Helper
@inject IConfigHelper config
@{
var enableCsvImports = bool.Parse(Configuration[nameof(UserConfig.EnableCsvImports)]);
var hideZero = bool.Parse(Configuration[nameof(UserConfig.HideZero)]);
var enableCsvImports = config.GetUserConfig(User).EnableCsvImports;
var hideZero = config.GetUserConfig(User).HideZero;
}
@model List<UpgradeRecord>
<div class="row">

View File

@@ -1,8 +1,9 @@
@inject IConfiguration Configuration
@using CarCareTracker.Helper
@inject IConfigHelper config
@{
var hideZero = bool.Parse(Configuration[nameof(UserConfig.HideZero)]);
var useMPG = bool.Parse(Configuration[nameof(UserConfig.UseMPG)]);
var useUKMPG = bool.Parse(Configuration[nameof(UserConfig.UseUKMPG)]);
var hideZero = config.GetUserConfig(User).HideZero;
var useMPG = config.GetUserConfig(User).UseMPG;
var useUKMPG = config.GetUserConfig(User).UseUKMPG;
var useKwh = Model.VehicleData.IsElectric;
string fuelEconomyUnit;
if (useKwh)

View File

@@ -14,6 +14,7 @@ function hideAddVehicleModal() {
function loadGarage() {
$.get('/Home/Garage', function (data) {
$("#garageContainer").html(data);
loadSettings();
});
}
function loadSettings() {