Merge branch 'Hargata/user.config' into Hargata/users
# Conflicts: # Helper/ConfigHelper.cs # Views/Home/Index.cshtml
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
39
External/Implementations/UserConfigDataAccess.cs
vendored
Normal file
39
External/Implementations/UserConfigDataAccess.cs
vendored
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
11
External/Interfaces/IUserConfigDataAccess.cs
vendored
Normal file
11
External/Interfaces/IUserConfigDataAccess.cs
vendored
Normal 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
137
Helper/ConfigHelper.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
11
Models/User/UserConfigData.cs
Normal file
11
Models/User/UserConfigData.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
@@ -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>();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -14,6 +14,7 @@ function hideAddVehicleModal() {
|
||||
function loadGarage() {
|
||||
$.get('/Home/Garage', function (data) {
|
||||
$("#garageContainer").html(data);
|
||||
loadSettings();
|
||||
});
|
||||
}
|
||||
function loadSettings() {
|
||||
|
||||
Reference in New Issue
Block a user