2024-05-07 13:11:30 +00:00
using Common.SqlExtensions ;
using Newtonsoft.Json ;
2021-10-01 09:09:20 +00:00
using System ;
using System.Collections.Generic ;
using System.Data ;
using System.IO ;
using System.Linq ;
using System.Net ;
using System.Net.Http ;
using System.Text ;
2024-05-07 13:11:30 +00:00
using System.Text.RegularExpressions ;
2021-10-01 09:09:20 +00:00
using System.Threading.Tasks ;
using System.Web ;
using System.Web.Http ;
using Xylem.Common.Cryptology.Security ;
2024-05-07 13:11:30 +00:00
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore ;
2023-12-11 12:26:15 +00:00
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers ;
2022-05-10 13:34:48 +00:00
using Xylem.Common.Logic.ProductionOrderCore.OrderData ;
2022-09-23 11:52:57 +00:00
using Xylem.Common.Logic.ServiceCore ;
2021-10-01 09:09:20 +00:00
using Xylem.ServiceFwUpdate.Common.FwUpdateDb ;
namespace Xylem.Common.Service.MeterProcessState.Controllers
{
public class FwUpdateController : ApiController
{
public static class GlobalConfig
{
2022-10-19 10:58:08 +00:00
public static Lazy < String > connectionString = new Lazy < String > ( ( )
2021-10-01 09:09:20 +00:00
= >
System . Configuration . ConfigurationManager . ConnectionStrings [ "default" ] . ConnectionString
) ;
}
//
[Route("GetUserList"), HttpGet]
2022-10-19 10:58:08 +00:00
public async Task < HttpResponseMessage > GetUserList ( String LogInName = "" , Int32 ? Id = null )
2021-10-01 09:09:20 +00:00
{
return await Task . Run ( ( ) = >
{
try
{
return Request . CreateResponse ( HttpStatusCode . OK , getUserList ( LogInName , Id ) ) ;
}
catch ( Exception ex )
{
return Request . CreateResponse ( HttpStatusCode . InternalServerError , ex ) ;
}
} ) ;
}
2022-10-19 10:58:08 +00:00
private System . Collections . Generic . List < UserInformation > getUserList ( String LogInName = "" , Int32 ? Id = null )
2021-10-01 09:09:20 +00:00
{
var ret = new System . Collections . Generic . List < UserInformation > ( ) ;
using ( var dataacces = new SqlDataAccess ( GlobalConfig . connectionString . Value ) )
{
var sb = new StringBuilder ( ) ;
sb . AppendLine ( $" select UserId, FullName,LogInName, Domain,HardwareId,PasswordHash,RegisterDate,ValidDate,AccountActive from FWUpdateUser " ) ;
if ( Id . HasValue )
{
sb . Append ( $" where UserId={Id.Value} " ) ;
}
else if ( ! string . IsNullOrEmpty ( LogInName ) )
{
sb . Append ( $" where LogInName like '%{LogInName}%' " ) ;
}
var dbResult = dataacces . ExecuteQuery ( sb . ToString ( ) ) ;
foreach ( DataRow row in dbResult . Rows )
{
ret . Add (
2022-10-19 10:58:08 +00:00
new UserInformation ( ( Int32 ) row [ "UserId" ] )
2021-10-01 09:09:20 +00:00
{
2022-10-19 10:58:08 +00:00
FullName = row [ "FullName" ] = = DBNull . Value ? "" : ( String ) row [ "FullName" ] ,
LogInName = ( String ) row [ "LogInName" ] ,
Domain = ( String ) row [ "Domain" ] ,
HardwareId = row [ "HardwareId" ] = = DBNull . Value ? "" : ( String ) row [ "HardwareId" ] ,
PasswordHash = row [ "PasswordHash" ] = = DBNull . Value ? "" : ( String ) row [ "PasswordHash" ] ,
2021-10-01 09:09:20 +00:00
RegisterDate = ( DateTimeOffset ) row [ "RegisterDate" ] ,
ValidDate = ( DateTimeOffset ) row [ "ValidDate" ] ,
2022-10-19 10:58:08 +00:00
AccountActive = ( Boolean ) row [ "AccountActive" ] ,
2021-10-01 09:09:20 +00:00
} ) ;
}
return ret ;
}
}
[Route("GetAllBuilderOperator"), HttpGet]
public async Task < HttpResponseMessage > GetAllBuilderOperator ( )
{
return await Task . Run ( ( ) = >
{
try
{
var ret = new System . Collections . Generic . List < UserInformation > ( ) ;
using ( var dataacces = new SqlDataAccess ( GlobalConfig . connectionString . Value ) )
{
var sb = new StringBuilder ( ) ;
sb . AppendLine ( $" select UserId, FullName,LogInName, Domain,HardwareId,AccountActive from FWUpdateBuilderUser " ) ;
var dbResult = dataacces . ExecuteQuery ( sb . ToString ( ) ) ;
foreach ( DataRow row in dbResult . Rows )
{
ret . Add (
2022-10-19 10:58:08 +00:00
new UserInformation ( ( Int32 ) row [ "UserId" ] )
2021-10-01 09:09:20 +00:00
{
2022-10-19 10:58:08 +00:00
FullName = row [ "FullName" ] = = DBNull . Value ? "" : ( String ) row [ "FullName" ] ,
LogInName = ( String ) row [ "LogInName" ] ,
Domain = ( String ) row [ "Domain" ] ,
HardwareId = row [ "HardwareId" ] = = DBNull . Value ? "" : ( String ) row [ "HardwareId" ] ,
AccountActive = ( Boolean ) row [ "AccountActive" ] ,
2021-10-01 09:09:20 +00:00
} ) ;
}
return Request . CreateResponse ( HttpStatusCode . OK , ret ) ;
}
}
catch ( Exception ex )
{
return Request . CreateResponse ( HttpStatusCode . InternalServerError , ex ) ;
}
} ) ;
}
[Route("RefreshUsersHardwareId"), HttpGet]
2022-10-19 10:58:08 +00:00
public async Task < HttpResponseMessage > RefreshUsersHardwareId ( Int32 id , String HardwareId )
2021-10-01 09:09:20 +00:00
{
return await Task . Run ( ( ) = >
{
try
{
var ret = new System . Collections . Generic . List < UserInformation > ( ) ;
using ( var dataacces = new SqlDataAccess ( GlobalConfig . connectionString . Value ) )
{
var sb = new StringBuilder ( ) ;
sb . AppendLine ( $" Update FWUpdateUser set HardwareId = '{HardwareId}' where UserId = {id} " ) ;
var dbResult = dataacces . ExecuteQuery ( sb . ToString ( ) ) ;
return Request . CreateResponse ( HttpStatusCode . OK , true ) ;
}
}
catch ( Exception ex )
{
return Request . CreateResponse ( HttpStatusCode . InternalServerError , ex ) ;
}
} ) ;
}
[Route("RefreshUsersPasswordHash"), HttpGet]
2022-10-19 10:58:08 +00:00
public async Task < HttpResponseMessage > RefreshUsersPasswordHash ( Int32 id , String PasswordHash )
2021-10-01 09:09:20 +00:00
{
return await Task . Run ( ( ) = >
{
try
{
var ret = new System . Collections . Generic . List < UserInformation > ( ) ;
using ( var dataacces = new SqlDataAccess ( GlobalConfig . connectionString . Value ) )
{
var sb = new StringBuilder ( ) ;
sb . AppendLine ( $" Update FWUpdateUser set PasswordHash = '{PasswordHash}' where UserId = {id} " ) ;
var dbResult = dataacces . ExecuteQuery ( sb . ToString ( ) ) ;
return Request . CreateResponse ( HttpStatusCode . OK , true ) ;
}
}
catch ( Exception ex )
{
return Request . CreateResponse ( HttpStatusCode . InternalServerError , ex ) ;
}
} ) ;
}
[Route("EditUserValidity"), HttpGet]
2022-10-19 10:58:08 +00:00
public async Task < HttpResponseMessage > EditUserValidity ( Int32 id , DateTimeOffset ? ValidDate = null , Boolean ? AccountActive = null )
2021-10-01 09:09:20 +00:00
{
return await Task . Run ( ( ) = >
{
try
{
if ( ValidDate . HasValue | | AccountActive . HasValue )
{
var ret = new System . Collections . Generic . List < UserInformation > ( ) ;
using ( var dataacces = new SqlDataAccess ( GlobalConfig . connectionString . Value ) )
{
var sb = new StringBuilder ( ) ;
sb . AppendLine ( $" Update FWUpdateUser set " ) ;
if ( ValidDate . HasValue )
{
sb . AppendLine ( $" ValidDate = '{ValidDate.Value.ToUniversalTime().ToString(" yyyy - MM - dd HH : mm : ss + 00 : 00 ")}' " ) ;
}
if ( AccountActive . HasValue )
{
if ( ValidDate . HasValue )
{
sb . AppendLine ( $" , " ) ;
}
if ( AccountActive . Value )
{
sb . AppendLine ( $" AccountActive = 1 " ) ;
}
else
{
sb . AppendLine ( $" AccountActive = 0 " ) ;
}
}
sb . AppendLine ( $" where UserId = {id} " ) ;
var dbResult = dataacces . ExecuteQuery ( sb . ToString ( ) ) ;
return Request . CreateResponse ( HttpStatusCode . OK , true ) ;
}
}
return Request . CreateResponse ( HttpStatusCode . InternalServerError , "no change" ) ;
}
catch ( Exception ex )
{
return Request . CreateResponse ( HttpStatusCode . InternalServerError , ex ) ;
}
} ) ;
}
[Route("GetFileContent"), HttpGet]
2022-10-19 10:58:08 +00:00
public async Task < HttpResponseMessage > GetFileContent ( Int32 FileId )
2021-10-01 09:09:20 +00:00
{
return await Task . Run ( ( ) = >
{
try
{
using ( var dataacces = new SqlDataAccess ( GlobalConfig . connectionString . Value ) )
{
var sb = new StringBuilder ( ) ;
sb . AppendLine ( $" SELECT TOP (1) [FileContent] FROM [Auftrag].[dbo].[File] where FileId = {FileId}" ) ;
var dbResult = dataacces . ExecuteQuery ( sb . ToString ( ) ) ;
return Request . CreateResponse ( HttpStatusCode . OK , dbResult . Rows [ 0 ] [ 0 ] ) ;
}
}
catch ( Exception ex )
{
return Request . CreateResponse ( HttpStatusCode . InternalServerError , ex ) ;
}
} ) ;
}
[Route("GetFWUpdateSafeContainers"), HttpGet]
2022-10-19 10:58:08 +00:00
public async Task < HttpResponseMessage > GetFWUpdateSafeContainers ( Int32 UserId )
2021-10-01 09:09:20 +00:00
{
return await Task . Run ( ( ) = >
{
try
{
var ret = new System . Collections . Generic . List < FwUpdateSafeDb > ( ) ;
using ( var dataacces = new SqlDataAccess ( GlobalConfig . connectionString . Value ) )
{
var sb = new StringBuilder ( ) ;
sb . AppendLine ( $" select * from [dbo].[FWUpdateSafeContainer] " ) ;
2022-04-06 08:42:16 +00:00
sb . Append ( $" where FWUpdateSafeContainer_UserId ={UserId} " ) ;
//FWUpdateSafeContainer_ValidDate >= CURRENT_TIMESTAMP and
2021-10-01 09:09:20 +00:00
var dbResult = dataacces . ExecuteQuery ( sb . ToString ( ) ) ;
foreach ( DataRow row in dbResult . Rows )
{
ret . Add (
new FwUpdateSafeDb ( )
{
2022-10-19 10:58:08 +00:00
ContainerId = ( Int32 ) row [ "FWUpdateSafeContainer_ID" ] ,
Name = ( String ) row [ "FWUpdateSafeContainer_Name" ] ,
UserId = ( Int32 ) row [ "FWUpdateSafeContainer_UserId" ] ,
FilePartId = ( Int32 ) row [ "FWUpdateSafeContainer_FileId" ] ,
2021-10-01 09:09:20 +00:00
ValidDate = ( DateTime ) row [ "FWUpdateSafeContainer_ValidDate" ]
} ) ;
}
}
return Request . CreateResponse ( HttpStatusCode . OK , ret ) ;
}
catch ( Exception ex )
{
return Request . CreateResponse ( HttpStatusCode . InternalServerError , ex ) ;
}
} ) ;
}
[Route("AddPcbIdsToSafe"), HttpPost]
2022-10-19 10:58:08 +00:00
public async Task < HttpResponseMessage > AddPcbIdsToSafe ( Int32 ContainerDbId , [ FromBody ] List < Int32 > PcbIds )
2021-10-01 09:09:20 +00:00
{
return await Task . Run ( ( ) = >
{
try
{
using ( var dataacces = new SqlDataAccess ( GlobalConfig . connectionString . Value ) )
{
StringBuilder sb = null ;
foreach ( var item in PcbIds )
{
if ( sb = = null )
{
sb = new StringBuilder ( ) ;
sb . AppendLine ( $" insert into FWUpdateSafeContainerPcbIds " ) ;
}
else
{
sb . AppendLine ( $" UNION " ) ;
}
sb . AppendLine ( $" SELECT {ContainerDbId}, {item}" ) ;
}
var dbResult = dataacces . ExecuteQuery ( sb . ToString ( ) ) ;
return Request . CreateResponse ( HttpStatusCode . OK , true ) ;
}
}
catch ( Exception ex )
{
return Request . CreateResponse ( HttpStatusCode . InternalServerError , ex ) ;
}
} ) ;
}
[Route("GetPcbIdsFromSafe"), HttpGet]
2022-10-19 10:58:08 +00:00
public async Task < HttpResponseMessage > GetPcbIdsFromSafe ( Int32 ContainerDbId )
2021-10-01 09:09:20 +00:00
{
return await Task . Run ( ( ) = >
{
try
{
2022-10-19 10:58:08 +00:00
var ret = new System . Collections . Generic . List < Int32 > ( ) ;
2021-10-01 09:09:20 +00:00
using ( var dataacces = new SqlDataAccess ( GlobalConfig . connectionString . Value ) )
{
var sb = new StringBuilder ( ) ;
sb . AppendLine ( $" select [FWUpdateSafeContainer_PcbId] from [dbo].[FWUpdateSafeContainerPcbIds] " ) ;
sb . Append ( $" where [FWUpdateSafeContainer_ID] = {ContainerDbId} " ) ;
var dbResult = dataacces . ExecuteQuery ( sb . ToString ( ) ) ;
foreach ( DataRow row in dbResult . Rows )
{
2022-10-19 10:58:08 +00:00
ret . Add ( ( Int32 ) row [ "FWUpdateSafeContainer_PcbId" ] ) ;
2021-10-01 09:09:20 +00:00
}
}
return Request . CreateResponse ( HttpStatusCode . OK , ret ) ;
}
catch ( Exception ex )
{
return Request . CreateResponse ( HttpStatusCode . InternalServerError , ex ) ;
}
} ) ;
}
2022-06-23 08:20:26 +00:00
/// <summary>
///
/// </summary>
/// <param name="PUserId"></param>
/// <param name="PFileName"></param>
/// <param name="PValidDate"></param>
/// <param name="PBuilderOperatorName"></param>
/// <returns></returns>
2021-10-01 09:09:20 +00:00
[Route("PostFWUpdateSafeOdd"), HttpPost]
2022-06-23 08:20:26 +00:00
2022-10-19 10:58:08 +00:00
public async Task < HttpResponseMessage > PostFWUpdateSafeOdd ( Int32 PUserId , String PFileName , DateTime PValidDate , String PBuilderOperatorName = "none" )
2021-10-01 09:09:20 +00:00
{
2022-06-23 08:20:26 +00:00
if ( PFileName . Length > 150 )
{
throw new ApplicationException ( "File name is to long" ) ;
}
2021-10-01 09:09:20 +00:00
var inpStrem = HttpContext . Current . Request . GetBufferlessInputStream ( true ) ;
var inpHeaders = Request . Content . Headers ;
return await Task . Run ( async ( ) = >
{
try
{
using ( var dataacces = new SqlDataAccess ( GlobalConfig . connectionString . Value ) )
{
var parameters = new List < System . Data . SqlClient . SqlParameter > ( ) ;
2022-06-23 08:20:26 +00:00
var FileName = new System . Data . SqlClient . SqlParameter ( "@FileName" , SqlDbType . NVarChar , 150 ) ;
2021-10-01 09:09:20 +00:00
var UserId = new System . Data . SqlClient . SqlParameter ( "@UserId" , SqlDbType . Int ) ;
var ValidDate = new System . Data . SqlClient . SqlParameter ( "@ValidDate" , SqlDbType . Date ) ;
FileName . Value = PFileName ;
UserId . Value = PUserId ;
ValidDate . Value = PValidDate ;
parameters . Add ( ValidDate ) ;
var sb = new StringBuilder ( ) ;
sb . AppendLine ( $" Declare @FileID as int " ) ;
2022-06-23 08:20:26 +00:00
sb . AppendLine ( $" Declare @FileName as NVarChar(150) " ) ;
2021-10-01 09:09:20 +00:00
sb . AppendLine ( $" Declare @UserId as int " ) ;
sb . AppendLine ( $" set @FileName = '{PFileName}' " ) ;
sb . AppendLine ( $" set @UserId = {PUserId} " ) ;
//sb.AppendLine($" INSERT INTO [dbo].[File] ([FileContent], [FileName]) VALUES (@FileContent, @FileName) ;");
//sb.AppendLine($" SELECT @FileID = @@IDENTITY; ");
sb . AppendLine ( $" INSERT INTO [dbo].[FWUpdateSafeContainer] ([FWUpdateSafeContainer_Name],[FWUpdateSafeContainer_UserId],[FWUpdateSafeContainer_FileId],[FWUpdateSafeContainer_ValidDate])" ) ;
sb . AppendLine ( $" VALUES(@FileName,@UserId,0,@ValidDate); " ) ;
sb . AppendLine ( $" select @@IDENTITY as ContainerID, @FileID as FilePartId " ) ;
var retDT = dataacces . ExecuteQuery ( sb . ToString ( ) , parameters ) ;
var newID = Convert . ToInt32 ( retDT . Rows [ 0 ] [ 0 ] . ToString ( ) ) ;
var fileuploadPath = $"C:\\\\Temp\\{newID}\\" ;
Directory . CreateDirectory ( fileuploadPath ) ;
var provider = new MultipartFormDataStreamProvider ( fileuploadPath ) ;
var content = new StreamContent ( inpStrem ) ;
foreach ( var header in inpHeaders )
{
content . Headers . TryAddWithoutValidation ( header . Key , header . Value ) ;
}
await content . ReadAsMultipartAsync ( provider ) ;
2022-10-19 10:58:08 +00:00
String uploadingFileName = provider . FileData . Select ( x = > x . LocalFileName ) . FirstOrDefault ( ) ;
String originalFileName = string . Concat ( fileuploadPath , "\\" + ( provider . Contents [ 0 ] . Headers . ContentDisposition . FileName ) . Trim ( new Char [ ] { '"' } ) ) ;
2021-10-01 09:09:20 +00:00
if ( File . Exists ( originalFileName ) )
{
File . Delete ( originalFileName ) ;
}
File . Move ( uploadingFileName , originalFileName ) ;
return Request . CreateResponse ( HttpStatusCode . OK , newID ) ;
}
2022-04-06 08:42:16 +00:00
2021-10-01 09:09:20 +00:00
}
catch ( Exception ex )
{
return Request . CreateResponse ( HttpStatusCode . InternalServerError , ex ) ;
}
} ) ;
}
[Route("GetFWUpdateSafeContainerContent"), HttpGet]
2022-10-19 10:58:08 +00:00
public async Task < HttpResponseMessage > GetFWUpdateSafeContainerContent ( Int32 SafeContainerId )
2021-10-01 09:09:20 +00:00
{
return await Task . Run ( ( ) = >
{
try
{
var ret = new System . Collections . Generic . List < FwUpdateSafeDb > ( ) ;
using ( var dataacces = new SqlDataAccess ( GlobalConfig . connectionString . Value ) )
{
var sb = new StringBuilder ( ) ;
sb . AppendLine ( $" select * from [dbo].[FWUpdateSafeContainer] " ) ;
sb . Append ( $" where FWUpdateSafeContainer_ValidDate >= CURRENT_TIMESTAMP and FWUpdateSafeContainer_ID ={SafeContainerId} " ) ;
var dbResult = dataacces . ExecuteQuery ( sb . ToString ( ) ) ;
foreach ( DataRow row in dbResult . Rows )
{
2022-10-19 10:58:08 +00:00
var content = new Byte [ ] { } ;
var filePath = $"C:\\\\Temp\\{(Int32)row[" FWUpdateSafeContainer_ID "]}\\{(String)row[" FWUpdateSafeContainer_Name "]}" ;
2021-10-01 09:09:20 +00:00
if ( File . Exists ( filePath ) )
{
content = File . ReadAllBytes ( filePath ) ;
}
else
{
content = ASCIIEncoding . ASCII . GetBytes ( "File Not Found" ) ;
}
ret . Add (
new FwUpdateSafeDb ( )
{
2022-10-19 10:58:08 +00:00
ContainerId = ( Int32 ) row [ "FWUpdateSafeContainer_ID" ] ,
Name = ( String ) row [ "FWUpdateSafeContainer_Name" ] ,
UserId = ( Int32 ) row [ "FWUpdateSafeContainer_UserId" ] ,
FilePartId = ( Int32 ) row [ "FWUpdateSafeContainer_FileId" ] ,
2021-10-01 09:09:20 +00:00
ValidDate = ( DateTime ) row [ "FWUpdateSafeContainer_ValidDate" ] ,
Content = content
} ) ;
}
}
return Request . CreateResponse ( HttpStatusCode . OK , ret ) ;
}
catch ( Exception ex )
{
return Request . CreateResponse ( HttpStatusCode . InternalServerError , ex ) ;
}
} ) ;
}
[Route("PostFWUpdateSafe"), HttpPost]
public async Task < HttpResponseMessage > PostFWUpdateSafe ( [ FromBody ] FwUpdateSafeDb fwc )
{
return await Task . Run ( ( ) = >
{
try
{
using ( var dataacces = new SqlDataAccess ( GlobalConfig . connectionString . Value ) )
{
var parameters = new List < System . Data . SqlClient . SqlParameter > ( ) ;
var FileContent = new System . Data . SqlClient . SqlParameter ( "FileContent" , SqlDbType . VarBinary ) ;
// var FileName = new System.Data.SqlClient.SqlParameter("FileName", SqlDbType.NVarChar, 50);
var UserId = new System . Data . SqlClient . SqlParameter ( "UserId" , SqlDbType . Int ) ;
var ValidDate = new System . Data . SqlClient . SqlParameter ( "ValidDate" , SqlDbType . Date ) ;
// FileName.Value = fwc.Name;
FileContent . Value = fwc . Content ;
UserId . Value = fwc . UserId ;
ValidDate . Value = fwc . ValidDate . Date ;
//parameters.Add(FileName);
parameters . Add ( UserId ) ;
parameters . Add ( FileContent ) ;
parameters . Add ( ValidDate ) ;
var sb = new StringBuilder ( ) ;
sb . AppendLine ( $" Declare @FileID as int " ) ;
sb . AppendLine ( $" INSERT INTO [dbo].[File] ([FileContent], [FileName]) VALUES (@FileContent, 't') ;" ) ;
sb . AppendLine ( $" SELECT @FileID = @@IDENTITY; " ) ;
sb . AppendLine ( $" INSERT INTO [dbo].[FWUpdateSafeContainer] ([FWUpdateSafeContainer_Name],[FWUpdateSafeContainer_UserId],[FWUpdateSafeContainer_FileId],[FWUpdateSafeContainer_ValidDate])" ) ;
sb . AppendLine ( $" VALUES('t',@UserId,@FileID,@ValidDate); " ) ;
sb . AppendLine ( $" select @@IDENTITY as ContainerID, @FileID as FilePartId " ) ;
var retDT = dataacces . ExecuteQuery ( sb . ToString ( ) , parameters ) ;
var newID = Convert . ToInt32 ( retDT . Rows [ 0 ] [ 0 ] . ToString ( ) ) ;
return Request . CreateResponse ( HttpStatusCode . OK , newID ) ;
}
}
catch ( Exception ex )
{
return Request . CreateResponse ( HttpStatusCode . InternalServerError , ex ) ;
}
} ) ;
}
2022-10-19 10:58:08 +00:00
public virtual Byte [ ] GetFileBytes ( HttpPostedFile uploadedFile )
2021-10-01 09:09:20 +00:00
{
2022-10-19 10:58:08 +00:00
var bytes = new Byte [ uploadedFile . ContentLength ] ;
2021-10-01 09:09:20 +00:00
uploadedFile . InputStream . Read ( bytes , 0 , uploadedFile . ContentLength ) ;
return bytes ;
}
[Route("PostFWUpdateReportFile"), HttpPost]
public async Task < HttpResponseMessage > PostFWUpdateReportFiles ( [ FromBody ] FwUpdateReportDb FileContent )
{
return await Task . Run ( ( ) = >
{
try
{
using ( var dataacces = new SqlDataAccess ( GlobalConfig . connectionString . Value ) )
{
var parameters = new List < System . Data . SqlClient . SqlParameter > ( ) ;
var DbFileContent = new System . Data . SqlClient . SqlParameter ( "@FileContent" , SqlDbType . VarBinary ) ;
2022-06-23 08:20:26 +00:00
var DbFileName = new System . Data . SqlClient . SqlParameter ( "@FileName" , SqlDbType . NVarChar , 150 ) ;
2021-10-01 09:09:20 +00:00
2022-04-06 08:42:16 +00:00
2021-10-01 09:09:20 +00:00
DbFileName . Value = FileContent . FileName ;
DbFileContent . Value = UTF32Encoding . UTF32 . GetBytes ( JsonConvert . SerializeObject ( FileContent ) ) ;
parameters . Add ( DbFileName ) ;
parameters . Add ( DbFileContent ) ;
var sb = new StringBuilder ( ) ;
sb . AppendLine ( $" Declare @FileID as int " ) ;
sb . AppendLine ( $" INSERT INTO [dbo].[File] ([FileContent], [FileName]) VALUES (@FileContent, @FileName) ;" ) ;
sb . AppendLine ( $" SELECT @FileID = @@IDENTITY; " ) ;
sb . AppendLine ( $" INSERT INTO [dbo].[FWUpdateReports] ([FWUpdateReport_Name],[FWUpdateReport_UserId], [FWUpdateReport_FileId],[FWUpdateReport_Date],[FWUpdateReport_PcbId], [FWUpdateReport_OrderNr], [FWUpdateReport_OrderPos]) " ) ;
sb . AppendLine ( $" VALUES(@FileName,{FileContent.UserId},@FileID,CURRENT_TIMESTAMP, {FileContent.PcbId}, {FileContent.OrderNr}, {FileContent.OrderPos} ); " ) ;
sb . AppendLine ( $" select @@IDENTITY as FWUpdateReportsId, @FileID as FilePartId " ) ;
var retDT = dataacces . ExecuteQuery ( sb . ToString ( ) , parameters ) ;
var newID = Convert . ToInt32 ( retDT . Rows [ 0 ] [ 0 ] . ToString ( ) ) ;
return Request . CreateResponse ( HttpStatusCode . OK , newID ) ;
}
return Request . CreateResponse ( HttpStatusCode . OK , false ) ;
}
catch ( Exception ex )
{
return Request . CreateResponse ( HttpStatusCode . InternalServerError , ex ) ;
}
} ) ;
}
[Route("GetFWUpdateReportFile"), HttpGet]
2022-10-19 10:58:08 +00:00
public async Task < HttpResponseMessage > GetFWUpdateReportFile ( Int32 ? PcbId = null , Int32 ? UserId = null , Int32 ? OrderNr = null , Boolean WithContent = true )
2021-10-01 09:09:20 +00:00
{
return await Task . Run ( ( ) = >
{
try
{
var ret = new System . Collections . Generic . List < FwUpdateReportDb > ( ) ;
using ( var dataacces = new SqlDataAccess ( GlobalConfig . connectionString . Value ) )
{
var sb = new StringBuilder ( ) ;
2022-04-06 08:42:16 +00:00
sb . AppendLine ( $" select FWUpdateReport_ID, FWUpdateReport_Name, FWUpdateReport_UserId, FWUpdateReport_FileId, FWUpdateReport_Date, FWUpdateReport_PcbId, FWUpdateReport_OrderNr " ) ;
if ( WithContent )
{
sb . Append ( ", FileContent " ) ;
}
2021-10-01 09:09:20 +00:00
sb . AppendLine ( $" from [dbo].[FWUpdateReports] r " ) ;
2022-04-06 08:42:16 +00:00
if ( WithContent )
{
sb . AppendLine ( $" inner join [dbo].[File] f on r.FWUpdateReport_FileId = f.FileId " ) ;
}
2021-10-01 09:09:20 +00:00
sb . AppendLine ( $" where FWUpdateReport_ID > 0 " ) ;
if ( PcbId . HasValue )
{
sb . AppendLine ( $" and FWUpdateReport_PcbId = {PcbId.Value}" ) ;
}
if ( UserId . HasValue )
{
sb . AppendLine ( $" and FWUpdateReport_UserId = {UserId.Value}" ) ;
}
if ( OrderNr . HasValue )
{
sb . AppendLine ( $" and FWUpdateReport_OrderNr = {OrderNr.Value}" ) ;
}
var dbResult = dataacces . ExecuteQuery ( sb . ToString ( ) ) ;
foreach ( DataRow row in dbResult . Rows )
{
2022-10-19 10:58:08 +00:00
var addOBJ = JsonConvert . DeserializeObject < FwUpdateReportDb > ( UTF32Encoding . UTF32 . GetString ( ( Byte [ ] ) row [ "FileContent" ] ) ) ;
addOBJ . FileId = ( Int32 ) row [ "FWUpdateReport_ID" ] ;
2021-10-01 09:09:20 +00:00
addOBJ . Date = ( DateTime ) row [ "FWUpdateReport_Date" ] ;
ret . Add ( addOBJ ) ;
2023-11-27 15:54:53 +00:00
//help to download all file to local store
//File.WriteAllText($"E:\\bat\\report\\{addOBJ.PcbId}_{addOBJ.FileId}.txt", addOBJ.Content);
2021-10-01 09:09:20 +00:00
}
}
return Request . CreateResponse ( HttpStatusCode . OK , ret ) ;
}
catch ( Exception ex )
{
return Request . CreateResponse ( HttpStatusCode . InternalServerError , ex ) ;
}
} ) ;
}
2022-05-10 13:34:48 +00:00
[Route("GetRecoveryFile"), HttpGet]
2023-02-19 09:57:55 +00:00
public async Task < HttpResponseMessage > GetRecoveryFile ( String pcbId , Int32 ? radioFrq , String region , String flexnetVersion )
2022-04-29 07:58:45 +00:00
{
2022-12-06 12:15:53 +00:00
var file = new RecoverySettings { PcbId = pcbId , RadioFrequencyMhz = radioFrq , Region = region , Release = flexnetVersion ,
RecoveryRegisters = new List < RecoveryRegisterItem >
{
2023-02-20 17:53:49 +00:00
new RecoveryRegisterItem { RegisterIdent = "GENESISFLOW_SealDisplay" , WriteValue = new Byte [ ] { 0x00 , 0x00 , 0x00 , 0x00 } ,
2022-12-06 12:15:53 +00:00
IsCritical = true , ReadBackValue = new Byte [ ] { 0x00 , 0x00 , 0x00 , 0x00 } }
}
} ;
2022-05-10 13:34:48 +00:00
2023-02-20 17:53:49 +00:00
var csdRet = OrderProgrammingParameters . GetProgrammingParameters ( pcbId , GlobalConfig . connectionString . Value ) ;
2022-05-10 13:34:48 +00:00
foreach ( var item in csdRet . Where ( w = > w . Source = = Logic . ProductionOrderCore . ProgrammingSource . Vako ) )
{
file . RecoveryRegisters . Add ( new RecoveryRegisterItem ( )
{
RegisterIdent = item . RegisterName ,
WriteValue = item . RegisterValue ,
2022-12-06 12:15:53 +00:00
ReadBackValue = null ,
IsCritical = false ,
2022-05-10 13:34:48 +00:00
Access = RegisterRecoveryAccess . SetAlways ,
} ) ;
}
foreach ( var item in csdRet . Where ( w = > w . Source = = Logic . ProductionOrderCore . ProgrammingSource . Csd ) )
{
file . RecoveryRegisters . Add ( new RecoveryRegisterItem ( )
{
RegisterIdent = item . RegisterName ,
WriteValue = item . RegisterValue ,
2022-12-06 12:15:53 +00:00
ReadBackValue = null ,
IsCritical = false ,
2022-05-10 13:34:48 +00:00
Access = RegisterRecoveryAccess . SetAlways ,
} ) ;
}
2022-12-06 12:15:53 +00:00
file . RecoveryRegisters . Add ( new RecoveryRegisterItem ( ) { RegisterIdent = "GENESISFLOW_SealDisplay" , WriteValue = new Byte [ ] { 0x00 , 0x00 , 0x00 , 0x01 } , IsCritical = true } ) ;
2022-05-10 13:34:48 +00:00
2022-12-06 12:15:53 +00:00
file . RecoveryRegisters . Add ( new RecoveryRegisterItem ( ) { RegisterIdent = "SENSUSRADIO_SystemState" , WriteValue = new Byte [ ] { 0x00 , 0x00 , 0x00 , 0x01 } , IsCritical = true , ReadBackValue = new Byte [ ] { 0x00 , 0x00 , 0x00 , 0x0c } } ) ;
2022-10-19 10:58:08 +00:00
file . RecoveryRegisters . Add ( new RecoveryRegisterItem ( ) { RegisterIdent = "SENSUSRADIO_MainAlarmMask" , WriteValue = new Byte [ ] { 0x00 , 0x00 , 0x00 , 0x00 } } ) ;
file . RecoveryRegisters . Add ( new RecoveryRegisterItem ( ) { RegisterIdent = "SENSUSRADIO_ExtendedAlarmMask" , WriteValue = new Byte [ ] { 0x00 , 0x00 , 0x00 , 0x00 } } ) ;
2022-05-10 13:34:48 +00:00
2022-12-06 12:15:53 +00:00
file . RecoveryRegisters . Add ( new RecoveryRegisterItem ( ) { RegisterIdent = "SENSUSRADIO_SystemState" , WriteValue = new Byte [ ] { 0x00 , 0x00 , 0x00 , 0xFF } , IsCritical = true , ReadBackValue = new Byte [ ] { 0x00 , 0x00 , 0x00 , 0x0c } } ) ;
2022-05-10 13:34:48 +00:00
2022-04-29 07:58:45 +00:00
2022-05-10 13:34:48 +00:00
2022-12-06 12:15:53 +00:00
var blackList = new List < String > ( )
2022-05-10 13:34:48 +00:00
{
"CUSTOMER_RebootCount" ,
"GENESISFLOW_ForwardArrow" ,
"SENSUSRADIO_FrequencyOffset" ,
"SENSUSRADIO_FrequencyIndicator" ,
"PERIODICLOG_AverageFlowPeriod" ,
"PERIODICLOG_PeriodicLogLifeTimeCounter" ,
"SENSUSRADIO_MetroRadioLifeTimeCounter"
} ;
2022-12-06 12:15:53 +00:00
var Critical = new List < String > ( )
2022-05-10 13:34:48 +00:00
{
"GENESISFLOW_SealDisplay" ,
"GENESISFLOW_MeterSize" ,
"GENESISFLOW_DisplayUnits" ,
"METROLOGYASST_FlowUnits" ,
"METROLOGYASST_FlowPoint" ,
"METROLOGYASST_PressurePresent" ,
"GENESISFLOW_DisplayPow10" ,
"POWERMON_WarnFromClamp" ,
"SYSTEM_UpgradePermissions" ,
"POWERMON_BatteryQuantity" ,
"GENESISFLOW_LedMode" ,
"GENESISFLOW_LowFlowMaxPeriod" ,
"GENESISFLOW_LowFlowThreshold" ,
"GENESISFLOW_MaxValidAmplitude" ,
"GENESISFLOW_MaxValidDeltaToF" ,
"GENESISFLOW_MaxValidToF" ,
"GENESISFLOW_MinValidAmplitude" ,
"GENESISFLOW_MinValidToF" ,
"GENESISFLOW_Timeout" ,
"CUSTOMER_Locale" ,
"SENSUSRADIO_EncryptionKey"
} ;
2022-12-06 12:15:53 +00:00
file . RecoveryRegisters . Where ( d = > Critical . Contains ( d . RegisterIdent ) ) . ToList ( ) . ForEach ( f = > { f . IsCritical = true ; f . ReadBackValue = f . WriteValue ; } ) ;
2022-05-10 13:34:48 +00:00
2022-12-06 12:15:53 +00:00
var onlyIfDefault = new List < String > ( )
2022-05-10 13:34:48 +00:00
{
"METROLOGYASST_PulseWeight" ,
"METROLOGYASST_PressureUnits" ,
"METROLOGYASST_TemperatureUnits" ,
"METROLOGYASST_PulseLength" ,
"METROLOGYASST_PulseMode" ,
"CUSTOMER_LeakTimeThreshold" ,
"CUSTOMER_ExcessFlowTimeThreshold" ,
"CUSTOMER_ReverseFlowTimeThreshold" ,
"CUSTOMER_TemperatureHighThreshold" ,
"CUSTOMER_TemperatureHighDelay" ,
"CUSTOMER_TemperatureLowThreshold" ,
"CUSTOMER_TemperatureLowDelay" ,
"CUSTOMER_PressureHighThreshold" ,
"CUSTOMER_PressureHighDelay" ,
"CUSTOMER_PressureLowThreshold" ,
"CUSTOMER_PressureLowDelay" ,
"CUSTOMER_LeakFlowThreshold" ,
"METROLOGYASST_PressureOffset" ,
} ;
2022-12-06 12:15:53 +00:00
file . RecoveryRegisters . Where ( d = > onlyIfDefault . Contains ( d . RegisterIdent ) ) . ToList ( ) . ForEach ( f = > f . Access = RegisterRecoveryAccess . SetIfDefault ) ;
2022-04-29 07:58:45 +00:00
return Request . CreateResponse ( HttpStatusCode . OK , file ) ;
}
2021-10-01 09:09:20 +00:00
[Route("AddNewUser"), HttpGet]
2022-10-19 10:58:08 +00:00
public async Task < HttpResponseMessage > AddNewUser ( String FullName , String LogInName , String Domain , String HardwareId = null , String PasswordHash = null )
2021-10-01 09:09:20 +00:00
{
return await Task . Run ( ( ) = >
{
try
{
var ret = new System . Collections . Generic . List < UserInformation > ( ) ;
using ( var dataacces = new SqlDataAccess ( GlobalConfig . connectionString . Value ) )
{
var sb = new StringBuilder ( ) ;
sb . AppendLine ( $" insert into FWUpdateUser " ) ;
sb . AppendLine ( $" select " ) ;
sb . AppendLine ( $" '{FullName}', " ) ;
sb . AppendLine ( $" '{LogInName}', " ) ;
sb . AppendLine ( $" '{Domain}', " ) ;
sb . AppendLine ( string . IsNullOrEmpty ( HardwareId ) ? "null , " : $"'{HardwareId}' ," ) ;
sb . AppendLine ( string . IsNullOrEmpty ( PasswordHash ) ? "null , " : $"'{PasswordHash}' ," ) ;
sb . AppendLine ( $" '{DateTimeOffset.UtcNow.ToString(" yyyy - MM - dd HH : mm : ss + 01 : 00 ")}', " ) ;
sb . AppendLine ( $" '{DateTimeOffset.UtcNow.ToString(" yyyy - MM - dd HH : mm : ss + 01 : 00 ")}', " ) ;
sb . AppendLine ( $" 0 " ) ;
sb . AppendLine ( $" select @@IDENTITY " ) ;
var dbResult = dataacces . ExecuteQuery ( sb . ToString ( ) ) ;
var newID = Convert . ToInt32 ( dbResult . Rows [ 0 ] [ 0 ] . ToString ( ) ) ;
return Request . CreateResponse ( HttpStatusCode . OK , newID ) ;
}
}
catch ( Exception ex )
{
return Request . CreateResponse ( HttpStatusCode . InternalServerError , ex ) ;
}
} ) ;
}
2024-05-07 13:11:30 +00:00
[HttpGet]
[Route("api/fwupdate/databaseateol/{pcbid}")]
public IHttpActionResult DataBaseAtEOL ( string pcbid )
{
var databaseAtEOL = SQLConnection
. CreateSQLConnection ( GlobalConfig . connectionString . Value , error = >
{
throw new Exception ( error ) ;
} )
. CreateCommand ( $ @ "
DECLARE @latestRegisters AS TABLE (
2024-05-24 07:27:52 +00:00
[PcbId] VARCHAR ( 10 )
, [ Address ] VARCHAR ( 10 )
, [ Value ] VARCHAR ( 250 )
, [ Date ] DATETIME
, [ Identnr ] INT ) ;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2024-05-07 13:11:30 +00:00
INSERT INTO @latestRegisters
2024-05-24 07:27:52 +00:00
SELECT [ x ] . [ PcbId ]
, [ x ] . [ Address ]
, [ x ] . [ Value ]
, [ x ] . [ date ]
, [ x ] . [ IdentNr ]
FROM ( SELECT [ gnsrh ] . [ PcbId ]
, [ gnsrh ] . [ Address ]
, [ gnsrh ] . [ Value ]
, [ gnsrh ] . [ date ]
, [ aap ] . [ VersandDatum ]
, [ aap ] . [ IdentNr ]
, RANK ( ) OVER ( PARTITION BY [ gnsrh ] . [ Address ]
ORDER BY [ gnsrh ] . [ date ] DESC ) AS [ rank ]
FROM ( SELECT [ pcb2sn ] . [ MapPcbIdToSerialNumber_PcbId ] AS [ pcb ]
, [ pcb2sn ] . [ MapPcbIdToSerialNumber_SerialNumber ] AS [ sn ]
FROM [ MapPcbIdToSerialNumber ] AS [ pcb2sn ]
WHERE [ pcb2sn ] . [ MapPcbIdToSerialNumber_PcbId ] = @ { nameof ( pcbid ) } )
AS [ pcbsn ]
LEFT JOIN ( SELECT MAX ( [ rssi ] . [ Datum ] ) AS [ date ]
, [ gm ] . [ Seriennummer ] AS [ sn ]
FROM [ Cordonel_Radio_RSSI_History ] AS [ rssi ]
JOIN [ Genesis_Meter ] AS [ gm ]
ON [ rssi ] . [ RadioAdress ] = [ gm ] . [ Adresse ]
GROUP BY [ gm ] . [ Seriennummer ] ) AS [ latest ]
ON [ pcbsn ] . [ sn ] = [ latest ] . [ sn ]
JOIN [ AlleAuftragPositionen ] AS [ aap ]
ON [ aap ] . [ SerienNrVon ] < = [ pcbsn ] . [ sn ]
AND [ aap ] . [ SerienNrBis ] > = [ pcbsn ] . [ sn ]
JOIN [ GenesisMeterRegisterHistory ] AS [ gnsrh ]
ON [ pcbsn ] . [ pcb ] = [ gnsrh ] . [ PcbId ]
LEFT JOIN [ Identnr ] AS [ idn ]
ON [ idn ] . [ IdentNr ] = [ aap ] . [ IdentNr ]
WHERE [ gnsrh ] . [ date ] < = ISNULL ( [ latest ] . [ date ] , GETDATE ( ) )
AND [ gnsrh ] . [ Address ] IN ( ' 01 - 0 A ' , ' 01 - 09 ' , ' 10 - 09 ' , ' 12 - 03 ' , ' 14 - 02 ' , ' 12 - 11 ' ) )
AS [ x ]
WHERE [ x ] . [ rank ] = 1 ;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SELECT ( SELECT MAX ( [ PcbId ] ) FROM @latestRegisters ) AS [ PcbId ]
, ( SELECT MAX ( [ Date ] ) FROM @latestRegisters ) AS [ ProductionDate ]
, ( SELECT TOP 1 [ Value ] FROM @latestRegisters WHERE [ Address ] = ' 01 - 0 A ' ) AS [ TotalUsedSeconds ]
, ( SELECT TOP 1 [ Value ] FROM @latestRegisters WHERE [ Address ] = ' 01 - 09 ' ) AS [ TotalUsedCharge ]
, ( SELECT TOP 1 [ Value ] FROM @latestRegisters WHERE [ Address ] = ' 10 - 09 ' ) AS [ RadioSystemState ]
, ( SELECT TOP 1 [ Value ] FROM @latestRegisters WHERE [ Address ] = ' 12 - 03 ' ) AS [ PulseMode ]
, ( SELECT TOP 1 [ Value ] FROM @latestRegisters WHERE [ Address ] = ' 14 - 02 ' ) AS [ PulseSequenceCounter ]
, ( SELECT TOP 1 [ Value ] FROM @latestRegisters WHERE [ Address ] = ' 12 - 11 ' ) AS [ PulseEvenDistribution ]
, ( SELECT CAST ( CASE WHEN COUNT ( 1 ) > 0 THEN 1 ELSE 0 END AS BIT )
FROM [ Identnr ] AS [ idn ]
WHERE [ idn ] . [ IdentNr ] = ( SELECT MAX ( [ IdentNr ] ) FROM @latestRegisters )
AND [ idn ] . [ Typ ] = ' GNS '
AND SUBSTRING ( [ idn ] . [ VakoCode ] , 48 , 1 ) IN ( 'K' , 'Q' ) ) AS [ PulseAdapterIsInstalled ] ; ")
2024-05-07 13:11:30 +00:00
. SetParameter ( nameof ( pcbid ) , pcbid )
. FirstOrDefault ( x = >
{
var model = new PowerCorrection ( ) ;
model . PcbId = x . GetValue < string > ( 0 ) ;
if ( string . IsNullOrWhiteSpace ( model . PcbId ) )
{
return null ;
}
model . ProductionDateTimeUtc = x . GetValue < DateTime > ( 1 ) ;
model . ProductionTotalUsedSeconds_s = x . GetValue < string > ( 2 ) . ToUint ( ) ;
model . ProductionTotalUsedCharge_uAs = x . GetValue < string > ( 3 ) . ToUlong ( ) ;
model . ProductionRadioSystemState = x . GetValue < string > ( 4 ) . ToNullableByte ( ) ;
model . ProductionPulseMode = x . GetValue < string > ( 5 ) . ToByte ( ) ;
model . ProductionPulseSequenceCounter = x . GetValue < string > ( 6 ) . ToByte ( ) ;
model . ProductionPulseEvenDistribution = x . GetValue < string > ( 7 ) . ToBool ( ) ;
model . ProductionPulseAdapterIsInstalled = x . GetValue < bool > ( 8 ) ;
return model ;
} ) ;
return this . Json ( databaseAtEOL , new JsonSerializerSettings
{
DefaultValueHandling = DefaultValueHandling . Ignore ,
NullValueHandling = NullValueHandling . Ignore
} ) ;
}
}
public static class BitConverterExtensions
{
public static bool ToBool ( this string hexString )
{
var bytes = hexString . ToByteArray ( ) ;
if ( bytes . Length > = 1 )
{
return BitConverter . ToBoolean ( bytes , 0 ) ;
}
return default ( bool ) ;
}
public static byte ToByte ( this string hexString )
{
var bytes = hexString . ToByteArray ( ) ;
if ( bytes . Length > = 1 )
{
return bytes [ 0 ] ;
}
return default ( byte ) ;
}
public static byte? ToNullableByte ( this string hexString )
{
var bytes = hexString . ToByteArray ( ) ;
if ( bytes . Length > = 1 )
{
return bytes [ 0 ] ;
}
return default ( byte? ) ;
}
public static uint ToUint ( this string hexString )
{
var bytes = hexString . ToByteArray ( ) ;
if ( bytes . Length > = 4 )
{
return BitConverter . ToUInt32 ( bytes , 0 ) ;
}
return default ( uint ) ;
}
public static ulong ToUlong ( this string hexString )
{
var bytes = hexString . ToByteArray ( ) ;
if ( bytes . Length > = 8 )
{
return BitConverter . ToUInt64 ( bytes , 0 ) ;
}
return default ( ulong ) ;
}
public static byte [ ] ToByteArray ( this string hexString )
{
if ( ! string . IsNullOrWhiteSpace ( hexString ) )
{
var bytes = new List < byte > ( ) ;
var hex = string . Empty ;
foreach ( var @char in hexString )
{
if ( ( '0' < = @char & & @char < = '9' ) | | ( 'A' < = @char & & @char < = 'F' ) | | ( 'a' < = @char & & @char < = 'f' ) )
{
hex + = @char ;
}
if ( hex . Length = = 2 )
{
bytes . Add ( Convert . ToByte ( hex , 16 ) ) ;
hex = string . Empty ;
}
}
return bytes . ToArray ( ) ;
}
return Array . Empty < Byte > ( ) ;
}
2021-10-01 09:09:20 +00:00
}
}