User Households

This commit is contained in:
DESKTOP-T0O5CDB\DESK-555BD 2025-11-11 14:45:48 -07:00
parent 4d9c5c7237
commit b98585006b
9 changed files with 450 additions and 11 deletions

View File

@ -72,7 +72,11 @@ namespace CarCareTracker.Controllers
[HttpPost]
public IActionResult DeleteUser(int userId)
{
var result =_userLogic.DeleteAllAccessToUser(userId) && _configHelper.DeleteUserConfig(userId) && _loginLogic.DeleteUser(userId);
var result =_userLogic.DeleteAllAccessToUser(userId)
&& _configHelper.DeleteUserConfig(userId)
&& _loginLogic.DeleteUser(userId)
&& _userLogic.DeleteAllHouseholdByChildUserId(userId)
&& _userLogic.DeleteAllHouseholdByParentUserId(userId);
return Json(result);
}
[HttpPost]

View File

@ -54,7 +54,8 @@ namespace CarCareTracker.Controllers
"CREATE TABLE IF NOT EXISTS app.useraccessrecords (userId INT, vehicleId INT, PRIMARY KEY(userId, vehicleId))",
"CREATE TABLE IF NOT EXISTS app.extrafields (id INT primary key, data jsonb not null)",
"CREATE TABLE IF NOT EXISTS app.inspectionrecords (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
"CREATE TABLE IF NOT EXISTS app.inspectionrecordtemplates (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)"
"CREATE TABLE IF NOT EXISTS app.inspectionrecordtemplates (id INT GENERATED BY DEFAULT AS IDENTITY primary key, vehicleId INT not null, data jsonb not null)",
"CREATE TABLE IF NOT EXISTS app.userhouseholdrecords (parentUserId INT, childUserId INT, PRIMARY KEY(parentUserId, childUserId))"
};
foreach(string cmd in cmds)
{
@ -103,6 +104,7 @@ namespace CarCareTracker.Controllers
var extrafields = new List<RecordExtraField>();
var inspectionrecords = new List<InspectionRecord>();
var inspectionrecordtemplates = new List<InspectionRecordInput>();
var userhouseholdrecords = new List<UserHousehold>();
#region "Part1"
string cmd = $"SELECT data FROM app.vehicles";
using (var ctext = pgDataSource.CreateCommand(cmd))
@ -455,6 +457,32 @@ namespace CarCareTracker.Controllers
table.Upsert(record);
};
}
cmd = $"SELECT parentUserId, childUserId FROM app.userhouseholdrecords";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
UserHousehold result = new UserHousehold()
{
Id = new HouseholdAccess
{
ParentUserId = int.Parse(reader["parentUserId"].ToString()),
ChildUserId = int.Parse(reader["childUserId"].ToString())
}
};
userhouseholdrecords.Add(result);
}
}
foreach (var record in userhouseholdrecords)
{
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<UserHousehold>("userhouseholdrecords");
table.Upsert(record);
}
;
}
#endregion
var destFilePath = $"{fullFolderPath}.zip";
ZipFile.CreateFromDirectory(fullFolderPath, destFilePath);
@ -505,6 +533,7 @@ namespace CarCareTracker.Controllers
var extrafields = new List<RecordExtraField>();
var inspectionrecords = new List<InspectionRecord>();
var inspectionrecordtemplates = new List<InspectionRecordInput>();
var userhouseholdrecords = new List<UserHousehold>();
#region "Part1"
using (var db = new LiteDatabase(fullFileName))
{
@ -816,6 +845,22 @@ namespace CarCareTracker.Controllers
ctext.ExecuteNonQuery();
}
}
using (var db = new LiteDatabase(fullFileName))
{
var table = db.GetCollection<UserHousehold>("userhouseholdrecords");
userhouseholdrecords = table.FindAll().ToList();
}
;
foreach (var record in userhouseholdrecords)
{
string cmd = $"INSERT INTO app.userhouseholdrecords (parentUserId, childUserId) VALUES(@parentUserId, @childUserId)";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("parentUserId", record.Id.ParentUserId);
ctext.Parameters.AddWithValue("childUserId", record.Id.ChildUserId);
ctext.ExecuteNonQuery();
}
}
#endregion
return Json(OperationResponse.Succeed("Data Imported Successfully"));
}

View File

@ -65,7 +65,7 @@ namespace CarCareTracker.External.Implementations
return true;
}
/// <summary>
/// Delee all access records when a user is deleted.
/// Delete all access records when a user is deleted.
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>

View File

@ -0,0 +1,76 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
namespace CarCareTracker.External.Implementations
{
public class UserHouseholdDataAccess : IUserHouseholdDataAccess
{
private ILiteDBHelper _liteDB { get; set; }
private static string tableName = "userhouseholdrecords";
public UserHouseholdDataAccess(ILiteDBHelper liteDB)
{
_liteDB = liteDB;
}
public List<UserHousehold> GetUserHouseholdByParentUserId(int parentUserId)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<UserHousehold>(tableName);
return table.Find(x => x.Id.ParentUserId == parentUserId).ToList();
}
public List<UserHousehold> GetUserHouseholdByChildUserId(int childUserId)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<UserHousehold>(tableName);
return table.Find(x => x.Id.ChildUserId == childUserId).ToList();
}
public UserHousehold GetUserHouseholdByParentAndChildUserId(int parentUserId, int childUserId)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<UserHousehold>(tableName);
return table.Find(x => x.Id.ParentUserId == parentUserId && x.Id.ChildUserId == childUserId).FirstOrDefault();
}
public bool SaveUserHousehold(UserHousehold userHousehold)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<UserHousehold>(tableName);
table.Upsert(userHousehold);
db.Checkpoint();
return true;
}
public bool DeleteUserHousehold(int parentUserId, int childUserId)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<UserHousehold>(tableName);
table.DeleteMany(x => x.Id.ParentUserId == parentUserId && x.Id.ChildUserId == childUserId);
db.Checkpoint();
return true;
}
/// <summary>
/// Delete all household records when a parent user is deleted.
/// </summary>
/// <param name="parentUserId"></param>
/// <returns></returns>
public bool DeleteAllHouseholdRecordsByParentUserId(int parentUserId)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<UserHousehold>(tableName);
table.DeleteMany(x => x.Id.ParentUserId == parentUserId);
db.Checkpoint();
return true;
}
/// <summary>
/// Delete all household records when a child user is deleted.
/// </summary>
/// <param name="childUserId"></param>
/// <returns></returns>
public bool DeleteAllHouseholdRecordsByChildUserId(int childUserId)
{
var db = _liteDB.GetLiteDB();
var table = db.GetCollection<UserHousehold>(tableName);
table.DeleteMany(x => x.Id.ChildUserId == childUserId);
db.Checkpoint();
return true;
}
}
}

View File

@ -0,0 +1,207 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Models;
using Npgsql;
namespace CarCareTracker.External.Implementations
{
public class PGUserHouseholdDataAccess : IUserHouseholdDataAccess
{
private NpgsqlDataSource pgDataSource;
private readonly ILogger<PGUserHouseholdDataAccess> _logger;
private static string tableName = "userhouseholdrecords";
public PGUserHouseholdDataAccess(IConfiguration config, ILogger<PGUserHouseholdDataAccess> logger)
{
pgDataSource = NpgsqlDataSource.Create(config["POSTGRES_CONNECTION"]);
_logger = logger;
try
{
//create table if not exist.
string initCMD = $"CREATE SCHEMA IF NOT EXISTS app; CREATE TABLE IF NOT EXISTS app.{tableName} (parentUserId INT, childUserId INT, PRIMARY KEY(parentUserId, childUserId))";
using (var ctext = pgDataSource.CreateCommand(initCMD))
{
ctext.ExecuteNonQuery();
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
}
public List<UserHousehold> GetUserHouseholdByParentUserId(int parentUserId)
{
try
{
string cmd = $"SELECT parentUserId, childUserId FROM app.{tableName} WHERE parentUserId = @parentUserId";
var results = new List<UserHousehold>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("parentUserId", parentUserId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
UserHousehold result = new UserHousehold()
{
Id = new HouseholdAccess
{
ParentUserId = int.Parse(reader["parentUserId"].ToString()),
ChildUserId = int.Parse(reader["childUserId"].ToString())
}
};
results.Add(result);
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<UserHousehold>();
}
}
public List<UserHousehold> GetUserHouseholdByChildUserId(int childUserId)
{
try
{
string cmd = $"SELECT parentUserId, childUserId FROM app.{tableName} WHERE childUserId = @childUserId";
var results = new List<UserHousehold>();
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("childUserId", childUserId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
UserHousehold result = new UserHousehold()
{
Id = new HouseholdAccess
{
ParentUserId = int.Parse(reader["parentUserId"].ToString()),
ChildUserId = int.Parse(reader["childUserId"].ToString())
}
};
results.Add(result);
}
}
return results;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new List<UserHousehold>();
}
}
public UserHousehold GetUserHouseholdByParentAndChildUserId(int parentUserId, int childUserId)
{
try
{
string cmd = $"SELECT parentUserId, childUserId FROM app.{tableName} WHERE parentUserId = @parentUserId AND childUserId = @childUserId";
UserHousehold result = null;
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("parentUserId", parentUserId);
ctext.Parameters.AddWithValue("childUserId", childUserId);
using (NpgsqlDataReader reader = ctext.ExecuteReader())
while (reader.Read())
{
result = new UserHousehold()
{
Id = new HouseholdAccess
{
ParentUserId = int.Parse(reader["parentUserId"].ToString()),
ChildUserId = int.Parse(reader["childUserId"].ToString())
}
};
return result;
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new UserHousehold();
}
}
public bool SaveUserHousehold(UserHousehold userHousehold)
{
try
{
string cmd = $"INSERT INTO app.{tableName} (parentUserId, childUserId) VALUES(@parentUserId, @childUserId)";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("parentUserId", userHousehold.Id.ParentUserId);
ctext.Parameters.AddWithValue("childUserId", userHousehold.Id.ChildUserId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
public bool DeleteUserHousehold(int parentUserId, int childUserId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE parentUserId = @parentUserId AND childUserId = @childUserId";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("parentUserId", parentUserId);
ctext.Parameters.AddWithValue("childUserId", childUserId);
return ctext.ExecuteNonQuery() > 0;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
/// <summary>
/// Delete all household records when a parent user is deleted.
/// </summary>
/// <param name="parentUserId"></param>
/// <returns></returns>
public bool DeleteAllHouseholdRecordsByParentUserId(int parentUserId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE parentUserId = @parentUserId";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("parentUserId", parentUserId);
ctext.ExecuteNonQuery();
return true;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
/// <summary>
/// Delete all household records when a child user is deleted.
/// </summary>
/// <param name="childUserId"></param>
/// <returns></returns>
public bool DeleteAllHouseholdRecordsByChildUserId(int childUserId)
{
try
{
string cmd = $"DELETE FROM app.{tableName} WHERE childUserId = @childUserId";
using (var ctext = pgDataSource.CreateCommand(cmd))
{
ctext.Parameters.AddWithValue("childUserId", childUserId);
ctext.ExecuteNonQuery();
return true;
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return false;
}
}
}
}

View File

@ -0,0 +1,15 @@
using CarCareTracker.Models;
namespace CarCareTracker.External.Interfaces
{
public interface IUserHouseholdDataAccess
{
List<UserHousehold> GetUserHouseholdByParentUserId(int parentUserId);
List<UserHousehold> GetUserHouseholdByChildUserId(int childUserId);
UserHousehold GetUserHouseholdByParentAndChildUserId(int parentUserId, int childUserId);
bool SaveUserHousehold(UserHousehold userHousehold);
bool DeleteUserHousehold(int parentUserId, int childUserId);
bool DeleteAllHouseholdRecordsByParentUserId(int parentUserId);
bool DeleteAllHouseholdRecordsByChildUserId(int childUserId);
}
}

View File

@ -1,5 +1,4 @@
using CarCareTracker.External.Interfaces;
using CarCareTracker.Helper;
using CarCareTracker.Models;
namespace CarCareTracker.Logic
@ -15,15 +14,22 @@ namespace CarCareTracker.Logic
bool UserCanEditVehicle(int userId, int vehicleId);
bool DeleteAllAccessToVehicle(int vehicleId);
bool DeleteAllAccessToUser(int userId);
OperationResponse AddUserToHousehold(int parentUserId, string childUsername);
bool DeleteUserFromHousehold(int parentUserId, int childUserId);
bool DeleteAllHouseholdByParentUserId(int parentUserId);
bool DeleteAllHouseholdByChildUserId(int childUserId);
}
public class UserLogic: IUserLogic
{
private readonly IUserAccessDataAccess _userAccess;
private readonly IUserRecordDataAccess _userData;
private readonly IUserHouseholdDataAccess _userHouseholdData;
public UserLogic(IUserAccessDataAccess userAccess,
IUserRecordDataAccess userData) {
IUserRecordDataAccess userData,
IUserHouseholdDataAccess userHouseholdData) {
_userAccess = userAccess;
_userData = userData;
_userHouseholdData = userHouseholdData;
}
public List<UserCollaborator> GetCollaboratorsForVehicle(int vehicleId)
{
@ -108,10 +114,24 @@ namespace CarCareTracker.Logic
{
return results;
}
var accessibleVehicles = _userAccess.GetUserAccessByUserId(userId);
List<int> userIds = new List<int> { userId };
List<int> vehicleIds = new List<int>();
var userHouseholds = _userHouseholdData.GetUserHouseholdByChildUserId(userId);
if (userHouseholds.Any())
{
//add parent's user ids
userIds.AddRange(userHouseholds.Select(x => x.Id.ParentUserId));
}
foreach(int userIdToCheck in userIds)
{
var accessibleVehicles = _userAccess.GetUserAccessByUserId(userIdToCheck);
if (accessibleVehicles.Any())
{
var vehicleIds = accessibleVehicles.Select(x => x.Id.VehicleId);
vehicleIds.AddRange(accessibleVehicles.Select(x => x.Id.VehicleId));
}
}
if (vehicleIds.Any())
{
return results.Where(x => vehicleIds.Contains(x.Id)).ToList();
}
else
@ -125,11 +145,21 @@ namespace CarCareTracker.Logic
{
return true;
}
var userAccess = _userAccess.GetUserAccessByVehicleAndUserId(userId, vehicleId);
if (userAccess != null)
List<int> userIds = new List<int> { userId };
var userHouseholds = _userHouseholdData.GetUserHouseholdByChildUserId(userId);
if (userHouseholds.Any())
{
//add parent's user ids
userIds.AddRange(userHouseholds.Select(x => x.Id.ParentUserId));
}
foreach (int userIdToCheck in userIds)
{
var userAccess = _userAccess.GetUserAccessByVehicleAndUserId(userIdToCheck, vehicleId);
if (userAccess != null && userAccess.Id.UserId == userIdToCheck && userAccess.Id.VehicleId == vehicleId)
{
return true;
}
}
return false;
}
public bool DeleteAllAccessToVehicle(int vehicleId)
@ -142,5 +172,53 @@ namespace CarCareTracker.Logic
var result = _userAccess.DeleteAllAccessRecordsByUserId(userId);
return result;
}
public OperationResponse AddUserToHousehold(int parentUserId, string childUsername)
{
//attempting to add to root user
if (parentUserId == -1)
{
return OperationResponse.Failed("Root user household not allwoed");
}
//try to find existing user.
var existingUser = _userData.GetUserRecordByUserName(childUsername);
if (existingUser.Id != default)
{
//user exists.
//check if user already belongs to the household
var householdAccess = _userHouseholdData.GetUserHouseholdByParentAndChildUserId(parentUserId, existingUser.Id);
if (householdAccess != null && householdAccess.Id.ChildUserId == existingUser.Id && householdAccess.Id.ParentUserId == parentUserId)
{
return OperationResponse.Failed("User already belongs to this household");
}
//check if a circular dependency will exist
var circularHouseholdAccess = _userHouseholdData.GetUserHouseholdByParentAndChildUserId(existingUser.Id, parentUserId);
if (circularHouseholdAccess != null && circularHouseholdAccess.Id.ChildUserId == existingUser.Id && circularHouseholdAccess.Id.ParentUserId == parentUserId)
{
return OperationResponse.Failed("Circular dependency is not allowed");
}
var result = _userHouseholdData.SaveUserHousehold(new UserHousehold { Id = new HouseholdAccess { ParentUserId = parentUserId, ChildUserId = existingUser.Id} });
if (result)
{
return OperationResponse.Succeed("User Added to Household");
}
return OperationResponse.Failed();
}
return OperationResponse.Failed($"Unable to find user {childUsername} in the system");
}
public bool DeleteUserFromHousehold(int parentUserId, int childUserId)
{
var result = _userHouseholdData.DeleteUserHousehold(parentUserId, childUserId);
return result;
}
public bool DeleteAllHouseholdByParentUserId(int parentUserId)
{
var result = _userHouseholdData.DeleteAllHouseholdRecordsByParentUserId(parentUserId);
return result;
}
public bool DeleteAllHouseholdByChildUserId(int childUserId)
{
var result = _userHouseholdData.DeleteAllHouseholdRecordsByChildUserId(childUserId);
return result;
}
}
}

View File

@ -0,0 +1,12 @@
namespace CarCareTracker.Models
{
public class HouseholdAccess
{
public int ParentUserId { get; set; }
public int ChildUserId { get; set; }
}
public class UserHousehold
{
public HouseholdAccess Id { get; set; }
}
}

View File

@ -60,6 +60,7 @@ if (!string.IsNullOrWhiteSpace(builder.Configuration["POSTGRES_CONNECTION"])){
builder.Services.AddSingleton<IExtraFieldDataAccess, PGExtraFieldDataAccess>();
builder.Services.AddSingleton<IInspectionRecordDataAccess, PGInspectionRecordDataAccess>();
builder.Services.AddSingleton<IInspectionRecordTemplateDataAccess, PGInspectionRecordTemplateDataAccess>();
builder.Services.AddSingleton<IUserHouseholdDataAccess, PGUserHouseholdDataAccess>();
}
else
{
@ -82,6 +83,7 @@ else
builder.Services.AddSingleton<IExtraFieldDataAccess, ExtraFieldDataAccess>();
builder.Services.AddSingleton<IInspectionRecordDataAccess, InspectionRecordDataAccess>();
builder.Services.AddSingleton<IInspectionRecordTemplateDataAccess, InspectionRecordTemplateDataAccess>();
builder.Services.AddSingleton<IUserHouseholdDataAccess, UserHouseholdDataAccess>();
}
//configure helpers