Completato fix gestione inventario magazzino

This commit is contained in:
Samuele Locatelli
2024-01-17 15:17:32 +01:00
parent 8762421407
commit 4e50f4332e
26 changed files with 1018 additions and 1169 deletions
+3
View File
@@ -7,9 +7,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Blazored.LocalStorage" Version="4.4.0" />
<PackageReference Include="Blazored.SessionStorage" Version="2.4.0" />
<PackageReference Include="MailKit" Version="4.2.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageReference Include="NLog" Version="5.2.7" />
<PackageReference Include="StackExchange.Redis" Version="2.7.10" />
</ItemGroup>
</Project>
+610
View File
@@ -0,0 +1,610 @@
using Blazored.LocalStorage;
using Blazored.SessionStorage;
using NLog;
using StackExchange.Redis;
using System.Diagnostics;
namespace MagMan.Core.Services
{
public class MessageService
{
#region Public Constructors
public MessageService(ILocalStorageService genLocalStorage, ISessionStorageService sessStore, IConnectionMultiplexer RedConn)
{
// gestione sessioni in browser
localStore = genLocalStorage;
sessionStore = sessStore;
// setup componenti REDIS
redisConn = RedConn;
redisDb = redisConn.GetDatabase();
}
#endregion Public Constructors
#region Public Events
public event Action EA_FilterUpdated = null!;
public event Action EA_HideSearch = null!;
public event Action EA_PageUpdated = null!;
public event Action EA_SearchUpdated = null!;
public event Action EA_ShowSearch = null!;
#endregion Public Events
#if false
public SelectData DetailFilter
{
get => _detailFilter;
set
{
if (_detailFilter != value)
{
_detailFilter = value;
if (EA_FilterUpdated != null)
{
EA_FilterUpdated?.Invoke();
}
}
}
}
public SelectOrderData Order_Filter { get; set; } = SelectOrderData.Init(5, 30);
#endif
#region Public Properties
public string PageIcon
{
get => _pageIcon;
set
{
if (_pageIcon != value)
{
_pageIcon = value;
ReportPageUpd();
}
}
}
public string PageName
{
get => _pageName;
set
{
if (_pageName != value)
{
_pageName = value;
ReportPageUpd();
}
}
}
public string SearchVal
{
get => _searchVal;
set
{
if (_searchVal != value)
{
_searchVal = value;
if (EA_SearchUpdated != null)
{
EA_SearchUpdated?.Invoke();
}
}
}
}
public string SelOrderCode { get; set; } = "";
public string SelPlantId { get; set; } = "0";
public bool ShowSearch
{
get => _showSearch;
set
{
if (_showSearch != value)
{
_showSearch = value;
if (_showSearch)
{
if (EA_ShowSearch != null)
{
EA_ShowSearch?.Invoke();
}
}
else
{
if (EA_HideSearch != null)
{
EA_HideSearch?.Invoke();
}
}
}
}
}
#endregion Public Properties
#region Public Methods
/// <summary>
/// Recupera CustomerID dal dizionario dei token noti o cercando sul DB
/// </summary>
/// <param name="RestToken"></param>
/// <returns></returns>
public async Task<int> CustomerIdByToken(string RestToken)
{
string currKey = $"{Const.rKeyConfig}:Dict:Token2CustID";
int answ = await RedisHashGetInt(currKey, RestToken);
return answ;
}
/// <summary>
/// salvataggio in dizionario Redis associativo Token / Customer
/// </summary>
/// <param name="RestToken"></param>
/// <param name="CustId"></param>
/// <returns></returns>
public bool CustomerIdByTokenSet(string RestToken, int CustId)
{
string currKey = $"{Const.rKeyConfig}:Dict:Token2CustID";
bool fatto = RedisHashSet(currKey, RestToken, $"{CustId}");
return fatto;
}
/// <summary>
/// Recupera CustomerID dal dizionario dei token noti o cercando sul DB
/// </summary>
/// <param name="CustID"></param>
/// <returns></returns>
public async Task<int> MainKeyByCustomer(int CustID)
{
string currKey = $"{Const.rKeyConfig}:Dict:Cust2MKey";
int answ = await RedisHashGetInt(currKey, $"{CustID}");
return answ;
}
/// <summary>
/// salvataggio in dizionario Redis associativo Token / Customer
/// </summary>
/// <param name="RestToken"></param>
/// <param name="CustId"></param>
/// <returns></returns>
public bool MainKeyByCustomerSet(int CustId, int MainKey)
{
string currKey = $"{Const.rKeyConfig}:Dict:Cust2MKey";
bool fatto = RedisHashSet(currKey, $"{CustId}", $"{MainKey}");
return fatto;
}
/// <summary>
/// Recupera MainKey dal dizionario dei token noti o cercando sul DB
/// </summary>
/// <param name="RestToken"></param>
/// <returns></returns>
public async Task<int> MainKeyByToken(string RestToken)
{
string currKey = $"{Const.rKeyConfig}:Dict:Token2MKey";
int answ = await RedisHashGetInt(currKey, RestToken);
return answ;
}
/// <summary>
/// salvataggio in dizionario Redis associativo Token / Customer
/// </summary>
/// <param name="RestToken"></param>
/// <param name="CustId"></param>
/// <returns></returns>
public bool MainKeyByTokenSet(string RestToken, int CustId)
{
string currKey = $"{Const.rKeyConfig}:Dict:Token2MKey";
bool fatto = RedisHashSet(currKey, RestToken, $"{CustId}");
return fatto;
}
/// <summary>
/// Get single hash record
/// </summary>
/// <param name="currKey">Redis Key for Hashlist</param>
/// <param name="chiave">Requested key on list</param>
/// <returns>Value as Int</returns>
public async Task<int> RedisHashGetInt(RedisKey currKey, string chiave)
{
int result = 0;
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
var hasVal = await redisDb.HashExistsAsync(currKey, chiave);
if (hasVal)
{
var rawRes = await redisDb.HashGetAsync(currKey, chiave);
if (rawRes.HasValue)
{
int.TryParse($"{rawRes}", out result);
}
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"RedisHashGetInt | {currKey} | in: {ts.TotalMilliseconds} ms");
return result;
}
/// <summary>
/// Get single hash record
/// </summary>
/// <param name="currKey">Redis Key for Hashlist</param>
/// <param name="chiave">Requested key on list</param>
/// <returns>Value as string</returns>
public async Task<string> RedisHashGetString(RedisKey currKey, string chiave)
{
string result = "";
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
var hasVal = await redisDb.HashExistsAsync(currKey, chiave);
if (hasVal)
{
var rawRes = await redisDb.HashGetAsync(currKey, chiave);
if (rawRes.HasValue)
{
result = $"{rawRes}";
}
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"RedisHashGetString | {currKey} | in: {ts.TotalMilliseconds} ms");
return result;
}
/// <summary>
/// Remove for single hash record
/// </summary>
/// <param name="currKey">Chiave redis della Hashlist</param>
/// <param name="chiave">Chiave nella HashList</param>
/// <returns>Esito rimozione</returns>
public async Task<bool> RedisHashRemove(RedisKey currKey, string chiave)
{
bool fatto = false;
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
fatto = await redisDb.HashDeleteAsync(currKey, chiave);
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"RedisHashRemove | {currKey} | in: {ts.TotalMilliseconds} ms");
return fatto;
}
/// <summary>
/// Resetta 1:1 i dizionari Hash in Redis
/// </summary>
/// <returns></returns>
public bool ResetHashDict()
{
bool fatto = false;
string baseKey = $"{Const.rKeyConfig}:Dict";
try
{
// salvo!
RedisHashDictSet($"{baseKey}:Token2CustID", new Dictionary<string, string>());
RedisHashDictSet($"{baseKey}:Token2MKey", new Dictionary<string, string>());
RedisHashDictSet($"{baseKey}:Cust2MKey", new Dictionary<string, string>());
fatto = true;
}
catch (Exception exc)
{
Log.Error($"Eccezione in ResetHashDict{Environment.NewLine}{exc}");
}
return fatto;
}
/// <summary>
/// Svuota localstorage (clear)
/// </summary>
/// <returns></returns>
public async Task<bool> StoreLocalClear()
{
bool answ = false;
try
{
await localStore.ClearAsync();
answ = true;
}
catch (Exception ex)
{
Log.Error($"Eccezione in StoreLocalClear{Environment.NewLine}{ex}");
}
return answ;
}
/// <summary>
/// Restituisce il valore richiesto da localstorage
/// </summary>
/// <param name="sKey">Chiave</param>
/// <returns></returns>
public async Task<string> StoreLocalGet(string sKey)
{
string answ = "";
var result = await localStore.GetItemAsync<string>(sKey);
if (result != null)
{
answ = result;
}
return answ;
}
/// <summary>
/// Scrive il valore nel localstorage
/// </summary>
/// <param name="sKey">Chiave</param>
/// <param name="sVal">Valore associato</param>
/// <returns></returns>
public async Task<bool> StoreLocalSet(string sKey, string sVal)
{
bool answ = false;
try
{
await localStore.SetItemAsStringAsync(sKey, sVal);
answ = true;
}
catch (Exception ex)
{
Log.Error($"Eccezione in StoreLocalSet{Environment.NewLine}{ex}");
}
return answ;
}
/// <summary>
/// Svuota sessionstorage (clear)
/// </summary>
/// <returns></returns>
public async Task<bool> StoreSessClear()
{
bool answ = false;
try
{
await sessionStore.ClearAsync();
answ = true;
}
catch (Exception ex)
{
Log.Error($"Eccezione in StoreLocalClear{Environment.NewLine}{ex}");
}
return answ;
}
/// <summary>
/// Restituisce il valore richiesto da sessionstorage
/// </summary>
/// <param name="sKey">Chiave</param>
/// <returns></returns>
public async Task<string> StoreSessGet(string sKey)
{
string answ = "";
var result = await sessionStore.GetItemAsync<string>(sKey);
if (result != null)
{
answ = result;
}
return answ;
}
/// <summary>
/// Scrive il valore nel sessionstorage (tab)
/// </summary>
/// <param name="sKey">Chiave</param>
/// <param name="sVal">Valore associato</param>
/// <returns></returns>
public async Task<bool> StoreSessSet(string sKey, string sVal)
{
bool answ = false;
try
{
await sessionStore.SetItemAsStringAsync(sKey, sVal);
answ = true;
}
catch (Exception ex)
{
Log.Error($"Eccezione in StoreSessSet{Environment.NewLine}{ex}");
}
return answ;
}
#endregion Public Methods
#region Protected Fields
/// <summary>
/// Oggetto per connessione a REDIS
/// </summary>
protected IConnectionMultiplexer redisConn = null!;
/// <summary>
/// Oggetto DB redis da impiegare x chiamate R/W
/// </summary>
protected IDatabase redisDb = null!;
#endregion Protected Fields
#region Protected Properties
protected ILocalStorageService localStore { get; set; } = null!;
protected ISessionStorageService sessionStore { get; set; } = null!;
#endregion Protected Properties
#region Protected Methods
/// <summary>
/// Effettua upsert in HasList redis
/// </summary>
/// <param name="currKey">Chiave redis della Hashlist</param>
/// <param name="chiave">Chiave nella HashList</param>
/// <param name="valore">Valore da salvare</param>
/// <returns>Num record nella HashList</returns>
protected async Task<long> RedisHashUpsert(RedisKey currKey, string chiave, string valore)
{
long numReq = 0;
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
await redisDb.HashSetAsync(currKey, chiave, valore);
numReq = await redisDb.HashLengthAsync(currKey);
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"RedisHashUpsert | {currKey} | in: {ts.TotalMilliseconds} ms");
return numReq;
}
#endregion Protected Methods
#if false
private SelectData _detailFilter = SelectData.Init(5, 15);
#endif
#region Private Fields
private string _pageIcon = "";
private string _pageName = "";
private string _searchVal = "";
private bool _showSearch = false;
private Logger Log = LogManager.GetCurrentClassLogger();
#endregion Private Fields
#region Private Methods
/// <summary>
/// Recupero HashSet redis come Dictionary
/// </summary>
/// <param name="currKey"></param>
/// <param name="dict"></param>
private Dictionary<string, string> RedisHashDictGet(RedisKey currKey)
{
Dictionary<string, string> answ = new Dictionary<string, string>();
try
{
answ = redisDb
.HashGetAll(currKey)
.ToDictionary(x => $"{x.Name}", x => $"{x.Value}");
}
catch (Exception exc)
{
Log.Info($"Errore RedisHashDictGet | currKey: {currKey}{Environment.NewLine}{exc}");
}
return answ;
}
/// <summary>
/// Salvataggio Dictionary come HashSet Redis
/// </summary>
/// <param name="currKey"></param>
/// <param name="dict"></param>
private bool RedisHashDictSet(RedisKey currKey, Dictionary<string, string> dict)
{
bool fatto = false;
try
{
HashEntry[] data2ins = new HashEntry[dict.Count];
int i = 0;
foreach (KeyValuePair<string, string> kvp in dict)
{
data2ins[i] = new HashEntry(kvp.Key, kvp.Value);
i++;
}
// salvo!
redisDb.HashSet(currKey, data2ins);
fatto = true;
}
catch (Exception exc)
{
Log.Error($"Eccezione in RedisHashDictSet | currKey: {currKey}{Environment.NewLine}{exc}");
}
return fatto;
}
/// <summary>
/// Salvataggio Dictionary come HashSet Redis
/// </summary>
/// <param name="currKey"></param>
/// <param name="dict"></param>
/// <param name="ttl"></param>
private bool RedisHashDictSet(RedisKey currKey, Dictionary<string, string> dict, TimeSpan ttl)
{
bool fatto = false;
try
{
HashEntry[] data2ins = new HashEntry[dict.Count];
int i = 0;
foreach (KeyValuePair<string, string> kvp in dict)
{
data2ins[i] = new HashEntry(kvp.Key, kvp.Value);
i++;
}
// salvo!
redisDb.HashSet(currKey, data2ins);
redisDb.KeyExpire(currKey, ttl);
fatto = true;
}
catch (Exception exc)
{
Log.Error($"Eccezione in RedisHashDictSet(+TTL) | currKey: {currKey} | ttl: {ttl}{Environment.NewLine}{exc}");
}
return fatto;
}
/// <summary>
/// Aggiunta KVP in HashSet Redis
/// </summary>
/// <param name="currKey"></param>
/// <param name="dict"></param>
private bool RedisHashSet(RedisKey currKey, string hashField, string value)
{
bool fatto = false;
try
{
// salvo!
redisDb.HashSet(currKey, hashField, value);
fatto = true;
}
catch (Exception exc)
{
Log.Error($"Eccezione in RedisHashSet | currKey: {currKey}{Environment.NewLine}{exc}");
}
return fatto;
}
private void ReportPageUpd()
{
if (EA_PageUpdated != null)
{
EA_PageUpdated?.Invoke();
}
}
private void ReportSearch()
{
if (EA_SearchUpdated != null)
{
EA_SearchUpdated?.Invoke();
}
}
#endregion Private Methods
#if false
/// <summary>
/// Dizionario totale preferenze utente
/// </summary>
public Dictionary<string, string> UsersPrefDict
{
get => RedisHashDictGet((RedisKey)$"{redisBaseKey}:{MatrOpr}");
set => RedisHashDictSet((RedisKey)$"{redisBaseKey}:{MatrOpr}", value);
}
#endif
}
}
+75 -77
View File
@@ -1,4 +1,5 @@
using MagMan.Core;
using MagMan.Core.Services;
using MagMan.Data.Admin.Controllers;
using MagMan.Data.Admin.DbModels;
using Microsoft.AspNetCore.Identity.UI.Services;
@@ -14,12 +15,6 @@ namespace MagMan.Data.Admin.Services
{
public class MTAdminService : BaseServ
{
#region Public Fields
public static MTAdminController dbController = null!;
#endregion Public Fields
#region Public Constructors
public MTAdminService(IConfiguration configuration, IConnectionMultiplexer redisConnMult, IEmailSender emailSender)
@@ -238,6 +233,34 @@ namespace MagMan.Data.Admin.Services
return dbResult;
}
/// <summary>
/// Recupera CustomerID dal dizionario dei token noti o cercando sul DB
/// </summary>
/// <param name="RestToken"></param>
/// <returns></returns>
public async Task<int> CustomerIdByToken(string RestToken)
{
int answ = -1;
if (TokenCustList.ContainsKey(RestToken))
{
answ = TokenCustList[RestToken];
}
else
{
// cerco nel DB
var custList = await CustomerGetAll();
var custRow = custList.FirstOrDefault(x => x.RestToken == RestToken);
// se trovato salvo
if (custRow != null)
{
answ = custRow.CustomerID;
TokenCustList.Add(RestToken, answ);
Log.Info($"TokenCustList: added {RestToken} --> {answ}");
}
}
return answ;
}
/// <summary>
/// Update record customer + refresh cache
/// </summary>
@@ -395,64 +418,6 @@ namespace MagMan.Data.Admin.Services
return fatto;
}
#endregion Public Methods
#region Protected Methods
/// <summary>
/// Recupera CustomerID dal dizionario dei token noti o cercando sul DB
/// </summary>
/// <param name="RestToken"></param>
/// <returns></returns>
public async Task<int> CustomerIdByToken(string RestToken)
{
int answ = -1;
if (TokenCustList.ContainsKey(RestToken))
{
answ = TokenCustList[RestToken];
}
else
{
// cerco nel DB
var custList = await CustomerGetAll();
var custRow = custList.FirstOrDefault(x => x.RestToken == RestToken);
// se trovato salvo
if (custRow != null)
{
answ = custRow.CustomerID;
TokenCustList.Add(RestToken, answ);
Log.Info($"TokenCustList: added {RestToken} --> {answ}");
}
}
return answ;
}
/// <summary>
/// Recupera MainKey dal dizionario dei token noti o cercando sul DB
/// </summary>
/// <param name="RestToken"></param>
/// <returns></returns>
public async Task<int> MainKeyByToken(string RestToken)
{
int answ = -1;
if (TokenMKeyList.ContainsKey(RestToken))
{
answ = TokenMKeyList[RestToken];
}
else
{
// cerco nel DB
var custList = await CustomerGetAll();
var custRow = custList.FirstOrDefault(x => x.RestToken == RestToken);
// se trovato salvo
if (custRow != null)
{
answ = custRow.MainKey;
TokenMKeyList.Add(RestToken, answ);
Log.Info($"TokenMKeyList: added {RestToken} --> {answ}");
}
}
return answ;
}
/// <summary>
/// Recupera CustomerID dal dizionario dei token noti o cercando sul DB
/// </summary>
@@ -481,11 +446,44 @@ namespace MagMan.Data.Admin.Services
return answ;
}
#endregion Protected Methods
/// <summary>
/// Recupera MainKey dal dizionario dei token noti o cercando sul DB
/// </summary>
/// <param name="RestToken"></param>
/// <returns></returns>
public async Task<int> MainKeyByToken(string RestToken)
{
int answ = -1;
if (TokenMKeyList.ContainsKey(RestToken))
{
answ = TokenMKeyList[RestToken];
}
else
{
// cerco nel DB
var custList = await CustomerGetAll();
var custRow = custList.FirstOrDefault(x => x.RestToken == RestToken);
// se trovato salvo
if (custRow != null)
{
answ = custRow.MainKey;
TokenMKeyList.Add(RestToken, answ);
Log.Info($"TokenMKeyList: added {RestToken} --> {answ}");
}
}
return answ;
}
#endregion Public Methods
#region Protected Fields
protected static MTAdminController dbController = null!;
#endregion Protected Fields
#region Private Fields
private static JsonSerializerSettings? JSSettings;
private static Logger Log = LogManager.GetCurrentClassLogger();
@@ -522,22 +520,22 @@ namespace MagMan.Data.Admin.Services
#region Private Properties
/// <summary>
/// Dizionario dei token 2 customer
/// </summary>
private Dictionary<string, int> TokenCustList { get; set; } = new Dictionary<string, int>();
/// <summary>
/// Dizionario dei token 2 MainKey (x calcolo DB)
/// </summary>
private Dictionary<string, int> TokenMKeyList { get; set; } = new Dictionary<string, int>();
/// <summary>
/// Dizionario customer 2 MainKey (x calcolo DB)
/// Dizionario customer 2 MainKey (x calcolo DB)
/// </summary>
private Dictionary<int, int> CustMKeyList { get; set; } = new Dictionary<int, int>();
/// <summary>
/// Dizionario dei token 2 customer
/// </summary>
private Dictionary<string, int> TokenCustList { get; set; } = new Dictionary<string, int>();
/// <summary>
/// Dizionario dei token 2 MainKey (x calcolo DB)
/// </summary>
private Dictionary<string, int> TokenMKeyList { get; set; } = new Dictionary<string, int>();
#endregion Private Properties
#region Private Methods
/// <summary>
@@ -203,18 +203,69 @@ namespace MagMan.Data.Tenant.Controllers
/// </summary>
/// <param name="connString">Stringa connessione (variabile x cliente)</param>
/// <returns></returns>
public List<MaterialModel> MaterialGetAll(string connString)
public List<MaterialModel> MaterialGetAll(string connString, bool withChild)
{
List<MaterialModel> dbResult = new List<MaterialModel>();
using (MagManContext dbCtx = new MagManContext(connString))
{
dbResult = dbCtx
.DbSetMaterials
.OrderBy(x => x.MatDesc)
.ThenBy(x => x.WMm)
.ThenBy(x => x.TMm)
.ThenBy(x => x.LMm)
.ToList();
if (withChild)
{
dbResult = dbCtx
.DbSetMaterials
.Include(x => x.ItemNav)
.OrderBy(x => x.MatDesc)
.ThenBy(x => x.WMm)
.ThenBy(x => x.TMm)
.ThenBy(x => x.LMm)
.ToList();
}
else
{
dbResult = dbCtx
.DbSetMaterials
.OrderBy(x => x.MatDesc)
.ThenBy(x => x.WMm)
.ThenBy(x => x.TMm)
.ThenBy(x => x.LMm)
.ToList();
}
}
return dbResult;
} /// <summary>
/// Elenco Materiali gestiti a magazzino
/// </summary>
/// <param name="connString">Stringa connessione (variabile x cliente)</param>
/// <param name="matID">Materiale richiesto</param>
/// <param name="withChild">Se true allora include record child (Items)</param>
/// <returns></returns>
public List<MaterialModel> MaterialGetFilt(string connString, int matID, bool withChild)
{
List<MaterialModel> dbResult = new List<MaterialModel>();
using (MagManContext dbCtx = new MagManContext(connString))
{
if (withChild)
{
dbResult = dbCtx
.DbSetMaterials
.Where(x=> x.MatID == matID)
.Include(x => x.ItemNav)
.OrderBy(x => x.MatDesc)
.ThenBy(x => x.WMm)
.ThenBy(x => x.TMm)
.ThenBy(x => x.LMm)
.ToList();
}
else
{
dbResult = dbCtx
.DbSetMaterials
.Where(x => x.MatID == matID)
.OrderBy(x => x.MatDesc)
.ThenBy(x => x.WMm)
.ThenBy(x => x.TMm)
.ThenBy(x => x.LMm)
.ToList();
}
}
return dbResult;
}
@@ -234,7 +285,7 @@ namespace MagMan.Data.Tenant.Controllers
{
var currData = dbCtx
.DbSetMaterials
.Where(x => x.MatID == rec2upd.MatID || x.MatExtCode==rec2upd.MatExtCode)
.Where(x => x.MatID == rec2upd.MatID || x.MatExtCode == rec2upd.MatExtCode)
.FirstOrDefault();
if (currData != null)
{
@@ -12,6 +12,10 @@
<None Remove="Migrations\UserIdentityDb\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Services\MessageService.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Blazored.LocalStorage" Version="4.4.0" />
<PackageReference Include="Blazored.SessionStorage" Version="2.4.0" />
@@ -1,311 +0,0 @@
// <auto-generated />
using System;
using MagMan.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace MagMan.Data.Migrations.UserIdentityDb
{
[DbContext(typeof(UserIdentityDbContext))]
[Migration("20231222165912_CreateIdentitySchema")]
partial class CreateIdentitySchema
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "6.0.25")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("MagMan.Data.DbModels.TableCount", b =>
{
b.Property<int>("Count")
.HasColumnType("int");
b.Property<string>("TableName")
.IsRequired()
.HasColumnType("longtext");
b.ToTable("DbSetCounts");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("varchar(255)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("longtext");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
b.HasData(
new
{
Id = "eebed9c1-7433-4716-a62f-df9829dc0f09",
ConcurrencyStamp = "4a1affe9-543f-4165-816a-2ed6d3f06c77",
Name = "Undef",
NormalizedName = "UNDEF"
},
new
{
Id = "ca44b425-5c7e-4812-a28a-047ec6aa2e68",
ConcurrencyStamp = "a1357889-6a23-49cb-9d33-6bc5ef6eb4e6",
Name = "User",
NormalizedName = "USER"
},
new
{
Id = "86a8f484-ca14-4e4d-a786-3eba35da6e06",
ConcurrencyStamp = "9dd579c3-bdfa-4c44-b6ca-6dd10d34debb",
Name = "Admin",
NormalizedName = "ADMIN"
},
new
{
Id = "f5bd74e5-df26-4c52-963e-2d87e858c4d6",
ConcurrencyStamp = "1d620875-05b0-490d-91d5-6f21a83844f1",
Name = "SuperAdmin",
NormalizedName = "SUPERADMIN"
});
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ClaimType")
.HasColumnType("longtext");
b.Property<string>("ClaimValue")
.HasColumnType("longtext");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("varchar(255)");
b.Property<int>("AccessFailedCount")
.HasColumnType("int");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("longtext");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("tinyint(1)");
b.Property<bool>("LockoutEnabled")
.HasColumnType("tinyint(1)");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("datetime(6)");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("PasswordHash")
.HasColumnType("longtext");
b.Property<string>("PhoneNumber")
.HasColumnType("longtext");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("tinyint(1)");
b.Property<string>("SecurityStamp")
.HasColumnType("longtext");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("tinyint(1)");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ClaimType")
.HasColumnType("longtext");
b.Property<string>("ClaimValue")
.HasColumnType("longtext");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("varchar(255)");
b.Property<string>("ProviderKey")
.HasColumnType("varchar(255)");
b.Property<string>("ProviderDisplayName")
.HasColumnType("longtext");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("varchar(255)");
b.Property<string>("RoleId")
.HasColumnType("varchar(255)");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("varchar(255)");
b.Property<string>("LoginProvider")
.HasColumnType("varchar(255)");
b.Property<string>("Name")
.HasColumnType("varchar(255)");
b.Property<string>("Value")
.HasColumnType("longtext");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}
@@ -1,286 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MagMan.Data.Migrations.UserIdentityDb
{
public partial class CreateIdentitySchema : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterDatabase()
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "AspNetRoles",
columns: table => new
{
Id = table.Column<string>(type: "varchar(255)", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Name = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
NormalizedName = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
ConcurrencyStamp = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<string>(type: "varchar(255)", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
UserName = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
NormalizedUserName = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
Email = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
NormalizedEmail = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
EmailConfirmed = table.Column<bool>(type: "tinyint(1)", nullable: false),
PasswordHash = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
SecurityStamp = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
ConcurrencyStamp = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
PhoneNumber = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
PhoneNumberConfirmed = table.Column<bool>(type: "tinyint(1)", nullable: false),
TwoFactorEnabled = table.Column<bool>(type: "tinyint(1)", nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(type: "datetime(6)", nullable: true),
LockoutEnabled = table.Column<bool>(type: "tinyint(1)", nullable: false),
AccessFailedCount = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "DbSetCounts",
columns: table => new
{
Count = table.Column<int>(type: "int", nullable: false),
TableName = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
RoleId = table.Column<string>(type: "varchar(255)", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ClaimType = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
ClaimValue = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
UserId = table.Column<string>(type: "varchar(255)", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ClaimType = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
ClaimValue = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "varchar(255)", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ProviderKey = table.Column<string>(type: "varchar(255)", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ProviderDisplayName = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
UserId = table.Column<string>(type: "varchar(255)", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<string>(type: "varchar(255)", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
RoleId = table.Column<string>(type: "varchar(255)", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<string>(type: "varchar(255)", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
LoginProvider = table.Column<string>(type: "varchar(255)", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Name = table.Column<string>(type: "varchar(255)", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Value = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.InsertData(
table: "AspNetRoles",
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,]
{
{ "86a8f484-ca14-4e4d-a786-3eba35da6e06", "9dd579c3-bdfa-4c44-b6ca-6dd10d34debb", "Admin", "ADMIN" },
{ "ca44b425-5c7e-4812-a28a-047ec6aa2e68", "a1357889-6a23-49cb-9d33-6bc5ef6eb4e6", "User", "USER" },
{ "eebed9c1-7433-4716-a62f-df9829dc0f09", "4a1affe9-543f-4165-816a-2ed6d3f06c77", "Undef", "UNDEF" },
{ "f5bd74e5-df26-4c52-963e-2d87e858c4d6", "1d620875-05b0-490d-91d5-6f21a83844f1", "SuperAdmin", "SUPERADMIN" }
});
migrationBuilder.CreateIndex(
name: "IX_AspNetRoleClaims_RoleId",
table: "AspNetRoleClaims",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "AspNetRoles",
column: "NormalizedName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserRoles_RoleId",
table: "AspNetUserRoles",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AspNetRoleClaims");
migrationBuilder.DropTable(
name: "AspNetUserClaims");
migrationBuilder.DropTable(
name: "AspNetUserLogins");
migrationBuilder.DropTable(
name: "AspNetUserRoles");
migrationBuilder.DropTable(
name: "AspNetUserTokens");
migrationBuilder.DropTable(
name: "DbSetCounts");
migrationBuilder.DropTable(
name: "AspNetRoles");
migrationBuilder.DropTable(
name: "AspNetUsers");
}
}
}
@@ -1,309 +0,0 @@
// <auto-generated />
using System;
using MagMan.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace MagMan.Data.Migrations.UserIdentityDb
{
[DbContext(typeof(UserIdentityDbContext))]
partial class UserIdentityDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "6.0.25")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("MagMan.Data.DbModels.TableCount", b =>
{
b.Property<int>("Count")
.HasColumnType("int");
b.Property<string>("TableName")
.IsRequired()
.HasColumnType("longtext");
b.ToTable("DbSetCounts");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("varchar(255)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("longtext");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
b.HasData(
new
{
Id = "eebed9c1-7433-4716-a62f-df9829dc0f09",
ConcurrencyStamp = "4a1affe9-543f-4165-816a-2ed6d3f06c77",
Name = "Undef",
NormalizedName = "UNDEF"
},
new
{
Id = "ca44b425-5c7e-4812-a28a-047ec6aa2e68",
ConcurrencyStamp = "a1357889-6a23-49cb-9d33-6bc5ef6eb4e6",
Name = "User",
NormalizedName = "USER"
},
new
{
Id = "86a8f484-ca14-4e4d-a786-3eba35da6e06",
ConcurrencyStamp = "9dd579c3-bdfa-4c44-b6ca-6dd10d34debb",
Name = "Admin",
NormalizedName = "ADMIN"
},
new
{
Id = "f5bd74e5-df26-4c52-963e-2d87e858c4d6",
ConcurrencyStamp = "1d620875-05b0-490d-91d5-6f21a83844f1",
Name = "SuperAdmin",
NormalizedName = "SUPERADMIN"
});
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ClaimType")
.HasColumnType("longtext");
b.Property<string>("ClaimValue")
.HasColumnType("longtext");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("varchar(255)");
b.Property<int>("AccessFailedCount")
.HasColumnType("int");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("longtext");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("tinyint(1)");
b.Property<bool>("LockoutEnabled")
.HasColumnType("tinyint(1)");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("datetime(6)");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("PasswordHash")
.HasColumnType("longtext");
b.Property<string>("PhoneNumber")
.HasColumnType("longtext");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("tinyint(1)");
b.Property<string>("SecurityStamp")
.HasColumnType("longtext");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("tinyint(1)");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ClaimType")
.HasColumnType("longtext");
b.Property<string>("ClaimValue")
.HasColumnType("longtext");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("varchar(255)");
b.Property<string>("ProviderKey")
.HasColumnType("varchar(255)");
b.Property<string>("ProviderDisplayName")
.HasColumnType("longtext");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("varchar(255)");
b.Property<string>("RoleId")
.HasColumnType("varchar(255)");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("varchar(255)");
b.Property<string>("LoginProvider")
.HasColumnType("varchar(255)");
b.Property<string>("Name")
.HasColumnType("varchar(255)");
b.Property<string>("Value")
.HasColumnType("longtext");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}
@@ -311,7 +311,6 @@ namespace MagMan.Data.Tenant.Services
}
return answ;
}
private string redisBaseKey = "MagMan";
/// <summary>
/// Oggetto per connessione a REDIS
/// </summary>
+115 -50
View File
@@ -79,6 +79,28 @@ namespace MagMan.Data.Tenant.Services
return fatto;
}
/// <summary>
/// Converte il DTO in ItemModel
/// </summary>
/// <param name="origItem"></param>
/// <returns></returns>
public ItemModel ItemFromDto(ItemDTO origItem)
{
ItemModel answ = new ItemModel()
{
MatID = origItem.MatID,
Note = origItem.Note,
LMm = origItem.LMm,
WMm = origItem.WMm,
TMm = origItem.TMm,
IsRemn = origItem.IsRemn,
Location = origItem.Location,
QtyAvail = origItem.QtyAvail
};
return answ;
}
/// <summary>
/// Lista Items gestiti a magazzino
/// </summary>
@@ -91,7 +113,7 @@ namespace MagMan.Data.Tenant.Services
List<ItemModel>? dbResult = new List<ItemModel>();
try
{
string currKey = $"{Const.rKeyConfig}:{nKey}:ItemList";
string currKey = $"{Const.rKeyConfig}:ItemList:{nKey}";
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string? rawData = await redisDb.StringGetAsync(currKey);
@@ -230,19 +252,40 @@ namespace MagMan.Data.Tenant.Services
return fatto;
}
/// <summary>
/// Converte il DTO in MaterialModel
/// </summary>
/// <param name="origItem"></param>
/// <returns></returns>
public MaterialModel MaterialFromDto(MaterialDTO origItem)
{
MaterialModel answ = new MaterialModel()
{
MatExtCode = origItem.MatExtCode,
MatDesc = origItem.MatDesc,
LMm = origItem.LMm,
WMm = origItem.WMm,
TMm = origItem.TMm
};
return answ;
}
/// <summary>
/// Lista Materiali gestiti a magazzino
/// </summary>
/// <param name="nKey">Key di riferimento</param>
/// <param name="withChild">Se true allora include record child (Items)</param>
/// <returns></returns>
public async Task<List<MaterialModel>> MaterialGetAll(int nKey)
public async Task<List<MaterialModel>> MaterialGetAll(int nKey, bool withChild)
{
string source = "DB";
string cString = ConnString(nKey);
List<MaterialModel>? dbResult = new List<MaterialModel>();
try
{
string currKey = $"{Const.rKeyConfig}:{nKey}:Materials";
string dType = withChild ? "MaterialsFull" : "Materials";
string currKey = $"{Const.rKeyConfig}:{dType}:{nKey}";
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string? rawData = await redisDb.StringGetAsync(currKey);
@@ -261,9 +304,15 @@ namespace MagMan.Data.Tenant.Services
}
else
{
dbResult = dbController.MaterialGetAll(cString);
dbResult = dbController.MaterialGetAll(cString, withChild);
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
await redisDb.StringSetAsync(currKey, rawData, LongCache);
// per evitare loopback uso deserialize...
var tempResult = JsonConvert.DeserializeObject<List<MaterialModel>>(rawData);
if (tempResult != null)
{
dbResult = tempResult;
}
}
if (dbResult == null)
{
@@ -279,6 +328,64 @@ namespace MagMan.Data.Tenant.Services
}
return dbResult;
}
/// <summary>
/// Lista Materiali gestiti a magazzino
/// </summary>
/// <param name="nKey">Key di riferimento</param>
/// <param name="matID">Materiale richiesto</param>
/// <param name="withChild">Se true allora include record child (Items)</param>
/// <returns></returns>
public async Task<List<MaterialModel>> MaterialGetFilt(int nKey, int matID, bool withChild)
{
string source = "DB";
string cString = ConnString(nKey);
List<MaterialModel>? dbResult = new List<MaterialModel>();
try
{
string dType = withChild ? "MatInvFull" : "MatInv";
string currKey = $"{Const.rKeyConfig}:{dType}:{nKey}:{matID}";
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string? rawData = await redisDb.StringGetAsync(currKey);
if (!string.IsNullOrEmpty(rawData) && rawData.Length > 2)
{
source = "REDIS";
var tempResult = JsonConvert.DeserializeObject<List<MaterialModel>>(rawData);
if (tempResult == null)
{
dbResult = new List<MaterialModel>();
}
else
{
dbResult = tempResult;
}
}
else
{
dbResult = dbController.MaterialGetFilt(cString, matID, withChild);
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
await redisDb.StringSetAsync(currKey, rawData, LongCache);
// per evitare loopback uso deserialize...
var tempResult = JsonConvert.DeserializeObject<List<MaterialModel>>(rawData);
if (tempResult != null)
{
dbResult = tempResult;
}
}
if (dbResult == null)
{
dbResult = new List<MaterialModel>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"MaterialGetFilt | {source} in: {ts.TotalMilliseconds} ms");
}
catch (Exception exc)
{
Log.Error($"Error during MaterialGetFilt:{Environment.NewLine}{exc}");
}
return dbResult;
}
/// <summary>
/// Update record Materiale + refresh cache
@@ -305,47 +412,6 @@ namespace MagMan.Data.Tenant.Services
return fatto;
}
/// <summary>
/// Converte il DTO in MaterialModel
/// </summary>
/// <param name="origItem"></param>
/// <returns></returns>
public MaterialModel MaterialFromDto(MaterialDTO origItem)
{
MaterialModel answ = new MaterialModel()
{
MatExtCode = origItem.MatExtCode,
MatDesc = origItem.MatDesc,
LMm = origItem.LMm,
WMm = origItem.WMm,
TMm = origItem.TMm
};
return answ;
}
/// <summary>
/// Converte il DTO in ItemModel
/// </summary>
/// <param name="origItem"></param>
/// <returns></returns>
public ItemModel ItemFromDto(ItemDTO origItem)
{
ItemModel answ = new ItemModel()
{
MatID = origItem.MatID,
Note = origItem.Note,
LMm = origItem.LMm,
WMm = origItem.WMm,
TMm = origItem.TMm,
IsRemn= origItem.IsRemn,
Location = origItem.Location,
QtyAvail = origItem.QtyAvail
};
return answ;
}
#endregion Public Methods
#region Private Fields
@@ -391,13 +457,14 @@ namespace MagMan.Data.Tenant.Services
return answ;
}
#endregion Private Methods
#if false
/// <summary>
/// Dizionario dei token 2 connectionStrings
/// Dizionario dei token 2 connectionStrings
/// </summary>
private Dictionary<string, string> TokenList { get; set; } = new Dictionary<string, string>();
/// <summary>
/// Recupera ConnectionString dal dizionario dei token noti o cercando sul DB
/// </summary>
@@ -424,9 +491,7 @@ namespace MagMan.Data.Tenant.Services
}
}
return answ;
}
}
#endif
#endregion Private Methods
}
}
+1 -7
View File
@@ -1,10 +1,4 @@
@using MagMan.UI.Components
@using System.Security.Claims
@using Microsoft.AspNetCore.Components.Authorization
@inject MessageService AppMessages
<div class="row pt-3">
<div class="row pt-3">
<div class="col-7 col-md-6 col-lg-4 col-xl-3">
<LoginDisplay></LoginDisplay>
</div>
+22 -13
View File
@@ -1,22 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.AspNetCore.Components;
using MagMan.UI.Components;
using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;
using MagMan.Core.Services;
namespace MagMan.UI.Components
{
public partial class CmpTop
{
#region Private Properties
private string PageIcon { get; set; } = "";
private string PageName { get; set; } = "";
[CascadingParameter(Name = "ShowSearch")]
private bool ShowSearch { get; set; } = false;
#endregion Private Properties
#region Public Methods
public void Dispose()
@@ -36,6 +27,13 @@ namespace MagMan.UI.Components
#endregion Public Methods
#region Protected Properties
[Inject]
protected MessageService AppMessages { get; set; } = null!;
#endregion Protected Properties
#region Protected Methods
protected override void OnInitialized()
@@ -49,5 +47,16 @@ namespace MagMan.UI.Components
}
#endregion Protected Methods
#region Private Properties
private string PageIcon { get; set; } = "";
private string PageName { get; set; } = "";
[CascadingParameter(Name = "ShowSearch")]
private bool ShowSearch { get; set; } = false;
#endregion Private Properties
}
}
+9 -3
View File
@@ -1,13 +1,19 @@
@if (CurrRecord != null)
{
<div class="row g-1">
<div class="col-md-7">
<div class="col-md-6">
<div class="form-floating">
<input type="text" class="form-control" @bind="@CurrRecord.Name">
<label class="small">Nome</label>
</div>
</div>
<div class="col-md-4">
<div class="col-md-2">
<div class="form-floating">
<input type="number" class="form-control" @bind="@CurrRecord.MainKey">
<label class="small">MainKey</label>
</div>
</div>
<div class="col-md-3">
<div class="form-floating">
<input type="date" class="form-control" @bind="@CurrRecord.DtActivation">
<label class="small">Data</label>
@@ -29,7 +35,7 @@
<label class="small">Note</label>
</div>
</div>
<div class="col-md-9 pt-2">
<div class="col-md-3 pt-2">
<button class="btn btn-success w-100" @onclick="() => DoSave()"><i class="fa-solid fa-floppy-disk"></i> Save</button>
</div>
</div>
@@ -1,4 +1,5 @@
using MagMan.Core;
using MagMan.Core.Services;
using MagMan.Data.Admin.DbModels;
using MagMan.Data.Admin.Services;
using MagMan.Data.Tenant.DbModels;
@@ -13,7 +14,7 @@ namespace MagMan.UI.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ItemsController : ControllerBase
public class InventoryController : ControllerBase
{
/// <summary>
/// Classe per logging
@@ -22,7 +23,7 @@ namespace MagMan.UI.Controllers
private MTAdminService MTAdminService { get; set; } = null!;
private static JsonSerializerSettings? JSSettings;
private TenantService TService { get; set; } = null!;
public ItemsController(MTAdminService MTDataService, TenantService TDataService)
public InventoryController(MTAdminService MTDataService, TenantService TDataService)
{
MTAdminService = MTDataService;
TService = TDataService;
@@ -31,12 +32,12 @@ namespace MagMan.UI.Controllers
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
Log.Info("Avviata classe ItemsController");
Log.Info("Avviata classe InventoryController");
}
/// <summary>
/// Controllo status Alive
/// GET: api/Items/alive
/// GET: api/Inventory/alive
/// </summary>
/// <returns></returns>
[HttpGet("alive")]
@@ -46,11 +47,11 @@ namespace MagMan.UI.Controllers
return $"OK";
}
// GET api/Items
// GET api/Inventory
[HttpGet]
public async Task<List<ItemModel>> Get()
{
// se non ho chaive --> vuoto!
// se non ho chiave --> vuoto!
List<ItemModel> ListRecords = new List<ItemModel>();
await Task.Delay(100);
return ListRecords;
@@ -62,20 +63,20 @@ namespace MagMan.UI.Controllers
/// <param name="id">Rest Token cliente</param>
/// <param name="MatId">ID del materiale cercato</param>
/// <returns></returns>
// GET api/Items/00000000-0000-0000-0000-000000000000
// GET api/Inventory/00000000-0000-0000-0000-000000000000
[HttpGet("{id}")]
public async Task<List<ItemModel>> Get(string id, int MatId)
public async Task<List<MaterialModel>> Get(string id, int MatId)
{
// in primis recupero codice chiave da token...
int nKey = await MTAdminService.MainKeyByToken(id);
// ora recupero direttametne i materiali
var ListRecords = await TService.ItemGetByMat(nKey, MatId);
var ListRecords = await TService.MaterialGetFilt(nKey, MatId, true);
return ListRecords;
}
/// <summary>
/// Processa una chiamata POST per l'invio di un array Json di oggetti MaterialModel da salvare
/// PUT: api/Items/upsert/00000000-0000-0000-0000-000000000000
/// PUT: api/Inventory/upsert/00000000-0000-0000-0000-000000000000
/// </summary>
/// <param name="id">token comunicazione</param>
/// <returns></returns>
@@ -89,20 +90,23 @@ namespace MagMan.UI.Controllers
{
// in primis recupero codice chiave da token...
int nKey = await MTAdminService.MainKeyByToken(id);
// creo oggetti materiale da lista ricevuta
List<ItemModel> matList = rawList.ItemList.Select(jpl => TService.ItemFromDto(jpl)).ToList();
foreach (var item in matList)
if (nKey > 0)
{
try
// creo oggetti materiale da lista ricevuta
List<ItemModel> matList = rawList.ItemList.Select(jpl => TService.ItemFromDto(jpl)).ToList();
foreach (var item in matList)
{
await TService.ItemUpdate(nKey, item);
fatto = true;
}
catch (Exception exc)
{
Log.Error($"ItemsController.upsert | Errore in fase salvataggio ItemDto{Environment.NewLine}{exc}");
fatto = false;
try
{
await TService.ItemUpdate(nKey, item);
fatto = true;
}
catch (Exception exc)
{
Log.Error($"InventoryController.upsert | Errore in fase salvataggio ItemDto{Environment.NewLine}{exc}");
fatto = false;
}
}
}
}
+16 -13
View File
@@ -68,7 +68,7 @@ namespace MagMan.UI.Controllers
// in primis recupero codice chiave da token...
int nKey = await MTAdminService.MainKeyByToken(id);
// ora recupero direttametne i materiali
var ListRecords = await TService.MaterialGetAll(nKey);
var ListRecords = await TService.MaterialGetAll(nKey, false);
return ListRecords;
}
@@ -88,20 +88,23 @@ namespace MagMan.UI.Controllers
{
// in primis recupero codice chiave da token...
int nKey = await MTAdminService.MainKeyByToken(id);
// creo oggetti materiale da lista ricevuta
List<MaterialModel> matList = rawList.MatList.Select(jpl => TService.MaterialFromDto(jpl)).ToList();
foreach (var item in matList)
if (nKey > 0)
{
try
// creo oggetti materiale da lista ricevuta
List<MaterialModel> matList = rawList.MatList.Select(jpl => TService.MaterialFromDto(jpl)).ToList();
foreach (var item in matList)
{
await TService.MaterialUpdate(nKey, item);
fatto = true;
}
catch (Exception exc)
{
Log.Error($"MaterialsController.upsert | Errore in fase salvataggio MaterialDto{Environment.NewLine}{exc}");
fatto = false;
try
{
await TService.MaterialUpdate(nKey, item);
fatto = true;
}
catch (Exception exc)
{
Log.Error($"MaterialsController.upsert | Errore in fase salvataggio MaterialDto{Environment.NewLine}{exc}");
fatto = false;
}
}
}
}
+1 -1
View File
@@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Version>1.0.2401.1614</Version>
<Version>1.0.2401.1715</Version>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
+1 -4
View File
@@ -1,9 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this
// file to you under the MIT license.
using k8s.Models;
using MagMan.Core.Services;
using MagMan.Data.Admin.DbModels;
using MagMan.Data.Admin.Services;
using MagMan.Data.Tenant.Services;
using Microsoft.AspNetCore.Components;
namespace MagMan.UI.Pages
+1 -2
View File
@@ -1,6 +1,5 @@
using MagMan.Data.Tenant.Services;
using MagMan.Core.Services;
using Microsoft.AspNetCore.Components;
using System;
namespace MagMan.UI.Pages
{
+1 -6
View File
@@ -1,11 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using k8s.KubeConfigModels;
using MagMan.Core.Services;
using MagMan.Data.Admin.Services;
using MagMan.Data.Tenant.Services;
using MagMan.UI.Shared;
using Microsoft.AspNetCore.Components;
using System;
namespace MagMan.UI.Pages
{
+1 -4
View File
@@ -1,9 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using k8s.Models;
using MagMan.Core.Services;
using MagMan.Data.Admin.DbModels;
using MagMan.Data.Admin.Services;
using MagMan.Data.Tenant.Services;
using Microsoft.AspNetCore.Components;
namespace MagMan.UI.Pages
-48
View File
@@ -1,10 +1,5 @@
@inherits LayoutComponentBase
@using MagMan.UI.Components
@inject MessageService MessageService
@implements IDisposable
<PageTitle>MagMan UI</PageTitle>
<div class="page">
@@ -27,46 +22,3 @@
</div>
</div>
</div>
@code {
bool ShowSearch { get; set; } = false;
protected override void OnInitialized()
{
MessageService.EA_ShowSearch += OnShowSearch;
MessageService.EA_HideSearch += OnHideSearch;
}
public void OnShowSearch()
{
ShowSearch = true;
InvokeAsync(() =>
{
StateHasChanged();
});
}
public void OnHideSearch()
{
ShowSearch = false;
InvokeAsync(() =>
{
StateHasChanged();
});
}
public void Dispose()
{
MessageService.EA_ShowSearch -= OnShowSearch;
MessageService.EA_ShowSearch -= OnHideSearch;
}
protected bool navLarge { get; set; } = true;
protected string sideClass { get; set; } = "sidebar";
protected void UpdateNavDisplay()
{
navLarge = !navLarge;
sideClass = navLarge ? "sidebar" : "sidebarSmall";
}
}
+68
View File
@@ -0,0 +1,68 @@
using MagMan.Core.Services;
using Microsoft.AspNetCore.Components;
namespace MagMan.UI.Shared
{
public partial class MainLayout : IDisposable
{
#region Public Methods
public void Dispose()
{
MessageService.EA_ShowSearch -= OnShowSearch;
MessageService.EA_ShowSearch -= OnHideSearch;
}
public void OnHideSearch()
{
ShowSearch = false;
InvokeAsync(() =>
{
StateHasChanged();
});
}
public void OnShowSearch()
{
ShowSearch = true;
InvokeAsync(() =>
{
StateHasChanged();
});
}
#endregion Public Methods
#region Protected Properties
[Inject]
protected MessageService MessageService { get; set; } = null!;
protected bool navLarge { get; set; } = true;
protected string sideClass { get; set; } = "sidebar";
#endregion Protected Properties
#region Protected Methods
protected override void OnInitialized()
{
MessageService.EA_ShowSearch += OnShowSearch;
MessageService.EA_HideSearch += OnHideSearch;
}
protected void UpdateNavDisplay()
{
navLarge = !navLarge;
sideClass = navLarge ? "sidebar" : "sidebarSmall";
}
#endregion Protected Methods
#region Private Properties
private bool ShowSearch { get; set; } = false;
#endregion Private Properties
}
}
+1
View File
@@ -1,6 +1,7 @@
@using EgwCoreLib.Razor
@using MagMan.Core
@using MagMan.Core.DTO
@using MagMan.Core.Services
@using MagMan.Data
@using MagMan.Data.Admin
@using MagMan.Data.Admin.DbModels
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>MagMan - Wood Warehouse Management System</i>
<h4>Versione: 1.0.2401.1614</h4>
<h4>Versione: 1.0.2401.1715</h4>
<br /> Note di rilascio:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
1.0.2401.1614
1.0.2401.1715
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>1.0.2401.1614</version>
<version>1.0.2401.1715</version>
<url>http://nexus.steamware.net/repository/SWS/MagMan/stable/0/MagMan.UI.zip</url>
<changelog>http://nexus.steamware.net/repository/SWS/MagMan/stable/0/ChangeLog.html</changelog>
<mandatory>false</mandatory>