/// <summary> /// Formats the confirmation that a new alert has been set up. /// </summary> /// <param name="body">The body.</param> /// <returns></returns> public string FormatNewAlertConfirmation(JobAlert alert) { var alertUrl = _encoder.AddIdToUrl(_alertSettings.ChangeAlertBaseUrl, alert.AlertId).ToString(); var alertDescription = alert.Query.ToString(false); var bodyHtml = TidyUpEmailHtml(_alertSettings.NewAlertEmailBodyHtml) .Replace("{alert-description}", alertDescription) .Replace("{change-alert-url}", alertUrl); return(_newAlertTemplateHtml.Replace("{body}", bodyHtml)); }
/// <summary> /// Saves a new or updated alert. /// </summary> /// <param name="alert">The alert.</param> /// <exception cref="ArgumentNullException">alert</exception> /// <exception cref="ArgumentException">The alert must have an AlertId - alert</exception> public void SaveAlert(JobAlert alert) { if (alert == null) { throw new ArgumentNullException(nameof(alert)); } if (String.IsNullOrEmpty(alert.AlertId)) { throw new ArgumentException("The alert must have an AlertId", nameof(alert)); } var table = _tableClient.GetTableReference(_alertsTable); table.CreateIfNotExistsAsync().Wait(); var query = _queryConverter.ToCollection(alert.Query); query.Remove("page"); query.Remove("pagesize"); query.Remove("sort"); var serialised = query.ToString(); // Azure tables use an index clustered first by partition key then by row key, // so use email as the partition key to make it easy to get all alerts for a user. var entity = new JobAlertTableEntity() { PartitionKey = ToAzureKeyString(alert.Email), RowKey = alert.AlertId, Criteria = serialised, Frequency = alert.Frequency, JobsSet = alert.JobsSet.ToString() }; try { table.Execute(TableOperation.InsertOrReplace(entity)); } catch (StorageException ex) { if (ex.Message.Contains("(400) Bad Request")) { var alertQuery = _queryConverter.ToCollection(alert.Query).ToString(); LogHelper.Error <AzureTableStorageAlertsRepository>(alertQuery + " returned " + ex.RequestInformation.ExtendedErrorInformation.ErrorMessage, ex); ex.ToExceptionless().Submit(); } else { throw; } } }
private JobAlert BuildAlertFromEntity(JobAlertTableEntity entity) { JobAlert alert = null; if (entity != null) { var searchQuery = HttpUtility.ParseQueryString(String.IsNullOrEmpty(entity.Criteria) ? String.Empty : entity.Criteria); alert = new JobAlert() { AlertId = entity.RowKey, Query = _queryConverter.ToQuery(searchQuery), Email = entity.PartitionKey, Frequency = entity.Frequency, JobsSet = (JobsSet)Enum.Parse(typeof(JobsSet), entity.JobsSet) }; alert.Query.JobsSet = alert.JobsSet; } return(alert); }
/// <summary> /// Generates a new unique identifier based on the content of a job alert. /// </summary> /// <param name="alert">The alert.</param> /// <returns></returns> public string GenerateId(JobAlert alert) { if (alert == null) { throw new ArgumentNullException(nameof(alert)); } if (String.IsNullOrEmpty(alert.Email)) { throw new ArgumentException("The alert must include an email address to generate a unique ID", nameof(alert)); } HashAlgorithm algorithm = SHA1.Create(); var bytes = Encoding.ASCII.GetBytes(alert.JobsSet + alert.Email + _queryConverter.ToCollection(alert.Query).ToString()); var hash = algorithm.ComputeHash(bytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hash.Length; i++) { sb.Append(hash[i].ToString("X2")); } return(sb.ToString().ToLowerInvariant()); }
/// <summary> /// Sends a confirmation that a new alert has been set up. /// </summary> /// <param name="alert">The alert.</param> public void SendNewAlertConfirmation(JobAlert alert) { var bodyHtml = _formatter.FormatNewAlertConfirmation(alert); SendEmail(alert.Email, _alertSettings.NewAlertEmailSubject, bodyHtml); }