New: SendGrid Notifications

This commit is contained in:
Skyler Mäntysaari 2020-05-20 21:22:05 +03:00 committed by Qstick
parent 4eac1c5663
commit 998a2df7f0
5 changed files with 264 additions and 0 deletions

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using FluentValidation.Results;
using NLog;
namespace NzbDrone.Core.Notifications.SendGrid
{
public class SendGrid : NotificationBase<SendGridSettings>
{
private readonly ISendGridProxy _proxy;
private readonly Logger _logger;
public SendGrid(ISendGridProxy proxy, Logger logger)
{
_proxy = proxy;
_logger = logger;
}
public override string Name => "SendGrid";
public override string Link => "https://sendgrid.com/";
public override void OnGrab(GrabMessage grabMessage)
{
_proxy.SendNotification(ALBUM_GRABBED_TITLE, grabMessage.Message, Settings);
}
public override void OnReleaseImport(AlbumDownloadMessage message)
{
_proxy.SendNotification(ALBUM_DOWNLOADED_TITLE, message.Message, Settings);
}
public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck)
{
_proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings);
}
public override void OnDownloadFailure(DownloadFailedMessage message)
{
_proxy.SendNotification(DOWNLOAD_FAILURE_TITLE, message.Message, Settings);
}
public override void OnImportFailure(AlbumDownloadMessage message)
{
_proxy.SendNotification(IMPORT_FAILURE_TITLE, message.Message, Settings);
}
public override ValidationResult Test()
{
var failures = new List<ValidationFailure>();
try
{
const string title = "Test Notification";
const string body = "This is a test message from Lidarr";
_proxy.SendNotification(title, body, Settings);
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to send test message");
failures.Add(new ValidationFailure("", "Unable to send test message"));
}
return new ValidationResult(failures);
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using NzbDrone.Common.Exceptions;
namespace NzbDrone.Core.Notifications.SendGrid
{
public class SendGridException : NzbDroneException
{
public SendGridException(string message)
: base(message)
{
}
public SendGridException(string message, Exception innerException, params object[] args)
: base(message, innerException, args)
{
}
}
}

View File

@ -0,0 +1,50 @@
using System.Collections.Generic;
namespace NzbDrone.Core.Notifications.SendGrid
{
public class SendGridPayload
{
public SendGridPayload()
{
Personalizations = new List<SendGridPersonalization>();
Content = new List<SendGridContent>();
}
public List<SendGridContent> Content { get; set; }
public SendGridEmail From { get; set; }
public List<SendGridPersonalization> Personalizations { get; set; }
}
public class SendGridContent
{
public string Type { get; set; }
public string Value { get; set; }
}
public class SendGridEmail
{
public string Email { get; set; }
}
public class SendGridPersonalization
{
public SendGridPersonalization()
{
To = new List<SendGridEmail>();
}
public List<SendGridEmail> To { get; set; }
public string Subject { get; set; }
}
public class SendGridSenderResponse
{
public List<SendGridSender> Result { get; set; }
}
public class SendGridSender
{
public SendGridEmail From { get; set; }
public string Nickname { get; set; }
}
}

View File

@ -0,0 +1,83 @@
using System.Net;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
namespace NzbDrone.Core.Notifications.SendGrid
{
public interface ISendGridProxy
{
void SendNotification(string title, string message, SendGridSettings settings);
}
public class SendGridProxy : ISendGridProxy
{
private readonly IHttpClient _httpClient;
public SendGridProxy(IHttpClient httpClient)
{
_httpClient = httpClient;
}
public void SendNotification(string title, string message, SendGridSettings settings)
{
try
{
var request = BuildRequest(settings, "mail/send", HttpMethod.POST);
var payload = new SendGridPayload
{
From = new SendGridEmail
{
Email = settings.From
}
};
payload.Content.Add(new SendGridContent
{
Type = "text/plain",
Value = message
});
var personalization = new SendGridPersonalization
{
Subject = title,
};
foreach (var recipient in settings.Recipients)
{
personalization.To.Add(new SendGridEmail
{
Email = recipient
});
}
payload.Personalizations.Add(personalization);
request.SetContent(payload.ToJson());
_httpClient.Execute(request);
}
catch (HttpException ex)
{
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
{
throw new SendGridException("Unauthorized - AuthToken is invalid");
}
throw new SendGridException("Unable to connect to SendGrid. Status Code: {0}", ex);
}
}
private HttpRequest BuildRequest(SendGridSettings settings, string resource, HttpMethod method)
{
var request = new HttpRequestBuilder(settings.BaseUrl).Resource(resource)
.SetHeader("Authorization", $"Bearer {settings.ApiKey}")
.Build();
request.Headers.ContentType = "application/json";
request.Method = method;
return request;
}
}
}

View File

@ -0,0 +1,46 @@
using System.Collections.Generic;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Notifications.SendGrid
{
public class SendGridSettingsValidator : AbstractValidator<SendGridSettings>
{
public SendGridSettingsValidator()
{
RuleFor(c => c.ApiKey).NotEmpty();
RuleFor(c => c.From).NotEmpty().EmailAddress();
RuleFor(c => c.Recipients).NotEmpty();
RuleForEach(c => c.Recipients).NotEmpty().EmailAddress();
}
}
public class SendGridSettings : IProviderConfig
{
private static readonly SendGridSettingsValidator Validator = new SendGridSettingsValidator();
public SendGridSettings()
{
BaseUrl = "https://api.sendgrid.com/v3/";
Recipients = new string[] { };
}
public string BaseUrl { get; set; }
[FieldDefinition(1, Label = "API Key", HelpText = "The API Key generated by SendGrid", HelpLink = "https://sendgrid.com/docs/ui/account-and-settings/api-keys/#creating-an-api-key")]
public string ApiKey { get; set; }
[FieldDefinition(2, Label = "From Address")]
public string From { get; set; }
[FieldDefinition(3, Label = "Recipient Address(es)", Type = FieldType.Tag)]
public IEnumerable<string> Recipients { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}