Imports System.Data.SqlClient Imports DigitalData.Modules.Database Imports DigitalData.Modules.Database.MSSQLServer.TransactionMode Imports DigitalData.Modules.Logging Imports DigitalData.Services.EDMIService.Methods Imports DigitalData.Services.EDMIService.GlobalState Namespace Methods.IDB.NewFile Public Class NewFileMethod Inherits BaseMethod Private ReadOnly Connection As SqlConnection Private ReadOnly Transaction As SqlTransaction Public Sub New(pLogConfig As LogConfig, pDatabaseIDB As MSSQLServer, pDatabaseECM As MSSQLServer, pGlobalState As GlobalState) MyBase.New(pLogConfig, pDatabaseIDB, pDatabaseECM, pGlobalState) Connection = DatabaseIDB.GetConnection() Transaction = Connection.BeginTransaction() End Sub Public Function Run(pData As NewFile.NewFileRequest) As Methods.IDB.NewFile.NewFileResponse Dim oFilePath As String = Nothing Dim oExistingObjectId = TestFileChecksumExists(pData.File.FileChecksum) If oExistingObjectId > 0 Then Return New NewFile.NewFileResponse(oExistingObjectId) End If Try Dim oObjectId = NewObjectId(pData.KindType, pData.BusinessEntity, pData.User.UserName) If oObjectId = 0 Then LogAndThrow("Could not create new ObjectId!") End If ' Find ObjectStore by Title Logger.Debug("Checking for DataStore [{0}].", pData.StoreName) Dim oStore = GlobalState.ObjectStores. Where(Function(store) store.Title.Equals(pData.StoreName, StringComparison.OrdinalIgnoreCase)). SingleOrDefault() If oStore Is Nothing Then LogAndThrow($"DataStore [{pData.StoreName}] does not exist. Exiting.") End If ' Get Store base path Dim oBasePath As String = oStore.Path Logger.Debug("Store BasePath is [{0}]", oBasePath) ' Get directory by DateImported or, if not supplied, by current date Dim oSubDirectory As String If IsNothing(pData.File.FileImportedAt) Then oSubDirectory = GetDateSubDirectory(Now) Else oSubDirectory = GetDateSubDirectory(pData.File.FileImportedAt) End If Logger.Debug("Subdirectory is [{0}]", oSubDirectory) ' Check and create final path, if necessary Dim oFinalPath = IO.Path.Combine(oBasePath, oSubDirectory) If Not IO.Directory.Exists(oFinalPath) Then Try Logger.Debug("Path does not exist, creating: [{0}]", oFinalPath) IO.Directory.CreateDirectory(oFinalPath) Logger.Debug("Created folder [{0}]", oFinalPath) Catch ex As Exception LogAndThrow(ex, $"Store Directory [{oFinalPath}] could not be created!") End Try End If Logger.Debug("Final Directory is [{0}]", oFinalPath) ' Get filename Dim oKeepFileName As Boolean = False If oStore.IsArchive Then Logger.Debug("Object Store is an archive: [{0}]", oStore.IsArchive) oKeepFileName = True End If Dim oFileName As String = GetFileObjectFileName(oObjectId, pData.File.FileName, oKeepFileName) Logger.Debug("Filename is [{0}]", oFileName) oFilePath = IO.Path.Combine(oFinalPath, oFileName) Dim oFileObjectInfo As IO.FileInfo = New IO.FileInfo(oFilePath) Dim oFileObjectSize As Long = pData.File.FileContents.Length Dim oFileObjectName As String = oFileObjectInfo.Name Dim oOriginalExtension As String = pData.File.FileInfoRaw.Extension.Substring(1) Logger.Debug("File Information for [{0}]:", oFileObjectName) Logger.Debug("Size: [{0}]", oFileObjectSize) Logger.Debug("Original Extension: [{0}]", oOriginalExtension) Logger.Debug("Checksum: [{0}]", pData.File.FileChecksum) Try Using oStream = New IO.FileStream(oFilePath, IO.FileMode.Create, IO.FileAccess.Write) Logger.Info("Saving file to path [{0}]", oFilePath) oStream.Write(pData.File.FileContents, 0, oFileObjectSize) oStream.Flush(True) oStream.Close() End Using Catch ex As Exception LogAndThrow(ex, $"Could not write file [{oFilePath}] to disk!") End Try '--------------------------------------------------------------------------- Logger.Info("Creating IDB FileObject for ObjectId [{0}].", oObjectId) ' Insert into DB Dim oSQL As String = $"EXEC PRIDB_NEW_IDBFO '{oFinalPath}', '{oFileObjectName}', '{oOriginalExtension}', {oFileObjectSize}, '{pData.File.FileChecksum}' , '{pData.User.UserName}', '{oObjectId}', {oStore.Id}" Dim oResult As Boolean = DatabaseIDB.ExecuteNonQueryWithConnectionObject(oSQL, Connection, ExternalTransaction, Transaction) If oResult = False Then LogAndThrow("IDB FileObject could not be created!") End If '--------------------------------------------------------------------------- 'TODO: File dates in try catch Dim oSystemAttributes As New Dictionary(Of String, Object) From { {"OriginFileName", pData.File.FileName}, {"OriginCreationDatetime", pData.File.FileCreatedAt}, {"OriginChangedDatetime", pData.File.FileChangedAt} } For Each oAttribute As KeyValuePair(Of String, Object) In oSystemAttributes Try ' Dont write empty attributes If oAttribute.Value Is Nothing Then Continue For End If Dim oSuccess = Helpers.SetAttributeValue(Connection, Transaction, oObjectId, oAttribute.Key, oAttribute.Value, pData.User.Language, pData.User.UserName) If oSuccess Then Logger.Debug("System Attribute [{0}] written with value [{1}]", oAttribute.Key, oAttribute.Value) Else Logger.Warn("System attribute value could not be written") End If Catch ex As Exception LogAndThrow(ex, $"System attribute [{oAttribute.Key}] could not be written!") End Try Next '--------------------------------------------------------------------------- ' Finally, commit the transaction Transaction?.Commit() Return New NewFile.NewFileResponse(oObjectId) Catch ex As Exception Logger.Warn("Error occurred while creating file!") Logger.Error(ex) Logger.Info("Cleaning up files.") If Not IsNothing(oFilePath) AndAlso IO.File.Exists(oFilePath) Then Try IO.File.Delete(oFilePath) Catch exInner As Exception Logger.Warn("Error while cleaning up files.") Logger.Error(exInner) End Try End If Logger.Info("Rolling back transaction.") Transaction?.Rollback() Return New NewFile.NewFileResponse(ex) End Try End Function Private Function TestFileChecksumExists(pChecksum As String) As Long Try Dim oChecksumSQL = $"SELECT IDB_OBJ_ID FROM TBIDB_FILE_OBJECT WHERE FILE_HASH = '{pChecksum}'" Dim oExistingObjectId As Long = DatabaseIDB.GetScalarValue(oChecksumSQL) If oExistingObjectId > 0 Then Logger.Info("Returning early with ObjectId [{0}] because Checksum [{1}] already exists.", oExistingObjectId, pChecksum) Return oExistingObjectId End If Return Nothing Catch ex As Exception Logger.Error(ex) Return Nothing End Try End Function Private Function NewObjectId(pKindType As String, pBusinessEntity As String, pWho As String) As Long Try Dim oNewObjectIdSQL = $"DECLARE @NEW_IDB_OBJ_ID BIGINT EXEC PRIDB_NEW_OBJECT '{pKindType}','{pWho}','{pBusinessEntity}',0, @IDB_OBJ_ID = @NEW_IDB_OBJ_ID OUTPUT; SELECT @NEW_IDB_OBJ_ID" Dim oObjectId As Long = DatabaseIDB.GetScalarValueWithConnectionObject(oNewObjectIdSQL, Connection, ExternalTransaction, Transaction) Logger.Info("New Object with Id [{0}] created!", oObjectId) If IsNothing(oObjectId) Then LogAndThrow("Could not create new ObjectId!") End If Return oObjectId Catch ex As Exception Logger.Error(ex) Return Nothing End Try End Function Private Function GetFileObjectFileName(IDB_OBJ_ID As Long, pFilename As String, pKeepFilename As Boolean) As String ' TODO: save actual extensions If pKeepFilename Then Return pFilename Else Return $"{IDB_OBJ_ID}.ddfo" End If End Function Private Function GetDateSubDirectory(pDate As Date) As String Return IO.Path.Combine(pDate.ToString("yyyy"), pDate.ToString("MM"), pDate.ToString("dd")) End Function End Class End Namespace