diff --git a/MP.FileData/Controllers/FileController.cs b/MP.FileData/Controllers/FileController.cs index bf5619a3..84b7a312 100644 --- a/MP.FileData/Controllers/FileController.cs +++ b/MP.FileData/Controllers/FileController.cs @@ -7,6 +7,7 @@ using Microsoft.EntityFrameworkCore; using System.Linq; using System.Text; using System.Threading.Tasks; +using MP.FileData.DatabaseModels; namespace MP.FileData.Controllers { @@ -31,6 +32,418 @@ namespace MP.FileData.Controllers #endregion Public Constructors + #region Public Methods + + /// + /// Elenco tabella Articoli (FILTRATO!!!) + /// + /// + /// + /// + public List ArtGetFilt(string searchVal, int maxNum = 100) + { + maxNum = maxNum <= 0 ? 100 : maxNum; + List dbResult = new List(); + using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) + { + int totRecord = localDbCtx + .DbSetArticoli + .Where(x => x.CodArticolo.Contains(searchVal) || x.DescArticolo.Contains(searchVal) || x.Disegno.Contains(searchVal)) + .Count(); + if (totRecord > maxNum) + { + dbResult = localDbCtx + .DbSetArticoli + .Where(x => x.CodArticolo.Contains(searchVal) || x.DescArticolo.Contains(searchVal) || x.Disegno.Contains(searchVal)) + .OrderBy(x => x.DescArticolo) + .Take(maxNum) + .ToList(); + dbResult.Add(new DatabaseModels.ArticoloModel() { CodArticolo = "#####", DescArticolo = $"... +{totRecord - maxNum} rec ..." }); + } + else + { + dbResult = localDbCtx + .DbSetArticoli + .Where(x => x.CodArticolo.Contains(searchVal) || x.DescArticolo.Contains(searchVal) || x.Disegno.Contains(searchVal)) + .OrderBy(x => x.DescArticolo) + .ToList(); + } + } + return dbResult; + } + + /// + /// Effettua la comparazione tra i file in archivio ed i file attuali e segna info LastCheck e Changed (se cambiati) + /// + /// + public bool CheckFileArchived(string idxMacchina, string path, string searchPattern) + { + bool answ = false; + DirectoryInfo dirInfo = new DirectoryInfo(path); + FileInfo[] fileList = dirInfo.GetFiles(searchPattern); + List fileNew = new List(); + List fileChecked = new List(); + List fileMod = new List(); + DateTime adesso = DateTime.Now; + + // recupera elenco file nel DB + var archivedFile = FileGetByPath(path, true); + using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create()) + { + // verifica i file + foreach (var file in fileList) + { + // cerca nel DB... + FileModel currRecord = archivedFile + .Where(x => x.Active && x.Path == file.FullName) + .OrderByDescending(y => y.Rev) + .FirstOrDefault(); + // se NON trova lo crea + if (currRecord == null) + { + fileNew.Add(file); + } + else + { + // verifico se data modifica sia cambiata... + if (currRecord.LastMod != file.LastWriteTime) + { + // calcolo e verifico MD5 + var fileContent = File.ReadAllBytes(file.FullName); + var hash = md5.ComputeHash(fileContent); + var newMD5 = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); + if (newMD5 != currRecord.MD5) + { + fileMod.Add(currRecord); + } + else + { + fileChecked.Add(currRecord); + } + } + else + { + fileChecked.Add(currRecord); + } + } + } + } + + // salvo i NUOVI file + if (fileNew != null && fileNew.Count > 0) + { + FileInsert(idxMacchina, fileNew, 0); + } + // aggiorno i file modificati + if (fileMod != null && fileMod.Count > 0) + { + FileSetUpdated(fileMod); + } + // segno data-ora ultimo controllo x file invariati + if (fileChecked != null && fileChecked.Count > 0) + { + FileSetChecked(fileChecked); + } + + return answ; + } + + public void Dispose() + { + // Clear database context + dbCtx.Dispose(); + } + + /// + /// ELiminazione file da tabella + /// + /// + /// + public bool FileDelete(FileModel currItem) + { + bool done = false; + using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) + { + // eliminazione di uno specifico file + rev da tabella + var file2del = localDbCtx + .DbSetProgFile + .Where(x => x.FileId == currItem.FileId) + .FirstOrDefault(); + localDbCtx + .DbSetProgFile + .Remove(file2del); + + // se ce ne fosse un altro precedente --> lo (ri)attiva + var file2open = localDbCtx + .DbSetProgFile + .Where(x => x.Articolo == currItem.Articolo && x.IdxMacchina == currItem.IdxMacchina) + .OrderByDescending(y => y.Rev) + .FirstOrDefault(); + if (file2open != null) + { + file2open.Active = true; + } + + // salvo! + localDbCtx.SaveChanges(); + done = true; + } + return done; + } + + public bool FileDiskStatusChange(List updFiles, FileState newStatus) + { + bool done = false; + using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) + { + foreach (var item in updFiles) + { + item.DiskStatus = newStatus; + localDbCtx.Entry(item).State = EntityState.Modified; + } + localDbCtx.SaveChanges(); + done = true; + } + return done; + } + + public FileModel FileGetByKey(int FileId) + { + FileModel thisFile = null; + using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) + { + thisFile = localDbCtx + .DbSetProgFile + .Where(x => x.FileId == FileId) + .FirstOrDefault(); + } + return thisFile; + } + + public List FileGetByPath(string path, bool onlyActive) + { + List dbResult = new List(); + using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) + { + dbResult = localDbCtx + .DbSetProgFile + .Where(x => x.Path.StartsWith(path) && ((onlyActive == x.Active) || !onlyActive)) + .OrderBy(x => x.Name) + .ToList(); + } + return dbResult; + } + + public List FileGetFilt(string IdxMacchina, string CodArticolo, bool OnlyActive, bool OnlyMod, string SearchVal = "") + { + List dbResult = new List(); + using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) + { + dbResult = localDbCtx + .DbSetProgFile + .Include(m => m.Macchina) + .Include(a => a.Articolo) + .Where(x => (x.IdxMacchina == IdxMacchina || IdxMacchina == "0") && (x.Active == OnlyActive || !OnlyActive) && (!OnlyMod || x.DiskStatus != FileState.Ok) && (x.Name.Contains(SearchVal) || string.IsNullOrEmpty(SearchVal))) + .OrderByDescending(x => x.LastMod) + .ToList(); + } + return dbResult; + } + + /// + /// Effettua inserimento di un elenco di record in archivio come NUOVO documento tracciato + /// + /// + /// + /// + /// + public bool FileInsert(string idxMacchina, List newFiles, int rev) + { + bool answ = false; + DateTime adesso = DateTime.Now; + // MD5 hash + using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create()) + { + using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) + { + // converto + List newRec = newFiles.Select(o => new DatabaseModels.FileModel() + { + Active = true, + CodArticolo = "ND", + DiskStatus = FileState.Ok, + IdxMacchina = idxMacchina, + LastCheck = adesso, + LastMod = o.LastWriteTime, + MimeType = o.Extension, + Name = o.Name, + Path = o.FullName, + Rev = rev, + Size = o.Length, + FileContent = File.ReadAllBytes(o.FullName) + }).ToList(); + + // calcolo MD5 + foreach (var item in newRec) + { + var hash = md5.ComputeHash(item.FileContent); + item.MD5 = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); + } + + // aggiungo in blocco + localDbCtx + .DbSetProgFile + .AddRange(newRec); + + // salvo + localDbCtx.SaveChanges(); + answ = true; + } + } + return answ; + } + + public bool FileModApprove(FileModel currFile) + { + bool done = false; + List listUpdate = new List(); + using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) + { + // rileggo dati file... + var newFileInfo = new FileInfo(currFile.Path); + listUpdate.Add(newFileInfo); + + // inserisco come REVISIONE + FileInsert(currFile.IdxMacchina, listUpdate, currFile.Rev + 1); + + // archivio vecchio file + currFile.Active = false; + currFile.DiskStatus = FileState.Ok; + localDbCtx.Entry(currFile).State = EntityState.Modified; + // salvo DB + localDbCtx.SaveChanges(); + + done = true; + } + return done; + } + + public bool FileModReject(FileModel currFile) + { + bool done = false; + using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) + { + // sovrascrivo il file su disco + File.WriteAllBytes(currFile.Path, currFile.FileContent); + + // rileggo file... + var newFileInfo = new FileInfo(currFile.Path); + + // aggiorno stato del file a unchanged e data mod ad ora... + currFile.DiskStatus = FileState.Ok; + currFile.LastMod = newFileInfo.LastWriteTime; + localDbCtx.Entry(currFile).State = EntityState.Modified; + + // salvo DB + localDbCtx.SaveChanges(); + done = true; + } + return done; + } + + /// + /// Effettua update di un record in archivio da lista (SOLO STATUS) + /// + /// + /// + public bool FileSetChecked(List updFiles) + { + bool answ = false; + DateTime adesso = DateTime.Now; + + using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) + { + foreach (var item in updFiles) + { + item.LastCheck = adesso; + localDbCtx.Entry(item).State = EntityState.Modified; + } + + // salvo + localDbCtx.SaveChanges(); + answ = true; + } + + return answ; + } + + /// + /// Effettua update di un record in archivio da lista (SOLO STATUS) + /// + /// + /// + public bool FileSetUpdated(List updFiles) + { + bool answ = false; + DateTime adesso = DateTime.Now; + + using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) + { + foreach (var item in updFiles) + { + item.DiskStatus = FileState.Changed; + item.LastCheck = adesso; + localDbCtx.Entry(item).State = EntityState.Modified; + } + + // salvo + localDbCtx.SaveChanges(); + answ = true; + } + + return answ; + } + + /// + /// Aggiorna un Ordine + /// + /// + /// + public bool FileUpdate(FileModel updItem) + { + bool done = false; + using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) + { + try + { + FileModel currData = null; + currData = dbCtx + .DbSetProgFile + .Where(x => x.FileId == updItem.FileId) + .FirstOrDefault(); + if (currData != null) + { + updItem.DiskStatus = FileState.Changed; + localDbCtx.Entry(updItem).State = EntityState.Modified; + localDbCtx.SaveChanges(); + } + else + { + dbCtx + .DbSetProgFile + .Add(updItem); + dbCtx.SaveChanges(); + } + done = true; + } + catch (Exception exc) + { + Log.Error(exc, "Eccezione durante FileUpdate"); + } + } + return done; + } + #if false /// /// Elenco Azioni (decodifica) @@ -88,211 +501,6 @@ namespace MP.FileData.Controllers } #endif - #region Public Methods - - /// - /// Elenco tabella Articoli (FILTRATO!!!) - /// - /// - /// - /// - public List ArtGetFilt(string searchVal, int maxNum = 100) - { - maxNum = maxNum <= 0 ? 100 : maxNum; - List dbResult = new List(); - using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) - { - int totRecord = localDbCtx - .DbSetArticoli - .Where(x => x.CodArticolo.Contains(searchVal) || x.DescArticolo.Contains(searchVal) || x.Disegno.Contains(searchVal)) - .Count(); - if (totRecord > maxNum) - { - dbResult = localDbCtx - .DbSetArticoli - .Where(x => x.CodArticolo.Contains(searchVal) || x.DescArticolo.Contains(searchVal) || x.Disegno.Contains(searchVal)) - .OrderBy(x => x.DescArticolo) - .Take(maxNum) - .ToList(); - dbResult.Add(new DatabaseModels.ArticoloModel() { CodArticolo = "#####", DescArticolo = $"... +{totRecord - maxNum} rec ..." }); - } - else - { - dbResult = localDbCtx - .DbSetArticoli - .Where(x => x.CodArticolo.Contains(searchVal) || x.DescArticolo.Contains(searchVal) || x.Disegno.Contains(searchVal)) - .OrderBy(x => x.DescArticolo) - .ToList(); - } - } - return dbResult; - } - - /// - /// Effettua la comparazione tra i file in archivio ed i file attuali e segna info LastCheck e Changed (se cambiati) - /// - /// - public bool CheckFileArchived(string idxMacchina, string path, string searchPattern) - { - bool answ = false; - DirectoryInfo dirInfo = new DirectoryInfo(path); - FileInfo[] fileList = dirInfo.GetFiles("*.*"); - List fileNew = new List(); - List fileMod = new List(); - - // recupera elenco file nel DB - var archivedFile = FileGetByPath(path, true); - - // verifica i file - foreach (var file in fileList) - { - // cerca nel DB... - var currRecord = archivedFile - .Where(x => x.Path == file.FullName) - .FirstOrDefault(); - // se NON trova lo crea - if (currRecord == null) - { - fileNew.Add(file); - } - else - { - fileMod.Add(file); - } - } - - // salvo i NUOVI file - if (fileNew != null && fileNew.Count > 0) - { - FileInsert(idxMacchina, fileNew); - } - // aggiorno i file modificati - if (fileMod != null && fileMod.Count > 0) - { - FileUpdate(idxMacchina, fileMod); - } - - return answ; - } - - public void Dispose() - { - // Clear database context - dbCtx.Dispose(); - } - - public List FileGetByPath(string path, bool onlyActive) - { - List dbResult = new List(); - using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) - { - dbResult = localDbCtx - .DbSetProgFile - .Where(x => x.Path.StartsWith(path) && ((onlyActive && x.Active) || !onlyActive)) - .OrderBy(x => x.Name) - .ToList(); - } - return dbResult; - } - - public List FileGetFilt(string IdxMacchina, string CodArticolo, string SearchVal = "") - { - List dbResult = new List(); - using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) - { - dbResult = localDbCtx - .DbSetProgFile - .Include(m => m.Macchina) - .Include(a => a.Articolo) - .Where(x => ((x.IdxMacchina == IdxMacchina || IdxMacchina == "0") || (x.CodArticolo == CodArticolo || CodArticolo == "ND" || CodArticolo == "")) && (x.Name.Contains(SearchVal) || string.IsNullOrEmpty(SearchVal))) - .OrderBy(x => x.Name) - .ToList(); - } - return dbResult; - } - - /// - /// effettua inserimento di un record in archivio come NUOVO documento tracciato - /// - /// - /// - /// - public bool FileInsert(string idxMacchina, List newFiles) - { - bool answ = false; - DateTime adesso = DateTime.Now; - using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) - { - // converto - List newRec = newFiles.Select(o => new DatabaseModels.FileModel() - { - Active = true, - CodArticolo = "ND", - Changed = false, - IdxMacchina = idxMacchina, - LastCheck = adesso, - LastMod = o.LastWriteTime, - MimeType = o.Extension, - Name = o.Name, - Path = o.FullName, - Rev = 0, - Size = o.Length, - FileContent = File.ReadAllBytes(o.FullName) - }).ToList(); - - // aggiungo in blocco - localDbCtx - .DbSetProgFile - .AddRange(newRec); - - // salvo - localDbCtx.SaveChanges(); - answ = true; - } - return answ; - } - - /// - /// effettua inserimento di un record in archivio come NUOVO documento tracciato - /// - /// - /// - /// - public bool FileUpdate(string idxMacchina, List updFiles) - { - bool answ = false; - DateTime adesso = DateTime.Now; - using (MoonPro_ProgContext localDbCtx = new MoonPro_ProgContext(_configuration)) - { - // converto - List newRec = updFiles.Select(o => new DatabaseModels.FileModel() - { - Active = true, - CodArticolo = "ND", - Changed = false, - IdxMacchina = idxMacchina, - LastCheck = adesso, - LastMod = o.LastWriteTime, - MimeType = o.Extension, - Name = o.Name, - Path = o.FullName, - Rev = 0, - Size = o.Length, - FileContent = File.ReadAllBytes(o.FullName) - }).ToList(); - - // aggiungo in blocco - localDbCtx - .DbSetProgFile - .UpdateRange(newRec); - - // salvo - localDbCtx.SaveChanges(); - answ = true; - } - return answ; - } - /// /// Elenco tabella Macchine /// diff --git a/MP.FileData/DatabaseModels/FileModel.cs b/MP.FileData/DatabaseModels/FileModel.cs index 8ec845e6..af9953b5 100644 --- a/MP.FileData/DatabaseModels/FileModel.cs +++ b/MP.FileData/DatabaseModels/FileModel.cs @@ -30,10 +30,27 @@ namespace MP.FileData.DatabaseModels public long Size { get; set; } = 0; public string Path { get; set; } = ""; public string MimeType { get; set; } = ""; - public bool Changed { get; set; } = false; + public string MD5 { get; set; } = ""; + public FileState DiskStatus { get; set; } = FileState.Ok; public DateTime LastCheck { get; set; } = DateTime.Now.AddYears(-1); public byte[] FileContent { get; set; } + public ICollection Tags { get; set; } + + [NotMapped] + public string FileStringContent + { + get + { + return Encoding.UTF8.GetString(FileContent); + } + set + { + // serializzo a byte + FileContent = Encoding.ASCII.GetBytes(value); + } + } + [ForeignKey("CodArticolo")] public virtual ArticoloModel Articolo { get; set; } [ForeignKey("IdxMacchina")] diff --git a/MP.FileData/DatabaseModels/TagModel.cs b/MP.FileData/DatabaseModels/TagModel.cs new file mode 100644 index 00000000..849cb577 --- /dev/null +++ b/MP.FileData/DatabaseModels/TagModel.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +// +// This is here so CodeMaid doesn't reorganize this document +// +namespace MP.FileData.DatabaseModels +{ + [Table("Tags")] + public partial class TagModel + { + + [Key] + public string TagId { get; set; } + + public ICollection Files { get; set; } + } +} diff --git a/MP.FileData/Enum.cs b/MP.FileData/Enum.cs new file mode 100644 index 00000000..5163fd93 --- /dev/null +++ b/MP.FileData/Enum.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MP.FileData +{ + /// + /// Stato File + /// + public enum FileState + { + ND = 0, + Changed, + Deleted, + Ok + } +} \ No newline at end of file diff --git a/MP.FileData/Migrations/20210903153915_InitDb.Designer.cs b/MP.FileData/Migrations/20210907103215_InitDb.Designer.cs similarity index 77% rename from MP.FileData/Migrations/20210903153915_InitDb.Designer.cs rename to MP.FileData/Migrations/20210907103215_InitDb.Designer.cs index 9960c4e3..eca66e12 100644 --- a/MP.FileData/Migrations/20210903153915_InitDb.Designer.cs +++ b/MP.FileData/Migrations/20210907103215_InitDb.Designer.cs @@ -10,7 +10,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace MP.FileData.Migrations { [DbContext(typeof(MoonPro_ProgContext))] - [Migration("20210903153915_InitDb")] + [Migration("20210907103215_InitDb")] partial class InitDb { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -22,6 +22,21 @@ namespace MP.FileData.Migrations .HasAnnotation("ProductVersion", "5.0.9") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + modelBuilder.Entity("FileModelTagModel", b => + { + b.Property("FilesFileId") + .HasColumnType("int"); + + b.Property("TagsTagId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("FilesFileId", "TagsTagId"); + + b.HasIndex("TagsTagId"); + + b.ToTable("FileModelTagModel"); + }); + modelBuilder.Entity("MP.FileData.DatabaseModels.ArticoloModel", b => { b.Property("CodArticolo") @@ -60,12 +75,12 @@ namespace MP.FileData.Migrations b.Property("Active") .HasColumnType("bit"); - b.Property("Changed") - .HasColumnType("bit"); - b.Property("CodArticolo") .HasColumnType("nvarchar(450)"); + b.Property("DiskStatus") + .HasColumnType("int"); + b.Property("FileContent") .HasColumnType("varbinary(max)"); @@ -78,6 +93,9 @@ namespace MP.FileData.Migrations b.Property("LastMod") .HasColumnType("datetime2"); + b.Property("MD5") + .HasColumnType("nvarchar(max)"); + b.Property("MimeType") .HasColumnType("nvarchar(max)"); @@ -146,6 +164,31 @@ namespace MP.FileData.Migrations }); }); + modelBuilder.Entity("MP.FileData.DatabaseModels.TagModel", b => + { + b.Property("TagId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("TagId"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("FileModelTagModel", b => + { + b.HasOne("MP.FileData.DatabaseModels.FileModel", null) + .WithMany() + .HasForeignKey("FilesFileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MP.FileData.DatabaseModels.TagModel", null) + .WithMany() + .HasForeignKey("TagsTagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("MP.FileData.DatabaseModels.FileModel", b => { b.HasOne("MP.FileData.DatabaseModels.ArticoloModel", "Articolo") diff --git a/MP.FileData/Migrations/20210903153915_InitDb.cs b/MP.FileData/Migrations/20210907103215_InitDb.cs similarity index 71% rename from MP.FileData/Migrations/20210903153915_InitDb.cs rename to MP.FileData/Migrations/20210907103215_InitDb.cs index 46126bf6..4ab48e1b 100644 --- a/MP.FileData/Migrations/20210903153915_InitDb.cs +++ b/MP.FileData/Migrations/20210907103215_InitDb.cs @@ -39,6 +39,17 @@ namespace MP.FileData.Migrations table.PrimaryKey("PK_Macchine", x => x.IdxMacchina); }); + migrationBuilder.CreateTable( + name: "Tags", + columns: table => new + { + TagId = table.Column(type: "nvarchar(450)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Tags", x => x.TagId); + }); + migrationBuilder.CreateTable( name: "Files", columns: table => new @@ -54,7 +65,8 @@ namespace MP.FileData.Migrations Size = table.Column(type: "bigint", nullable: false), Path = table.Column(type: "nvarchar(max)", nullable: true), MimeType = table.Column(type: "nvarchar(max)", nullable: true), - Changed = table.Column(type: "bit", nullable: false), + MD5 = table.Column(type: "nvarchar(max)", nullable: true), + DiskStatus = table.Column(type: "int", nullable: false), LastCheck = table.Column(type: "datetime2", nullable: false), FileContent = table.Column(type: "varbinary(max)", nullable: true) }, @@ -75,6 +87,30 @@ namespace MP.FileData.Migrations onDelete: ReferentialAction.Restrict); }); + migrationBuilder.CreateTable( + name: "FileModelTagModel", + columns: table => new + { + FilesFileId = table.Column(type: "int", nullable: false), + TagsTagId = table.Column(type: "nvarchar(450)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_FileModelTagModel", x => new { x.FilesFileId, x.TagsTagId }); + table.ForeignKey( + name: "FK_FileModelTagModel_Files_FilesFileId", + column: x => x.FilesFileId, + principalTable: "Files", + principalColumn: "FileId", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_FileModelTagModel_Tags_TagsTagId", + column: x => x.TagsTagId, + principalTable: "Tags", + principalColumn: "TagId", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.InsertData( table: "Articoli", columns: new[] { "CodArticolo", "DescArticolo", "Disegno", "Tipo" }, @@ -85,6 +121,11 @@ namespace MP.FileData.Migrations columns: new[] { "IdxMacchina", "BasePath", "CodMacchina", "Descrizione", "ImgUrl", "Nome", "Note", "ShowOrder" }, values: new object[] { "0", "", "0", "--- Tutte ---", "", "--- Tutte ---", "", 0 }); + migrationBuilder.CreateIndex( + name: "IX_FileModelTagModel_TagsTagId", + table: "FileModelTagModel", + column: "TagsTagId"); + migrationBuilder.CreateIndex( name: "IX_Files_CodArticolo", table: "Files", @@ -98,9 +139,15 @@ namespace MP.FileData.Migrations protected override void Down(MigrationBuilder migrationBuilder) { + migrationBuilder.DropTable( + name: "FileModelTagModel"); + migrationBuilder.DropTable( name: "Files"); + migrationBuilder.DropTable( + name: "Tags"); + migrationBuilder.DropTable( name: "Articoli"); diff --git a/MP.FileData/Migrations/MoonPro_ProgContextModelSnapshot.cs b/MP.FileData/Migrations/MoonPro_ProgContextModelSnapshot.cs index 7149d346..1be4c878 100644 --- a/MP.FileData/Migrations/MoonPro_ProgContextModelSnapshot.cs +++ b/MP.FileData/Migrations/MoonPro_ProgContextModelSnapshot.cs @@ -20,6 +20,21 @@ namespace MP.FileData.Migrations .HasAnnotation("ProductVersion", "5.0.9") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + modelBuilder.Entity("FileModelTagModel", b => + { + b.Property("FilesFileId") + .HasColumnType("int"); + + b.Property("TagsTagId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("FilesFileId", "TagsTagId"); + + b.HasIndex("TagsTagId"); + + b.ToTable("FileModelTagModel"); + }); + modelBuilder.Entity("MP.FileData.DatabaseModels.ArticoloModel", b => { b.Property("CodArticolo") @@ -58,12 +73,12 @@ namespace MP.FileData.Migrations b.Property("Active") .HasColumnType("bit"); - b.Property("Changed") - .HasColumnType("bit"); - b.Property("CodArticolo") .HasColumnType("nvarchar(450)"); + b.Property("DiskStatus") + .HasColumnType("int"); + b.Property("FileContent") .HasColumnType("varbinary(max)"); @@ -76,6 +91,9 @@ namespace MP.FileData.Migrations b.Property("LastMod") .HasColumnType("datetime2"); + b.Property("MD5") + .HasColumnType("nvarchar(max)"); + b.Property("MimeType") .HasColumnType("nvarchar(max)"); @@ -144,6 +162,31 @@ namespace MP.FileData.Migrations }); }); + modelBuilder.Entity("MP.FileData.DatabaseModels.TagModel", b => + { + b.Property("TagId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("TagId"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("FileModelTagModel", b => + { + b.HasOne("MP.FileData.DatabaseModels.FileModel", null) + .WithMany() + .HasForeignKey("FilesFileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MP.FileData.DatabaseModels.TagModel", null) + .WithMany() + .HasForeignKey("TagsTagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("MP.FileData.DatabaseModels.FileModel", b => { b.HasOne("MP.FileData.DatabaseModels.ArticoloModel", "Articolo") diff --git a/MP.Prog/Components/CodArtSelector.razor b/MP.Prog/Components/CodArtSelector.razor new file mode 100644 index 00000000..f76926fc --- /dev/null +++ b/MP.Prog/Components/CodArtSelector.razor @@ -0,0 +1,110 @@ +@using MP.FileData.DatabaseModels +@using MP.Prog.Data + +@inject FileArchDataService DataService +@inject MessageService AppMService + +@if (ArtList == null) +{ + +} +else +{ +
+
+ + + +
+ + +
+ +
+
+} + +@code { + + [Parameter] + public EventCallback searchUpdated { get; set; } + [Parameter] + public string SelCodArt + { + get + { + string answ = ""; + if (AppMService.File_Filter != null) + { + answ = AppMService.File_Filter.CodArticolo; + } + return answ; + } + set + { + if (!AppMService.File_Filter.CodArticolo.Equals(value)) + { + AppMService.File_Filter.CodArticolo = value; + } + reportChange(); + } + } + + private void reportChange() + { + searchUpdated.InvokeAsync(SelCodArt); + } + + protected string _SearchArt; + protected string defCodArt = ""; + protected List ArtList; + + protected string SearchArt + { + get + { + return _SearchArt; + } + set + { + _SearchArt = value; + // se son > 3 char... debounce... + if (string.IsNullOrEmpty(value)) + { + _SearchArt = defCodArt; + } + if (value.Length >= defCodArt.Length) + { + var pUpd = Task.Run(async () => + { + ArtList = await DataService.ArticoliGetFilt(SearchArt); + }); + pUpd.Wait(); + } + } + } + protected override async Task OnInitializedAsync() + { + await ReloadAllData(); + _SearchArt = defCodArt; + } + + protected async Task ReloadAllData() + { + SelCodArt = defCodArt; + ArtList = await DataService.ArticoliGetFilt(SearchArt); + } + + protected void ResetSearchArt() + { + SearchArt = defCodArt; + } +} \ No newline at end of file diff --git a/MP.Prog/Components/DiffView.razor b/MP.Prog/Components/DiffView.razor new file mode 100644 index 00000000..845fc93e --- /dev/null +++ b/MP.Prog/Components/DiffView.razor @@ -0,0 +1,154 @@ +@using MP.Prog.Data +@using System.Text +@using DiffMatchPatch + +
+
+
+
+

Archivio

+
+
+
+
+ +
+
+
+ @if (numChanges > 0) + { +
+
+
+

Attuale

+
+
+
+
+ @numChanges modifiche +
+
+
+ } +
+
+
+
+

@((MarkupString)oldResult)

+
+
+ @if (numChanges > 0) + { +
+
+

@((MarkupString)newResult)

+
+
+ } +
+ +@code { + + string sepDest = "
"; + + protected int pHeight = 25; + + protected string oldResult = ""; + protected string newResult = ""; + + protected string _oldText = ""; + protected string _newText = ""; + + [Parameter] + public EventCallback diffDone { get; set; } + + protected int numChanges { get; set; } = 0; + + [Parameter] + public string oldText + { + get + { + return _oldText; + } + set + { + _oldText = value; + } + } + + protected string oldTextFix + { + get + { + return _oldText.Replace(Environment.NewLine, sepDest).Replace("\n", sepDest).Replace("\r", sepDest); + } + } + + protected string newTextFix + { + get + { + return _newText.Replace(Environment.NewLine, sepDest).Replace("\n", sepDest).Replace("\r", sepDest); + } + } + [Parameter] + public string newText + { + get + { + return _newText; + } + set + { + _newText = value; + ReloadData(); + } + } + protected void ReloadData() + { + numChanges = 0; + // calcolo diff + diff_match_patch dmp = new diff_match_patch(); + List diff = dmp.diff_main(oldTextFix, newTextFix); + dmp.diff_cleanupSemantic(diff); + + // predispongo la stringa secondo l'elenco dei diff.... + StringBuilder sbNew = new StringBuilder(); + StringBuilder sbOld = new StringBuilder(); + foreach (var item in diff) + { + switch (item.operation) + { + case Operation.DELETE: + sbOld.Append($"{item.text}"); + break; + case Operation.INSERT: + sbNew.Append($"{item.text}"); + numChanges++; + break; + case Operation.EQUAL: + sbNew.Append($"{item.text}"); + sbOld.Append($"{item.text}"); + break; + default: + break; + } + } + + newResult = sbNew.ToString().Trim(); + oldResult = sbOld.ToString().Trim(); + var pUpd = Task.Run(async () => + { + await diffDone.InvokeAsync(numChanges); + }); + pUpd.Wait(); + } + + protected override Task OnInitializedAsync() + { + ReloadData(); + return base.OnInitializedAsync(); + } + +} \ No newline at end of file diff --git a/MP.Prog/Components/FileEditor.razor b/MP.Prog/Components/FileEditor.razor new file mode 100644 index 00000000..067157fa --- /dev/null +++ b/MP.Prog/Components/FileEditor.razor @@ -0,0 +1,31 @@ +
+
+
+
+
Dettaglio modifiche
+
+
+ @if (_currItem.DiskStatus != FileData.FileState.Ok) + { +
+
+ +
+
+ +
+
+ } +
+
+ @numDiff +
+
+ +
+
+
+
+ +
+
\ No newline at end of file diff --git a/MP.Prog/Components/FileEditor.razor.cs b/MP.Prog/Components/FileEditor.razor.cs new file mode 100644 index 00000000..d600311a --- /dev/null +++ b/MP.Prog/Components/FileEditor.razor.cs @@ -0,0 +1,161 @@ +using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; +using MP.FileData.DatabaseModels; +using MP.Prog.Data; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace MP.Prog.Components +{ + public partial class FileEditor : ComponentBase + { + #region Protected Fields + + protected int numDiff = 0; + + #endregion Protected Fields + + #region Public Fields + + public FileModel _currItem = new FileModel(); + + #endregion Public Fields + + #region Protected Properties + + [Inject] + protected FileArchDataService DataService { get; set; } + + [Inject] + protected IJSRuntime JSRuntime { get; set; } + + #endregion Protected Properties + + #region Public Properties + + [Parameter] + public List ArtList { get; set; } + + [Parameter] + public FileModel currItem + { + get + { + return _currItem = null; + } + set + { + _currItem = value; + } + } + + [Parameter] + public EventCallback DataReset { get; set; } + + [Parameter] + public EventCallback DataUpdated { get; set; } + + [Parameter] + public List MacList { get; set; } + + #endregion Public Properties + + #region Private Methods + + private async Task ApproveChange() + { + if (!await JSRuntime.InvokeAsync("confirm", "Sicuro di voler asccettare la modifica del file selezionato generando una nuova revisione?")) + return; + + if (_currItem != null) + { + await DataService.FileApprove(_currItem); + await DataUpdated.InvokeAsync(1); + } + else + { + Console.WriteLine("File null!"); + } + } + + private async Task cancelUpdate() + { + await DataReset.InvokeAsync(0); + } + + private async Task deleteRecord() + { + if (!await JSRuntime.InvokeAsync("confirm", "Sicuro di voler eliminare il file selezionato??")) + return; + + if (_currItem != null) + { + await DataService.FileDelete(_currItem); + await DataUpdated.InvokeAsync(1); + } + else + { + Console.WriteLine("File null!"); + } + } + + private async Task RejectChange() + { + if (!await JSRuntime.InvokeAsync("confirm", "Sicuro di voler eliminare la modifica del file selezionato e sovrascrivere la versione in rete?")) + return; + + if (_currItem != null) + { + await DataService.FileReject(_currItem); + await DataUpdated.InvokeAsync(1); + } + else + { + Console.WriteLine("File null!"); + } + } + + private async Task saveUpdate() + { + if (_currItem != null) + { + await DataService.FileUpdate(_currItem); + await DataUpdated.InvokeAsync(1); + } + else + { + Console.WriteLine("File null!"); + } + } + + #endregion Private Methods + + #region Protected Methods + + protected void diffDoneHandler(int numChanges) + { +#if false + numDiff = numChanges; +#endif + } + + #endregion Protected Methods + + #region Public Methods + + public string CurrFileContent(string fullPath) + { + string answ = ""; + if (File.Exists(fullPath)) + { + answ = File.ReadAllText(fullPath); + } + return answ; + } + + #endregion Public Methods + } +} \ No newline at end of file diff --git a/MP.Prog/Components/SearchMod.razor b/MP.Prog/Components/SearchMod.razor index 2d4f63ef..ba4df62a 100644 --- a/MP.Prog/Components/SearchMod.razor +++ b/MP.Prog/Components/SearchMod.razor @@ -28,9 +28,9 @@ } } - private void reportChange() + private async Task reportChange() { - searchUpdated.InvokeAsync(searchVal); + await searchUpdated.InvokeAsync(searchVal); } private void reset() diff --git a/MP.Prog/Data/FileArchDataService.cs b/MP.Prog/Data/FileArchDataService.cs index 6254e742..0f1d2a5c 100644 --- a/MP.Prog/Data/FileArchDataService.cs +++ b/MP.Prog/Data/FileArchDataService.cs @@ -102,6 +102,26 @@ namespace MP.Prog.Data #region Internal Methods + internal Task FileApprove(FileData.DatabaseModels.FileModel currItem) + { + return Task.FromResult(dbController.FileModApprove(currItem)); + } + + internal Task FileDelete(FileData.DatabaseModels.FileModel currItem) + { + return Task.FromResult(dbController.FileDelete(currItem)); + } + + internal Task FileReject(FileData.DatabaseModels.FileModel currItem) + { + return Task.FromResult(dbController.FileModReject(currItem)); + } + + internal Task FileUpdate(FileData.DatabaseModels.FileModel updItem) + { + return Task.FromResult(dbController.FileUpdate(updItem)); + } + internal void ResetController() { dbController.ResetController(); @@ -187,7 +207,8 @@ namespace MP.Prog.Data public Task> ArticoliGetFilt(string SearchVal) { - return Task.FromResult(dbController.ArtGetFilt(SearchVal, 20).ToList()); + return Task.FromResult(dbController.ArtGetFilt(SearchVal, 200).ToList()); + //return Task.FromResult(dbController.ArtGetFilt(SearchVal, 20).ToList()); } public void Dispose() @@ -196,9 +217,14 @@ namespace MP.Prog.Data dbController.Dispose(); } - public Task> FileGetFilt(string IdxMacchina, string CodArticolo, string SearchVal) + public Task FileGetByKey(int FileId) { - return Task.FromResult(dbController.FileGetFilt(IdxMacchina, CodArticolo, SearchVal).ToList()); + return Task.FromResult(dbController.FileGetByKey(FileId)); + } + + public Task> FileGetFilt(string IdxMacchina, string CodArticolo, bool OnlyActive, bool OnlyMod, string SearchVal) + { + return Task.FromResult(dbController.FileGetFilt(IdxMacchina, CodArticolo, OnlyActive, OnlyMod, SearchVal).ToList()); } public Task> MacchineGetAll() diff --git a/MP.Prog/Data/SelectData.cs b/MP.Prog/Data/SelectData.cs index 187318e8..62f2a68b 100644 --- a/MP.Prog/Data/SelectData.cs +++ b/MP.Prog/Data/SelectData.cs @@ -13,6 +13,8 @@ namespace MP.Prog.Data public DateTime DateEnd { get; set; } = DateTime.Now.AddMinutes(1); public DateTime DateStart { get; set; } = DateTime.Now.AddDays(-7); public string IdxMacchina { get; set; } = ""; + public bool OnlyActive { get; set; } = true; + public bool OnlyMod { get; set; } = false; #endregion Public Properties @@ -41,7 +43,10 @@ namespace MP.Prog.Data { if (!(obj is SelectData item)) return false; - + if (OnlyActive != item.OnlyActive) + return false; + if (OnlyMod != item.OnlyMod) + return false; if (CodArticolo != item.CodArticolo) return false; if (IdxMacchina != item.IdxMacchina) diff --git a/MP.Prog/MP.Prog.csproj b/MP.Prog/MP.Prog.csproj index 74f23af8..8f98d113 100644 --- a/MP.Prog/MP.Prog.csproj +++ b/MP.Prog/MP.Prog.csproj @@ -13,6 +13,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/MP.Prog/Pages/Archive.razor b/MP.Prog/Pages/Archive.razor index 4e567d7e..31c0b83f 100644 --- a/MP.Prog/Pages/Archive.razor +++ b/MP.Prog/Pages/Archive.razor @@ -15,7 +15,27 @@ -
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+ + +
+
+
+
@@ -33,28 +53,6 @@
-
-
-
- - - -
- - -
- -
-
-
@@ -67,12 +65,12 @@
@if (currRecord != null) { -

mostrare dettaglio: diff? comando accetta/annulla?

- @**@ + } @if (ListRecords == null) { - + + RELOADING } else if (totalCount == 0) { @@ -86,18 +84,14 @@ - Macchina - Articolo File Rev Size - Modifica - Controllo - OK - @*Fornitore - Richiesta - Carico - Effettivo*@ + State + Macchina + Articolo + Modificato + @*Controllo*@ @@ -105,10 +99,9 @@ { - - @if (currRecord == null) + @if (currRecord == null && record.Active) { - } @@ -118,7 +111,25 @@ } -
[@record.FileId]
+ + +
+
@record.Name
+
@record.Path
+
+ + +
@record.Rev
+ + +
@((((double)record.Size)/1024).ToString("N2")) k
+ + + + + @record.DiskStatus + +
@record.Macchina.CodMacchina
@@ -128,25 +139,14 @@
@record.Articolo.Disegno
@record.Articolo.DescArticolo
- -
@record.Name
-
@record.Path
- - -
@record.Rev
- - -
@((double)record.Size)/1024
- - +
@record.LastMod.ToString("yyyy.MM.dd")
@record.LastMod.ToString("ddd HH:mm.ss")
- -
@record.LastCheck.ToString("yyyy.MM.dd")
-
@record.LastCheck.ToString("ddd HH:mm.ss")
- - @record.Changed + @* +
@record.LastCheck.ToString("yyyy.MM.dd")
+
@record.LastCheck.ToString("ddd HH:mm.ss")
+ *@ } diff --git a/MP.Prog/Pages/Archive.razor.cs b/MP.Prog/Pages/Archive.razor.cs index d39ba288..f9279fde 100644 --- a/MP.Prog/Pages/Archive.razor.cs +++ b/MP.Prog/Pages/Archive.razor.cs @@ -14,6 +14,7 @@ namespace MP.Prog.Pages #region Private Fields private List ArtList; + private FileModel currRecord = null; private List ListRecords; private List MacList; @@ -23,7 +24,9 @@ namespace MP.Prog.Pages #region Protected Fields - protected string _SearchArt = "###"; + protected string _SearchArt; + + protected string defCodArt = ""; #endregion Protected Fields @@ -63,6 +66,50 @@ namespace MP.Prog.Pages } } + private bool OnlyActive + { + get + { + bool answ = false; + if (AppMService.File_Filter != null) + { + answ = AppMService.File_Filter.OnlyActive; + } + return answ; + } + set + { + if (!AppMService.File_Filter.OnlyActive.Equals(value)) + { + AppMService.File_Filter.OnlyActive = value; + var pUpd = Task.Run(async () => await ReloadData()); + pUpd.Wait(); + } + } + } + + private bool OnlyMod + { + get + { + bool answ = false; + if (AppMService.File_Filter != null) + { + answ = AppMService.File_Filter.OnlyMod; + } + return answ; + } + set + { + if (!AppMService.File_Filter.OnlyMod.Equals(value)) + { + AppMService.File_Filter.OnlyMod = value; + var pUpd = Task.Run(async () => await ReloadData()); + pUpd.Wait(); + } + } + } + private string SelCodArt { get @@ -136,9 +183,9 @@ namespace MP.Prog.Pages // se son > 3 char... debounce... if (string.IsNullOrEmpty(value)) { - _SearchArt = "###"; + _SearchArt = defCodArt; } - if (value.Length >= 3) + if (value.Length >= defCodArt.Length) { var pUpd = Task.Run(async () => { @@ -167,10 +214,41 @@ namespace MP.Prog.Pages #region Private Methods + private string cssActive(bool active) + { + string answ = active ? "text-dark" : "text-secondary textStriked"; + return answ; + } + + private string cssStatusByCod(FileData.FileState currStatus) + { + string answ = "badge"; + switch (currStatus) + { + case FileData.FileState.Changed: + answ += " badge-warning"; + break; + + case FileData.FileState.Deleted: + answ += " badge-danger"; + break; + + case FileData.FileState.Ok: + answ += " badge-success"; + break; + + case FileData.FileState.ND: + default: + answ += " badge-light"; + break; + } + return answ; + } + private async Task ReloadData() { isLoading = true; - SearchRecords = await DataService.FileGetFilt(AppMService.File_Filter.IdxMacchina, AppMService.File_Filter.CodArticolo, AppMService.SearchVal); + SearchRecords = await DataService.FileGetFilt(AppMService.File_Filter.IdxMacchina, AppMService.File_Filter.CodArticolo, AppMService.File_Filter.OnlyActive, AppMService.File_Filter.OnlyMod, AppMService.SearchVal); ListRecords = SearchRecords.Skip(numRecord * (currPage - 1)).Take(numRecord).ToList(); isLoading = false; } @@ -181,11 +259,9 @@ namespace MP.Prog.Pages protected void Edit(FileModel selRecord) { -#if false // rileggo dal DB il record corrente... - var pUpd = Task.Run(async () => currRecord = await DataService.OrderGetByCode(selRecord.OrderCode)); + var pUpd = Task.Run(async () => currRecord = await DataService.FileGetByKey(selRecord.FileId)); pUpd.Wait(); -#endif } protected async Task ForceCheck() @@ -213,6 +289,7 @@ namespace MP.Prog.Pages protected override async Task OnInitializedAsync() { DataService.ResetController(); + SearchArt = defCodArt; AppMService.ShowSearch = false; AppMService.PageName = "Archivio File Programmi"; AppMService.PageIcon = "fas fa-folder pr-2"; @@ -225,8 +302,10 @@ namespace MP.Prog.Pages isLoading = true; MacList = await DataService.MacchineGetAll(); SelIdxMacc = "0"; + SearchArt = defCodArt; + ArtList = await DataService.ArticoliGetFilt(SearchArt); - SelCodArt = "###"; + isLoading = false; await ReloadData(); } @@ -243,13 +322,18 @@ namespace MP.Prog.Pages SearchRecords = null; ListRecords = null; AppMService.File_Filter = SelectData.Init(5, 10); - SearchArt = "###"; + SearchArt = defCodArt; await ReloadAllData(); } protected void ResetSearchArt() { - SearchArt = "###"; + SearchArt = defCodArt; + } + + protected void searchArtUpd(string newCod) + { + SelCodArt = newCod; } protected void Select(FileModel selRecord) diff --git a/MP.Prog/Pages/Setup.razor b/MP.Prog/Pages/Setup.razor new file mode 100644 index 00000000..d7f551ca --- /dev/null +++ b/MP.Prog/Pages/Setup.razor @@ -0,0 +1,52 @@ +@page "/Setup" + +@using MP.Prog.Data +@using System.Text +@using DiffMatchPatch + +@inject MessageService AppMService + +

Setup

+ +
+
+