/// <summary> /// Gets a list of the received event records /// </summary> /// <returns></returns> public static List <ReceivedEvent> EventRecords(int count) { using (var dbContext = new CampusLogicContext()) { return(dbContext.ReceivedEvents.OrderByDescending(x => x.ReceivedDateTime).Take(count).ToList()); } }
/// <summary> /// Logs the notification in the notification log table /// </summary> /// <param name="notificationData"></param> public static void LogNotification(NotificationData notificationData) { try { if (campusLogicConfigSection.SMTPSettings.NotificationsEnabled ?? false) { using (var dbContext = new CampusLogicContext()) { dbContext.NotificationLogs.Add(new NotificationLog() { Recipients = notificationData.MailMessage.To.ToString(), Sender = notificationData.MailMessage.From.ToString(), DateSent = DateTime.UtcNow, Subject = notificationData.MailMessage.Subject, Body = notificationData.MailMessage.Body, FailedSending = !notificationData.SendCompleted ?? false, }); dbContext.SaveChanges(); } } } catch (Exception ex) { //Log here any exceptions logger.ErrorFormat("DataService LogNotification Error logging recently sent email: {0}", ex); } }
/// <summary> /// Data Cleanup - Run on a scheduled basis. Configured in the Startup.cs /// Removes old records from the ReceivedEvents and Logging to keep the database size down /// </summary> public static void DataCleanup() { try { var purgeReceivedEventsAfterDays = String.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["PurgeReceivedEventsAfterDays"]) ? 30 : Convert.ToInt32(ConfigurationManager.AppSettings["PurgeReceivedEventsAfterDays"]); var purgeLogRecordsAfterDays = String.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["PurgeLogRecordsAfterDays"]) ? 30 : Convert.ToInt32(ConfigurationManager.AppSettings["PurgeLogRecordsAfterDays"]); var purgeNotificaitonLogRecordsAfterDays = String.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["PurgeNotificationLogRecordsAfterDays"]) ? 30 : Convert.ToInt32(ConfigurationManager.AppSettings["PurgeNotificationLogRecordsAfterDays"]); using (var dbContext = new CampusLogicContext()) { //Clean up log records older then configured number of days dbContext.Database.ExecuteSqlCommand("Delete from [Log] where [Date] < DateAdd(d, -" + purgeLogRecordsAfterDays + ", GetUtcDate())"); //Clean up notification log records older then configured number of days dbContext.Database.ExecuteSqlCommand("Delete from [NotificationLog] where [DateSent] < DateAdd(d, -" + purgeNotificaitonLogRecordsAfterDays + ", GetUtcDate())"); //Clean up Received event records older then configured number of days dbContext.Database.ExecuteSqlCommand("Delete from [ReceivedEvent] where [ReceivedDateTime] < DateAdd(d, -" + purgeReceivedEventsAfterDays + ", GetUtcDate())"); //Clean up event notifications logged in the EventNotification table dbContext.Database.ExecuteSqlCommand("DELETE FROM [dbo].[EventNotification] WHERE [CreatedDateTime] < DateAdd(d, -" + purgeReceivedEventsAfterDays + ", GetUtcDate()) AND [ProcessGuid] IS NOT NULL"); } } catch (Exception ex) { logger.ErrorFormat("DataService DataCleanup Error: {0}", ex); } }
/// <summary> /// Gets a list of the log records /// </summary> /// <returns></returns> public static List <Log> LogRecords(int count) { using (var dbContext = new CampusLogicContext()) { return(dbContext.Logs.OrderByDescending(x => x.Date).Take(count).ToList()); } }
/// <summary> /// Process the Notification Events by storing each event received and then queue them each for processing /// </summary> /// <param name="eventData"></param> public static void ReceivePostedEvents(IEnumerable <JObject> eventData) { if (campusLogicConfigSection.EventNotifications.EventNotificationsEnabled ?? false) { using (var dbContext = new CampusLogicContext()) { foreach (JObject notificationEvent in eventData) { //SV-1698 Allowing requeue of events already processed //First verify we didn't already get and process this event using the unique identifier within the configured purge day window before we clear old events var id = notificationEvent["Id"].ToString(); var existingEvent = dbContext.ReceivedEvents.FirstOrDefault(x => x.Id == id); if (existingEvent == null) { dbContext.ReceivedEvents.Add(new ReceivedEvent() { Id = notificationEvent["Id"].ToString(), EventData = notificationEvent.ToString(), ReceivedDateTime = DateTime.UtcNow }); } else { existingEvent.EventData = notificationEvent.ToString(); existingEvent.ReceivedDateTime = DateTime.UtcNow; } dbContext.SaveChanges(); BackgroundJob.Enqueue(() => ProcessPostedEvent(notificationEvent)); } } } }
/// <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)"); } }
public static void RunBatchPowerFaidsProcess() { Guid processGuid = Guid.NewGuid(); using (var dbContext = new CampusLogicContext()) { // Get all records to process var records = dbContext.PowerFaidsRecords.Where(p => p.ProcessGuid == null); if (records.Any()) { // Lock to prevent from being processed again dbContext.Database.ExecuteSqlCommand($"update [dbo].[PowerFaidsRecord] set [ProcessGuid] = '{processGuid}' from [dbo].[PowerFaidsRecord] where [Id] in (select [Id] from [dbo].[PowerFaidsRecord] where [ProcessGuid] is NULL)"); // Get the records to process var recordsToProcess = dbContext.PowerFaidsRecords.Where(p => p.ProcessGuid == processGuid).Select(p => p).ToList(); var powerFaidsList = new List <PowerFaidsDto>(); foreach (var record in recordsToProcess) { try { PowerFaidsDto powerFaidsRecord = JsonConvert.DeserializeObject <PowerFaidsDto>(record.Json); powerFaidsList.Add(powerFaidsRecord); } catch (Exception) { dynamic data = JObject.Parse(record.Json); NotificationService.ErrorNotification("PowerFAIDS", $"Error occurred while processing PowerFAIDS record. EventId: {data.EventId}"); // Delete the bad record dbContext.Database.ExecuteSqlCommand($"DELETE FROM [dbo].[PowerFaidsRecord] WHERE [Id] = {record.Id}"); } } try { ProcessPowerFaidsRecords(powerFaidsList); } catch (Exception) { NotificationService.ErrorNotification("PowerFAIDS", $"Error occurred while generating XML. Affected events: {string.Join(", ", powerFaidsList.Select(x => x.EventId).ToList())}"); } // Delete the records to never be processed again! dbContext.Database.ExecuteSqlCommand($"DELETE FROM [dbo].[PowerFaidsRecord] WHERE [ProcessGuid] = '{processGuid}'"); } } }
/// <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}"); } }
private static void UpdateData(bool updateFromPmSuccessful) { using (var dbContext = new CampusLogicContext()) { // if PM data is available, backup to local CL DB if (updateFromPmSuccessful) { using (DbContextTransaction tran = dbContext.Database.BeginTransaction()) { try { dbContext.Database.ExecuteSqlCommand("DELETE FROM [dbo].[EventProperty]"); dbContext.EventProperty.AddRange(EventPropertyManager.Instance.EventProperties.Select(p => new EventProperty { Id = p.Id, Name = p.Name, DisplayName = p.DisplayName, DisplayFormula = p.DisplayFormula })); tran.Commit(); dbContext.SaveChanges(); } catch (Exception e) { tran.Rollback(); logger.Error($"EventPropertyService UpdateData Error: {e}"); } } } // else, use the local CL Connect data else { IQueryable <Implementation.Models.EventProperty> properties = dbContext.EventProperty.Select(p => new Implementation.Models.EventProperty { Id = p.Id, Name = p.Name, DisplayName = p.DisplayName, DisplayFormula = p.DisplayFormula }); EventPropertyManager.Instance.EventProperties = properties.ToList(); } } }
private static void CleanEventNotificationRecords(Guid processingGuid, ref List <int> succeededRecords, ref List <int> failedRecords) { using (var dbContext = new CampusLogicContext()) { //Remove events that succeeded and reset failed events, so they can be processed again if (succeededRecords.Count > 0) { dbContext.Database.ExecuteSqlCommand($"DELETE FROM [dbo].[EventNotification] WHERE [ProcessGuid] = '{processingGuid}' and [Id] IN ({string.Join(",", succeededRecords)})"); succeededRecords.Clear(); } if (failedRecords.Count > 0) { dbContext.Database.ExecuteSqlCommand($"UPDATE [dbo].[EventNotification] SET [ProcessGuid] = NULL WHERE [ProcessGuid] = '{processingGuid}' and [Id] IN ({string.Join(",", failedRecords)})"); failedRecords.Clear(); } } }
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 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; } }