first commit
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using OpenWarehouse.auth.Common.ApiInterfeiceLib;
|
||||
using OpenWarehouse.auth.lib;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Common.CustimIdentifyManager;
|
||||
|
||||
public class HasPrivilage : Attribute, IAsyncAuthorizationFilter
|
||||
{
|
||||
public ServicePrivilage Privilage;
|
||||
|
||||
public HasPrivilage(ServicePrivilage privilage)
|
||||
{
|
||||
Privilage = privilage;
|
||||
}
|
||||
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
||||
{
|
||||
context.HttpContext.Request.Headers.TryGetValue("Authorization", out var token);
|
||||
|
||||
var sToken = token.ToString();
|
||||
|
||||
if (sToken == "") context.Result = new UnauthorizedResult();
|
||||
|
||||
var config = context.HttpContext.RequestServices.GetRequiredService<IConfiguration>();
|
||||
var handler = new AuthTokenHandler(sToken);
|
||||
var httpClient = new HttpClient(handler);
|
||||
var client = new OpenWarehouseAuthClient(config["Auth:Url"], httpClient);
|
||||
|
||||
var privilage = await client.GetUserPrivilagesAsync();
|
||||
if (privilage is {Count: 0} && !privilage.Any(s => s.Equals(Privilage.GetName())))
|
||||
{
|
||||
context.Result = new ForbidResult();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.CustimIdentifyManager;
|
||||
|
||||
public enum ServicePrivilage
|
||||
{
|
||||
Admin, ServiceAdmin, ManageWarehouse, EditWarehouse, AddWarehouse, DeleteWarehouse, ManageItems, EditItems,
|
||||
AddItems, DeleteItems, ManageInvetory, EditInventory, AddItemToInventory, SeeInventory, ManageServicePrivilage, ServiceUser
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.CustimIdentifyManager;
|
||||
|
||||
public static class ServicePrivilageClass
|
||||
{
|
||||
private static readonly string PrivilagePrefix = "WarehouseApi";
|
||||
private static readonly Dictionary<ServicePrivilage, string> PrivilageNameMap = new()
|
||||
{
|
||||
{ ServicePrivilage.Admin, "Admin" },
|
||||
{ ServicePrivilage.ServiceAdmin, $"{PrivilagePrefix}-Admin" },
|
||||
{ ServicePrivilage.ManageWarehouse, $"{PrivilagePrefix}-Warehouse-Manage" },
|
||||
{ ServicePrivilage.EditWarehouse, $"{PrivilagePrefix}-Warehouse-Edit" },
|
||||
{ ServicePrivilage.AddWarehouse, $"{PrivilagePrefix}-Warehouse-Add" },
|
||||
{ ServicePrivilage.DeleteWarehouse, $"{PrivilagePrefix}-Warehouse-Delete" },
|
||||
{ ServicePrivilage.ManageItems, $"{PrivilagePrefix}-Items-Manage" },
|
||||
{ ServicePrivilage.EditItems, $"{PrivilagePrefix}-Items-Edit" },
|
||||
{ ServicePrivilage.AddItems, $"{PrivilagePrefix}-Items-Add" },
|
||||
{ ServicePrivilage.DeleteItems, $"{PrivilagePrefix}-Items-Delete" },
|
||||
{ ServicePrivilage.ManageInvetory, $"{PrivilagePrefix}-Inventory-mange"},
|
||||
{ ServicePrivilage.EditInventory, $"{PrivilagePrefix}-Inventory-Edit"},
|
||||
{ ServicePrivilage.AddItemToInventory, $"{PrivilagePrefix}-Inventory-Add-Item"},
|
||||
{ ServicePrivilage.SeeInventory, $"{PrivilagePrefix}-Inventory-See"},
|
||||
{ ServicePrivilage.ServiceUser, $"{PrivilagePrefix}-User"}
|
||||
};
|
||||
|
||||
private static readonly Dictionary<ServicePrivilage, List<ServicePrivilage>> PrivilageMap = new()
|
||||
{
|
||||
{ ServicePrivilage.Admin, [ServicePrivilage.Admin] },
|
||||
{ ServicePrivilage.ServiceAdmin, [ServicePrivilage.Admin, ServicePrivilage.ServiceAdmin] },
|
||||
{
|
||||
ServicePrivilage.ManageWarehouse,
|
||||
[ServicePrivilage.Admin, ServicePrivilage.ServiceAdmin, ServicePrivilage.ManageWarehouse]
|
||||
},
|
||||
{
|
||||
ServicePrivilage.EditWarehouse,
|
||||
[
|
||||
ServicePrivilage.Admin, ServicePrivilage.ServiceAdmin, ServicePrivilage.ManageWarehouse,
|
||||
ServicePrivilage.EditWarehouse
|
||||
]
|
||||
},
|
||||
{
|
||||
ServicePrivilage.AddWarehouse,
|
||||
[
|
||||
ServicePrivilage.Admin, ServicePrivilage.ServiceAdmin, ServicePrivilage.ManageWarehouse,
|
||||
ServicePrivilage.AddWarehouse
|
||||
]
|
||||
},
|
||||
{
|
||||
ServicePrivilage.DeleteWarehouse,
|
||||
[
|
||||
ServicePrivilage.Admin, ServicePrivilage.ServiceAdmin, ServicePrivilage.ManageWarehouse,
|
||||
ServicePrivilage.DeleteWarehouse
|
||||
]
|
||||
},
|
||||
{
|
||||
ServicePrivilage.ManageItems,
|
||||
[ServicePrivilage.Admin, ServicePrivilage.ServiceAdmin, ServicePrivilage.ManageItems]
|
||||
},
|
||||
{
|
||||
ServicePrivilage.EditItems,
|
||||
[
|
||||
ServicePrivilage.Admin, ServicePrivilage.ServiceAdmin, ServicePrivilage.ManageItems,
|
||||
ServicePrivilage.EditItems
|
||||
]
|
||||
},
|
||||
{
|
||||
ServicePrivilage.AddItems,
|
||||
[
|
||||
ServicePrivilage.Admin, ServicePrivilage.ServiceAdmin, ServicePrivilage.ManageItems,
|
||||
ServicePrivilage.AddItems
|
||||
]
|
||||
},
|
||||
{
|
||||
ServicePrivilage.DeleteItems,
|
||||
[
|
||||
ServicePrivilage.Admin, ServicePrivilage.ServiceAdmin, ServicePrivilage.ManageItems,
|
||||
ServicePrivilage.DeleteItems
|
||||
]
|
||||
},
|
||||
{
|
||||
ServicePrivilage.ManageInvetory,
|
||||
[ServicePrivilage.Admin, ServicePrivilage.ServiceAdmin, ServicePrivilage.ManageInvetory]
|
||||
},
|
||||
{
|
||||
ServicePrivilage.EditInventory,
|
||||
[
|
||||
ServicePrivilage.Admin, ServicePrivilage.ServiceAdmin, ServicePrivilage.ManageInvetory,
|
||||
ServicePrivilage.EditInventory
|
||||
]
|
||||
},
|
||||
{
|
||||
ServicePrivilage.AddItemToInventory,
|
||||
[
|
||||
ServicePrivilage.Admin, ServicePrivilage.ServiceAdmin, ServicePrivilage.ManageInvetory,
|
||||
ServicePrivilage.AddItemToInventory
|
||||
]
|
||||
},
|
||||
{
|
||||
ServicePrivilage.SeeInventory,
|
||||
[
|
||||
ServicePrivilage.Admin, ServicePrivilage.ServiceAdmin, ServicePrivilage.ManageInvetory,
|
||||
ServicePrivilage.SeeInventory
|
||||
]
|
||||
},
|
||||
{ ServicePrivilage.ServiceUser, GetAllPrivilageList() }
|
||||
};
|
||||
|
||||
public static List<ServicePrivilage> GetAllPrivilageList()
|
||||
{
|
||||
var list = PrivilageNameMap.Select(pair => pair.Key).ToList();
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<ServicePrivilage> GetServicePrivilageList()
|
||||
{
|
||||
var list = PrivilageNameMap.Where(pair => pair.Value.Contains(PrivilagePrefix))
|
||||
.Select(pair => pair.Key).ToList();
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<string> GetServicePrivilageNameList()
|
||||
{
|
||||
var list = PrivilageNameMap.Where(pair => pair.Value.Contains(PrivilagePrefix))
|
||||
.Select(pair => pair.Value).ToList();
|
||||
return list;
|
||||
}
|
||||
|
||||
public static string GetName(this ServicePrivilage servicePrivilage)
|
||||
{
|
||||
var result = PrivilageNameMap.TryGetValue(servicePrivilage, out var name);
|
||||
return (result ? name : $"Uknow-{servicePrivilage}") ?? $"Role {servicePrivilage} Uknow";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using System.Net.Http.Headers;
|
||||
using OpenWarehouse.auth.Common.ApiInterfeiceLib;
|
||||
using OpenWarehouse.auth.lib;
|
||||
using OpenWarehouse.auth.lib.Model.Role;
|
||||
using OpenWarehouse.auth.lib.Model.Service;
|
||||
using OpenWarehouse.warehouse.api.Common.CustimIdentifyManager;
|
||||
using OpenWarehouse.warehouse.api.Common.ServiceClaims;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Common.DefaultServiceAccountAndRole;
|
||||
|
||||
public class DefaultIdentify(ILogger<DefaultIdentify> logger, IConfiguration configuration,
|
||||
IServiceClaimsManager serviceClaimsManager)
|
||||
{
|
||||
|
||||
private List<RoleModel> _listOfRole = new()
|
||||
{
|
||||
new RoleModel()
|
||||
{
|
||||
RoleName = ServicePrivilage.ServiceAdmin.GetName(),
|
||||
Privilage = new()
|
||||
{
|
||||
ServicePrivilage.ServiceAdmin.GetName(),
|
||||
ServicePrivilage.ServiceUser.GetName(),
|
||||
}
|
||||
},
|
||||
new RoleModel()
|
||||
{
|
||||
RoleName = ServicePrivilage.ServiceUser.GetName(),
|
||||
Privilage = new()
|
||||
{
|
||||
ServicePrivilage.ServiceUser.GetName(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
public async Task<bool> TestAuth(string token)
|
||||
{
|
||||
var handler = new AuthTokenHandler(token);
|
||||
var httpClient = new HttpClient(handler);
|
||||
var client = new OpenWarehouseAuthClient(configuration["Auth:Url"], httpClient);
|
||||
|
||||
try
|
||||
{
|
||||
return await client.TestServiceTokenAsync();
|
||||
}
|
||||
catch (ApiException e)
|
||||
{
|
||||
if (e.StatusCode == 401) return false;
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public async Task<CreateServiceTokenReturnModel> SeedAsync(string adminToken)
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
var token = adminToken.Split(" ");
|
||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(token[0], token[1]);
|
||||
var client = new OpenWarehouseAuthClient(configuration["Auth:Url"], httpClient);
|
||||
|
||||
try
|
||||
{
|
||||
var service = new CreateServiceTokenModel()
|
||||
{
|
||||
ServiceName = "Warehouse",
|
||||
ServicePrivilages = ServicePrivilageClass.GetServicePrivilageNameList(),
|
||||
ServiceRoles = _listOfRole
|
||||
};
|
||||
var result = await client.GetTokenForServiceAsync(service);
|
||||
|
||||
logger.LogInformation($"Auth service initialized: \n " +
|
||||
$"Is success: {result.IsSuccess} \n " +
|
||||
$"Service username: {result.ServiceUsername} \n " +
|
||||
$"Service allerady exist: {result.UserAllereadyExist}");
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (ApiException e)
|
||||
{
|
||||
logger.LogWarning($"ApiException with code {e.StatusCode} and nessage {e.Message}");
|
||||
throw;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
logger.LogWarning(e.Message);
|
||||
throw;
|
||||
}
|
||||
|
||||
throw new Exception("This exemption shoudnt happen");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.Inventory;
|
||||
|
||||
public interface IInventoryManger
|
||||
{
|
||||
public Task<List<ItemInWarehouse>> GetListOfItemInWarehouse(Data.Item item);
|
||||
public Task<ItemInWarehouse?> GetPositionById(string id);
|
||||
public Task<List<ItemInWarehouse>> GetPositionByPosition(string position);
|
||||
public Task<bool> CreateAsync(ItemInWarehouse itemInWarehouse);
|
||||
public Task<bool> AddClaims(ItemInWarehouse itemInWarehouse, List<Claim> claims);
|
||||
public Task<bool> AddClaim(ItemInWarehouse itemInWarehouse, Claim claim);
|
||||
public Task<bool> DeleteClaim(ItemInWarehouse itemInWarehouse, string claimType);
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using System.Data;
|
||||
using OpenWarehouse.warehouse.api.Common.Warehouse;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Common.Inventory;
|
||||
|
||||
public class InventoryManger(ILogger<InventoryManger> logger,
|
||||
ApplicationDbContext context, IWarehouseManager warehouseManager,
|
||||
IItemManager itemManager) : IInventoryManger
|
||||
{
|
||||
public async Task<List<ItemInWarehouse>> GetListOfItemInWarehouse(Data.Item item)
|
||||
{
|
||||
return await context.ItemInWarehouses
|
||||
.Where(q => q.Item == item)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ItemInWarehouse?> GetPositionById(string id)
|
||||
{
|
||||
return await context.ItemInWarehouses
|
||||
.Where(q => q.Id == Guid.Parse(id))
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ItemInWarehouse>> GetPositionByPosition(string position)
|
||||
{
|
||||
return await context.ItemInWarehouses
|
||||
.Where(q => q.Positions == position)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> CreateAsync(ItemInWarehouse itemInWarehouse)
|
||||
{
|
||||
context.ItemInWarehouses.Add(itemInWarehouse);
|
||||
|
||||
var res = await context.SaveChangesAsync();
|
||||
|
||||
return res > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> AddClaims(ItemInWarehouse itemInWarehouse, List<Claim> claims)
|
||||
{
|
||||
foreach (Claim claim in claims)
|
||||
{
|
||||
if (itemInWarehouse.ItemInWarehouseClaims.Any(q => q.ClaimType == claim.Type))
|
||||
{
|
||||
var itemInWarehouseClaims = itemInWarehouse.ItemInWarehouseClaims
|
||||
.FirstOrDefault(warehouseClaims => warehouseClaims.ClaimType == claim.Type);
|
||||
if (itemInWarehouseClaims == null) return false;
|
||||
itemInWarehouseClaims.ClaimValue = claim.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemInWarehouse.ItemInWarehouseClaims.Add(new ItemInWarehouseClaims(){ClaimType = claim.Type, ClaimValue = claim.Value});
|
||||
}
|
||||
}
|
||||
|
||||
var res = await context.SaveChangesAsync();
|
||||
|
||||
return res == claims.Count;
|
||||
}
|
||||
|
||||
public async Task<bool> AddClaim(ItemInWarehouse itemInWarehouse, Claim claim)
|
||||
{
|
||||
if (itemInWarehouse.ItemInWarehouseClaims.Any(q => q.ClaimType == claim.Type))
|
||||
{
|
||||
var itemInWarehouseClaims = itemInWarehouse.ItemInWarehouseClaims
|
||||
.FirstOrDefault(warehouseClaims => warehouseClaims.ClaimType == claim.Type);
|
||||
if (itemInWarehouseClaims == null) return false;
|
||||
itemInWarehouseClaims.ClaimValue = claim.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemInWarehouse.ItemInWarehouseClaims.Add(new ItemInWarehouseClaims(){ClaimType = claim.Type, ClaimValue = claim.Value});
|
||||
}
|
||||
|
||||
var res = await context.SaveChangesAsync();
|
||||
return res > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteClaim(ItemInWarehouse itemInWarehouse, string claimType)
|
||||
{
|
||||
var res = await context.ItemInWarehousesClaims
|
||||
.Where(q => q.ClaimType == claimType && q.Item == itemInWarehouse)
|
||||
.ExecuteDeleteAsync();
|
||||
if (res > 1) throw new DataException("Deleted more than one record!!");
|
||||
return res == 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.Item;
|
||||
|
||||
public interface IItemManager
|
||||
{
|
||||
public Task<Data.Item?> FindItemByIdAsync(string id);
|
||||
public Task<Data.Item?> FindItemByNameAsync(string producerName, string itemName);
|
||||
public Task<Data.Item?> FindItemByNameAsync(Producers producers, string itemName);
|
||||
public Task<ActionResult> CreateAsync(Data.Item item);
|
||||
public Task<List<Claim>> GetListOfClaims(Data.Item item);
|
||||
public Task<ActionResult> AddClaim(Data.Item item, Claim claim);
|
||||
public Task<ActionResult> UpdateClaim(Data.Item item, Claim claim);
|
||||
public Task<ActionResult> DeleteClaim(Data.Item item, string claimType);
|
||||
public Task<ActionResult> EditClaim(Data.Item item, string claimType, string newValue);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.Item;
|
||||
|
||||
public enum ItemClaimsType
|
||||
{
|
||||
Exp, DateOfProduction, Description, Price, ManufactoreContry
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.Item;
|
||||
|
||||
public static class ItemClaimsTypeClass
|
||||
{
|
||||
private static readonly Dictionary<ItemClaimsType, string> ItemClaimType = new()
|
||||
{
|
||||
{ ItemClaimsType.Exp, "Exp" },
|
||||
{ ItemClaimsType.DateOfProduction, "Date_of_production" },
|
||||
{ ItemClaimsType.Price, "Price" },
|
||||
{ ItemClaimsType.Description, "Description" },
|
||||
{ ItemClaimsType.ManufactoreContry, "Manufactore_Country" },
|
||||
};
|
||||
|
||||
public static string GetName(this ItemClaimsType itemClaim)
|
||||
{
|
||||
var result = ItemClaimType.TryGetValue(itemClaim, out var name);
|
||||
|
||||
if (!result || name == null) throw new Exception("Key not found");
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
public static Claim GerClaims(this ItemClaimsType itemClaim, string value, string? issuer = null)
|
||||
{
|
||||
var result = ItemClaimType.TryGetValue(itemClaim, out var name);
|
||||
|
||||
if (!result || name == null) throw new Exception("Key not found");
|
||||
|
||||
Claim claim;
|
||||
|
||||
if (issuer != null) claim = new Claim(name, value, issuer);
|
||||
else claim = new Claim(name, value);
|
||||
|
||||
return claim;
|
||||
}
|
||||
|
||||
public static List<string> GetAllClaimName()
|
||||
{
|
||||
return ItemClaimType
|
||||
.Select(q => q.Value)
|
||||
.ToList();
|
||||
|
||||
}
|
||||
|
||||
public static bool IsDefaultClaimType(string val)
|
||||
{
|
||||
var res = ItemClaimType
|
||||
.Any(q => q.Value == val);
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
using OpenWarehouse.warehouse.api.Common.Producer;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Common.Item;
|
||||
|
||||
public class ItemManager(ApplicationDbContext context, IProducerManager producerManager) : IItemManager
|
||||
{
|
||||
public async Task<Data.Item?> FindItemByIdAsync(string id)
|
||||
{
|
||||
var result = await context.Items
|
||||
.Include(item => item.ItemCategoryTags)
|
||||
.Include(item => item.ItemClaims)
|
||||
.FirstOrDefaultAsync(item => item.Id != null && item.Id.Equals(id));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Data.Item?> FindItemByNameAsync(string producerName, string itemName)
|
||||
{
|
||||
var producer = await producerManager.FindProducerByName(producerName);
|
||||
if (producer != null)
|
||||
{
|
||||
return await FindItemByNameAsync(producer, itemName);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<Data.Item?> FindItemByNameAsync(Producers producers, string itemName)
|
||||
{
|
||||
return await context.Items
|
||||
.FirstOrDefaultAsync(item => item.Name != null &&
|
||||
item.Producer == producers && item.Name.Equals(itemName));
|
||||
}
|
||||
|
||||
public async Task<ActionResult> CreateAsync(Data.Item item)
|
||||
{
|
||||
context.Items.Add(item);
|
||||
|
||||
ActionResult? res = null;
|
||||
|
||||
var error = new Dictionary<string, string>();
|
||||
|
||||
try
|
||||
{
|
||||
res= new ActionResult((await context.SaveChangesAsync()) == 1);
|
||||
}
|
||||
catch (OperationCanceledException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
|
||||
return res ?? new ActionResult(false, error);
|
||||
}
|
||||
|
||||
public async Task<List<Claim>> GetListOfClaims(Data.Item item)
|
||||
{
|
||||
var result = await context.ItemClaims.Where(claims => claims.Item == item)
|
||||
.Select(claims => new Claim(claims.ClaimType ?? "Uknow", claims.ClaimValue ?? "Uknow"))
|
||||
.ToListAsync();
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<ActionResult> AddClaim(Data.Item item, Claim claim)
|
||||
{
|
||||
var newClaim = new ItemClaims(item, claim);
|
||||
context.ItemClaims.Add(newClaim);
|
||||
|
||||
ActionResult? res = null;
|
||||
|
||||
var error = new Dictionary<string, string>();
|
||||
|
||||
try
|
||||
{
|
||||
res= new ActionResult((await context.SaveChangesAsync()) == 1);
|
||||
}
|
||||
catch (OperationCanceledException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
|
||||
return res ?? new ActionResult(false, error);
|
||||
}
|
||||
|
||||
public async Task<ActionResult> UpdateClaim(Data.Item item, Claim claim)
|
||||
{
|
||||
var claimF = await context.ItemClaims
|
||||
.FirstOrDefaultAsync(q => q.ClaimType.Equals(claim.Type) && q.ClaimIssuer.Equals(claim.Issuer)
|
||||
&& q.Item == item);
|
||||
var result = 0;
|
||||
|
||||
if (claimF == null)
|
||||
{
|
||||
result = (await AddClaim(item, claim)).IsSuccess ? 0 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
claimF.ClaimValue = claim.Value;
|
||||
result= await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
|
||||
return result > 0 ? new ActionResult(true, null) : new ActionResult(false, null);
|
||||
}
|
||||
|
||||
public async Task<ActionResult> DeleteClaim(Data.Item item, string claimType)
|
||||
{
|
||||
ActionResult? res = null;
|
||||
|
||||
var error = new Dictionary<string, string>();
|
||||
int delCount = 0;
|
||||
|
||||
try
|
||||
{
|
||||
delCount = await context.ItemClaims
|
||||
.Where(claims => claims.ClaimType != null && claims.Item == item && claims.ClaimType.Equals(claimType))
|
||||
.ExecuteDeleteAsync();
|
||||
}
|
||||
catch (OperationCanceledException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
|
||||
if (res == null)
|
||||
{
|
||||
res = new ActionResult(delCount == 1, error);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public async Task<ActionResult> EditClaim(Data.Item item, string claimType, string newValue)
|
||||
{
|
||||
ActionResult? res = null;
|
||||
|
||||
var error = new Dictionary<string, string>();
|
||||
int editCount = 0;
|
||||
|
||||
try
|
||||
{
|
||||
var claim = await context.ItemClaims.FirstOrDefaultAsync(claims =>
|
||||
claims.ClaimType != null && claims.Item == item && claims.ClaimType.Equals(claimType));
|
||||
if (claim != null) claim.ClaimValue = newValue;
|
||||
else
|
||||
{
|
||||
error["Database"] = $"Claim {item.Name}-{claimType} not found.";
|
||||
}
|
||||
|
||||
editCount = await context.SaveChangesAsync();
|
||||
}
|
||||
catch (OperationCanceledException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
|
||||
if (res == null)
|
||||
{
|
||||
res = new ActionResult(editCount == 1, error);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using OpenWarehouse.warehouse.api.Services;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Common.ItemTagManager;
|
||||
|
||||
public interface IItemTagManager
|
||||
{
|
||||
public Task<bool> CreateTag(string name, Guid? parentId);
|
||||
public Task<ItemCategoryTag?> GetTagByName(string name);
|
||||
public Task<ItemCategoryTag?> GetTagById(Guid id);
|
||||
public Task<ItemCategoryTag?> GetTagById(string id);
|
||||
public Task<bool> DeleteTag(ItemCategoryTag tag);
|
||||
public Task<bool> DeleteTag(Guid id);
|
||||
public Task<int> DeleteTagsByNames(List<Model.Item.ItemCategoryTag> names);
|
||||
public Task<bool> DeleteTag(String id);
|
||||
public Task<int> CreateTagTree(List<Model.Item.ItemCategoryTag> itemCategoryTags);
|
||||
public Task<bool> DeleteAllChild(Guid id);
|
||||
public Task<bool> DeleteAllChild(String id);
|
||||
public Task<ItemCategoryTag?> GetTagTree(string root);
|
||||
public Task<List<ItemCategoryTag>> GetFullTagTree();
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.ItemTagManager;
|
||||
|
||||
public class ItemTagManager(ApplicationDbContext applicationDbContext, ILogger<ItemManager> logger) : IItemTagManager
|
||||
{
|
||||
public async Task<bool> CreateTag(string name, Guid? parentId)
|
||||
{
|
||||
logger.LogDebug("Attempting to create a new tag with name {TagName} and parent ID {ParentId}", name, parentId);
|
||||
|
||||
ItemCategoryTag? parent = null;
|
||||
|
||||
if (parentId != null)
|
||||
{
|
||||
parent = await applicationDbContext.ItemCategoryTags
|
||||
.FirstOrDefaultAsync(q => q.Id == parentId);
|
||||
|
||||
if (parent == null)
|
||||
{
|
||||
logger.LogWarning("Parent tag with ID {ParentId} not found.", parentId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var newTag = new ItemCategoryTag()
|
||||
{
|
||||
Name = name,
|
||||
ParentTag = parent
|
||||
};
|
||||
|
||||
applicationDbContext.ItemCategoryTags.Add(newTag);
|
||||
|
||||
bool isSaved = (await applicationDbContext.SaveChangesAsync()) > 0;
|
||||
|
||||
if (isSaved)
|
||||
{
|
||||
logger.LogInformation("Successfully created tag {Name} with ID {TagId}.", name, newTag.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogError("Failed to save the new tag {Name}.", name);
|
||||
}
|
||||
|
||||
return isSaved;
|
||||
}
|
||||
|
||||
public async Task<ItemCategoryTag?> GetTagByName(string name)
|
||||
{
|
||||
logger.LogDebug("Fetching tags with name {TagName}.", name);
|
||||
|
||||
var tags = await applicationDbContext.ItemCategoryTags
|
||||
.Where(tag => tag.Name != null && tag.Name.Equals(name)).FirstOrDefaultAsync();
|
||||
|
||||
if (tags == null)
|
||||
{
|
||||
logger.LogWarning("No tags found with name {Name}.", name);
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
public async Task<ItemCategoryTag?> GetTagById(Guid id)
|
||||
{
|
||||
logger.LogDebug("Fetching tag with ID {TagId}.", id);
|
||||
|
||||
var tag = await applicationDbContext.ItemCategoryTags
|
||||
.Where(tag => tag.Id == id).FirstOrDefaultAsync();
|
||||
|
||||
if (tag == null)
|
||||
{
|
||||
logger.LogWarning("No tag found with ID {Id}.", id);
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
public async Task<ItemCategoryTag?> GetTagById(string id)
|
||||
{
|
||||
logger.LogDebug("Fetching tag with string ID {TagId}.", id);
|
||||
return await GetTagById(Guid.Parse(id));
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteTag(ItemCategoryTag tag)
|
||||
{
|
||||
logger.LogDebug("Attempting to delete tag with object reference {Tag}.", tag);
|
||||
return await DeleteTag(tag.Id);
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteTag(Guid id)
|
||||
{
|
||||
logger.LogDebug("Attempting to delete tag with ID {TagId}.", id);
|
||||
|
||||
bool isDeleted = await applicationDbContext.ItemCategoryTags.Where(q => q.Id == id)
|
||||
.ExecuteDeleteAsync() > 0;
|
||||
|
||||
if (isDeleted)
|
||||
{
|
||||
logger.LogInformation("Successfully deleted tag with ID {TagId}.", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogError("Failed to delete tag with ID {TagId}.", id);
|
||||
}
|
||||
|
||||
return isDeleted;
|
||||
}
|
||||
|
||||
public async Task<int> DeleteTagsByNames(List<Model.Item.ItemCategoryTag> names)
|
||||
{
|
||||
logger.LogDebug("Attempting to delete tags by names.");
|
||||
|
||||
if (!names.Any())
|
||||
{
|
||||
logger.LogWarning("No tags provided for deletion.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var res = 0;
|
||||
|
||||
foreach (var tag in names)
|
||||
{
|
||||
logger.LogDebug("Deleting tag with name {TagName}.", tag.Name);
|
||||
res += await applicationDbContext.ItemCategoryTags
|
||||
.Where(q => q.Name == tag.Name)
|
||||
.ExecuteDeleteAsync();
|
||||
}
|
||||
|
||||
logger.LogInformation("{Count} tags were successfully deleted.", res);
|
||||
return res;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "An error occurred while deleting tags.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteTag(string id)
|
||||
{
|
||||
logger.LogDebug("Attempting to delete tag with string ID {TagId}.", id);
|
||||
return await DeleteTag(Guid.Parse(id));
|
||||
}
|
||||
|
||||
public async Task<int> CreateTagTree(List<Model.Item.ItemCategoryTag> itemCategoryTags)
|
||||
{
|
||||
logger.LogDebug("Attempting to create a tag tree.");
|
||||
|
||||
var result = 0;
|
||||
try
|
||||
{
|
||||
if (itemCategoryTags.All(q => q.ParentName != null))
|
||||
{
|
||||
logger.LogError("Tag tree must have at least one root node.");
|
||||
throw new InvalidOperationException("Tag tree must have at least one root node.");
|
||||
}
|
||||
|
||||
var tempParent = new List<ItemCategoryTag>();
|
||||
|
||||
while (itemCategoryTags.Count > 0)
|
||||
{
|
||||
var currentLevel = itemCategoryTags
|
||||
.Where(q => q.ParentName == null || itemCategoryTags.All(qq => qq.Name != q.ParentName))
|
||||
.ToList();
|
||||
|
||||
itemCategoryTags.RemoveAll(q => currentLevel.Contains(q));
|
||||
|
||||
foreach (var tag in currentLevel)
|
||||
{
|
||||
logger.LogDebug("Processing tag {TagName} with parent {ParentName}.", tag.Name, tag.ParentName);
|
||||
|
||||
var exists = await applicationDbContext.ItemCategoryTags
|
||||
.AnyAsync(t => t.Name == tag.Name && t.ParentTag != null && (t.ParentTag.Name == tag.ParentName ||
|
||||
(t.ParentTag == null && tag.ParentName == null)));
|
||||
|
||||
if (exists)
|
||||
{
|
||||
logger.LogInformation("Tag with name {TagName} already exists.", tag.Name);
|
||||
continue;
|
||||
}
|
||||
|
||||
ItemCategoryTag? parent = null;
|
||||
|
||||
if (tag.ParentName != null)
|
||||
{
|
||||
parent = await applicationDbContext.ItemCategoryTags
|
||||
.Where(q => q.Name == tag.ParentName).FirstOrDefaultAsync();
|
||||
|
||||
if (parent == null)
|
||||
{
|
||||
if (tempParent.Any(q => q.Name == tag.ParentName))
|
||||
{
|
||||
parent = tempParent.FirstOrDefault(q => q.Name == tag.ParentName);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning("Parent tag with name {ParentName} not found for child {Name}.",
|
||||
tag.ParentName, tag.Name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tagNew = new ItemCategoryTag()
|
||||
{
|
||||
Name = tag.Name,
|
||||
ParentTag = parent
|
||||
};
|
||||
|
||||
applicationDbContext.ItemCategoryTags.Add(tagNew);
|
||||
tempParent.Add(tagNew);
|
||||
|
||||
logger.LogDebug("Added new tag {TagName} with parent {ParentName}.", tagNew.Name,
|
||||
parent?.Name);
|
||||
}
|
||||
|
||||
result += await applicationDbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
logger.LogInformation("Successfully created tag tree with {Changes} changes.", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "An error occurred while creating the tag tree.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAllChild(Guid id)
|
||||
{
|
||||
logger.LogDebug("Attempting to delete all children for tag ID {TagId}.", id);
|
||||
|
||||
var parentTag = await GetTagById(id);
|
||||
if (parentTag == null)
|
||||
{
|
||||
logger.LogWarning("Parent tag with ID {Id} not found.", id);
|
||||
return false;
|
||||
}
|
||||
|
||||
var childTags = await applicationDbContext.ItemCategoryTags
|
||||
.Where(q => q.ParentTagId == id).ToListAsync();
|
||||
|
||||
if (!childTags.Any())
|
||||
{
|
||||
logger.LogInformation("No child tags found for parent tag with ID {Id}.", id);
|
||||
return true;
|
||||
}
|
||||
|
||||
applicationDbContext.ItemCategoryTags.RemoveRange(childTags);
|
||||
bool isDeleted = (await applicationDbContext.SaveChangesAsync()) > 0;
|
||||
|
||||
if (isDeleted)
|
||||
{
|
||||
logger.LogInformation("Successfully deleted all child tags for parent tag with ID {Id}.", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogError("Failed to delete child tags for parent tag with ID {Id}.", id);
|
||||
}
|
||||
|
||||
return isDeleted;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAllChild(string id)
|
||||
{
|
||||
logger.LogDebug("Attempting to delete all children for tag string ID {TagId}.", id);
|
||||
return await DeleteAllChild(Guid.Parse(id));
|
||||
}
|
||||
|
||||
public async Task<ItemCategoryTag?> GetTagTree(string root)
|
||||
{
|
||||
logger.LogDebug("Fetching tag tree starting from root {RootName}.", root);
|
||||
|
||||
var rootElement = await applicationDbContext.ItemCategoryTags
|
||||
.Where(q => q.Name != null && q.Name.Equals(root))
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (rootElement == null)
|
||||
{
|
||||
logger.LogWarning("Root tag with name {RootName} not found.", root);
|
||||
return null;
|
||||
}
|
||||
|
||||
await LoadChildren(rootElement);
|
||||
|
||||
return rootElement;
|
||||
}
|
||||
|
||||
public async Task<List<ItemCategoryTag>> GetFullTagTree()
|
||||
{
|
||||
logger.LogDebug("Fetching the full tag tree.");
|
||||
|
||||
var allTags = await applicationDbContext.ItemCategoryTags
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
|
||||
var tagDictionary = allTags.ToDictionary(tag => tag.Id);
|
||||
|
||||
var rootTags = new List<ItemCategoryTag>();
|
||||
|
||||
foreach (var tag in allTags)
|
||||
{
|
||||
if (tag.ParentTagId == null)
|
||||
{
|
||||
rootTags.Add(tag);
|
||||
}
|
||||
else if (tagDictionary.TryGetValue(tag.ParentTagId.Value, out var parentTag))
|
||||
{
|
||||
if (parentTag.ListOfChildrenTag == null)
|
||||
{
|
||||
parentTag.ListOfChildrenTag = new List<ItemCategoryTag>();
|
||||
}
|
||||
|
||||
parentTag.ListOfChildrenTag.Add(tag);
|
||||
}
|
||||
}
|
||||
|
||||
logger.LogInformation("Successfully fetched the full tag tree with {Count} root nodes.", rootTags.Count);
|
||||
|
||||
return rootTags;
|
||||
}
|
||||
|
||||
private async Task LoadChildren(ItemCategoryTag parentTag)
|
||||
{
|
||||
logger.LogDebug("Loading children for tag {TagName} with ID {TagId}.", parentTag.Name, parentTag.Id);
|
||||
|
||||
parentTag.ListOfChildrenTag = await applicationDbContext.ItemCategoryTags
|
||||
.Where(child => child.ParentTagId == parentTag.Id)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var child in parentTag.ListOfChildrenTag)
|
||||
{
|
||||
await LoadChildren(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.Kafka;
|
||||
|
||||
public enum Actions
|
||||
{
|
||||
Create, Update, Delete, CheckIntegrality
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.Kafka.Item;
|
||||
|
||||
public interface IItemKafkaMessage
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.Kafka.Item;
|
||||
|
||||
public class ItemKafkaMessage
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.Kafka;
|
||||
|
||||
public class KafkaConfig
|
||||
{
|
||||
public string? BootstrapServers { get; set; }
|
||||
public string? TopicRoot { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using ItemCategoryTag = OpenWarehouse.warehouse.api.Model.Item.ItemCategoryTag;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Common.Kafka.TagTree;
|
||||
|
||||
public interface ITagTreeKafkaMessage
|
||||
{
|
||||
public Guid Guid { get; init; }
|
||||
public Actions Action { get; init; }
|
||||
public List<ItemCategoryTag> ItemCategoryTagsList { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using OpenWarehouse.warehouse.api.Model.Item;
|
||||
using ItemCategoryTag = OpenWarehouse.warehouse.api.Model.Item.ItemCategoryTag;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Common.Kafka.TagTree;
|
||||
|
||||
public class TagTreeKafkaMessage : ITagTreeKafkaMessage
|
||||
{
|
||||
public Guid Guid { get; init; }
|
||||
public Actions Action { get; init; }
|
||||
public List<ItemCategoryTag> ItemCategoryTagsList { get; init; } = new();
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.Producer;
|
||||
|
||||
public interface IProducerManager
|
||||
{
|
||||
public Task<Producers?> FindProducerByName(string name);
|
||||
public Task<Producers?> FindProducerById(Guid? guid);
|
||||
public Task<List<Producers>> GetProducerList();
|
||||
|
||||
public Task<bool> DeleteProducerByName(string name);
|
||||
public Task<List<Claim>> GetClaims(Producers producers);
|
||||
public Task<ActionResult> CreateAsync(Producers producers);
|
||||
public Task<ActionResult> AddClaim(Producers producers, Claim claim);
|
||||
public Task<ActionResult> DeleteClaim(Producers producers, string claimType);
|
||||
public Task<ActionResult> UpdateClaim(Producers producers, Claim claim);
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.Producer;
|
||||
|
||||
public class ProducerManager(ApplicationDbContext context) : IProducerManager
|
||||
{
|
||||
public async Task<Producers?> FindProducerByName(string name)
|
||||
{
|
||||
return await context.Producers
|
||||
.Include(q => q.Claims)
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(producer1 => producer1.Name != null &&
|
||||
producer1.Name.Equals(name));
|
||||
}
|
||||
|
||||
public async Task<Producers?> FindProducerById(Guid? guid)
|
||||
{
|
||||
return await context.Producers
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(producer1 => producer1.Name != null &&
|
||||
producer1.Id == guid);
|
||||
}
|
||||
|
||||
public async Task<List<Producers>> GetProducerList()
|
||||
{
|
||||
return await context.Producers.Include(q => q.Claims).AsNoTracking().ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteProducerByName(string name)
|
||||
{
|
||||
var res = await context.Producers
|
||||
.Where(q => q.Name != null && q.Name.Equals(name))
|
||||
.Include(q => q.Claims)
|
||||
.AsNoTracking()
|
||||
.ExecuteDeleteAsync();
|
||||
return res > 0;
|
||||
}
|
||||
|
||||
public async Task<List<Claim>> GetClaims(Producers producers)
|
||||
{
|
||||
return await context.ProducerClaims.Where(claims => claims.Producer == producers)
|
||||
.Select(claims => new Claim(claims.ClaimType ?? "Unknown", claims.ClaimValue ?? "Unknown"))
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ActionResult> CreateAsync(Producers producers)
|
||||
{
|
||||
context.Producers.Add(producers);
|
||||
ActionResult? res = null;
|
||||
|
||||
var error = new Dictionary<string, string>();
|
||||
|
||||
try
|
||||
{
|
||||
res= new ActionResult((await context.SaveChangesAsync()) == 1);
|
||||
}
|
||||
catch (OperationCanceledException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
|
||||
return res ?? new ActionResult(false, error);
|
||||
}
|
||||
|
||||
public async Task<ActionResult> AddClaim(Producers producers, Claim claim)
|
||||
{
|
||||
context.ProducerClaims.Add(new ProducerClaims(producers, claim));
|
||||
|
||||
ActionResult? res = null;
|
||||
|
||||
var error = new Dictionary<string, string>();
|
||||
|
||||
try
|
||||
{
|
||||
res= new ActionResult((await context.SaveChangesAsync()) == 1);
|
||||
}
|
||||
catch (OperationCanceledException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
|
||||
return res ?? new ActionResult(false, error);
|
||||
}
|
||||
|
||||
public async Task<ActionResult> DeleteClaim(Producers producers, string claimType)
|
||||
{
|
||||
ActionResult? res = null;
|
||||
|
||||
var error = new Dictionary<string, string>();
|
||||
|
||||
try
|
||||
{
|
||||
var delRes = await context.ProducerClaims
|
||||
.Where(claims => claims.ClaimType != null &&
|
||||
claims.Producer == producers && claims.ClaimType.Equals(claimType))
|
||||
.ExecuteDeleteAsync();
|
||||
res= new ActionResult((delRes) == 1);
|
||||
|
||||
}
|
||||
catch (OperationCanceledException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
error[e.Source ?? "Unknown"] = e.Message;
|
||||
}
|
||||
|
||||
if (res == null)
|
||||
{
|
||||
res = new ActionResult(false, error);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public async Task<ActionResult> UpdateClaim(Producers producers, Claim claim1)
|
||||
{
|
||||
var claim = await context.ProducerClaims
|
||||
.Where(claims => claims.ClaimType != null &&
|
||||
claims.Producer == producers && claims.ClaimType.Equals(claim1.Type)
|
||||
&& claims.ClaimIssuer == claim1.Issuer).FirstOrDefaultAsync();
|
||||
|
||||
var res = 0;
|
||||
|
||||
if (claim == null)
|
||||
{
|
||||
res = (await AddClaim(producers, claim1)).IsSuccess ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
claim.ClaimValue = claim1.Value;
|
||||
res = await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
|
||||
return new ActionResult(res > 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.ServiceClaims;
|
||||
|
||||
public interface IServiceClaimsManager
|
||||
{
|
||||
public Task<Claim> GetServiceClaims(ServiceClaim claim);
|
||||
public Task<List<Claim>> GetListServiceClaims();
|
||||
public Task<bool> UpdateClaim(ServiceClaim claim, string value);
|
||||
public Task<bool> ClaimIsSet(ServiceClaim claim);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.ServiceClaims;
|
||||
|
||||
public enum ServiceClaim
|
||||
{
|
||||
ServiceAcoountUsername, ServiceAcoountToken, SericeIsnitialized,
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.ServiceClaims;
|
||||
|
||||
public static class ServiceClaimsClass
|
||||
{
|
||||
private static readonly Dictionary<ServiceClaim, string> ServiceClaimsMap = new()
|
||||
{
|
||||
{ ServiceClaim.ServiceAcoountToken, "Service_account_token" },
|
||||
{ ServiceClaim.ServiceAcoountUsername, "Service_account_username" }
|
||||
};
|
||||
|
||||
public static string GetName(this ServiceClaim serviceClaim)
|
||||
{
|
||||
var result = ServiceClaimsMap.TryGetValue(serviceClaim, out var name);
|
||||
return (result ? name : $"Uknow-{serviceClaim}") ?? $"Role {serviceClaim} Uknow";
|
||||
}
|
||||
|
||||
public static Claim GerClaims(this ServiceClaim serviceClaim, string value)
|
||||
{
|
||||
var result = ServiceClaimsMap.TryGetValue(serviceClaim, out var name);
|
||||
if (!result || value == null) throw new Exception("Claims type not implement");
|
||||
|
||||
return new Claim(name ?? throw new NullReferenceException("Claim name excemption"), value);
|
||||
}
|
||||
|
||||
public static Data.ServiceClaims CreateServiceClaims(this ServiceClaim serviceClaim, string value)
|
||||
{
|
||||
return new Data.ServiceClaims() { ClaimType = serviceClaim.GetName(), ClaimValue = value };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.ServiceClaims;
|
||||
|
||||
public class ServiceClaimsManager(ApplicationDbContext context) : IServiceClaimsManager
|
||||
{
|
||||
public async Task<Claim> GetServiceClaims(ServiceClaim claim)
|
||||
{
|
||||
var result = await context.ServiceClaims
|
||||
.Where(claims => claims.ClaimType == claim.GetName())
|
||||
.FirstOrDefaultAsync();
|
||||
if (result == null)
|
||||
{
|
||||
return new Claim(claim.GetName(), "");
|
||||
}
|
||||
|
||||
return result.Claim;
|
||||
}
|
||||
|
||||
public async Task<List<Claim>> GetListServiceClaims()
|
||||
{
|
||||
return await context.ServiceClaims.Select(q => new Claim(q.ClaimType ?? "Uknow", q.ClaimValue ?? "")).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateClaim(ServiceClaim claim, string value)
|
||||
{
|
||||
var result = await context.ServiceClaims
|
||||
.Where(claims => claims.ClaimType == claim.GetName())
|
||||
.FirstOrDefaultAsync();
|
||||
if (result == null)
|
||||
{
|
||||
Data.ServiceClaims claims = claim.CreateServiceClaims(value);
|
||||
context.ServiceClaims.Add(claims);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.ClaimValue = value;
|
||||
}
|
||||
|
||||
var res = await context.SaveChangesAsync();
|
||||
|
||||
return res > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> ClaimIsSet(ServiceClaim claim)
|
||||
{
|
||||
var result = await context.ServiceClaims
|
||||
.Where(q => q.ClaimType == claim.GetName()).AnyAsync();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.TaskManager;
|
||||
|
||||
public interface ITaskManager
|
||||
{
|
||||
public Task<string?> GetTaskStatus(Guid id);
|
||||
public Task<bool?> CreateTask(Guid id, string? actorId);
|
||||
public Task<bool> UpdateTaskStatus(Guid id, TaskStatus status);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.TaskManager;
|
||||
|
||||
public class TaskManager(ApplicationDbContext context, ILogger<TaskManager> logger) : ITaskManager
|
||||
{
|
||||
public async Task<string?> GetTaskStatus(Guid id)
|
||||
{
|
||||
logger.LogInformation("Get status of task with id:{id}", id);
|
||||
|
||||
var result = await context.TaskStatus
|
||||
.FirstOrDefaultAsync(status => status.TaskId == id);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
logger.LogWarning("Task with id:{id} not found", id);
|
||||
return null;
|
||||
}
|
||||
|
||||
return result.Status;
|
||||
}
|
||||
|
||||
public async Task<bool?> CreateTask(Guid id, string? actorId)
|
||||
{
|
||||
logger.LogInformation("Creating new task with id {id}", id);
|
||||
var newTask = new TaskStatusTable()
|
||||
{
|
||||
TaskId = id,
|
||||
Actor = actorId,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
UpdatedAt = DateTime.UtcNow,
|
||||
Status = TaskStatus.Accepted.ToString()
|
||||
};
|
||||
|
||||
context.TaskStatus.Add(newTask);
|
||||
|
||||
var result = await context.SaveChangesAsync();
|
||||
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateTaskStatus(Guid id, TaskStatus status)
|
||||
{
|
||||
logger.LogInformation("Updating task with id:{id} to status:{status}", id, status.ToString());
|
||||
var task = await context.TaskStatus
|
||||
.FirstOrDefaultAsync(q => q.TaskId == id);
|
||||
|
||||
if (task == null)
|
||||
{
|
||||
logger.LogWarning("Task with id:{id} not found", id);
|
||||
return false;
|
||||
}
|
||||
|
||||
task.Status = status.ToString();
|
||||
task.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
return (await context.SaveChangesAsync()) > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.TaskManager;
|
||||
|
||||
public enum TaskStatus
|
||||
{
|
||||
Crated, Accepted, Processing, Error, Success, NotFullSuccess
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.TaskManager;
|
||||
|
||||
public static class TaskStatusClass
|
||||
{
|
||||
private static readonly Dictionary<TaskStatus, string?> TaskStatusDictionary = new()
|
||||
{
|
||||
{ TaskStatus.Accepted, "Accepted" },
|
||||
{ TaskStatus.Crated, "Created" },
|
||||
{ TaskStatus.Error, "Error" },
|
||||
{ TaskStatus.Processing, "Processing" },
|
||||
{ TaskStatus.Success, "Success" },
|
||||
{ TaskStatus.NotFullSuccess, "Not full sucess"}
|
||||
};
|
||||
|
||||
public static string ToString(this TaskStatus status)
|
||||
{
|
||||
if (!TaskStatusDictionary.TryGetValue(status, out string? value) && value == "")
|
||||
throw new NotImplementedException();
|
||||
return value ?? "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.Warehouse;
|
||||
|
||||
public interface IWarehouseManager
|
||||
{
|
||||
public Task<Data.Warehouse?> GetWarehouse(string id);
|
||||
public Task<ActionResult> EditWarehouse(Data.Warehouse warehouse, string? newName, string? newFiestLineAdres, string? newSecondLineAdress, Image? image);
|
||||
public Task<ActionResult> CreateWarehouse(Data.Warehouse warehouse);
|
||||
public Task<ActionResult> AddWarehouseClaim(Data.Warehouse warehouse, Claim claim);
|
||||
public Task<ActionResult> AddWarehouseClaims(Data.Warehouse warehouse, List<Claim> claims);
|
||||
public Task<List<Claim>> GetWarehouseClaim(Data.Warehouse warehouse);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.Warehouse;
|
||||
|
||||
public enum WarehouseClaimsType
|
||||
{
|
||||
Company, Email, Phone, OwnerId, OwnerUsername, WarehousePrivilageManage, WarehouseManageInfo, WarehouseAdmin,
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.Warehouse;
|
||||
|
||||
public static class WarehouseClaimsTypeClass
|
||||
{
|
||||
private static Dictionary<WarehouseClaimsType, string> _warehouseClaimsString = new()
|
||||
{
|
||||
{ WarehouseClaimsType.Company, "Company" },
|
||||
{ WarehouseClaimsType.Email, "Email" },
|
||||
{ WarehouseClaimsType.Phone, "Phone" },
|
||||
{ WarehouseClaimsType.OwnerId, "OwnerID" },
|
||||
{ WarehouseClaimsType.OwnerUsername, "OwnerUsername" },
|
||||
{ WarehouseClaimsType.WarehouseAdmin, "WarehouseManagePrivilage" },
|
||||
{ WarehouseClaimsType.WarehouseManageInfo, "WarehouseManagePrivilageInfo" },
|
||||
{ WarehouseClaimsType.WarehousePrivilageManage, "WarehouseAdminPrivilage" }
|
||||
};
|
||||
|
||||
public static string ToString(this WarehouseClaimsType warehouseClaimsType)
|
||||
{
|
||||
var result = _warehouseClaimsString.TryGetValue(warehouseClaimsType, out var claim);
|
||||
if (!result) throw new NotImplementedException("Claim tyoe not implemented");
|
||||
return claim ?? throw new NotImplementedException("Claim tyoe not implemented");
|
||||
}
|
||||
|
||||
public static Claim ToClaim(this WarehouseClaimsType warehouseClaimsType, string value, string? issuer = null)
|
||||
{
|
||||
var result = _warehouseClaimsString.TryGetValue(warehouseClaimsType, out var claim);
|
||||
if (!result || claim == null) throw new NotImplementedException("Claim tyoe not implemented");
|
||||
|
||||
if (issuer != null)
|
||||
{
|
||||
return new Claim(claim, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Claim(claim, value, issuer);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
namespace OpenWarehouse.warehouse.api.Common.Warehouse;
|
||||
|
||||
public class WarehouseManager(ApplicationDbContext context) : IWarehouseManager
|
||||
{
|
||||
public async Task<Data.Warehouse?> GetWarehouse(string id)
|
||||
{
|
||||
var warehouse = await context.Warehouses
|
||||
.Include(warehouse1 => warehouse1.Image)
|
||||
.FirstOrDefaultAsync(warehouse1 => warehouse1.Id != null && warehouse1.Id.Equals(id));
|
||||
return warehouse;
|
||||
}
|
||||
|
||||
public async Task<ActionResult> EditWarehouse(Data.Warehouse warehouse, string? newName = null,
|
||||
string? newFiestLineAdres = null, string? newSecondLineAdress = null,
|
||||
Image? image = null)
|
||||
{
|
||||
ActionResult? res = null;
|
||||
|
||||
var error = new Dictionary<string, string>();
|
||||
|
||||
var warehouseEntry = await context.Warehouses
|
||||
.Include(warehouse1 => warehouse.Image)
|
||||
.FirstOrDefaultAsync(warehouse1 => warehouse1 == warehouse);
|
||||
|
||||
if (warehouseEntry == null)
|
||||
{
|
||||
error["Database"] = "Not found";
|
||||
return new ActionResult(false, error);
|
||||
}
|
||||
|
||||
if (newName != null)
|
||||
{
|
||||
warehouseEntry.Name = newName;
|
||||
}
|
||||
|
||||
if (newFiestLineAdres != null)
|
||||
{
|
||||
warehouse.FiestLineAdress = newFiestLineAdres;
|
||||
}
|
||||
|
||||
if (newSecondLineAdress != null)
|
||||
{
|
||||
warehouse.SecondLineAdress = newSecondLineAdress;
|
||||
}
|
||||
|
||||
if (image != null)
|
||||
{
|
||||
var imageToDel = warehouse.Image;
|
||||
warehouse.Image = image;
|
||||
if (imageToDel != null)
|
||||
{
|
||||
await context.Images.Where(image1 => image1 == imageToDel).ExecuteDeleteAsync();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
res= new ActionResult((await context.SaveChangesAsync()) > 0);
|
||||
}
|
||||
catch (OperationCanceledException e)
|
||||
{
|
||||
error[e.Source ?? "Uknow"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
error[e.Source ?? "Uknow"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
error[e.Source ?? "Uknow"] = e.Message;
|
||||
}
|
||||
|
||||
if (res == null)
|
||||
{
|
||||
res = new ActionResult(false, error);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public async Task<ActionResult> CreateWarehouse(Data.Warehouse warehouse)
|
||||
{
|
||||
ActionResult? res = null;
|
||||
|
||||
var error = new Dictionary<string, string>();
|
||||
|
||||
context.Warehouses
|
||||
.Add(warehouse);
|
||||
try
|
||||
{
|
||||
res= new ActionResult((await context.SaveChangesAsync()) == 1);
|
||||
}
|
||||
catch (OperationCanceledException e)
|
||||
{
|
||||
error[e.Source ?? "Uknow"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
error[e.Source ?? "Uknow"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
error[e.Source ?? "Uknow"] = e.Message;
|
||||
}
|
||||
|
||||
if (res == null)
|
||||
{
|
||||
res = new ActionResult(false, error);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public async Task<ActionResult> AddWarehouseClaim(Data.Warehouse warehouse, Claim claim)
|
||||
{
|
||||
ActionResult? res = null;
|
||||
var error = new Dictionary<string, string>();
|
||||
|
||||
var claimData = new WarehouseClaims(warehouse, claim);
|
||||
context.WarehouseClaims.Add(claimData);
|
||||
try
|
||||
{
|
||||
res = new ActionResult((await context.SaveChangesAsync()) == 1);
|
||||
}
|
||||
catch (OperationCanceledException e)
|
||||
{
|
||||
error[e.Source ?? "Uknow"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
error[e.Source ?? "Uknow"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
error[e.Source ?? "Uknow"] = e.Message;
|
||||
}
|
||||
|
||||
if (res == null)
|
||||
{
|
||||
res = new ActionResult(false, error);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public async Task<ActionResult> AddWarehouseClaims(Data.Warehouse warehouse, List<Claim> claims)
|
||||
{
|
||||
ActionResult? res = null;
|
||||
var error = new Dictionary<string, string>();
|
||||
|
||||
foreach (var claim in claims)
|
||||
{
|
||||
var claimData = new WarehouseClaims(warehouse, claim);
|
||||
context.WarehouseClaims.Add(claimData);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
res = new ActionResult((await context.SaveChangesAsync()) == 1);
|
||||
}
|
||||
catch (OperationCanceledException e)
|
||||
{
|
||||
error[e.Source ?? "Uknow"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
error[e.Source ?? "Uknow"] = e.Message;
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
error[e.Source ?? "Uknow"] = e.Message;
|
||||
}
|
||||
|
||||
if (res == null)
|
||||
{
|
||||
res = new ActionResult(false, error);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
public async Task<List<Claim>> GetWarehouseClaim(Data.Warehouse warehouse)
|
||||
{
|
||||
var claims = await context.WarehouseClaims
|
||||
.Where(warehouseClaims => warehouseClaims.Warehouse == warehouse)
|
||||
.Select(warehouseClaims => new Claim(warehouseClaims.ClaimType ?? "Uknow", warehouseClaims.ClaimValue ?? "Uknow"))
|
||||
.ToListAsync();
|
||||
|
||||
return claims;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
using MassTransit;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using OpenWarehouse.warehouse.api.Common.ItemTagManager;
|
||||
using OpenWarehouse.warehouse.api.Common.Kafka;
|
||||
using OpenWarehouse.warehouse.api.Common.Kafka.TagTree;
|
||||
using OpenWarehouse.warehouse.api.Common.Producer;
|
||||
using OpenWarehouse.warehouse.api.Common.TaskManager;
|
||||
using OpenWarehouse.warehouse.api.Model.Item;
|
||||
using ActionResult = Microsoft.AspNetCore.Mvc.ActionResult;
|
||||
using ItemCategoryTag = OpenWarehouse.warehouse.api.Data.ItemCategoryTag;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Controller;
|
||||
|
||||
[ApiController]
|
||||
[Route("[controller]/[action]")]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
public class Item(IItemManager itemManager, ILogger<Item> logger,
|
||||
ITopicProducer<TagTreeKafkaMessage> publishTagTreeEndpoint, ITaskManager taskManager,
|
||||
IItemTagManager itemTagManager, IProducerManager producerManager) : ControllerBase
|
||||
{
|
||||
[HttpGet("{id}")]
|
||||
public async Task<ActionResult<ItemModel>> GetItemById([FromRoute] string id)
|
||||
{
|
||||
logger.LogInformation("GetItemById called for item id {id}", id);
|
||||
var item = await itemManager.FindItemByIdAsync(id);
|
||||
logger.LogDebug("Item retrieved: {@Item}", item);
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
logger.LogWarning("Item with ID:{id} not found", id);
|
||||
return NotFound();
|
||||
}
|
||||
var result = new ItemModel()
|
||||
{
|
||||
Id = item.Id.ToString(),
|
||||
Name = item.Name,
|
||||
Claims = item.ItemClaims?.ToDictionary(
|
||||
q => q.ClaimType ?? $"Unknown type, {Guid.NewGuid()} ",
|
||||
q => new ClaimValueModel()
|
||||
{
|
||||
Issuer = q.ClaimIssuer,
|
||||
Value = q.ClaimValue,
|
||||
}),
|
||||
ProducerId = item.ProducerId.ToString(),
|
||||
ProducerName = item.Producer?.Name,
|
||||
};
|
||||
logger.LogDebug("Returning item model: {@Result}", result);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<CreateItemRespond>> CreateItem([FromBody]CreateItemRequest request)
|
||||
{
|
||||
CreateItemRespond respond = new CreateItemRespond();
|
||||
|
||||
bool ready = true;
|
||||
if (request is { ProducerName: null, ItemName: null}) return BadRequest();
|
||||
|
||||
var producer = await producerManager.FindProducerByName(request.ProducerName ?? "");
|
||||
|
||||
if (producer == null)
|
||||
{
|
||||
ready = false;
|
||||
respond.Errors["Producer"] = $"Producer {request.ProducerName} is not found";
|
||||
}
|
||||
|
||||
var listOfTags = new List<ItemCategoryTag>();
|
||||
|
||||
foreach (var itemTag in request.Tags)
|
||||
{
|
||||
var tag = await itemTagManager.GetTagByName(itemTag);
|
||||
|
||||
|
||||
if (tag == null)
|
||||
{
|
||||
ready = false;
|
||||
respond.Errors[$"Tag:{itemTag}"] = "Not found";
|
||||
continue;
|
||||
}
|
||||
|
||||
listOfTags.Add(tag);
|
||||
}
|
||||
|
||||
if (!ready)
|
||||
{
|
||||
return BadRequest(respond);
|
||||
}
|
||||
|
||||
var item = new Data.Item()
|
||||
{
|
||||
Name = request.ItemName,
|
||||
ItemCategoryTags = listOfTags,
|
||||
Producer = producer,
|
||||
};
|
||||
|
||||
var res = await itemManager.CreateAsync(item);
|
||||
|
||||
return res.IsSuccess ? Ok(item) : BadRequest(respond);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult> CreateTagTree([FromBody] CreateTagTreeRequest request)
|
||||
{
|
||||
Guid id = Guid.NewGuid();
|
||||
logger.LogInformation("Request with id:{id} to create tag tree received", id);
|
||||
if (request.ItemCategoryTagsList == null || request.ItemCategoryTagsList.Count == 0)
|
||||
{
|
||||
logger.LogWarning("Request with id:{id} cannot be accepted ", id);
|
||||
return BadRequest("List cannot be empty!");
|
||||
}
|
||||
logger.LogInformation("Request with id:{id} to create item tag tree accepted", id);
|
||||
|
||||
var actor = (HttpContext.User.Identity as CaseSensitiveClaimsIdentity)?
|
||||
.Claims.Where(q => q.Type == ClaimTypes.NameIdentifier)
|
||||
.Select(q => q.Value).FirstOrDefault();
|
||||
logger.LogDebug("Actor identified: {Actor}", actor);
|
||||
|
||||
await taskManager.CreateTask(id, actor);
|
||||
logger.LogDebug("Task created with ID {TaskId}", id);
|
||||
|
||||
var kafkaMess = new TagTreeKafkaMessage()
|
||||
{
|
||||
Guid = id,
|
||||
ItemCategoryTagsList = request.ItemCategoryTagsList,
|
||||
Action = Actions.Create
|
||||
};
|
||||
logger.LogDebug("Publishing Kafka message: {@KafkaMessage}", kafkaMess);
|
||||
|
||||
_ = publishTagTreeEndpoint.Produce(kafkaMess);
|
||||
|
||||
return Accepted($"/status/{id}");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult> DeleteTagList([FromBody] CreateTagTreeRequest request)
|
||||
{
|
||||
Guid id = Guid.NewGuid();
|
||||
logger.LogInformation("Request with id:{id} to delete tag list received", id);
|
||||
|
||||
if (request.ItemCategoryTagsList == null || request.ItemCategoryTagsList.Count == 0)
|
||||
{
|
||||
logger.LogWarning("Request with id:{id} cannot be accepted ", id);
|
||||
return BadRequest("List cannot be empty!");
|
||||
}
|
||||
|
||||
logger.LogInformation("Request with id:{id} to delete tag list accepted", id);
|
||||
|
||||
var actor = (HttpContext.User.Identity as CaseSensitiveClaimsIdentity)?
|
||||
.Claims.Where(q => q.Type == ClaimTypes.NameIdentifier)
|
||||
.Select(q => q.Value).FirstOrDefault();
|
||||
logger.LogDebug("Actor identified: {Actor}", actor);
|
||||
|
||||
await taskManager.CreateTask(id, actor);
|
||||
logger.LogDebug("Task created with ID {TaskId}", id);
|
||||
|
||||
var kafkaMess = new TagTreeKafkaMessage()
|
||||
{
|
||||
Guid = id,
|
||||
ItemCategoryTagsList = request.ItemCategoryTagsList,
|
||||
Action = Actions.Delete
|
||||
};
|
||||
logger.LogDebug("Publishing Kafka message: {@KafkaMessage}", kafkaMess);
|
||||
|
||||
_ = publishTagTreeEndpoint.Produce(kafkaMess);
|
||||
|
||||
return Accepted($"/status/{id}");
|
||||
}
|
||||
|
||||
[HttpGet("{root}")]
|
||||
public async Task<ActionResult<TagTreeModel>> GetTagTree([FromRoute]string root)
|
||||
{
|
||||
logger.LogInformation("GetTagTree called for root {root}", root);
|
||||
|
||||
var result = await itemTagManager.GetTagTree(root);
|
||||
logger.LogDebug("Tag tree retrieved for root {Root}: {@Result}", root, result);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
logger.LogWarning("No tag tree found for root {Root}", root);
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var returnResult = GetChild(result);
|
||||
logger.LogDebug("Returning tag tree model: {@ReturnResult}", returnResult);
|
||||
|
||||
return Ok(returnResult);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<int>> UpdateItemClaims([FromBody]UpdateItemClaimRequest request)
|
||||
{
|
||||
|
||||
if (request.ItemId == null || request.ListOfUpdatedClaims.Count == 0) return BadRequest();
|
||||
int result = 0;
|
||||
|
||||
var item = await itemManager.FindItemByIdAsync(request.ItemId);
|
||||
if (item == null) return NotFound();
|
||||
|
||||
foreach (var claim in request.ListOfUpdatedClaims)
|
||||
{
|
||||
if (claim.ClaimType == null) continue;
|
||||
|
||||
if (claim.ClaimValue == null)
|
||||
{
|
||||
var resultLocal = await itemManager.DeleteClaim(item, claim.ClaimType);
|
||||
|
||||
if (resultLocal.IsSuccess)
|
||||
{
|
||||
result++;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning("Failed to delete claim: {ClaimType}", claim.ClaimType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var resultLocal = await itemManager.UpdateClaim(item, new Claim(claim.ClaimType, claim.ClaimValue, claim.ClaimIssuer));
|
||||
|
||||
if (resultLocal.IsSuccess)
|
||||
{
|
||||
result++;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning("Failed to update claim: {ClaimType}", claim.ClaimType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result> 0 ? Ok(result) : BadRequest();
|
||||
}
|
||||
|
||||
private TagTreeModel GetChild(ItemCategoryTag model)
|
||||
{
|
||||
logger.LogDebug("Building child model for tag {TagName}", model.Name);
|
||||
var result = new TagTreeModel(){Name = model.Name};
|
||||
if (model.ListOfChildrenTag != null)
|
||||
foreach (var element in model.ListOfChildrenTag)
|
||||
{
|
||||
logger.LogDebug("Processing child tag {ChildTagName}", element.Name);
|
||||
result.Child.Add(GetChild(element));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using OpenWarehouse.warehouse.api.Common.Producer;
|
||||
using OpenWarehouse.warehouse.api.Model.Producer;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Controller;
|
||||
|
||||
[ApiController]
|
||||
[Route("[controller]/[action]")]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
public class Producer(ILogger<Producer> logger, IProducerManager producerManager) : ControllerBase
|
||||
{
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> CreateProducer([FromBody] Model.Producer.Producer? producer)
|
||||
{
|
||||
if (producer == null)
|
||||
{
|
||||
logger.LogWarning("Received null producer in CreateProducer");
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
var newProducer = new Data.Producers()
|
||||
{
|
||||
FiestLineAdress = producer.FirstLineAddress,
|
||||
SecondLineAdress = producer.SecondLineAddress,
|
||||
Name = producer.Name,
|
||||
Email = producer.Email,
|
||||
Phone = producer.PhoneNumber
|
||||
};
|
||||
|
||||
var res = await producerManager.CreateAsync(newProducer);
|
||||
|
||||
if (!res.IsSuccess)
|
||||
{
|
||||
logger.LogError("Failed to create producer: {Errors}", res.Errors);
|
||||
return BadRequest(res.Errors);
|
||||
}
|
||||
|
||||
logger.LogInformation("Producer created successfully: {ProducerName}", producer.Name);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpGet("{name}")]
|
||||
public async Task<ActionResult<Model.Producer.Producer>> GetProducer([FromRoute] string name)
|
||||
{
|
||||
logger.LogInformation("Fetching producer with name: {Name}", name);
|
||||
|
||||
var res = await producerManager.FindProducerByName(name);
|
||||
|
||||
if (res == null)
|
||||
{
|
||||
logger.LogWarning("Producer not found with name: {Name}", name);
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var processedRes = new Model.Producer.Producer
|
||||
{
|
||||
Name = res.Name,
|
||||
Email = res.Email,
|
||||
PhoneNumber = res.Phone,
|
||||
FirstLineAddress = res.FiestLineAdress,
|
||||
SecondLineAddress = res.SecondLineAdress,
|
||||
Claims = res.Claims?.Select(q => q as ClaimBase).ToList(),
|
||||
};
|
||||
|
||||
logger.LogInformation("Producer fetched successfully: {Name}", name);
|
||||
return Ok(processedRes);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<IEnumerable<Model.Producer.Producer>>> GetProducers()
|
||||
{
|
||||
logger.LogInformation("Fetching list of producers");
|
||||
|
||||
var res = await producerManager.GetProducerList();
|
||||
|
||||
var processedRes = res.Select(producer => new Model.Producer.Producer
|
||||
{
|
||||
Name = producer.Name,
|
||||
Email = producer.Email,
|
||||
PhoneNumber = producer.Phone,
|
||||
FirstLineAddress = producer.FiestLineAdress,
|
||||
SecondLineAddress = producer.SecondLineAdress,
|
||||
Claims = producer.Claims?.Select(q => q as ClaimBase).ToList(),
|
||||
}).ToList();
|
||||
|
||||
logger.LogInformation("Fetched {Count} producers", processedRes.Count);
|
||||
return Ok(processedRes);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
public async Task<IActionResult> DeleteProducerByName([FromBody] string name)
|
||||
{
|
||||
logger.LogInformation("Deleting producer with name: {Name}", name);
|
||||
|
||||
var res = await producerManager.DeleteProducerByName(name);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
logger.LogWarning("Failed to delete producer: {Name}", name);
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
logger.LogInformation("Deleted producer successfully: {Name}", name);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<int>> UpdateProducerClaim([FromBody] UpdateClaimRequest request)
|
||||
{
|
||||
logger.LogInformation("Updating claims for producer");
|
||||
|
||||
int result = 0;
|
||||
Producers? producers;
|
||||
|
||||
if (request.Id != null)
|
||||
{
|
||||
producers = await producerManager.FindProducerById(request.Id);
|
||||
}
|
||||
else if (request.Name != null)
|
||||
{
|
||||
producers = await producerManager.FindProducerByName(request.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning("Invalid request: both Id and Name are null");
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
if (producers == null)
|
||||
{
|
||||
logger.LogWarning("Producer not found during claim update");
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
foreach (var claim in request.ListOfUpdateClaim)
|
||||
{
|
||||
if (claim.ClaimType == null) continue;
|
||||
|
||||
if (claim.ClaimValue == null)
|
||||
{
|
||||
var resultOperation = await producerManager.DeleteClaim(producers, claim.ClaimType);
|
||||
|
||||
if (resultOperation.IsSuccess)
|
||||
{
|
||||
result++;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning("Failed to delete claim: {ClaimType}", claim.ClaimType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var resultOperation = await producerManager.UpdateClaim(producers,
|
||||
new Claim(claim.ClaimType, claim.ClaimValue, claim.ClaimIssuer));
|
||||
|
||||
if (resultOperation.IsSuccess)
|
||||
{
|
||||
result++;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning("Failed to update claim: {ClaimType}", claim.ClaimType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.LogInformation("Claims updated successfully. Total updated: {Count}", result);
|
||||
return result > 0 ? Ok(result) : BadRequest();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using OpenWarehouse.auth.lib.Model.Service;
|
||||
using OpenWarehouse.warehouse.api.Common.DefaultServiceAccountAndRole;
|
||||
using OpenWarehouse.warehouse.api.Common.ServiceClaims;
|
||||
using OpenWarehouse.warehouse.api.Model.Tool;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Controller;
|
||||
|
||||
[ApiController]
|
||||
[Route("[action]")]
|
||||
public class Tools(
|
||||
IConfiguration configuration,
|
||||
DefaultIdentify defaultIdentify,
|
||||
IServiceClaimsManager serviceClaimsManager) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public Task<ActionResult<PingModel>> Ping()
|
||||
{
|
||||
return Task.FromResult<ActionResult<PingModel>>(Ok(new PingModel()));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
public async Task<ActionResult<InitialziationResultModel>> InitServiceConnectionWithAuth()
|
||||
{
|
||||
Request.Headers.TryGetValue("Authorization", out var token);
|
||||
|
||||
|
||||
var result = await defaultIdentify.SeedAsync(token.ToString());
|
||||
|
||||
var testResult = false;
|
||||
|
||||
if (result.IsSuccess || result.UserAllereadyExist)
|
||||
{
|
||||
testResult = await defaultIdentify.TestAuth(result.ServiceToken ??
|
||||
throw new ArgumentNullException(
|
||||
$"Service {result.ServiceName} token is null"));
|
||||
if (testResult)
|
||||
{
|
||||
await serviceClaimsManager.UpdateClaim(ServiceClaim.ServiceAcoountToken, result.ServiceToken);
|
||||
await serviceClaimsManager.UpdateClaim(ServiceClaim.ServiceAcoountUsername, result.ServiceUsername ??
|
||||
throw new ArgumentNullException(
|
||||
$"Service {result.ServiceName} username is null"));
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(new InitialziationResultModel()
|
||||
{
|
||||
Success = result.IsSuccess,
|
||||
IsAlreadyInitialized = result.UserAllereadyExist,
|
||||
ServiceAccountName = result.ServiceName,
|
||||
TestAuthSuccess = testResult
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Data;
|
||||
|
||||
public class ApplicationDbContext: DbContext, IDataProtectionKeyContext
|
||||
{
|
||||
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
var itemInWarehouseClaims = modelBuilder.Entity<ItemInWarehouseClaims>();
|
||||
itemInWarehouseClaims.HasOne(e => e.Item)
|
||||
.WithMany(e => e.ItemInWarehouseClaims)
|
||||
.HasForeignKey(e => e.ItemId);
|
||||
itemInWarehouseClaims.HasIndex(ic => new { ic.ItemId, ic.ClaimType })
|
||||
.IsUnique();
|
||||
|
||||
var wrehouseClaims = modelBuilder.Entity<WarehouseClaims>();
|
||||
wrehouseClaims.HasOne(e => e.Warehouse)
|
||||
.WithMany(e => e.Claims)
|
||||
.HasForeignKey(e => e.WarehouseId);
|
||||
wrehouseClaims.HasIndex(ic => new { ic.WarehouseId, ic.ClaimType })
|
||||
.IsUnique();
|
||||
|
||||
var itemClaims = modelBuilder.Entity<ItemClaims>();
|
||||
itemClaims.HasIndex(ic => new { ic.ItemId, ic.ClaimType })
|
||||
.IsUnique();
|
||||
itemClaims.HasOne(ic => ic.Item)
|
||||
.WithMany(i => i.ItemClaims)
|
||||
.HasForeignKey(ic => ic.ItemId);
|
||||
|
||||
var itemTag = modelBuilder.Entity<ItemCategoryTag>();
|
||||
itemTag.HasOne(e => e.ParentTag)
|
||||
.WithMany(e => e.ListOfChildrenTag)
|
||||
.HasForeignKey(e => e.ParentTagId);
|
||||
itemTag.HasIndex(ic => new { ic.Name })
|
||||
.IsUnique();
|
||||
|
||||
var item = modelBuilder.Entity<Item>();
|
||||
item.HasOne(e => e.Producer)
|
||||
.WithMany(e => e.Items)
|
||||
.HasForeignKey(e => e.ProducerId)
|
||||
.IsRequired(true);
|
||||
item.HasIndex(ic => new { ic.Name, ic.ProducerId })
|
||||
.IsUnique();
|
||||
item.Navigation(ic => ic.ItemClaims)
|
||||
.UsePropertyAccessMode(PropertyAccessMode.Property);
|
||||
|
||||
var producers = modelBuilder.Entity<Producers>();
|
||||
producers.HasIndex(ic => new { ic.Name })
|
||||
.IsUnique();
|
||||
producers.Navigation(ic => ic.Claims)
|
||||
.UsePropertyAccessMode(PropertyAccessMode.Property);
|
||||
|
||||
var producerClaims = modelBuilder.Entity<ProducerClaims>();
|
||||
producerClaims.HasOne(e => e.Producer)
|
||||
.WithMany(e => e.Claims)
|
||||
.HasForeignKey(e => e.ProducerId);
|
||||
producerClaims.HasIndex(ic => new { ic.ProducerId, ic.ClaimType })
|
||||
.IsUnique();
|
||||
|
||||
modelBuilder.Entity<ServiceClaims>()
|
||||
.HasIndex(ic => ic.ClaimType)
|
||||
.IsUnique();
|
||||
|
||||
modelBuilder.Entity<ItemInWarehouse>()
|
||||
.Navigation(ic => ic.ItemInWarehouseClaims)
|
||||
.UsePropertyAccessMode(PropertyAccessMode.Property);
|
||||
|
||||
modelBuilder.Entity<Warehouse>()
|
||||
.Navigation(ic => ic.Claims)
|
||||
.UsePropertyAccessMode(PropertyAccessMode.Property);
|
||||
|
||||
}
|
||||
|
||||
public DbSet<Image> Images { get; init; }
|
||||
public DbSet<Item> Items { get; init; }
|
||||
public DbSet<ItemCategoryTag> ItemCategoryTags { get; init; }
|
||||
public DbSet<ItemClaims> ItemClaims { get; init; }
|
||||
public DbSet<ItemInWarehouse> ItemInWarehouses { get; init; }
|
||||
public DbSet<ItemInWarehouseClaims> ItemInWarehousesClaims { get; init; }
|
||||
public DbSet<Producers> Producers { get; init; }
|
||||
public DbSet<ProducerClaims> ProducerClaims { get; init; }
|
||||
public DbSet<Warehouse> Warehouses { get; init; }
|
||||
public DbSet<WarehouseClaims> WarehouseClaims { get; init; }
|
||||
public DbSet<ServiceClaims> ServiceClaims { get; init; }
|
||||
public DbSet<DataProtectionKey> DataProtectionKeys { get; init; }
|
||||
public DbSet<TaskStatusTable> TaskStatus { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Data;
|
||||
|
||||
public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
|
||||
|
||||
{
|
||||
public ApplicationDbContext CreateDbContext(string[] args)
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.SetBasePath(Directory.GetCurrentDirectory())
|
||||
.AddJsonFile("appsettings.json")
|
||||
.Build();
|
||||
|
||||
var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
|
||||
optionsBuilder.UseNpgsql(configuration.GetConnectionString("DefaultConnection"));
|
||||
|
||||
return new ApplicationDbContext(optionsBuilder.Options);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Claim = System.Security.Claims.Claim;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Data;
|
||||
|
||||
public class ClaimBase
|
||||
{
|
||||
[Required]
|
||||
public string? ClaimType { get; set; }
|
||||
[Required]
|
||||
public string? ClaimValue { get; set; }
|
||||
public string? ClaimIssuer { get; set; }
|
||||
|
||||
|
||||
[NotMapped]
|
||||
public Claim Claim {
|
||||
get
|
||||
{
|
||||
return new Claim(ClaimType ?? throw new Exception("Null exemption")
|
||||
, ClaimValue ?? throw new Exception("Null exemption")
|
||||
, ClaimIssuer ?? "Local");
|
||||
}
|
||||
set
|
||||
{
|
||||
ClaimType = value.Type;
|
||||
ClaimValue = value.Value;
|
||||
ClaimIssuer = value.Issuer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace OpenWarehouse.warehouse.api.Data;
|
||||
|
||||
public class Image
|
||||
{
|
||||
[Key]
|
||||
public Guid? Id { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace OpenWarehouse.warehouse.api.Data;
|
||||
|
||||
public class Item
|
||||
{
|
||||
[Key]
|
||||
public Guid? Id { get; set; }
|
||||
[Required, MaxLength(30), MinLength(4)]
|
||||
public string? Name { get; set; }
|
||||
public Image Image { get; set; }
|
||||
[Required]
|
||||
public Producers? Producer { get; set; }
|
||||
[Required]
|
||||
public Guid? ProducerId { get; set; }
|
||||
|
||||
public List<ItemCategoryTag>? ItemCategoryTags { get; set; }
|
||||
|
||||
public List<ItemClaims>? ItemClaims { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace OpenWarehouse.warehouse.api.Data;
|
||||
|
||||
public class ItemCategoryTag
|
||||
{
|
||||
[Key]
|
||||
public Guid Id { get; set; }
|
||||
[Required]
|
||||
[MinLength(4),MaxLength(30)]
|
||||
public string? Name { get; set; }
|
||||
|
||||
public ItemCategoryTag? ParentTag { get; set; }
|
||||
public Guid? ParentTagId { get; set; }
|
||||
|
||||
[DeleteBehavior(DeleteBehavior.Cascade)]
|
||||
public List<ItemCategoryTag>? ListOfChildrenTag { get; set; }
|
||||
|
||||
public List<Item>? Items { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Claim = System.Security.Claims.Claim;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Data;
|
||||
|
||||
public class ItemClaims() : ClaimBase
|
||||
{
|
||||
public ItemClaims(Item item, Claim claim) : this()
|
||||
{
|
||||
Item = item;
|
||||
ClaimType = claim.Type;
|
||||
ClaimValue = claim.Value;
|
||||
}
|
||||
[Key]
|
||||
public Guid Id { get; set; }
|
||||
[Required, MaxLength(30)]
|
||||
public Guid? ItemId { get; set; }
|
||||
public Item? Item { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace OpenWarehouse.warehouse.api.Data;
|
||||
|
||||
public class ItemInWarehouse()
|
||||
{
|
||||
public ItemInWarehouse(List<ItemInWarehouseClaims>? itemInWarehouses = null) : this()
|
||||
{
|
||||
if (itemInWarehouses != null)
|
||||
ItemInWarehouseClaims = itemInWarehouses;
|
||||
else
|
||||
ItemInWarehouseClaims = new List<ItemInWarehouseClaims>();
|
||||
}
|
||||
|
||||
public ItemInWarehouse(Item item, string positions, List<ItemInWarehouseClaims> itemInWarehouses) : this(itemInWarehouses)
|
||||
{
|
||||
Item = item;
|
||||
Positions = positions;
|
||||
ItemInWarehouseClaims = itemInWarehouses;
|
||||
}
|
||||
|
||||
[Key]
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
[Required]
|
||||
public Item? Item { get; set; }
|
||||
|
||||
[Required, MaxLength(30)]
|
||||
public string? Positions { get; set; }
|
||||
|
||||
[DeleteBehavior(DeleteBehavior.Cascade)]
|
||||
public List<ItemInWarehouseClaims>? ItemInWarehouseClaims { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace OpenWarehouse.warehouse.api.Data;
|
||||
|
||||
public class ItemInWarehouseClaims : ClaimBase
|
||||
{
|
||||
[Key]
|
||||
public Guid Id { get; set; }
|
||||
[Required]
|
||||
public Guid? ItemId { get; set; }
|
||||
public ItemInWarehouse? Item { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Claim = System.Security.Claims.Claim;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Data;
|
||||
|
||||
public class ProducerClaims() : ClaimBase
|
||||
{
|
||||
|
||||
public ProducerClaims(Producers producer, Claim claim) : this()
|
||||
{
|
||||
this.Producer = producer;
|
||||
ClaimType = claim.Type;
|
||||
ClaimValue = claim.Value;
|
||||
}
|
||||
|
||||
[Key]
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
[Required, MaxLength(100)]
|
||||
public Guid? ProducerId { get; set; }
|
||||
public Producers? Producer { get; set; }
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace OpenWarehouse.warehouse.api.Data;
|
||||
|
||||
public class Producers
|
||||
{
|
||||
[Key]
|
||||
public Guid? Id { get; set; }
|
||||
public Image? Image { get; set; }
|
||||
[Required, MaxLength(50)]
|
||||
public string? Name { get; set; }
|
||||
[Required, MaxLength(60)]
|
||||
public string? FiestLineAdress { get; set; }
|
||||
[MaxLength(60)]
|
||||
public string? SecondLineAdress { get; set; }
|
||||
[EmailAddress, MaxLength(40)]
|
||||
public string? Email { get; set; }
|
||||
[Phone, MaxLength(15)]
|
||||
public string? Phone { get; set; }
|
||||
|
||||
[DeleteBehavior(DeleteBehavior.SetNull)]
|
||||
public List<Item>? Items { get; set; }
|
||||
[DeleteBehavior(DeleteBehavior.Cascade)]
|
||||
public List<ProducerClaims>? Claims { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Claim = System.Security.Claims.Claim;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Data;
|
||||
|
||||
public class ServiceClaims
|
||||
{
|
||||
[Key, Required, MinLength(3), MaxLength(40)]
|
||||
public string? ClaimType { get; set; }
|
||||
[Required, MinLength(3), MaxLength(40)]
|
||||
public string? ClaimValue { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public Claim Claim
|
||||
{
|
||||
get =>
|
||||
new(ClaimType ??
|
||||
throw new InvalidOperationException(),
|
||||
ClaimValue ?? throw new InvalidOperationException());
|
||||
set
|
||||
{
|
||||
ClaimType = value.Type;
|
||||
ClaimValue = value.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace OpenWarehouse.warehouse.api.Data;
|
||||
|
||||
public class TaskStatusTable
|
||||
{
|
||||
[Required, Key]
|
||||
public Guid TaskId { get; init; }
|
||||
[MaxLength(50)]
|
||||
public string? Actor { get; init; }
|
||||
[MaxLength(20), Required]
|
||||
public string? Status { get; set; }
|
||||
[Required]
|
||||
public DateTime CreatedAt { get; init; }
|
||||
[Required]
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace OpenWarehouse.warehouse.api.Data;
|
||||
|
||||
[Index(nameof(Name), IsUnique = true)]
|
||||
public class Warehouse
|
||||
{
|
||||
[Key]
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
[Required, MinLength(4), MaxLength(30)]
|
||||
public string? Name { get; set; }
|
||||
[Required, MinLength(4), MaxLength(40)]
|
||||
public string? FiestLineAdress { get; set; }
|
||||
[MinLength(0), MaxLength(40)]
|
||||
public string? SecondLineAdress { get; set; }
|
||||
|
||||
public Image? Image { get; set; }
|
||||
[DeleteBehavior(DeleteBehavior.Cascade)]
|
||||
public List<WarehouseClaims>? Claims { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Claim = System.Security.Claims.Claim;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Data;
|
||||
|
||||
public class WarehouseClaims() : ClaimBase
|
||||
{
|
||||
public WarehouseClaims(Warehouse warehouse, Claim claim) : this()
|
||||
{
|
||||
Warehouse = warehouse;
|
||||
ClaimType = claim.Type;
|
||||
ClaimValue = claim.Value;
|
||||
ClaimIssuer = claim.Issuer;
|
||||
|
||||
}
|
||||
|
||||
public Claim GetClaim()
|
||||
{
|
||||
return new Claim(ClaimType ?? "Uknow", ClaimValue ?? "Uknow");
|
||||
}
|
||||
|
||||
[Key, MaxLength(100)]
|
||||
public Guid? Id { get; set; }
|
||||
[Required, MaxLength(100)]
|
||||
public Guid? WarehouseId { get; set; }
|
||||
public Warehouse? Warehouse { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||
USER $APP_UID
|
||||
WORKDIR /app
|
||||
EXPOSE 8080
|
||||
EXPOSE 8081
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
WORKDIR /src
|
||||
COPY ["OpenWarehouse.warehouse.api/OpenWarehouse.warehouse.api.csproj", "OpenWarehouse.warehouse.api/"]
|
||||
COPY ["OpenWarehouse.auth.lib/OpenWarehouse.auth.lib.csproj", "OpenWarehouse.auth.lib/"]
|
||||
COPY ["OpenWarehouse.Common.Lib/OpenWarehouse.Common.Lib.csproj", "OpenWarehouse.Common.Lib/"]
|
||||
COPY ["Kafka.Lib/Kafka.Lib.csproj", "Kafka.Lib/"]
|
||||
RUN dotnet restore "OpenWarehouse.warehouse.api/OpenWarehouse.warehouse.api.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/OpenWarehouse.warehouse.api"
|
||||
RUN dotnet build "OpenWarehouse.warehouse.api.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
RUN dotnet publish "OpenWarehouse.warehouse.api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "Openwarehouse.warehouse.api.dll"]
|
||||
@@ -0,0 +1,6 @@
|
||||
global using System.ComponentModel.DataAnnotations;
|
||||
global using System.Security.Claims;
|
||||
global using Microsoft.EntityFrameworkCore;
|
||||
global using OpenWarehouse.warehouse.api.Common.Item;
|
||||
global using OpenWarehouse.warehouse.api.Data;
|
||||
global using OpenWarehouse.warehouse.api.Model;
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace OpenWarehouse.warehouse.api.Model;
|
||||
|
||||
public class ActionResult
|
||||
{
|
||||
public ActionResult(bool isSuccess, Dictionary<string, string>? errors)
|
||||
{
|
||||
IsSuccess = isSuccess;
|
||||
Errors = errors;
|
||||
}
|
||||
|
||||
public ActionResult(bool isSuccess) : this(isSuccess, null)
|
||||
{
|
||||
|
||||
}
|
||||
public ActionResult() : this(true,null)
|
||||
{
|
||||
|
||||
}
|
||||
public bool IsSuccess { get; }
|
||||
public Dictionary<string, string>? Errors { get; }
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace OpenWarehouse.warehouse.api.Model.Item;
|
||||
|
||||
public class CreateItemRequest
|
||||
{
|
||||
public string? ItemName { get; set; }
|
||||
public string? ProducerName { get; set; }
|
||||
public List<string> Tags { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace OpenWarehouse.warehouse.api.Model.Item;
|
||||
|
||||
public class CreateItemRespond
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public Dictionary<string, string> Errors { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Model.Item;
|
||||
|
||||
public class CreateTagTreeRequest
|
||||
{
|
||||
public List<ItemCategoryTag>? ItemCategoryTagsList { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Model.Item;
|
||||
|
||||
public class CreateTagTreeRespond
|
||||
{
|
||||
public string? TaskId { get; set; }
|
||||
public bool? CreatedSuccess { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace OpenWarehouse.warehouse.api.Model.Item;
|
||||
|
||||
public class ItemCategoryTag()
|
||||
{
|
||||
public string? ParentName { get; set; }
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using NJsonSchema.Annotations;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Model.Item;
|
||||
|
||||
public class ClaimValueModel
|
||||
{
|
||||
public string? Value { get; set; }
|
||||
public string? Issuer { get; set; }
|
||||
}
|
||||
|
||||
public class ItemModel
|
||||
{
|
||||
[NotNull, MaxLength(30), Required]
|
||||
public string? Id { get; set; }
|
||||
|
||||
[NotNull, MaxLength(30), Required]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[NotNull, MaxLength(30), Required]
|
||||
public string? ProducerId { get; set; }
|
||||
|
||||
[NotNull, MaxLength(30), Required]
|
||||
public string? ProducerName { get; set; }
|
||||
|
||||
[Required]
|
||||
public Dictionary<string, ClaimValueModel>? Claims { get; set; }
|
||||
|
||||
[Required]
|
||||
public List<string>? CategoryTag { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace OpenWarehouse.warehouse.api.Model.Item;
|
||||
|
||||
public class TagTreeModel
|
||||
{
|
||||
public string? Name { get; init; }
|
||||
public List<TagTreeModel> Child { get; } = new();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace OpenWarehouse.warehouse.api.Model.Item;
|
||||
|
||||
public class UpdateItemClaimRequest
|
||||
{
|
||||
public string? ItemId { get; set; }
|
||||
|
||||
public List<ClaimBase> ListOfUpdatedClaims { get; set; } = new List<ClaimBase>();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace OpenWarehouse.warehouse.api.Model.Producer;
|
||||
|
||||
public class Producer
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
public string? FirstLineAddress { get; set; }
|
||||
public string? SecondLineAddress { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? PhoneNumber { get; set; }
|
||||
|
||||
public List<ClaimBase>? Claims { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace OpenWarehouse.warehouse.api.Model.Producer;
|
||||
|
||||
public class UpdateClaimRequest
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public string? Name { get; set; }
|
||||
|
||||
public List<ClaimBase> ListOfUpdateClaim { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using NJsonSchema.Annotations;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Model.Tool;
|
||||
|
||||
public class InitializationModel
|
||||
{
|
||||
[NotNull]
|
||||
public string? Login { get; set; }
|
||||
[NotNull]
|
||||
public string? Password { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Model.Tool;
|
||||
|
||||
public class InitialziationResultModel
|
||||
{
|
||||
[DefaultValue(false)]
|
||||
public bool IsAlreadyInitialized { get; set; }
|
||||
[DefaultValue(false)]
|
||||
public bool Success { get; set; }
|
||||
[DefaultValue(false)]
|
||||
public bool TestAuthSuccess { get; set; }
|
||||
public string? ServiceAccountName { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<UserSecretsId>5749d66d-04bd-461c-99cf-edd55df080e3</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Confluent.Kafka" Version="2.6.0" />
|
||||
<PackageReference Include="Confluent.SchemaRegistry" Version="2.6.0" />
|
||||
<PackageReference Include="MassTransit" Version="8.3.1" />
|
||||
<PackageReference Include="MassTransit.Kafka" Version="8.3.1" />
|
||||
<PackageReference Include="MassTransit.SqlTransport.PostgreSQL" Version="8.3.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="8.0.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.IdentityModel.Abstractions" Version="8.2.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.10" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="..\.dockerignore">
|
||||
<Link>.dockerignore</Link>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenWarehouse.auth.lib\OpenWarehouse.auth.lib.csproj" />
|
||||
<ProjectReference Include="..\OpenWarehouse.Common.Lib\OpenWarehouse.Common.Lib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Data\Migrations\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,4 @@
|
||||
@Openwarehouse.warehouse.api_HostAddress = http://localhost:5048
|
||||
|
||||
|
||||
###
|
||||
@@ -0,0 +1,161 @@
|
||||
using System.Text.Json;
|
||||
using MassTransit;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using OpenWarehouse.auth.lib;
|
||||
using OpenWarehouse.Common.Lib;
|
||||
using OpenWarehouse.warehouse.api.Common.DefaultServiceAccountAndRole;
|
||||
using OpenWarehouse.warehouse.api.Common.Inventory;
|
||||
using OpenWarehouse.warehouse.api.Common.ItemTagManager;
|
||||
using OpenWarehouse.warehouse.api.Common.Kafka;
|
||||
using OpenWarehouse.warehouse.api.Common.Kafka.TagTree;
|
||||
using OpenWarehouse.warehouse.api.Common.Producer;
|
||||
using OpenWarehouse.warehouse.api.Common.ServiceClaims;
|
||||
using OpenWarehouse.warehouse.api.Common.TaskManager;
|
||||
using OpenWarehouse.warehouse.api.Common.Warehouse;
|
||||
using OpenWarehouse.warehouse.api.Services;
|
||||
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
var logger = builder.GetBuildLogger();
|
||||
|
||||
var authUrl = builder.Configuration["Auth:Url"] ;
|
||||
|
||||
if (authUrl == null)
|
||||
{
|
||||
logger.LogCritical("Auth url not set!!");
|
||||
return;
|
||||
}
|
||||
|
||||
await builder.WaitForAut(authUrl, logger);
|
||||
|
||||
var kafkaConnectionString = builder.Configuration["Kafka"];
|
||||
if (string.IsNullOrEmpty(kafkaConnectionString))
|
||||
{
|
||||
logger.LogCritical("Kafka environment variable is not set");
|
||||
throw new ArgumentNullException($"Kafka environment variable is not set");
|
||||
}
|
||||
|
||||
var kafkaConfig = JsonSerializer.Deserialize<KafkaConfig>(kafkaConnectionString);
|
||||
if (kafkaConfig != null) builder.Services.AddSingleton(kafkaConfig);
|
||||
|
||||
await builder.AddAuthService(authUrl, logger);
|
||||
|
||||
|
||||
builder.Host
|
||||
.UseMassTransit((hostContext, configurator) =>
|
||||
{
|
||||
configurator.UsingInMemory();
|
||||
|
||||
configurator.AddRider(r =>
|
||||
{
|
||||
try
|
||||
{
|
||||
r.AddConsumer<TagTreeConsumer>();
|
||||
|
||||
r.AddProducer<TagTreeKafkaMessage>($"{kafkaConfig?.TopicRoot}-tag-tree");
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError("Error configuring Kafka producers: {Message}", e.Message);
|
||||
}
|
||||
|
||||
r.UsingKafka((context, cfg) =>
|
||||
{
|
||||
cfg.Host(kafkaConfig?.BootstrapServers);
|
||||
|
||||
cfg.TopicEndpoint<TagTreeKafkaMessage>($"{kafkaConfig?.TopicRoot}-tag-tree",
|
||||
"TagTreeCreate" , e =>
|
||||
{
|
||||
e.ConfigureConsumer<TagTreeConsumer>(context);
|
||||
});
|
||||
});
|
||||
});
|
||||
}).ConfigureServices(services =>
|
||||
{
|
||||
services.AddMassTransitHostedService();
|
||||
});
|
||||
|
||||
|
||||
var connectionString = Environment.GetEnvironmentVariable("ConnectionString")
|
||||
?? builder.Configuration.GetConnectionString("DefaultConnection")
|
||||
?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
|
||||
|
||||
builder.Services.AddDbContext<ApplicationDbContext>(options =>
|
||||
options.UseNpgsql(connectionString));
|
||||
|
||||
builder.Services.AddDataProtection()
|
||||
.PersistKeysToDbContext<ApplicationDbContext>();
|
||||
|
||||
|
||||
builder.Services.AddScoped<DefaultIdentify>();
|
||||
builder.Services.AddScoped<IServiceClaimsManager, ServiceClaimsManager>();
|
||||
builder.Services.AddScoped<IProducerManager, ProducerManager>();
|
||||
builder.Services.AddScoped<IWarehouseManager, WarehouseManager>();
|
||||
builder.Services.AddScoped<IItemManager, ItemManager>();
|
||||
builder.Services.AddScoped<IInventoryManger, InventoryManger>();
|
||||
builder.Services.AddScoped<ITaskManager, TaskManager>();
|
||||
builder.Services.AddScoped<IItemTagManager, ItemTagManager>();
|
||||
|
||||
builder.Services.AddControllers()
|
||||
.ConfigureApiBehaviorOptions(options =>
|
||||
{
|
||||
options.SuppressConsumesConstraintForFormFileParameters = true;
|
||||
options.SuppressInferBindingSourcesForParameters = true;
|
||||
options.SuppressModelStateInvalidFilter = true;
|
||||
options.SuppressMapClientErrors = true;
|
||||
});
|
||||
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
|
||||
builder.Services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
In = ParameterLocation.Header,
|
||||
Description = "Please insert JWT with Bearer into field",
|
||||
Name = "Authorization",
|
||||
Type = SecuritySchemeType.ApiKey,
|
||||
Scheme = "Bearer"
|
||||
});
|
||||
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
|
||||
{
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
}
|
||||
},
|
||||
Array.Empty<string>()
|
||||
}
|
||||
});
|
||||
|
||||
options.AddServer(new OpenApiServer()
|
||||
{
|
||||
Url = "/warehouse/"
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
|
||||
using var scope = app.Services.CreateScope();
|
||||
var services = scope.ServiceProvider;
|
||||
var context = services.GetRequiredService<ApplicationDbContext>();
|
||||
context.Database.Migrate();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseAuthentication();
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:49002",
|
||||
"sslPort": 44368
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "http://localhost:5048",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "https://localhost:7095;http://localhost:5048",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
using MassTransit;
|
||||
using OpenWarehouse.warehouse.api.Common.ItemTagManager;
|
||||
using OpenWarehouse.warehouse.api.Common.Kafka;
|
||||
using OpenWarehouse.warehouse.api.Common.Kafka.TagTree;
|
||||
using OpenWarehouse.warehouse.api.Common.TaskManager;
|
||||
using OpenWarehouse.warehouse.api.Model.Item;
|
||||
using ItemCategoryTag = OpenWarehouse.warehouse.api.Model.Item.ItemCategoryTag;
|
||||
using TaskStatus = OpenWarehouse.warehouse.api.Common.TaskManager.TaskStatus;
|
||||
|
||||
namespace OpenWarehouse.warehouse.api.Services;
|
||||
|
||||
public class TagTreeConsumer(ILogger<TagTreeConsumer> logger, ITaskManager taskManager
|
||||
,IItemTagManager itemTagManager) : IConsumer<TagTreeKafkaMessage>
|
||||
{
|
||||
public async Task Consume(ConsumeContext<TagTreeKafkaMessage> context)
|
||||
{
|
||||
logger.LogInformation("Received and processing Kafka Message: {Guid}", context.Message.Guid);
|
||||
|
||||
var status = TaskStatus.Processing;
|
||||
|
||||
try
|
||||
{
|
||||
await taskManager.UpdateTaskStatus(context.Message.Guid, status);
|
||||
|
||||
switch (context.Message.Action)
|
||||
{
|
||||
case Actions.Create:
|
||||
status = await Create(context.Message);
|
||||
break;
|
||||
case Actions.Delete:
|
||||
status = await Delete(context.Message.ItemCategoryTagsList);
|
||||
break;
|
||||
default:
|
||||
logger.LogWarning("Action not allowed in request: {Guid}", context.Message.Guid);
|
||||
status = TaskStatus.Error;
|
||||
break;
|
||||
}
|
||||
|
||||
await taskManager.UpdateTaskStatus(context.Message.Guid, status);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error occurred while processing Kafka message: {Guid}", context.Message.Guid);
|
||||
status = TaskStatus.Error;
|
||||
await taskManager.UpdateTaskStatus(context.Message.Guid, status);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<TaskStatus> Create(TagTreeKafkaMessage context)
|
||||
{
|
||||
try
|
||||
{
|
||||
var len = context.ItemCategoryTagsList.Count;
|
||||
var preProcessingData = context.ItemCategoryTagsList
|
||||
.Distinct()
|
||||
.ToList();
|
||||
var result = await itemTagManager.CreateTagTree(preProcessingData);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
logger.LogWarning("Failed to create tag tree for message: {Guid}", context.Guid);
|
||||
return TaskStatus.Error;
|
||||
}
|
||||
else if (result < len)
|
||||
{
|
||||
logger.LogInformation("Partial success in creating tag tree for message: {Guid}", context.Guid);
|
||||
return TaskStatus.NotFullSuccess;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogInformation("Successfully created tag tree for message: {Guid}", context.Guid);
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error occurred while creating tag tree for message: {Guid}", context.Guid);
|
||||
return TaskStatus.Error;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<TaskStatus> Delete(List<ItemCategoryTag> names)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await itemTagManager.DeleteTagsByNames(names);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
logger.LogWarning("Failed to delete tags for names: {Names}", names);
|
||||
return TaskStatus.Error;
|
||||
}
|
||||
else if (result < names.Count)
|
||||
{
|
||||
logger.LogInformation("Partial success in deleting tags for names: {Names}", names);
|
||||
return TaskStatus.NotFullSuccess;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogInformation("Successfully deleted tags for names: {Names}", names);
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error occurred while deleting tags for names: {Names}", names);
|
||||
return TaskStatus.Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user