New: Add OnDelete Notification to TraktConnection

to remove movies from Trakt Collection when they are removed from Radarr

Add OnDelete Notification to TraktConnection to remove movies from Trakt Collection when they are removed from Radarr

skip the deleteHandler if the delete Event was triggered for reason: Upgrade

change migration from 180 to 182 since 180 and 181 are already in plan
to be used

address comments regarding helpText for OnDelete
and move check for OnUpgrade deletion reason into trakt connection OnDelete handler

reuse TraktCollectMoviesResource for OnDelete
trakt api should just ignore the other properties anyway

add WithDefaultValue to migration

add unit test case for onDelete to

fix unit testcase for onDelete
pull/4949/head
geogolem 4 years ago committed by Qstick
parent 261e598c99
commit e033ce1eff

@ -59,11 +59,13 @@ class Notification extends Component {
onDownload, onDownload,
onUpgrade, onUpgrade,
onRename, onRename,
onDelete,
onHealthIssue, onHealthIssue,
supportsOnGrab, supportsOnGrab,
supportsOnDownload, supportsOnDownload,
supportsOnUpgrade, supportsOnUpgrade,
supportsOnRename, supportsOnRename,
supportsOnDelete,
supportsOnHealthIssue supportsOnHealthIssue
} = this.props; } = this.props;
@ -84,6 +86,13 @@ class Notification extends Component {
</Label> </Label>
} }
{
supportsOnDelete && onDelete &&
<Label kind={kinds.SUCCESS}>
On Delete
</Label>
}
{ {
supportsOnDownload && onDownload && supportsOnDownload && onDownload &&
<Label kind={kinds.SUCCESS}> <Label kind={kinds.SUCCESS}>
@ -113,7 +122,7 @@ class Notification extends Component {
} }
{ {
!onGrab && !onDownload && !onRename && !onHealthIssue && !onGrab && !onDownload && !onRename && !onHealthIssue && !onDelete &&
<Label <Label
kind={kinds.DISABLED} kind={kinds.DISABLED}
outline={true} outline={true}
@ -150,9 +159,11 @@ Notification.propTypes = {
onDownload: PropTypes.bool.isRequired, onDownload: PropTypes.bool.isRequired,
onUpgrade: PropTypes.bool.isRequired, onUpgrade: PropTypes.bool.isRequired,
onRename: PropTypes.bool.isRequired, onRename: PropTypes.bool.isRequired,
onDelete: PropTypes.bool.isRequired,
onHealthIssue: PropTypes.bool.isRequired, onHealthIssue: PropTypes.bool.isRequired,
supportsOnGrab: PropTypes.bool.isRequired, supportsOnGrab: PropTypes.bool.isRequired,
supportsOnDownload: PropTypes.bool.isRequired, supportsOnDownload: PropTypes.bool.isRequired,
supportsOnDelete: PropTypes.bool.isRequired,
supportsOnUpgrade: PropTypes.bool.isRequired, supportsOnUpgrade: PropTypes.bool.isRequired,
supportsOnRename: PropTypes.bool.isRequired, supportsOnRename: PropTypes.bool.isRequired,
supportsOnHealthIssue: PropTypes.bool.isRequired, supportsOnHealthIssue: PropTypes.bool.isRequired,

@ -19,11 +19,13 @@ function NotificationEventItems(props) {
onDownload, onDownload,
onUpgrade, onUpgrade,
onRename, onRename,
onDelete,
onHealthIssue, onHealthIssue,
supportsOnGrab, supportsOnGrab,
supportsOnDownload, supportsOnDownload,
supportsOnUpgrade, supportsOnUpgrade,
supportsOnRename, supportsOnRename,
supportsOnDelete,
supportsOnHealthIssue, supportsOnHealthIssue,
includeHealthWarnings includeHealthWarnings
} = item; } = item;
@ -84,6 +86,17 @@ function NotificationEventItems(props) {
/> />
</div> </div>
<div>
<FormInputGroup
type={inputTypes.CHECK}
name="onDelete"
helpText="On Delete"
isDisabled={!supportsOnDelete.value}
{...onDelete}
onChange={onInputChange}
/>
</div>
<div> <div>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}

@ -17,10 +17,12 @@ namespace NzbDrone.Api.Notifications
resource.OnDownload = definition.OnDownload; resource.OnDownload = definition.OnDownload;
resource.OnUpgrade = definition.OnUpgrade; resource.OnUpgrade = definition.OnUpgrade;
resource.OnRename = definition.OnRename; resource.OnRename = definition.OnRename;
resource.OnDelete = definition.OnDelete;
resource.SupportsOnGrab = definition.SupportsOnGrab; resource.SupportsOnGrab = definition.SupportsOnGrab;
resource.SupportsOnDownload = definition.SupportsOnDownload; resource.SupportsOnDownload = definition.SupportsOnDownload;
resource.SupportsOnUpgrade = definition.SupportsOnUpgrade; resource.SupportsOnUpgrade = definition.SupportsOnUpgrade;
resource.SupportsOnRename = definition.SupportsOnRename; resource.SupportsOnRename = definition.SupportsOnRename;
resource.SupportsOnDelete = definition.SupportsOnDelete;
resource.Tags = definition.Tags; resource.Tags = definition.Tags;
} }
@ -32,10 +34,12 @@ namespace NzbDrone.Api.Notifications
definition.OnDownload = resource.OnDownload; definition.OnDownload = resource.OnDownload;
definition.OnUpgrade = resource.OnUpgrade; definition.OnUpgrade = resource.OnUpgrade;
definition.OnRename = resource.OnRename; definition.OnRename = resource.OnRename;
definition.OnDelete = resource.OnDelete;
definition.SupportsOnGrab = resource.SupportsOnGrab; definition.SupportsOnGrab = resource.SupportsOnGrab;
definition.SupportsOnDownload = resource.SupportsOnDownload; definition.SupportsOnDownload = resource.SupportsOnDownload;
definition.SupportsOnUpgrade = resource.SupportsOnUpgrade; definition.SupportsOnUpgrade = resource.SupportsOnUpgrade;
definition.SupportsOnRename = resource.SupportsOnRename; definition.SupportsOnRename = resource.SupportsOnRename;
definition.SupportsOnDelete = resource.SupportsOnDelete;
definition.Tags = resource.Tags; definition.Tags = resource.Tags;
} }

@ -8,10 +8,12 @@ namespace NzbDrone.Api.Notifications
public bool OnDownload { get; set; } public bool OnDownload { get; set; }
public bool OnUpgrade { get; set; } public bool OnUpgrade { get; set; }
public bool OnRename { get; set; } public bool OnRename { get; set; }
public bool OnDelete { get; set; }
public bool SupportsOnGrab { get; set; } public bool SupportsOnGrab { get; set; }
public bool SupportsOnDownload { get; set; } public bool SupportsOnDownload { get; set; }
public bool SupportsOnUpgrade { get; set; } public bool SupportsOnUpgrade { get; set; }
public bool SupportsOnRename { get; set; } public bool SupportsOnRename { get; set; }
public bool SupportsOnDelete { get; set; }
public HashSet<int> Tags { get; set; } public HashSet<int> Tags { get; set; }
} }
} }

@ -62,6 +62,11 @@ namespace NzbDrone.Core.Test.NotificationTests
TestLogger.Info("OnRename was called"); TestLogger.Info("OnRename was called");
} }
public override void OnDelete(DeleteMessage message)
{
TestLogger.Info("OnDelete was called");
}
public override void OnHealthIssue(NzbDrone.Core.HealthCheck.HealthCheck artist) public override void OnHealthIssue(NzbDrone.Core.HealthCheck.HealthCheck artist)
{ {
TestLogger.Info("OnHealthIssue was called"); TestLogger.Info("OnHealthIssue was called");
@ -100,6 +105,7 @@ namespace NzbDrone.Core.Test.NotificationTests
notification.SupportsOnDownload.Should().BeTrue(); notification.SupportsOnDownload.Should().BeTrue();
notification.SupportsOnUpgrade.Should().BeTrue(); notification.SupportsOnUpgrade.Should().BeTrue();
notification.SupportsOnRename.Should().BeTrue(); notification.SupportsOnRename.Should().BeTrue();
notification.SupportsOnDelete.Should().BeTrue();
notification.SupportsOnHealthIssue.Should().BeTrue(); notification.SupportsOnHealthIssue.Should().BeTrue();
} }
@ -112,6 +118,7 @@ namespace NzbDrone.Core.Test.NotificationTests
notification.SupportsOnDownload.Should().BeFalse(); notification.SupportsOnDownload.Should().BeFalse();
notification.SupportsOnUpgrade.Should().BeFalse(); notification.SupportsOnUpgrade.Should().BeFalse();
notification.SupportsOnRename.Should().BeFalse(); notification.SupportsOnRename.Should().BeFalse();
notification.SupportsOnDelete.Should().BeFalse();
notification.SupportsOnHealthIssue.Should().BeFalse(); notification.SupportsOnHealthIssue.Should().BeFalse();
} }
} }

@ -0,0 +1,14 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(182)]
public class on_delete_notification : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("Notifications").AddColumn("OnDelete").AsBoolean().WithDefaultValue(false);
}
}
}

@ -86,6 +86,7 @@ namespace NzbDrone.Core.Datastore
.Ignore(i => i.SupportsOnDownload) .Ignore(i => i.SupportsOnDownload)
.Ignore(i => i.SupportsOnUpgrade) .Ignore(i => i.SupportsOnUpgrade)
.Ignore(i => i.SupportsOnRename) .Ignore(i => i.SupportsOnRename)
.Ignore(i => i.SupportsOnDelete)
.Ignore(i => i.SupportsOnHealthIssue); .Ignore(i => i.SupportsOnHealthIssue);
Mapper.Entity<MetadataDefinition>("Metadata").RegisterModel() Mapper.Entity<MetadataDefinition>("Metadata").RegisterModel()

@ -0,0 +1,20 @@
using System.Collections.Generic;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Movies;
namespace NzbDrone.Core.Notifications
{
public class DeleteMessage
{
public string Message { get; set; }
public Movie Movie { get; set; }
public MovieFile MovieFile { get; set; }
public DeleteMediaFileReason Reason { get; set; }
public override string ToString()
{
return Message;
}
}
}

@ -11,10 +11,12 @@ namespace NzbDrone.Core.Notifications
void OnDownload(DownloadMessage message); void OnDownload(DownloadMessage message);
void OnMovieRename(Movie movie); void OnMovieRename(Movie movie);
void OnHealthIssue(HealthCheck.HealthCheck healthCheck); void OnHealthIssue(HealthCheck.HealthCheck healthCheck);
void OnDelete(DeleteMessage deleteMessage);
bool SupportsOnGrab { get; } bool SupportsOnGrab { get; }
bool SupportsOnDownload { get; } bool SupportsOnDownload { get; }
bool SupportsOnUpgrade { get; } bool SupportsOnUpgrade { get; }
bool SupportsOnRename { get; } bool SupportsOnRename { get; }
bool SupportsOnHealthIssue { get; } bool SupportsOnHealthIssue { get; }
bool SupportsOnDelete { get; }
} }
} }

@ -46,11 +46,16 @@ namespace NzbDrone.Core.Notifications
{ {
} }
public virtual void OnDelete(DeleteMessage deleteMessage)
{
}
public bool SupportsOnGrab => HasConcreteImplementation("OnGrab"); public bool SupportsOnGrab => HasConcreteImplementation("OnGrab");
public bool SupportsOnRename => HasConcreteImplementation("OnMovieRename"); public bool SupportsOnRename => HasConcreteImplementation("OnMovieRename");
public bool SupportsOnDownload => HasConcreteImplementation("OnDownload"); public bool SupportsOnDownload => HasConcreteImplementation("OnDownload");
public bool SupportsOnUpgrade => SupportsOnDownload; public bool SupportsOnUpgrade => SupportsOnDownload;
public bool SupportsOnHealthIssue => HasConcreteImplementation("OnHealthIssue"); public bool SupportsOnHealthIssue => HasConcreteImplementation("OnHealthIssue");
public bool SupportsOnDelete => HasConcreteImplementation("OnDelete");
protected TSettings Settings => (TSettings)Definition.Settings; protected TSettings Settings => (TSettings)Definition.Settings;

@ -9,13 +9,15 @@ namespace NzbDrone.Core.Notifications
public bool OnUpgrade { get; set; } public bool OnUpgrade { get; set; }
public bool OnRename { get; set; } public bool OnRename { get; set; }
public bool OnHealthIssue { get; set; } public bool OnHealthIssue { get; set; }
public bool OnDelete { get; set; }
public bool SupportsOnGrab { get; set; } public bool SupportsOnGrab { get; set; }
public bool SupportsOnDownload { get; set; } public bool SupportsOnDownload { get; set; }
public bool SupportsOnUpgrade { get; set; } public bool SupportsOnUpgrade { get; set; }
public bool SupportsOnRename { get; set; } public bool SupportsOnRename { get; set; }
public bool SupportsOnHealthIssue { get; set; } public bool SupportsOnHealthIssue { get; set; }
public bool SupportsOnDelete { get; set; }
public bool IncludeHealthWarnings { get; set; } public bool IncludeHealthWarnings { get; set; }
public override bool Enable => OnGrab || OnDownload || (OnDownload && OnUpgrade) || OnHealthIssue; public override bool Enable => OnGrab || OnDownload || (OnDownload && OnUpgrade) || OnHealthIssue || OnDelete;
} }
} }

@ -14,6 +14,7 @@ namespace NzbDrone.Core.Notifications
List<INotification> OnUpgradeEnabled(); List<INotification> OnUpgradeEnabled();
List<INotification> OnRenameEnabled(); List<INotification> OnRenameEnabled();
List<INotification> OnHealthIssueEnabled(); List<INotification> OnHealthIssueEnabled();
List<INotification> OnDeleteEnabled();
} }
public class NotificationFactory : ProviderFactory<INotification, NotificationDefinition>, INotificationFactory public class NotificationFactory : ProviderFactory<INotification, NotificationDefinition>, INotificationFactory
@ -48,6 +49,11 @@ namespace NzbDrone.Core.Notifications
return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnHealthIssue).ToList(); return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnHealthIssue).ToList();
} }
public List<INotification> OnDeleteEnabled()
{
return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnDelete).ToList();
}
public override void SetProviderCharacteristics(INotification provider, NotificationDefinition definition) public override void SetProviderCharacteristics(INotification provider, NotificationDefinition definition)
{ {
base.SetProviderCharacteristics(provider, definition); base.SetProviderCharacteristics(provider, definition);
@ -57,6 +63,7 @@ namespace NzbDrone.Core.Notifications
definition.SupportsOnUpgrade = provider.SupportsOnUpgrade; definition.SupportsOnUpgrade = provider.SupportsOnUpgrade;
definition.SupportsOnRename = provider.SupportsOnRename; definition.SupportsOnRename = provider.SupportsOnRename;
definition.SupportsOnHealthIssue = provider.SupportsOnHealthIssue; definition.SupportsOnHealthIssue = provider.SupportsOnHealthIssue;
definition.SupportsOnDelete = provider.SupportsOnDelete;
} }
} }
} }

@ -16,7 +16,8 @@ namespace NzbDrone.Core.Notifications
: IHandle<MovieRenamedEvent>, : IHandle<MovieRenamedEvent>,
IHandle<MovieGrabbedEvent>, IHandle<MovieGrabbedEvent>,
IHandle<MovieDownloadedEvent>, IHandle<MovieDownloadedEvent>,
IHandle<HealthCheckFailedEvent> IHandle<HealthCheckFailedEvent>,
IHandle<MovieFileDeletedEvent>
{ {
private readonly INotificationFactory _notificationFactory; private readonly INotificationFactory _notificationFactory;
private readonly Logger _logger; private readonly Logger _logger;
@ -172,5 +173,29 @@ namespace NzbDrone.Core.Notifications
} }
} }
} }
public void Handle(MovieFileDeletedEvent message)
{
var deleteMessage = new DeleteMessage();
deleteMessage.Message = GetMessage(message.MovieFile.Movie, message.MovieFile.Quality);
deleteMessage.MovieFile = message.MovieFile;
deleteMessage.Movie = message.MovieFile.Movie;
deleteMessage.Reason = message.Reason;
foreach (var notification in _notificationFactory.OnDeleteEnabled())
{
try
{
if (ShouldHandleMovie(notification.Definition, message.MovieFile.Movie))
{
notification.OnDelete(deleteMessage);
}
}
catch (Exception ex)
{
_logger.Warn(ex, "Unable to send OnDelete notification to: " + notification.Definition.Name);
}
}
}
} }
} }

@ -29,6 +29,14 @@ namespace NzbDrone.Core.Notifications.Trakt
_traktService.AddMovieToCollection(Settings, message.Movie, message.MovieFile); _traktService.AddMovieToCollection(Settings, message.Movie, message.MovieFile);
} }
public override void OnDelete(DeleteMessage message)
{
if (message.Reason != MediaFiles.DeleteMediaFileReason.Upgrade)
{
_traktService.RemoveMovieFromCollection(Settings, message.Movie, message.MovieFile);
}
}
public override ValidationResult Test() public override ValidationResult Test()
{ {
var failures = new List<ValidationFailure>(); var failures = new List<ValidationFailure>();

@ -12,6 +12,7 @@ namespace NzbDrone.Core.Notifications.Trakt
HttpRequest GetOAuthRequest(string callbackUrl); HttpRequest GetOAuthRequest(string callbackUrl);
TraktAuthRefreshResource RefreshAuthToken(string refreshToken); TraktAuthRefreshResource RefreshAuthToken(string refreshToken);
void AddToCollection(TraktCollectMoviesResource payload, string accessToken); void AddToCollection(TraktCollectMoviesResource payload, string accessToken);
void RemoveFromCollection(TraktCollectMoviesResource payload, string accessToken);
HttpRequest BuildTraktRequest(string resource, HttpMethod method, string accessToken); HttpRequest BuildTraktRequest(string resource, HttpMethod method, string accessToken);
} }
@ -50,6 +51,24 @@ namespace NzbDrone.Core.Notifications.Trakt
} }
} }
public void RemoveFromCollection(TraktCollectMoviesResource payload, string accessToken)
{
var request = BuildTraktRequest("sync/collection/remove", HttpMethod.POST, accessToken);
request.Headers.ContentType = "application/json";
request.SetContent(payload.ToJson());
try
{
_httpClient.Execute(request);
}
catch (HttpException ex)
{
_logger.Error(ex, "Unable to post payload {0}", payload);
throw new TraktException("Unable to post payload", ex);
}
}
public string GetUserName(string accessToken) public string GetUserName(string accessToken)
{ {
var request = BuildTraktRequest("users/settings", HttpMethod.GET, accessToken); var request = BuildTraktRequest("users/settings", HttpMethod.GET, accessToken);

@ -19,6 +19,7 @@ namespace NzbDrone.Core.Notifications.Trakt
HttpRequest GetOAuthRequest(string callbackUrl); HttpRequest GetOAuthRequest(string callbackUrl);
TraktAuthRefreshResource RefreshAuthToken(string refreshToken); TraktAuthRefreshResource RefreshAuthToken(string refreshToken);
void AddMovieToCollection(TraktSettings settings, Movie movie, MovieFile movieFile); void AddMovieToCollection(TraktSettings settings, Movie movie, MovieFile movieFile);
void RemoveMovieFromCollection(TraktSettings settings, Movie movie, MovieFile movieFile);
string GetUserName(string accessToken); string GetUserName(string accessToken);
ValidationFailure Test(TraktSettings settings); ValidationFailure Test(TraktSettings settings);
} }
@ -75,6 +76,27 @@ namespace NzbDrone.Core.Notifications.Trakt
} }
} }
public void RemoveMovieFromCollection(TraktSettings settings, Movie movie, MovieFile movieFile)
{
var payload = new TraktCollectMoviesResource
{
Movies = new List<TraktCollectMovie>()
};
payload.Movies.Add(new TraktCollectMovie
{
Title = movie.Title,
Year = movie.Year,
Ids = new TraktMovieIdsResource
{
Tmdb = movie.TmdbId,
Imdb = movie.ImdbId ?? "",
}
});
_proxy.RemoveFromCollection(payload, settings.AccessToken);
}
public void AddMovieToCollection(TraktSettings settings, Movie movie, MovieFile movieFile) public void AddMovieToCollection(TraktSettings settings, Movie movie, MovieFile movieFile)
{ {
var payload = new TraktCollectMoviesResource var payload = new TraktCollectMoviesResource

@ -9,11 +9,13 @@ namespace Radarr.Api.V3.Notifications
public bool OnDownload { get; set; } public bool OnDownload { get; set; }
public bool OnUpgrade { get; set; } public bool OnUpgrade { get; set; }
public bool OnRename { get; set; } public bool OnRename { get; set; }
public bool OnDelete { get; set; }
public bool OnHealthIssue { get; set; } public bool OnHealthIssue { get; set; }
public bool SupportsOnGrab { get; set; } public bool SupportsOnGrab { get; set; }
public bool SupportsOnDownload { get; set; } public bool SupportsOnDownload { get; set; }
public bool SupportsOnUpgrade { get; set; } public bool SupportsOnUpgrade { get; set; }
public bool SupportsOnRename { get; set; } public bool SupportsOnRename { get; set; }
public bool SupportsOnDelete { get; set; }
public bool SupportsOnHealthIssue { get; set; } public bool SupportsOnHealthIssue { get; set; }
public bool IncludeHealthWarnings { get; set; } public bool IncludeHealthWarnings { get; set; }
public string TestCommand { get; set; } public string TestCommand { get; set; }
@ -34,11 +36,13 @@ namespace Radarr.Api.V3.Notifications
resource.OnDownload = definition.OnDownload; resource.OnDownload = definition.OnDownload;
resource.OnUpgrade = definition.OnUpgrade; resource.OnUpgrade = definition.OnUpgrade;
resource.OnRename = definition.OnRename; resource.OnRename = definition.OnRename;
resource.OnDelete = definition.OnDelete;
resource.OnHealthIssue = definition.OnHealthIssue; resource.OnHealthIssue = definition.OnHealthIssue;
resource.SupportsOnGrab = definition.SupportsOnGrab; resource.SupportsOnGrab = definition.SupportsOnGrab;
resource.SupportsOnDownload = definition.SupportsOnDownload; resource.SupportsOnDownload = definition.SupportsOnDownload;
resource.SupportsOnUpgrade = definition.SupportsOnUpgrade; resource.SupportsOnUpgrade = definition.SupportsOnUpgrade;
resource.SupportsOnRename = definition.SupportsOnRename; resource.SupportsOnRename = definition.SupportsOnRename;
resource.SupportsOnDelete = definition.SupportsOnDelete;
resource.SupportsOnHealthIssue = definition.SupportsOnHealthIssue; resource.SupportsOnHealthIssue = definition.SupportsOnHealthIssue;
resource.IncludeHealthWarnings = definition.IncludeHealthWarnings; resource.IncludeHealthWarnings = definition.IncludeHealthWarnings;
@ -58,11 +62,13 @@ namespace Radarr.Api.V3.Notifications
definition.OnDownload = resource.OnDownload; definition.OnDownload = resource.OnDownload;
definition.OnUpgrade = resource.OnUpgrade; definition.OnUpgrade = resource.OnUpgrade;
definition.OnRename = resource.OnRename; definition.OnRename = resource.OnRename;
definition.OnDelete = resource.OnDelete;
definition.OnHealthIssue = resource.OnHealthIssue; definition.OnHealthIssue = resource.OnHealthIssue;
definition.SupportsOnGrab = resource.SupportsOnGrab; definition.SupportsOnGrab = resource.SupportsOnGrab;
definition.SupportsOnDownload = resource.SupportsOnDownload; definition.SupportsOnDownload = resource.SupportsOnDownload;
definition.SupportsOnUpgrade = resource.SupportsOnUpgrade; definition.SupportsOnUpgrade = resource.SupportsOnUpgrade;
definition.SupportsOnRename = resource.SupportsOnRename; definition.SupportsOnRename = resource.SupportsOnRename;
definition.SupportsOnDelete = resource.SupportsOnDelete;
definition.SupportsOnHealthIssue = resource.SupportsOnHealthIssue; definition.SupportsOnHealthIssue = resource.SupportsOnHealthIssue;
definition.IncludeHealthWarnings = resource.IncludeHealthWarnings; definition.IncludeHealthWarnings = resource.IncludeHealthWarnings;

Loading…
Cancel
Save