/// <summary> /// Handles events that require the document retrieval /// This will get the metadata and pull the documents and optionally create an index file for the documents /// </summary> /// <param name="eventData"></param> private static void DocumentRetrievalHandler(EventNotificationData eventData) { var manager = new DocumentManager(); if (eventData.PropertyValues[EventPropertyConstants.SvDocumentId].IsNullOrEmpty()) { logger.ErrorFormat("DataService ProcessPostedEvent Missing Document Id for Event Id: {0}", eventData.PropertyValues[EventPropertyConstants.Id].Value <string>()); return; } //First make sure we have the document metadata otherwise get it if (eventData.DocumentMetaData.Id == 0) { eventData.DocumentMetaData = manager.GetDocumentMetaData(eventData.PropertyValues[EventPropertyConstants.SvDocumentId].Value <int>()); } //Get and Store the Documents var dataFiles = manager.GetDocumentFiles(eventData.PropertyValues[EventPropertyConstants.SvDocumentId].Value <int>(), eventData); //If required create an index file if (dataFiles.Any() && (campusLogicConfigSection.DocumentSettings.IndexFileEnabled ?? false)) { manager.CreateDocumentsIndexFile(dataFiles, eventData); } }
public static void GetDefaultDatabaseProcedure(EventNotificationData eventData, string storedProcedureName) { var parameters = new List <OdbcParameter>(); //Define parameters parameters.Add(new OdbcParameter { ParameterName = "StudentId", OdbcType = OdbcType.VarChar, Size = 9, Value = eventData.PropertyValues[EventPropertyConstants.StudentId].Value <string>() }); parameters.Add(new OdbcParameter { ParameterName = "AwardYear", OdbcType = OdbcType.VarChar, Size = 4, Value = eventData.PropertyValues[EventPropertyConstants.AwardYear].IsNullOrEmpty() ? string.Empty : (eventData.PropertyValues[EventPropertyConstants.AwardYear].Value <string>().Substring(2, 2) + eventData.PropertyValues[EventPropertyConstants.AwardYear].Value <string>().Substring(7, 2)) }); parameters.Add(new OdbcParameter { ParameterName = "TransactionCategoryId", OdbcType = OdbcType.Int, Value = eventData.PropertyValues[EventPropertyConstants.SvTransactionCategoryId].IsNullOrEmpty() ? 0 : eventData.PropertyValues[EventPropertyConstants.SvTransactionCategoryId].Value <int>() }); parameters.Add(new OdbcParameter { ParameterName = "EventNotificationId", OdbcType = OdbcType.Int, Value = eventData.PropertyValues[EventPropertyConstants.EventNotificationId].Value <int>() }); if (!eventData.PropertyValues[EventPropertyConstants.SvDocumentId].IsNullOrEmpty() && eventData.PropertyValues[EventPropertyConstants.SvDocumentId].Value <int>() > 0) { var manager = new DocumentManager(); DocumentMetaData metaData = manager.GetDocumentMetaData(eventData.PropertyValues[EventPropertyConstants.SvDocumentId].Value <int>()); parameters.Add(new OdbcParameter { ParameterName = "DocumentName", OdbcType = OdbcType.VarChar, Size = 128, Value = metaData != null ? metaData.DocumentName : string.Empty }); } else { parameters.Add(new OdbcParameter { ParameterName = "DocumentName", OdbcType = OdbcType.VarChar, Size = 128, Value = string.Empty }); } ClientDatabaseManager.ExecuteDatabaseStoredProcedure("{CALL " + storedProcedureName + " (?, ?, ?, ?, ?)}", parameters); }
/// <summary> /// Handles events that require the system to execute a database stored procedure based on the configuration. /// </summary> /// <param name="eventData"></param> /// <param name="storedProcedureName"></param> private static void DatabaseStoredProcedure(EventNotificationData eventData, string storedProcedureName) { var storedProcedureSettings = campusLogicConfigSection.StoredProcedures.GetStoredProcedure(storedProcedureName); if (storedProcedureSettings != null) { // Parse parameters based on config. List <OdbcParameter> parameters = storedProcedureSettings.GetParameters().Select(p => ParseParameter(p, eventData)).ToList(); //Adding logging in case client experiences weird argument error, we can better determine what we are trying to pass //logger.Info($"Parameters to be pass into database: { String.Join(", ", parameters.Select(x => x.ParameterName + ": " + x.Value.ToString() + " - DataType: " + Enum.GetName(typeof(OdbcType), x.OdbcType)))}"); // For each parameter, need to add a placeholder "?" in the sql command. // This is just part of the ODBC syntax. string placeholders = string.Join(",", parameters.Select(p => "?").ToArray()); if (placeholders.Length > 0) { placeholders = " (" + placeholders + ")"; } // Final output should look like this: {CALL sproc_name (?, ?, ?)} string command = $"{{CALL {storedProcedureSettings.Name}{placeholders}}}"; //logger.Info(command); ClientDatabaseManager.ExecuteDatabaseStoredProcedure(command, parameters); } else { //Static db procedure GetDefaultDatabaseProcedure(eventData, storedProcedureName); } }
/// <summary> /// Used for getting a batch of AL PDFs for printing. /// </summary> /// <param name="eventData"></param> private static void BatchProcessRetrievalHandler(string type, string name, EventNotificationData eventData) { var message = eventData.PropertyValues.ToString().Replace("'", "''"); using (var dbContext = new CampusLogicContext()) { //Insert the event into the BatchProcessRecord table so that it can be processed by the Automated Batch Process job. dbContext.Database.ExecuteSqlCommand($"INSERT INTO [dbo].[BatchProcessRecord]([Type], [Name], [Message], [ProcessGuid], [RetryCount], [RetryUpdatedDate]) VALUES('{type}', '{name}', '{message}', NULL, NULL, NULL)"); } }
/// <summary> /// Used to get PDF /// version of AL /// for printers /// </summary> /// <param name="eventData"></param> private static void AwardLetterDocumentRetrievalHandler(EventNotificationData eventData) { var manager = new DocumentManager(); if (eventData.PropertyValues[EventPropertyConstants.AlRecordId].IsNullOrEmpty()) { logger.ErrorFormat("DataService ProcessPostedEvent Missing Record Id for Event Id: {0}", eventData.PropertyValues[EventPropertyConstants.Id].Value <string>()); return; } //Get and Store the Documents manager.GetAwardLetterPdfFile(Guid.Parse(eventData.PropertyValues[EventPropertyConstants.AlRecordId].Value <string>()), eventData); }
// Update event list for given team id private void AddEventNotificationForTeam(string teamId, EventNotificationData eventNotificationData) { if (this.teamToEventNotificationsMap.TryGetValue(teamId, out List <EventNotificationData> events)) { events.Add(eventNotificationData); } else { this.teamToEventNotificationsMap.Add(teamId, new List <EventNotificationData> { eventNotificationData }); } }
/// <summary> /// The File Store Handler. Surprise! /// </summary> public static void FileStoreHandler(EventNotificationData eventData) { try { using (var dbContext = new CampusLogicContext()) { var dataToSerialize = eventData.PropertyValues.ToString().Replace("'", "''"); //Insert the event into the EventNotification table so that it can be processed by the Automated File Store job. dbContext.Database.ExecuteSqlCommand($"INSERT INTO [dbo].[EventNotification]([EventNotificationId], [Message], [CreatedDateTime], [ProcessGuid]) VALUES({eventData.PropertyValues[EventPropertyConstants.EventNotificationId].Value<int>()}, '{dataToSerialize}', GetUtcDate(), NULL)"); } } catch (Exception ex) { logger.Error($"An error occured when attempting to handle the event data for file store: {ex}"); } }
public static async Task RunBatchProcess(string type, string name, int size) { logger.Info("enter batch processing"); Guid processGuid = Guid.NewGuid(); using (var dbContext = new CampusLogicContext()) { try { // Get all records in our LocalDB to process var records = dbContext.BatchProcessRecords.Where(b => b.Name == name && b.Type == type && b.ProcessGuid == null); if (records.Any()) { // Lock these records from being processed again dbContext.Database.ExecuteSqlCommand($"UPDATE[dbo].[BatchProcessRecord] SET[ProcessGuid] = '{processGuid}' FROM [dbo].[BatchProcessRecord] WHERE[Id] IN(SELECT [Id] from[dbo].[BatchProcessRecord] WHERE [Type] = '{type}' AND [Name] = '{name}' AND [ProcessGuid] IS NULL)"); // Ensure there are locked records with this process guid if (dbContext.BatchProcessRecords.Any(b => b.ProcessGuid != null && b.ProcessGuid == processGuid)) { if (type == ConfigConstants.AwardLetterPrintBatchType) { var manager = new DocumentManager(); Dictionary <int, Guid> recordIds = new Dictionary <int, Guid>(); var recordList = dbContext.BatchProcessRecords.Where(b => b.ProcessGuid == processGuid).Select(b => b).ToList(); // Get all records with this process guid foreach (var record in recordList) { // Deserialize the message var eventData = new EventNotificationData(JObject.Parse(record.Message)); //Track retry attempts var now = DateTime.Now; var processSingularly = false; var retryTimeHasPassed = !record.RetryUpdatedDate.HasValue || record.RetryUpdatedDate.Value.AddHours(1) < DateTime.Now; if (record.RetryCount == null) { record.RetryCount = 1; dbContext.Database.ExecuteSqlCommand($"UPDATE[dbo].[BatchProcessRecord] SET [RetryCount] = 1, [RetryUpdatedDate] = '{now}' FROM [dbo].[BatchProcessRecord] WHERE[Id] = {record.Id}"); } else if (retryTimeHasPassed || record.RetryCount == RETRY_MAX) { record.RetryCount = record.RetryCount + 1; dbContext.Database.ExecuteSqlCommand($"UPDATE[dbo].[BatchProcessRecord] SET [RetryCount] = [RetryCount] + 1, [RetryUpdatedDate] = '{now}' FROM [dbo].[BatchProcessRecord] WHERE[Id] = {record.Id}"); } if (eventData.PropertyValues[EventPropertyConstants.AlRecordId].IsNullOrEmpty()) { SendErrorNotification("Batch AwardLetter process", $"This record has no AL-record-Id, record Id: {eventData.PropertyValues[EventPropertyConstants.Id].Value<string>()}. This likely means the notification event is not an AL event. Please contact your CampusLogic contact for next steps."); logger.Error($"Record for batch awardletter process has no AL-record-Id, with award letter record Id: {eventData.PropertyValues[EventPropertyConstants.Id].Value<string>()}. This likely means the notification event is not an AL event"); dbContext.Database.ExecuteSqlCommand($"DELETE FROM [dbo].[BatchProcessRecord] WHERE [ProcessGuid] = '{processGuid}' and [Id] = {record.Id}"); } else if (record.RetryCount > RETRY_MAX) { SendErrorNotification("Batch AwardLetter process", $"This record has reached it's maximum retry attempts, record Id: {record.Id}, AL-record-Id: {Guid.Parse(eventData.PropertyValues[EventPropertyConstants.AlRecordId].Value<string>())}. Please contact your CampusLogic contact for next steps."); logger.Error($"Record for batch awardletter process has reached maximum retry attempts, with award letter record Id: {record.Id}, AL-record-Id: {Guid.Parse(eventData.PropertyValues[EventPropertyConstants.AlRecordId].Value<string>())}."); dbContext.Database.ExecuteSqlCommand($"DELETE FROM [dbo].[BatchProcessRecord] WHERE [ProcessGuid] = '{processGuid}' and [Id] = {record.Id}"); } else if (record.RetryCount == RETRY_MAX && retryTimeHasPassed) { processSingularly = true; recordIds.Add(record.Id, Guid.Parse(eventData.PropertyValues[EventPropertyConstants.AlRecordId].Value <string>())); } else if (retryTimeHasPassed) { processSingularly = false; recordIds.Add(record.Id, Guid.Parse(eventData.PropertyValues[EventPropertyConstants.AlRecordId].Value <string>())); } if (recordIds.Count == size || processSingularly) { // Get event data for index file creation var recordIdList = string.Join(",", recordIds.Keys); var message = new EventNotificationData(JObject.Parse(dbContext.Database.SqlQuery <string>($"SELECT [Message] from [dbo].[BatchProcessRecord] WHERE [ProcessGuid] = '{processGuid}' and [Id] IN ({recordIdList})").First())); var response = await manager.GetBatchAwardLetterPdfFile(recordIds.Values.ToList(), name, message); //If the response was successful remove those records from the db so //we do not continue to process them if the file fails if (response.IsSuccessStatusCode) { dbContext.Database.ExecuteSqlCommand($"DELETE FROM [dbo].[BatchProcessRecord] WHERE [ProcessGuid] = '{processGuid}' and [Id] IN ({recordIdList})"); } recordIds.Clear(); } } // Process the last group of records that was smaller than the batch size if (recordIds.Any()) { var recordIdList = string.Join(",", recordIds.Keys); var message = new EventNotificationData(JObject.Parse(dbContext.Database.SqlQuery <string>($"SELECT [Message] from [dbo].[BatchProcessRecord] WHERE [ProcessGuid] = '{processGuid}' and [Id] IN ({recordIdList})").First())); var response = await manager.GetBatchAwardLetterPdfFile(recordIds.Values.ToList(), name, message); if (response.IsSuccessStatusCode) { dbContext.Database.ExecuteSqlCommand($"DELETE FROM [dbo].[BatchProcessRecord] WHERE [ProcessGuid] = '{processGuid}' and [Id] IN ({recordIdList})"); } } dbContext.Database.ExecuteSqlCommand($"UPDATE [dbo].[BatchProcessRecord] SET [ProcessGuid] = NULL WHERE [ProcessGuid] = '{processGuid}'"); } } } } catch (TaskCanceledException ex) { logger.Error($"The task was canceled: {ex}"); if (ex.InnerException != null) { logger.Error($"Inner exception: {ex.InnerException}"); } } catch (Exception e) { //Something happened during processing. Update any records that may have been marked for processing back to null so that they can be re-processed. logger.Error($"An error occured while attempting to execute the batch process: {e}"); } finally { dbContext.Database.ExecuteSqlCommand($"UPDATE [dbo].[BatchProcessRecord] SET [ProcessGuid] = NULL WHERE [ProcessGuid] = '{processGuid}'"); } } }
public static void ProcessFileStore() { //Guid to be applied to the records in the EventNotification table Guid processGuid = Guid.NewGuid(); using (var dbContext = new CampusLogicContext()) { //1. Create GUID //2. Assign GUID to all existing records in LocalDB table that have null ProcessGuid //3. Write to file(s) //4. Rinse & Repeat every x minutes. try { Dictionary <int, EventNotificationData> eventNotificationDataList = new Dictionary <int, EventNotificationData>(); List <int> successEventIds = new List <int>(); List <int> failEventIds = new List <int>(); //update all the current eventNotification records with no processguid to be processed. dbContext.Database.ExecuteSqlCommand($"UPDATE [dbo].[EventNotification] SET [ProcessGuid] = '{processGuid}' WHERE [ProcessGuid] IS NULL"); //make sure there are events to process if (dbContext.EventNotifications.Any(s => s.ProcessGuid != null && s.ProcessGuid == processGuid)) { //Get any individual or shared FileStore events configured from the web.config var individualEvents = campusLogicConfigSection.EventNotifications.Cast <EventNotificationHandler>() .Where(s => s.FileStoreType == "Individual").Select(e => e.EventNotificationId) .ToList(); var sharedEvents = campusLogicConfigSection.EventNotifications.Cast <EventNotificationHandler>() .Where(s => s.FileStoreType == "Shared").Select(e => e.EventNotificationId) .ToList(); if (sharedEvents.Any()) { //Make sure the event's processguid matches what we just generated so we're not re-processing events. var sharedEventsToProcess = dbContext.EventNotifications .Where(e => sharedEvents.Contains(e.EventNotificationId) && e.ProcessGuid == processGuid) .Select(m => new { id = m.Id, message = m.Message }); foreach (var eventRec in sharedEventsToProcess) { var eventData = new EventNotificationData(JObject.Parse(eventRec.message)); eventNotificationDataList.Add(eventRec.id, eventData); } if (eventNotificationDataList.Count > 0) { //send the list of events over to be processed into a file FileStoreManager filestoreManager = new FileStoreManager(); filestoreManager.CreateFileStoreFile(eventNotificationDataList, ref successEventIds, ref failEventIds); eventNotificationDataList.Clear(); CleanEventNotificationRecords(processGuid, ref successEventIds, ref failEventIds); } } if (individualEvents.Any()) { var individualEventsToProcess = dbContext.EventNotifications.Where(e => individualEvents.Contains(e.EventNotificationId) && e.ProcessGuid == processGuid); //Process any events configured for individual store into separate files (e.g., all 104 events in one file, all 105 in another) foreach (int eventNotificationId in individualEvents) { foreach (var eventRec in individualEventsToProcess.Where(s => s.EventNotificationId == eventNotificationId).Select(m => new { id = m.Id, message = m.Message })) { var eventData = new EventNotificationData(JObject.Parse(eventRec.message)); eventNotificationDataList.Add(eventRec.id, eventData); } if (eventNotificationDataList.Count > 0) { FileStoreManager filestoreManager = new FileStoreManager(); filestoreManager.CreateFileStoreFile(eventNotificationDataList, ref successEventIds, ref failEventIds); //clear out the list now that we've completed processing eventNotificationDataList.Clear(); CleanEventNotificationRecords(processGuid, ref successEventIds, ref failEventIds); } } } } } catch (Exception ex) { //Something happened during processing. Update any records that may have been marked for processing back to null so that they can be re-processed. logger.Error($"An error occured while attempting to process the event(s) for file store: {ex}"); dbContext.Database.ExecuteSqlCommand($"UPDATE [dbo].[EventNotification] SET [ProcessGuid] = NULL WHERE [ProcessGuid] = '{processGuid}'"); } } }
/// <summary> /// Handles an HTTP request for an endpoint. /// </summary> /// <param name="endpointName"></param> /// <param name="eventData"></param> private static void ApiIntegrationsHandler(string endpointName, EventNotificationData eventData) { try { using (var httpClient = new System.Net.Http.HttpClient()) { var apiEndpoint = campusLogicConfigSection.ApiEndpoints.GetEndpoints().FirstOrDefault(e => e.Name == endpointName); if (apiEndpoint == null) { throw new Exception("Invalid API Endpoint"); } var apiIntegration = campusLogicConfigSection.ApiIntegrations.GetApiIntegrations().FirstOrDefault(a => a.ApiId == apiEndpoint.ApiId); if (apiIntegration == null) { throw new Exception("Invalid API Integration"); } httpClient.BaseAddress = new Uri(apiIntegration.Root); // Allow 5 minutes for response httpClient.Timeout = new TimeSpan(0, 5, 0); // Custom header for API service to track requests httpClient.DefaultRequestHeaders.Add("EventId", eventData.PropertyValues[EventPropertyConstants.Id].Value <string>()); var authType = apiIntegration.Authentication; switch (authType) { case ConfigConstants.Basic: httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String( Encoding.ASCII.GetBytes( $"{apiIntegration.Username}:{apiIntegration.Password}"))); break; case ConfigConstants.OAuth2: var oauth2Token = GetOauth2TokenAsync(apiIntegration).Result; httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", oauth2Token); break; case ConfigConstants.OAuth_WRAP: var oauthwrapToken = GetOauthWrapTokenAsync(apiIntegration).Result; httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("WRAP", "access_token=\"" + oauthwrapToken + "\""); break; default: break; } // use the eventdata and its values to link up to the endpoint's parameters var parameterMappings = JArray.Parse(apiEndpoint.ParameterMappings); NameValueCollection eventParams = new NameValueCollection(); // foreach mapping, get event property, find its corresponding eventdata, get that eventdata's value, attach it to the parameter in mapping foreach (JObject mapping in parameterMappings) { var eventValue = eventData.PropertyValues[mapping["eventData"].Value <string>()].Value <string>(); eventParams.Add(mapping["parameter"].Value <string>(), eventValue); } HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK); var endpoint = apiEndpoint.Endpoint; var url = apiIntegration.Root + endpoint; switch (apiEndpoint.Method) { case WebRequestMethods.Http.Get: var array = (from key in eventParams.AllKeys from value in eventParams.GetValues(key) select $"{HttpUtility.UrlEncode(key)}={HttpUtility.UrlEncode(value)}").ToArray(); endpoint += "?" + string.Join("&", array); response = httpClient.GetAsync(endpoint).Result; break; case WebRequestMethods.Http.Post: response = httpClient.PostAsync(endpoint, GetHttpContent(eventParams, apiEndpoint.MimeType)).Result; break; case WebRequestMethods.Http.Put: response = httpClient.PutAsync(endpoint, GetHttpContent(eventParams, apiEndpoint.MimeType)).Result; break; default: break; } LogRequest(response, eventParams); if (!response.IsSuccessStatusCode) { throw new Exception("Invalid response - " + (int)response.StatusCode + " " + response.ReasonPhrase + " - Attempted to call " + apiEndpoint.Method + " " + url); } } } catch (Exception e) { logger.ErrorFormat("DataService ApiIntegrationsHandler Error: {0}", e); throw; } }
/// <summary> /// Builds an Odbc Parameter object from the arguments. /// </summary> /// <param name="parameterElement">Parameter definition from the config.</param> /// <param name="data">The event notification to pull the parameter's value from.</param> /// <returns></returns> private static OdbcParameter ParseParameter(ParameterElement parameterElement, EventNotificationData data) { try { // Need to convert the string representation of the type to the actual // enum OdbcType. string[] odbcTypes = Enum.GetNames(typeof(OdbcType)); string odbcTypeMatch = odbcTypes.First(t => t.Equals(parameterElement.DataType, StringComparison.InvariantCultureIgnoreCase)); OdbcType odbcType = (OdbcType)Enum.Parse(typeof(OdbcType), odbcTypeMatch); // Get property from the data using the property DisplayName (source) object value = HttpUtility.HtmlDecode(data.GetValueByDisplayName(parameterElement.Source)); // Build return object. var parameter = new OdbcParameter { ParameterName = parameterElement.Name, OdbcType = odbcType, Size = parameterElement.LengthAsInt, Value = value == null ? DBNull.Value : (string)value == string.Empty && odbcType == OdbcType.Int ? 0 : value }; return(parameter); } catch (Exception ex) { throw new Exception("Failed to parse parameter.", ex); } }
/// <summary> /// Handles events that require the system to execute a non-query database command /// </summary> /// <param name="eventData"></param> /// <param name="databaseCommand"></param> private static void DatabaseCommandNonQueryHandler(EventNotificationData eventData, string databaseCommand) { var commandText = eventData.ReplaceStringProperties(databaseCommand); ClientDatabaseManager.ExecuteDatabaseNonQuery(commandText); }
/// <summary> /// Handles PowerFAIDS integration. /// Will either queue up the eventData to be written to a file later /// or save the single record as an XML file. /// </summary> /// <param name="eventData"></param> private static void PowerFaidsHandler(EventNotificationData eventData) { try { // Get the settings the user has defined for PowerFAIDS var generalSettings = campusLogicConfigSection.PowerFaidsSettings; var awardYearToken = eventData.PropertyValues[EventPropertyConstants.AwardYear].Value <string>(); if (!string.IsNullOrEmpty(awardYearToken)) { awardYearToken = awardYearToken.Split('-')[0]; } var eventSettings = campusLogicConfigSection.PowerFaidsSettings.PowerFaidsSettingCollectionConfig.GetPowerFaidsSettingList(); var eventSetting = eventSettings .FirstOrDefault(e => !eventData.PropertyValues[EventPropertyConstants.SvTransactionCategoryId].IsNullOrEmpty() && eventData.PropertyValues[EventPropertyConstants.SvTransactionCategoryId].Value <string>() == e.TransactionCategory && e.Event == eventData.PropertyValues[EventPropertyConstants.EventNotificationId].Value <string>()); if (eventSetting != null) { var recordToProcess = new PowerFaidsDto() { EventId = eventData.PropertyValues[EventPropertyConstants.Id].Value <string>(), AwardYearToken = awardYearToken, AlternateId = eventData.PropertyValues[EventPropertyConstants.StudentId].Value <string>(), FilePath = generalSettings.FilePath, Outcome = eventSetting.Outcome, ShortName = eventSetting.ShortName, RequiredFor = eventSetting.RequiredFor, Status = eventSetting.Status, EffectiveDate = eventData.PropertyValues[EventPropertyConstants.DateTimeUtc].Value <DateTime>().ToString("yyyy-MM-dd"), DocumentLock = eventSetting.DocumentLock, VerificationOutcome = eventSetting.VerificationOutcome, VerificationOutcomeLock = eventSetting.VerificationOutcomeLock }; if (generalSettings.IsBatch.Value == false) { try { PowerFaidsService.ProcessPowerFaidsRecords(new List <PowerFaidsDto>() { recordToProcess }); } catch (Exception) { throw new Exception($"Error occurred while processing PowerFAIDS record. EventId: {recordToProcess.EventId}"); } } else { var json = JsonConvert.SerializeObject(recordToProcess).Replace("'", "''"); using (var dbContext = new CampusLogicContext()) { // Insert the record into the PowerFaidsRecord table so that it can be processed by the Automated PowerFAIDS job. dbContext.Database.ExecuteSqlCommand($"INSERT INTO [dbo].[PowerFaidsRecord]([Json], [ProcessGuid]) VALUES('{json}', NULL)"); } } } else { throw new Exception($"Error occured while processing PowerFAIDS record. Cannot find mapping for Event Notification: {eventData.PropertyValues[EventPropertyConstants.EventNotificationId].Value<string>()} and Transaction Category: {eventData.PropertyValues[EventPropertyConstants.SvTransactionCategoryId].Value<string>()}"); } } catch (Exception e) { NotificationService.ErrorNotification("PowerFAIDS", e); throw; } }
public static void ProcessPostedEvent(JObject notificationEvent) { try { using (var dbContext = new CampusLogicContext()) { var eventData = new EventNotificationData(notificationEvent); int eventNotificationId = eventData.PropertyValues[EventPropertyConstants.EventNotificationId].Value <int>(); var eventHandler = campusLogicConfigSection.EventNotifications.Cast <EventNotificationHandler>().FirstOrDefault(x => x.EventNotificationId == eventNotificationId) ?? campusLogicConfigSection.EventNotifications.Cast <EventNotificationHandler>().FirstOrDefault(x => x.EventNotificationId == 0); //If no specific handler was provided check for the catch all handler if (eventHandler != null) { //Enhance the Event Data for certain situations //Check if the transaction category was one of the three appeal types if (!eventData.PropertyValues[EventPropertyConstants.SvTransactionCategoryId].IsNullOrEmpty()) { if (((TransactionCategory)eventData.PropertyValues[EventPropertyConstants.SvTransactionCategoryId].Value <int>() != TransactionCategory.Verification && (TransactionCategory)eventData.PropertyValues[EventPropertyConstants.SvTransactionCategoryId].Value <int>() != TransactionCategory.Generic) && eventData.PropertyValues[EventPropertyConstants.EventNotificationName].Value <string>() == "Transaction Completed") { if (eventData.PropertyValues[EventPropertyConstants.SvTransactionId].IsNullOrEmpty()) { throw new Exception("A transaction Id is needed to get the appeal meta data"); } var manager = new AppealManager(); manager.GetAuthorizationForSV(); eventData.PropertyValues[EventPropertyConstants.TransactionOutcomeId] = manager.GetAppealMetaData(eventData.PropertyValues[EventPropertyConstants.SvTransactionId].Value <int>()).Result.ToString(); } } //Was a documentId sent over? If so, populate the Document Metadata. if (!eventData.PropertyValues[EventPropertyConstants.SvDocumentId].IsNullOrEmpty() && eventData.PropertyValues[EventPropertyConstants.SvDocumentId].Value <int>() > 0) { var manager = new DocumentManager(); DocumentMetaData documentMetaData = manager.GetDocumentMetaData(eventData.PropertyValues[EventPropertyConstants.SvDocumentId].Value <int>()); eventData.DocumentMetaData = documentMetaData; } //Check if this event notification is a communication event. If so, we need to call back to SV to get metadata about the communication if (eventNotificationId >= 300 && eventNotificationId <= 399) { if (eventData.PropertyValues[EventPropertyConstants.AdditionalInfoId].IsNullOrEmpty() || eventData.PropertyValues[EventPropertyConstants.AdditionalInfoId].Value <int>() == 0) { throw new Exception("An AdditionalInfoId is needed to get the communication event meta data"); } var manager = new CommunicationManager(); manager.GetAuthorizationForSV(); CommunicationActivityMetadata communicationActivityMetadata = manager.GetCommunicationActivityMetaData(eventData.PropertyValues[EventPropertyConstants.AdditionalInfoId].Value <int>()).Result; eventData.CommunicationActivityMetadata = communicationActivityMetadata; } //Check if this event notification is a Scholarship Universe Event (700's). If so, we need to call back to SU to get the metadata if (eventNotificationId >= 700 && eventNotificationId <= 799) { if (!eventData.PropertyValues[EventPropertyConstants.SuScholarshipAwardId].IsNullOrEmpty() && !eventData.PropertyValues[EventPropertyConstants.SuClientTermId].IsNullOrEmpty()) { var manager = new ScholarshipManager(); AwardPostItemData awardPostItemData = manager.GetAwardPostItemData( eventData.PropertyValues[EventPropertyConstants.SuScholarshipAwardId].Value <int>(), eventData.PropertyValues[EventPropertyConstants.SuClientTermId].Value <int>()); eventData.AwardPostItemData = awardPostItemData; } } // populate PropertyValues with all the values that have been gathered eventData.PopulatePropertyValues(); //Now Send it to the correct handler if (eventHandler.HandleMethod == "DatabaseCommandNonQuery") { DatabaseCommandNonQueryHandler(eventData, eventHandler.DbCommandFieldValue); } else if (eventHandler.HandleMethod == "DatabaseStoredProcedure") { DatabaseStoredProcedure(eventData, eventHandler.DbCommandFieldValue); } else if (eventHandler.HandleMethod == "DocumentRetrieval") { DocumentRetrievalHandler(eventData); } else if (eventHandler.HandleMethod == "DocumentRetrievalAndStoredProc") { DocumentRetrievalHandler(eventData); DatabaseStoredProcedure(eventData, eventHandler.DbCommandFieldValue); } else if (eventHandler.HandleMethod == "DocumentRetrievalAndNonQuery") { DocumentRetrievalHandler(eventData); DatabaseCommandNonQueryHandler(eventData, eventHandler.DbCommandFieldValue); } else if (eventHandler.HandleMethod == "FileStore") { FileStoreHandler(eventData); } else if (eventHandler.HandleMethod == "FileStoreAndDocumentRetrieval") { DocumentRetrievalHandler(eventData); //SV-2383: Moving the File Store handler *after* the Document Retrieval Handler so that if the Doc handler fails, it won't log the same event on retry. FileStoreHandler(eventData); } else if (eventHandler.HandleMethod == "AwardLetterPrint") { logger.Info("detect this is the AwardLetterPrint"); AwardLetterDocumentRetrievalHandler(eventData); } else if (eventHandler.HandleMethod == "BatchProcessingAwardLetterPrint") { logger.Info("detect this is the BatchProcessingAwardLetterPrint"); BatchProcessRetrievalHandler(ConfigConstants.AwardLetterPrintBatchType, eventHandler.BatchName, eventData); } else if (eventHandler.HandleMethod == "ApiIntegration") { ApiIntegrationsHandler(eventHandler.ApiEndpointName, eventData); } else if (eventHandler.HandleMethod == "PowerFAIDS") { PowerFaidsHandler(eventData); } } //Update the received event with a processed date time var eventId = eventData.PropertyValues[EventPropertyConstants.Id].Value <string>(); var storedEvent = dbContext.ReceivedEvents.FirstOrDefault(x => x.Id == eventId); if (storedEvent != null) { storedEvent.ProcessedDateTime = DateTime.UtcNow; dbContext.SaveChanges(); } } } catch (Exception ex) { //Log here any exceptions logger.ErrorFormat("DataService ProcessPostedEvent Error: {0}", ex); throw; } }
// Send the event individually private async Task SendSingleEventNotificationAsync(string teamId, EventNotificationData notification) { // Ideally this should send a single message with text and card, but because of message splitting, // such a message is split into two (text-only and card-only). As a workaround, we start a reply chain // with the text message, then send the card as a reply to this post. // Create the activity var activity = new Activity(ActivityTypes.Message) { Conversation = new ConversationAccount { Id = teamId }, AttachmentLayout = AttachmentLayoutTypes.Carousel, Text = notification.GetMessage(), Summary = Strings.MultipleEventsSummary, Attachments = new List <Attachment> { notification.GetCard() }, Entities = new List <Entity> { notification.GetMention() }, ServiceUrl = notification.User.ServiceUrl, }; // Add new entry to EventMessages collection for message type "preview" to track the status of message sent var eventMessage = new EventMessage { EventId = notification.Event.Id, OccurrenceId = notification.Occurrence.Id, Activity = activity, TenantId = notification.User.TenantId, MessageType = MessageType.Event, ExpireAt = notification.Occurrence.GetLastAllowableTimeToSendNotification(), }; eventMessage = await this.eventDataProvider.AddEventMessageAsync(eventMessage); // Send the message try { await eventMessage.SendAsync(this.connectorClientFactory); this.logProvider.LogInfo($"Event notifications sent to {teamId} for event {notification.Event.Id}"); } catch (Exception ex) { this.logProvider.LogError($"Failed to send notifications to team {teamId}", ex, new Dictionary <string, string> { { "EventId", eventMessage.EventId }, { "OccurrenceId", eventMessage.OccurrenceId }, { "TeamId", teamId }, { "LastAttemptTime", DateTimeOffset.UtcNow.ToString() }, { "LastAttemptStatusCode", eventMessage.MessageSendResult?.StatusCode.ToString() }, { "ResponseBody", eventMessage.MessageSendResult?.ResponseBody }, }); throw; } finally { // Record the result of the send await this.eventDataProvider.UpdateEventMessageAsync(eventMessage); } }