Imports System.IO Imports System.Net.Http Imports Newtonsoft.Json Imports DigitalData.Modules.Base Imports DigitalData.Modules.Base.ModuleExtensions Imports DigitalData.Modules.Database Imports DigitalData.Modules.Logging Imports Connectors.Form.slt.Constants Imports Connectors.Form.slt.Responses Imports Connectors.Form.slt.Entities Imports System.Threading.Tasks Imports DigitalData.Modules.Config Namespace slt Public Class sltSync Inherits BaseModule Implements ISync Private ReadOnly FileEx As FileEx Public Overrides Property Name As String = "slt Sync" Public Overrides Property IsLoggedIn As Boolean = False Public SessionId As String = Nothing Public AvailableSystems As New List(Of sltAvailableSystem) Public Sub New(pLogConfig As LogConfig, pDatabase As MSSQLServer, pConfig As Config) MyBase.New(pLogConfig, pDatabase, pConfig) FileEx = New FileEx() End Sub Public Overrides Async Function Run() As Threading.Tasks.Task Implements ISync.Run Try AddInfoEntry("Starting sltSync.") AddDivider() EnsureOutputDirectoryExists() Dim oExtDocIds = Await FetchDocIds() If oExtDocIds Is Nothing Then Throw New ApplicationException($"Document Ids could not be fetched!") End If AddInfoEntry("Logging in..") Await GetAvailableSystems() Await Login(Config.sltConfiguration.SystemId) For Each oDocId As String In oExtDocIds Try Logger.Debug("Fetching document from API..") Dim oDocument = Await GetDocumentContent(oDocId) Logger.Debug("Document fetched!") AddInfoEntry("Document: [{0}]", oDocument.Name) Logger.Info("ExtDocId: [{0}]", oDocument.ExtDocId) Dim oFileName = GetFilenameWithExtension(oDocument.Name, oDocument.DocMimeType) Dim oFilePath = Path.Combine(Config.OutputDirectory, oFileName) If CopyFileToOutputPath(oDocument.Data, oFilePath) = False Then Throw New ApplicationException("File could not be created in output path!") End If Dim oSQL = String.Format(Config.SQLQueryExport, oDocument.ExtDocId, oFileName) Await Database.ExecuteNonQueryAsync(oSQL) Catch ex As Exception Logger.Error(ex) AddWarnEntry("Error while running Sync: " & ex.Message) End Try Next Catch ex As Exception Logger.Error(ex) AddWarnEntry("Error while running Sync: " & ex.Message) End Try Try AddInfoEntry("Finished Sync.") AddInfoEntry("Logging Out..") Await Logout() Catch ex As Exception Logger.Error(ex) AddWarnEntry("Error while logging out: " & ex.Message) Finally AddDivider() End Try End Function Public Overrides Async Function Cleanup() As Task Implements ISync.Cleanup Await Logout() End Function Public Overrides Function TestConfigIsComplete() As Boolean Implements ISync.TestConfigIsComplete Dim oComplete = TestConfigIsCompleteBase() If Config.sltConfiguration.Hostname = String.Empty Then AddWarnEntry("Configuration for 'Hostname' is empty.") oComplete = False End If If Config.sltConfiguration.Port = String.Empty Then AddWarnEntry("Configuration for 'Port' is empty.") oComplete = False End If If Config.sltConfiguration.Username = String.Empty Then AddWarnEntry("Configuration for 'Username' is empty.") oComplete = False End If If Config.sltConfiguration.Password = String.Empty Then AddWarnEntry("Configuration for 'Password' is empty.") oComplete = False End If Return oComplete End Function Private Function GetFilenameWithExtension(pFilename As String, pMimetype As String) As String Try If pMimetype = "application/outlook" Then pMimetype = "application/vnd.ms-outlook" End If Dim oExtension = FileEx.GetExtension(pMimetype) Return StringEx.ConvertTextToSlug(pFilename) & oExtension Catch ex As Exception Logger.Error(ex) AddWarnEntry("File [{0}] does not have a valid mimetype [{1}]. Returning original filename.", pFilename, pMimetype) Return pFilename End Try End Function Private Async Function GetAvailableSystems() As Threading.Tasks.Task Try Logger.Debug("Fetching available systems..") Dim oUrl = "/slt/External/System/Authentication/Json/AvailableSystems" Dim oJson As String = Await SendRequest(oUrl) Dim oResponse = JsonConvert.DeserializeObject(Of sltAvailableSystemResponse)(oJson) TestRequestSuccessful(oUrl, oResponse, ErrorType.AvailableSystemError) AvailableSystems = oResponse.Value Logger.Debug("Fetched [{0}] available systems!", oResponse.Value.Count) Catch ex As Exception Logger.Error(ex) Throw New sltException(ErrorType.AvailableSystemError, ex.Message) End Try End Function Private Async Function Login(pSystemId As String) As Threading.Tasks.Task Try Logger.Debug("Logging in..") If AvailableSystems.Any(Function(s) s.SystemId = pSystemId) = False Then Dim oMessage = String.Format("SystemId [{0}] does not match any System returned from API.", pSystemId) Logger.Warn(oMessage) Throw New sltException(ErrorType.LoginError, oMessage) End If Dim oUrl = "/slt/External/System/Authentication/Json/Login" Dim oParams = New Dictionary(Of String, String) From { {"systemid", pSystemId}, {"user", Config.sltConfiguration.Username}, {"password", Config.sltConfiguration.Password} } Logger.Debug("Username: [{0}]", Config.sltConfiguration.Username) Logger.Debug("SystemId: [{0}]", pSystemId) Dim oJson As String = Await SendRequest(oUrl, oParams) Dim oResponse = JsonConvert.DeserializeObject(Of sltLoginResponse)(oJson) TestRequestSuccessful(oUrl, oResponse, ErrorType.LoginError) SessionId = oResponse.Value IsLoggedIn = True Logger.Debug("Login successful!") Catch ex As Exception Logger.Error(ex) Throw New sltException(ErrorType.LoginError, ex.Message) End Try End Function Private Async Function Logout() As Threading.Tasks.Task If Not IsLoggedIn Then Throw New sltException(ErrorType.NotLoggedInError, "No session found") End If Logger.Debug("Logging out..") Try Dim oUrl = "/slt/External/System/Authentication/Json/Logout" Dim oParams = New Dictionary(Of String, String) From { {"SessionId", SessionId} } Dim oJson As String = Await SendRequest(oUrl, oParams) Dim oResponse = JsonConvert.DeserializeObject(Of sltLogoutResponse)(oJson) TestRequestSuccessful(oUrl, oResponse, ErrorType.LogoutError) SessionId = Nothing IsLoggedIn = False Logger.Debug("Login successful!") Catch ex As Exception Logger.Error(ex) Throw New sltException(ErrorType.LogoutError, ex.Message) End Try End Function Private Async Function GetDocumentContent(pExternalDocumentId As String) As Threading.Tasks.Task(Of slt.Entities.sltDocument) If Not IsLoggedIn Then Throw New sltException(ErrorType.NotLoggedInError, "No session found") End If Try Logger.Debug("Fetching document with ExtDocId [{0}]", pExternalDocumentId) Dim oUrl = "/slt/External/Services/Allgemein/ExtDocs/JSon/GetDocument" Dim oParams As New Dictionary(Of String, String) From { {"extdocid", pExternalDocumentId}, {"sessionid", SessionId} } Dim oJson = Await SendRequest(oUrl, oParams) Dim oResponse = JsonConvert.DeserializeObject(Of sltDocumentResponse)(oJson) Logger.Debug("Document Fetched!") Return oResponse.Value Catch ex As Exception Logger.Error(ex) Throw New sltException(ErrorType.GetDocumentError, ex.Message) End Try End Function Private Async Function SendRequest(pUrl As String) As Threading.Tasks.Task(Of String) Return Await SendRequest(pUrl, New Dictionary(Of String, String)) End Function Private Async Function SendRequest(pUrl As String, pQueryParams As Dictionary(Of String, String)) As Threading.Tasks.Task(Of String) Try Dim oUrl = GetUrl(pUrl, pQueryParams) Logger.Debug("Preparing request to: [{0}]", oUrl) Using oClient As New HttpClient() oClient.DefaultRequestHeaders.Accept.Clear() oClient.DefaultRequestHeaders.Accept.Add(New Headers.MediaTypeWithQualityHeaderValue("application/json")) oClient.DefaultRequestHeaders.Add("User-Agent", "Digital Data sltSync") Logger.Debug("Sending request.") Return Await oClient.GetStringAsync(oUrl) End Using Catch ex As Exception Logger.Error(ex) Return Nothing End Try End Function Private Function GetUrl(pPath As String, pQueryParams As Dictionary(Of String, String)) As String Dim oUrl As String = $"http://{Config.sltConfiguration.Hostname}:{Config.sltConfiguration.Port}" If Not pPath.StartsWith("/") Then pPath &= "/" Dim queryString = pQueryParams.ToURLQueryString() Return $"{oUrl}{pPath}?{queryString}" End Function Private Sub TestRequestSuccessful(pUrl As String, pResponse As Responses.sltResponse, pErrorType As Constants.ErrorType) If pResponse.State = False Then Logger.Warn("Request to Url [{0}] returned error.", pUrl) Logger.Error(pResponse.Message) Throw New sltException(pErrorType, pResponse.Message) End If End Sub End Class End Namespace