Update gestione upload...

This commit is contained in:
Samuele E. Locatelli
2019-10-17 16:47:40 +02:00
parent 0ea6bd8663
commit 1b49a4a291
9 changed files with 355 additions and 85 deletions
+2 -7
View File
@@ -1,11 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebLCP
namespace WebLCP
{
public class BaseUserControl
public class BaseUserControl : SteamWare.UserControl
{
}
}
+2
View File
@@ -13,6 +13,8 @@
<div class="row">
<div class="col">
<uc1:mod_startJob runat="server" ID="mod_startJob" />
<asp:Label runat="server" ID="lblOutError" CssClass="text-danger" />
<asp:Label runat="server" ID="lblOutSuccess" CssClass="text-success" />
</div>
</div>
<div class="row my-2">
+77 -1
View File
@@ -1,6 +1,82 @@
namespace WebLCP
using SteamWare;
using System;
using System.Collections.Generic;
using System.Text;
namespace WebLCP
{
public partial class JobsList : BaseUserPage
{
protected override void Page_Load(object sender, EventArgs e)
{
base.Page_Load(sender, e);
if (!Page.IsPostBack)
{
lblOutError.Visible = false;
lblOutSuccess.Visible = false;
}
mod_startJob.eh_ucev += Mod_startJob_eh_ucev;
}
private void Mod_startJob_eh_ucev(object sender, EventArgs e)
{
// se trovo evento select/reset mostro/nascondo dettagli...
ucEvent evento = (ucEvent)e;
switch (evento.tipoEvento)
{
case ucEvType.Delete:
break;
case ucEvType.Edit:
break;
case ucEvType.New:
break;
case ucEvType.Reset:
break;
case ucEvType.ReqUpdateParent:
// leggo errori e successi attivi...
Dictionary<string, string> ctrError = mod_startJob.ctrError;
Dictionary<string, string> ctrSuccess = mod_startJob.ctrSuccess;
// se ho errori mostro!
if (ctrError.Count > 0)
{
lblOutError.Visible = true;
// compongo output
StringBuilder sb = new StringBuilder();
sb.Append("------------------------------------<br/>");
sb.Append("Error: fileCheck not passed!<br/>");
sb.Append("------------------------------------<br/>");
foreach (var item in ctrError)
{
sb.Append($"- {item.Key}: {item.Value}<br/>");
}
sb.Append("------------------------------------<br/>");
lblOutError.Text = sb.ToString();
}
else if(ctrSuccess.Count>0)
{
lblOutSuccess.Visible = true;
// compongo output
StringBuilder sb = new StringBuilder();
sb.Append("------------------------------------<br/>");
sb.Append("SUCCESS: fileCheck OK!<br/>");
sb.Append("------------------------------------<br/>");
foreach (var item in ctrSuccess)
{
sb.Append($"- {item.Key}: {item.Value}<br/>");
}
sb.Append("------------------------------------<br/>");
lblOutSuccess.Text = sb.ToString();
}
break;
case ucEvType.Selected:
break;
default:
break;
}
}
}
}
+18
View File
@@ -21,6 +21,24 @@ namespace WebLCP {
/// </remarks>
protected global::WebLCP.WUC.mod_startJob mod_startJob;
/// <summary>
/// Controllo lblOutError.
/// </summary>
/// <remarks>
/// Campo generato automaticamente.
/// Per la modifica, spostare la dichiarazione di campo dal file di progettazione al file code-behind.
/// </remarks>
protected global::System.Web.UI.WebControls.Label lblOutError;
/// <summary>
/// Controllo lblOutSuccess.
/// </summary>
/// <remarks>
/// Campo generato automaticamente.
/// Per la modifica, spostare la dichiarazione di campo dal file di progettazione al file code-behind.
/// </remarks>
protected global::System.Web.UI.WebControls.Label lblOutSuccess;
/// <summary>
/// Controllo mod_jobsList.
/// </summary>
+2 -3
View File
@@ -9,12 +9,11 @@
<h3>www.admodelling.org</h3>
</div>
<div class="card-body">
<uc1:tmp_wip runat="server" id="tmp_WIP" />
<uc1:tmp_WIP runat="server" ID="tmp_WIP" />
</div>
<div class="card-footer">
we'll be back soon...
</div>
</div>
</div>
</asp:Content>
+16 -10
View File
@@ -6,31 +6,37 @@
<div class="card">
<div class="card-header bg-primary">
<a class="card-link text-light" data-toggle="collapse" href="#collAddNew">
<i class="fa fa-plus" aria-hidden="true"></i> Caricamento Nuovo Job <i class="fa fa-plus" aria-hidden="true"></i>
<i class="fa fa-plus" aria-hidden="true"></i>&nbsp;Caricamento Nuovo Job&nbsp;<i class="fa fa-plus" aria-hidden="true"></i>
</a>
</div>
<div id="collAddNew" class="collapse" data-parent="#accordion">
<div class="card-body">
<div class="row">
<div class="col-9">
<div class="form-row">
<div class="form-row border border-dark p-2">
<div class="col">
<label for="txtJobDescr">Descrizione Job (facoltativa)</label>
<label for="txtJobDescr">Job description</label>
<asp:TextBox runat="server" ID="txtJobDescr" CssClass="form-control" />
<asp:RequiredFieldValidator runat="server" ID="rfvJobDescr" ControlToValidate="txtJobDescr" Text="<b>Description Missing</b>: please indicate a brief description for later retrieval" CssClass="text-danger" Display="Dynamic" />
</div>
</div>
<div class="form-row my-3">
<div class="form-row my-3 border border-primary p-2">
<div class="col">
<label for="txtJobDescr">DB INPUT (file csv) - <asp:HyperLink runat="server" ID="HyperLink1" Target="_blank" NavigateUrl="~/DB_INPUT">Specifiche e demo file</asp:HyperLink></label>
<asp:FileUpload ID="FUplCsv_A" runat="server" CssClass="form-control" />
<asp:RequiredFieldValidator runat="server" ID="rfvFUA" ControlToValidate="FUplCsv_A" Text="!!!" CssClass="text-danger" />
<label for="txtJobDescr">
DB INPUT (file csv) -
<asp:HyperLink runat="server" ID="HyperLink1" Target="_blank" NavigateUrl="~/DB_INPUT">Specifiche e demo file</asp:HyperLink></label>
<asp:FileUpload ID="FUplCsv_A" runat="server" CssClass="form-control" AllowMultiple="false" />
<asp:RequiredFieldValidator runat="server" ID="rfvFUA" ControlToValidate="FUplCsv_A" Text="<b>File Missing</b>: please select file to upload!" CssClass="text-danger" Display="Dynamic" />
</div>
</div>
<div class="form-row">
<div class="form-row border border-info p-2">
<div class="col">
<label for="txtJobDescr">DB INPUT 2 CLUSTER (file csv) - <asp:HyperLink runat="server" ID="hlDbInputClu" Target="_blank" NavigateUrl="~/DB_INPUT_CLU">Specifiche e demo file</asp:HyperLink></label>
<label for="txtJobDescr">
DB INPUT 2 CLUSTER (file csv) -
<asp:HyperLink runat="server" ID="hlDbInputClu" Target="_blank" NavigateUrl="~/DB_INPUT_CLU">Specifiche e demo file</asp:HyperLink></label>
<asp:FileUpload ID="FUplCsv_B" runat="server" CssClass="form-control" />
<asp:RequiredFieldValidator runat="server" ID="rfvFUB" ControlToValidate="FUplCsv_B" Text="!!!" CssClass="text-danger" />
<asp:RequiredFieldValidator runat="server" ID="rfvFUB" ControlToValidate="FUplCsv_B" Text="<b>File Missing</b>: please select file to upload!" CssClass="text-danger" Display="Dynamic" />
</div>
</div>
</div>
+228 -63
View File
@@ -1,85 +1,250 @@
using SteamWare;
using Newtonsoft.Json;
using SteamWare;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
namespace WebLCP.WUC
{
public partial class mod_startJob : System.Web.UI.UserControl
public partial class mod_startJob : BaseUserControl
{
public Dictionary<string, string> ctrError
{
get
{
Dictionary<string, string> answ = new Dictionary<string, string>();
string rawData = memLayer.ML.StringSessionObj("ctrError");
if (!string.IsNullOrEmpty(rawData))
{
answ = JsonConvert.DeserializeObject<Dictionary<string, string>>(rawData);
}
return answ;
}
set
{
string jsonData = JsonConvert.SerializeObject(value);
memLayer.ML.setSessionVal("ctrError", jsonData);
}
}
public Dictionary<string, string> ctrSuccess
{
get
{
Dictionary<string, string> answ = new Dictionary<string, string>();
string rawData = memLayer.ML.StringSessionObj("ctrSuccess");
if (!string.IsNullOrEmpty(rawData))
{
answ = JsonConvert.DeserializeObject<Dictionary<string, string>>(rawData);
}
return answ;
}
set
{
string jsonData = JsonConvert.SerializeObject(value);
memLayer.ML.setSessionVal("ctrSuccess", jsonData);
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
cleanupDir();
}
}
/// <summary>
/// pulisce folder upload da files in IN lascaiti da oltre 15 minuti...
/// </summary>
private void cleanupDir()
{
//fileMover.obj.deleteOldest();
}
protected void lbtUpload_Click(object sender, EventArgs e)
{
// controllo se ho i 2 files...
if (FUplCsv_A.FileName != "" && FUplCsv_B.FileName != "")
checkAndUploadFile(true);
}
private void checkAndUploadFile(bool doUpload)
{
// init dei dizionari errori/successi
ctrError = new Dictionary<string, string>();
ctrSuccess = new Dictionary<string, string>();
// inizio controlli...
if (FUplCsv_A.FileName != "" && (FUplCsv_A.FileName.EndsWith(".txt") || FUplCsv_A.FileName.EndsWith(".csv")))
{
// creo record
DS_App.JobsListDataTable tabJobs = dataLayer.man.taJL.insertNew(txtJobDescr.Text.Trim(), devicesAuthProxy.stObj.utente);
if (tabJobs.Count == 1)
ctrSuccess.Add("DB_INPUT", "OK Filename DB INPUT");
}
else
{
ctrError.Add("DB_INPUT", "WRONG Filename DB INPUT (only *.csv and *.txt)");
}
if (FUplCsv_B.FileName != "" && (FUplCsv_B.FileName.EndsWith(".txt") || FUplCsv_B.FileName.EndsWith(".csv")))
{
ctrSuccess.Add("DB_INPUT_CLU", "OK Filename DB INPUT CLU");
}
else
{
ctrError.Add("DB_INPUT_CLU", "WRONG Filename DB INPUT CLU (only *.csv and *.txt)");
}
// se ho errori mostro......
if (ctrError.Count == 0)
{
// se solo controllo --> folder temporanea (che poi elimino)
if (!doUpload)
{
/*************************************************
* CON il nome JOB (ID) creato...
* - devo creare una folder x il job
* - nella folder devo salvare i 2 files
* - sposto folder in area IN
* - devo creare un file *.req (anche vuoto) della richiesta di calcolo (in area IN)
*************************************************/
// recupero riga...
DS_App.JobsListRow currJob = tabJobs[0];
// uso il nome job creato x le path temporanee con 16 char...
string jobName = "J"+currJob.JobId.ToString("D9");
// creo upload dir...
string sourceDir = Server.MapPath($"{memLayer.ML.CRS("tempUploadDir")}\\{jobName}\\");
string jobName = $"TMP{DateTime.Now.ToString("yyyyMMdd_HHmmss_fff")}";
// carico localmente files
string sourceDir = uploadLocally(jobName);
// controllo i files...
checkFilesUploaded(sourceDir);
// elimino file locali...
fileMover.obj.setDirectory(sourceDir);
fileMover.obj.checkDir();
// proseguo con upload files...
string fileNameA = Path.GetFileName(FUplCsv_A.FileName);
string fileNameB = Path.GetFileName(FUplCsv_B.FileName);
FUplCsv_A.SaveAs($"{sourceDir}{fileNameA}");
FUplCsv_B.SaveAs($"{sourceDir}{fileNameB}");
// sposto folder in dir target..
// creo cartella in server target
#if false
//string sourceDir= Server.MapPath($"{tempUploadDir}");
//string destDir = Server.MapPath($"{memLayer.ML.CRS("clusterBaseDir")}\\IN\\"); // @"L:\IN\";
#endif
string destDir = $"{memLayer.ML.CRS("clusterBaseDir")}\\IN\\"; // @"L:\IN\";
#if false
fileMover.obj.copiaFile(sourceDir, destDir, FUplCsv_A.FileName);
fileMover.obj.copiaFile(sourceDir, destDir, FUplCsv_B.FileName);
#endif
fileMover.DirectoryCopy(sourceDir, destDir+$"{jobName}\\", true);
// aggiungo file di request...
File.WriteAllText($"{destDir}\\{jobName}.req", "");
#if false
//File.Create($"{destDir}\\{jobName}.req");
#endif
// NON VA con auth di rete (ha già creato?!?)
#if false
string destDir = $"{memLayer.ML.CRS("clusterBaseDir")}\\IN";
NetworkCredential destCred = new NetworkCredential
fileMover.obj.eliminaDir();
}
else
{
// creo record
DS_App.JobsListDataTable tabJobs = dataLayer.man.taJL.insertNew(txtJobDescr.Text.Trim(), devicesAuthProxy.stObj.utente);
if (tabJobs.Count == 1)
{
Domain = "",
UserName = "fbfusr",
Password = "fbfpwd2019!"
};
// trasferisco dati
fileMover.copiaFileL2N(sourceDir, destDir, destCred, FUplCsv_A.FileName, "File_A.csv");
fileMover.copiaFileL2N(sourceDir, destDir, destCred, FUplCsv_B.FileName, "File_B.csv");
#endif
/*************************************************
* CON il nome JOB (ID) creato...
* - devo creare una folder x il job
* - nella folder devo salvare i 2 files
* - sposto folder in area IN
* - devo creare un file *.req (anche vuoto) della richiesta di calcolo (in area IN)
*************************************************/
// registro trasferimento effettuato...
int sizeKb = (FUplCsv_A.PostedFile.ContentLength + FUplCsv_B.PostedFile.ContentLength) / 1024;
// update record!
dataLayer.man.taJL.updateUpload(currJob.JobId, DateTime.Now, sizeKb, destDir);
// recupero riga...
DS_App.JobsListRow currJob = tabJobs[0];
// uso il nome job creato x le path temporanee con 16 char...
string jobName = "J" + currJob.JobId.ToString("D9");
// carico localmente files
string sourceDir = uploadLocally(jobName);
// sposto su cluster
string destDir = moveToCluster(jobName, sourceDir);
// aggiorno su DB
updateDbRecord(currJob, destDir);
}
else
{
ctrError.Add("DB_JOB", "Error creating record on DB");
}
}
}
// se ho errori mostro......
if (ctrError.Count > 0)
{
raiseEvent(ucEvType.ReqUpdateParent);
}
}
/// <summary>
/// Controllo dei fiels caricati localmente
/// </summary>
/// <param name="sourceDir"></param>
private void checkFilesUploaded(string sourceDir)
{
string regExpHead = @"^\w*;\w*;\w*;\w*$"; ;
string[] linesDbIn;
// controllo DB_IN
linesDbIn = File.ReadAllLines($"{sourceDir}DB_INPUT.csv");
string regExpBody = @"^\d*;(0|1);(pos|neg);\-?\d+\,\d+d*$";
checkAllFile(linesDbIn, regExpHead, regExpBody);
// controllo DB_IN_CLU
linesDbIn = File.ReadAllLines($"{sourceDir}DB_INPUT_CLU.csv");
regExpBody = @"^(pos|neg);\d*;(0|1);\-?\d+\,\d+d*$";
checkAllFile(linesDbIn, regExpHead, regExpBody);
}
/// <summary>
/// controllo il file...
/// </summary>
/// <param name="linesDbIn"></param>
/// <param name="regExpHead"></param>
/// <param name="regExpBody"></param>
private void checkAllFile(string[] linesDbIn, string regExpHead, string regExpBody)
{
// controllo abbia ALMENO 2 linee (testata + valore)
if (linesDbIn.Length > 1)
{
Regex rgxHead = new Regex(regExpHead);
Regex rgxBody = new Regex(regExpBody);
// controllo linea intestazione
if (!rgxHead.IsMatch(linesDbIn[0]))
{
ctrError.Add("DB_INPUT.csv", $"HEADER ERROR (mismatch): found --> {linesDbIn[0]}");
}
// controllo linee successive
for (int i = 1; i < linesDbIn.Length; i++)
{
if (!rgxBody.IsMatch(linesDbIn[i]))
{
ctrError.Add("DB_INPUT.csv", $"DATA ERROR (mismatch): line {i} --> {linesDbIn[i]}");
}
}
}
else
{
ctrError.Add("DB_INPUT.csv", "Expected almost 2 lines (header + data)");
}
}
/// <summary>
/// aggiornamento record su DB post upload
/// </summary>
/// <param name="currJob"></param>
/// <param name="destDir"></param>
private void updateDbRecord(DS_App.JobsListRow currJob, string destDir)
{
// registro trasferimento effettuato...
int sizeKb = (FUplCsv_A.PostedFile.ContentLength + FUplCsv_B.PostedFile.ContentLength) / 1024;
// update record!
dataLayer.man.taJL.updateUpload(currJob.JobId, DateTime.Now, sizeKb, destDir);
}
/// <summary>
/// Sposta i dati da directory locale a cluster
/// </summary>
/// <param name="jobName"></param>
/// <param name="sourceDir"></param>
/// <returns></returns>
private static string moveToCluster(string jobName, string sourceDir)
{
// creo cartella in server target
string destDir = $"{memLayer.ML.CRS("clusterBaseDir")}\\IN\\"; // @"L:\IN\";
// sposto folder in dir target..
fileMover.DirectoryCopy(sourceDir, destDir + $"{jobName}\\", true);
// aggiungo file di request...
File.WriteAllText($"{destDir}\\{jobName}.req", "");
return destDir;
}
/// <summary>
/// Carica localmente (sul server) i dati e restituisce path locale (compreso di jobName nella path)
/// </summary>
/// <param name="jobName"></param>
/// <returns></returns>
private string uploadLocally(string jobName)
{
// creo upload dir...
string sourceDir = Server.MapPath($"{memLayer.ML.CRS("tempUploadDir")}\\{jobName}\\");
fileMover.obj.setDirectory(sourceDir);
fileMover.obj.checkDir();
// proseguo con upload files...
string fileNameA = Path.GetFileName(FUplCsv_A.FileName);
string fileNameB = Path.GetFileName(FUplCsv_B.FileName);
FUplCsv_A.SaveAs($"{sourceDir}DB_INPUT.csv");
FUplCsv_B.SaveAs($"{sourceDir}DB_INPUT_CLU.csv");
return sourceDir;
}
}
}
+9
View File
@@ -21,6 +21,15 @@ namespace WebLCP.WUC {
/// </remarks>
protected global::System.Web.UI.WebControls.TextBox txtJobDescr;
/// <summary>
/// Controllo rfvJobDescr.
/// </summary>
/// <remarks>
/// Campo generato automaticamente.
/// Per la modifica, spostare la dichiarazione di campo dal file di progettazione al file code-behind.
/// </remarks>
protected global::System.Web.UI.WebControls.RequiredFieldValidator rfvJobDescr;
/// <summary>
/// Controllo HyperLink1.
/// </summary>
Vendored
+1 -1
View File
@@ -17,7 +17,7 @@ pipeline {
/* calcolo numero versione... diverso x branch MASTER/DEVELOP */
script {
withEnv(['NEXT_BUILD_NUMBER=42']) {
withEnv(['NEXT_BUILD_NUMBER=43']) {
// env.versionNumber = VersionNumber(versionNumberString : '0.8.${BUILD_DATE_FORMATTED, "yyMM"}.${BUILDS_ALL_TIME}', projectStartDate : '2019-07-01', skipFailedBuilds: true)
env.versionNumber = VersionNumber(versionNumberString : '0.8.${BUILD_DATE_FORMATTED, "yyMM"}.${BUILDS_ALL_TIME}', projectStartDate : '2019-07-01', skipFailedBuilds: true, overrideBuildsAllTime: '${NEXT_BUILD_NUMBER}')
env.APP_NAME = 'LCP'