diff --git a/docs/data-sources/notification.md b/docs/data-sources/notification.md index 6c2a4d74..605a6928 100644 --- a/docs/data-sources/notification.md +++ b/docs/data-sources/notification.md @@ -33,8 +33,10 @@ data "radarr_notification" "example" { - `api_key` (String) API key. - `app_token` (String) App token. - `arguments` (String) Arguments. +- `auth_password` (String, Sensitive) Password. - `auth_token` (String) Auth token. - `auth_user` (String) Auth user. +- `auth_username` (String) Username. - `author` (String) Author. - `avatar` (String) Avatar. - `bcc` (Set of String) Bcc. @@ -46,6 +48,7 @@ data "radarr_notification" "example" { - `clean_library` (Boolean) Clean library flag. - `click_url` (String) Click URL. - `config_contract` (String) Notification configuration template. +- `configuration_key` (String, Sensitive) Configuration key. - `consumer_key` (String) Consumer key. - `consumer_secret` (String) Consumer secret. - `device_ids` (Set of String) Device IDs. @@ -71,6 +74,7 @@ data "radarr_notification" "example" { - `map_to` (String) Map To. - `mention` (String) Mention. - `method` (Number) Method. `1` POST, `2` PUT. +- `notification_type` (Number) Notification type. `0` Info, `1` Success, `2` Warning, `3` Failure. - `notify` (Boolean) Notify flag. - `on_application_update` (Boolean) On application update flag. - `on_download` (Boolean) On download flag. @@ -99,6 +103,7 @@ data "radarr_notification" "example" { - `server_url` (String) Server url. - `sign_in` (String) Sign in. - `sound` (String) Sound. +- `stateless_urls` (String) Stateless URLs. - `tags` (Set of Number) List of associated tags. - `to` (Set of String) To. - `token` (String) Token. diff --git a/docs/data-sources/notifications.md b/docs/data-sources/notifications.md index fade0167..2273e58e 100644 --- a/docs/data-sources/notifications.md +++ b/docs/data-sources/notifications.md @@ -36,8 +36,10 @@ Read-Only: - `api_key` (String) API key. - `app_token` (String) App token. - `arguments` (String) Arguments. +- `auth_password` (String, Sensitive) Password. - `auth_token` (String) Auth token. - `auth_user` (String) Auth user. +- `auth_username` (String) Username. - `author` (String) Author. - `avatar` (String) Avatar. - `bcc` (Set of String) Bcc. @@ -49,6 +51,7 @@ Read-Only: - `clean_library` (Boolean) Clean library flag. - `click_url` (String) Click URL. - `config_contract` (String) Notification configuration template. +- `configuration_key` (String, Sensitive) Configuration key. - `consumer_key` (String) Consumer key. - `consumer_secret` (String) Consumer secret. - `device_ids` (Set of String) Device IDs. @@ -75,6 +78,7 @@ Read-Only: - `mention` (String) Mention. - `method` (Number) Method. `1` POST, `2` PUT. - `name` (String) Notification name. +- `notification_type` (Number) Notification type. `0` Info, `1` Success, `2` Warning, `3` Failure. - `notify` (Boolean) Notify flag. - `on_application_update` (Boolean) On application update flag. - `on_download` (Boolean) On download flag. @@ -103,6 +107,7 @@ Read-Only: - `server_url` (String) Server url. - `sign_in` (String) Sign in. - `sound` (String) Sound. +- `stateless_urls` (String) Stateless URLs. - `tags` (Set of Number) List of associated tags. - `to` (Set of String) To. - `token` (String) Token. diff --git a/docs/resources/notification.md b/docs/resources/notification.md index 9b522e4c..98f79cce 100644 --- a/docs/resources/notification.md +++ b/docs/resources/notification.md @@ -55,8 +55,10 @@ resource "radarr_notification" "example" { - `api_key` (String) API key. - `app_token` (String) App token. - `arguments` (String) Arguments. +- `auth_password` (String, Sensitive) Password. - `auth_token` (String) Auth token. - `auth_user` (String) Auth user. +- `auth_username` (String) Username. - `author` (String) Author. - `avatar` (String) Avatar. - `bcc` (Set of String) Bcc. @@ -67,6 +69,7 @@ resource "radarr_notification" "example" { - `chat_id` (String) Chat ID. - `clean_library` (Boolean) Clean library flag. - `click_url` (String) Click URL. +- `configuration_key` (String, Sensitive) Configuration key. - `consumer_key` (String) Consumer key. - `consumer_secret` (String) Consumer secret. - `device_ids` (Set of String) Device IDs. @@ -90,6 +93,7 @@ resource "radarr_notification" "example" { - `map_to` (String) Map To. - `mention` (String) Mention. - `method` (Number) Method. `1` POST, `2` PUT. +- `notification_type` (Number) Notification type. `0` Info, `1` Success, `2` Warning, `3` Failure. - `notify` (Boolean) Notify flag. - `on_application_update` (Boolean) On application update flag. - `on_download` (Boolean) On download flag. @@ -117,6 +121,7 @@ resource "radarr_notification" "example" { - `server_url` (String) Server url. - `sign_in` (String) Sign in. - `sound` (String) Sound. +- `stateless_urls` (String) Stateless URLs. - `tags` (Set of Number) List of associated tags. - `to` (Set of String) To. - `token` (String) Token. diff --git a/docs/resources/notification_apprise.md b/docs/resources/notification_apprise.md new file mode 100644 index 00000000..70a4af1f --- /dev/null +++ b/docs/resources/notification_apprise.md @@ -0,0 +1,81 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "radarr_notification_apprise Resource - terraform-provider-radarr" +subcategory: "Notifications" +description: |- + Notification Apprise resource. + For more information refer to Notification https://wiki.servarr.com/radarr/settings#connect and Apprise https://wiki.servarr.com/radarr/supported#apprise. +--- + +# radarr_notification_apprise (Resource) + +Notification Apprise resource. +For more information refer to [Notification](https://wiki.servarr.com/radarr/settings#connect) and [Apprise](https://wiki.servarr.com/radarr/supported#apprise). + +## Example Usage + +```terraform +resource "radarr_notification_apprise" "example" { + on_grab = false + on_download = true + on_upgrade = true + on_movie_added = false + on_movie_delete = false + on_movie_file_delete = false + on_movie_file_delete_for_upgrade = true + on_health_issue = false + on_application_update = false + + include_health_warnings = false + name = "Example" + + notification_type = 1 + server_url = "https://apprise.go" + auth_username = "User" + auth_password = "Password" + field_tags = ["warning", "skull"] +} +``` + + +## Schema + +### Required + +- `name` (String) NotificationBoxcar name. +- `on_movie_delete` (Boolean) On movie delete flag. +- `server_url` (String) Server URL. + +### Optional + +- `auth_password` (String, Sensitive) Password. +- `auth_username` (String) Username. +- `configuration_key` (String, Sensitive) Configuration key. +- `field_tags` (Set of String) Tags and emojis. +- `include_health_warnings` (Boolean) Include health warnings. +- `notification_type` (Number) Notification type. `0` Info, `1` Success, `2` Warning, `3` Failure. +- `on_application_update` (Boolean) On application update flag. +- `on_download` (Boolean) On download flag. +- `on_grab` (Boolean) On grab flag. +- `on_health_issue` (Boolean) On health issue flag. +- `on_health_restored` (Boolean) On health restored flag. +- `on_manual_interaction_required` (Boolean) On manual interaction required flag. +- `on_movie_added` (Boolean) On movie added flag. +- `on_movie_file_delete` (Boolean) On movie file delete flag. +- `on_movie_file_delete_for_upgrade` (Boolean) On movie file delete for upgrade flag. +- `on_upgrade` (Boolean) On upgrade flag. +- `stateless_urls` (String) Stateless URLs. +- `tags` (Set of Number) List of associated tags. + +### Read-Only + +- `id` (Number) Notification ID. + +## Import + +Import is supported using the following syntax: + +```shell +# import using the API/UI ID +terraform import radarr_notification_apprise.example 1 +``` diff --git a/examples/resources/radarr_notification_apprise/import.sh b/examples/resources/radarr_notification_apprise/import.sh new file mode 100644 index 00000000..37a3fd2f --- /dev/null +++ b/examples/resources/radarr_notification_apprise/import.sh @@ -0,0 +1,2 @@ +# import using the API/UI ID +terraform import radarr_notification_apprise.example 1 \ No newline at end of file diff --git a/examples/resources/radarr_notification_apprise/resource.tf b/examples/resources/radarr_notification_apprise/resource.tf new file mode 100644 index 00000000..d3f890ec --- /dev/null +++ b/examples/resources/radarr_notification_apprise/resource.tf @@ -0,0 +1,20 @@ +resource "radarr_notification_apprise" "example" { + on_grab = false + on_download = true + on_upgrade = true + on_movie_added = false + on_movie_delete = false + on_movie_file_delete = false + on_movie_file_delete_for_upgrade = true + on_health_issue = false + on_application_update = false + + include_health_warnings = false + name = "Example" + + notification_type = 1 + server_url = "https://apprise.go" + auth_username = "User" + auth_password = "Password" + field_tags = ["warning", "skull"] +} \ No newline at end of file diff --git a/internal/provider/notification_apprise_resource.go b/internal/provider/notification_apprise_resource.go new file mode 100644 index 00000000..87cf7abc --- /dev/null +++ b/internal/provider/notification_apprise_resource.go @@ -0,0 +1,366 @@ +package provider + +import ( + "context" + "strconv" + + "github.com/devopsarr/radarr-go/radarr" + "github.com/devopsarr/terraform-provider-radarr/internal/helpers" + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +const ( + notificationAppriseResourceName = "notification_apprise" + notificationAppriseImplementation = "Apprise" + notificationAppriseConfigContract = "AppriseSettings" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var ( + _ resource.Resource = &NotificationAppriseResource{} + _ resource.ResourceWithImportState = &NotificationAppriseResource{} +) + +func NewNotificationAppriseResource() resource.Resource { + return &NotificationAppriseResource{} +} + +// NotificationAppriseResource defines the notification implementation. +type NotificationAppriseResource struct { + client *radarr.APIClient +} + +// NotificationApprise describes the notification data model. +type NotificationApprise struct { + Tags types.Set `tfsdk:"tags"` + FieldTags types.Set `tfsdk:"field_tags"` + Name types.String `tfsdk:"name"` + StatelessURLs types.String `tfsdk:"stateless_urls"` + ServerURL types.String `tfsdk:"server_url"` + AuthUsername types.String `tfsdk:"auth_username"` + AuthPassword types.String `tfsdk:"auth_password"` + ConfigurationKey types.String `tfsdk:"configuration_key"` + NotificationType types.Int64 `tfsdk:"notification_type"` + ID types.Int64 `tfsdk:"id"` + OnGrab types.Bool `tfsdk:"on_grab"` + OnMovieFileDeleteForUpgrade types.Bool `tfsdk:"on_movie_file_delete_for_upgrade"` + OnMovieFileDelete types.Bool `tfsdk:"on_movie_file_delete"` + OnMovieAdded types.Bool `tfsdk:"on_movie_added"` + IncludeHealthWarnings types.Bool `tfsdk:"include_health_warnings"` + OnApplicationUpdate types.Bool `tfsdk:"on_application_update"` + OnHealthIssue types.Bool `tfsdk:"on_health_issue"` + OnHealthRestored types.Bool `tfsdk:"on_health_restored"` + OnManualInteractionRequired types.Bool `tfsdk:"on_manual_interaction_required"` + OnMovieDelete types.Bool `tfsdk:"on_movie_delete"` + OnUpgrade types.Bool `tfsdk:"on_upgrade"` + OnDownload types.Bool `tfsdk:"on_download"` +} + +func (n NotificationApprise) toNotification() *Notification { + return &Notification{ + Tags: n.Tags, + FieldTags: n.FieldTags, + StatelessURLs: n.StatelessURLs, + ServerURL: n.ServerURL, + AuthUsername: n.AuthUsername, + AuthPassword: n.AuthPassword, + ConfigurationKey: n.ConfigurationKey, + NotificationType: n.NotificationType, + Name: n.Name, + ID: n.ID, + OnGrab: n.OnGrab, + OnMovieFileDeleteForUpgrade: n.OnMovieFileDeleteForUpgrade, + OnMovieAdded: n.OnMovieAdded, + OnMovieFileDelete: n.OnMovieFileDelete, + IncludeHealthWarnings: n.IncludeHealthWarnings, + OnApplicationUpdate: n.OnApplicationUpdate, + OnHealthIssue: n.OnHealthIssue, + OnHealthRestored: n.OnHealthRestored, + OnManualInteractionRequired: n.OnManualInteractionRequired, + OnMovieDelete: n.OnMovieDelete, + OnUpgrade: n.OnUpgrade, + OnDownload: n.OnDownload, + ConfigContract: types.StringValue(notificationAppriseConfigContract), + Implementation: types.StringValue(notificationAppriseImplementation), + } +} + +func (n *NotificationApprise) fromNotification(notification *Notification) { + n.Tags = notification.Tags + n.FieldTags = notification.FieldTags + n.StatelessURLs = notification.StatelessURLs + n.ServerURL = notification.ServerURL + n.AuthUsername = notification.AuthUsername + n.AuthPassword = notification.AuthPassword + n.ConfigurationKey = notification.ConfigurationKey + n.NotificationType = notification.NotificationType + n.Name = notification.Name + n.ID = notification.ID + n.OnGrab = notification.OnGrab + n.OnMovieFileDeleteForUpgrade = notification.OnMovieFileDeleteForUpgrade + n.OnMovieFileDelete = notification.OnMovieFileDelete + n.IncludeHealthWarnings = notification.IncludeHealthWarnings + n.OnApplicationUpdate = notification.OnApplicationUpdate + n.OnHealthIssue = notification.OnHealthIssue + n.OnHealthRestored = notification.OnHealthRestored + n.OnManualInteractionRequired = notification.OnManualInteractionRequired + n.OnMovieAdded = notification.OnMovieAdded + n.OnMovieDelete = notification.OnMovieDelete + n.OnUpgrade = notification.OnUpgrade + n.OnDownload = notification.OnDownload +} + +func (r *NotificationAppriseResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_" + notificationAppriseResourceName +} + +func (r *NotificationAppriseResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: "Notification Apprise resource.\nFor more information refer to [Notification](https://wiki.servarr.com/radarr/settings#connect) and [Apprise](https://wiki.servarr.com/radarr/supported#apprise).", + Attributes: map[string]schema.Attribute{ + "on_grab": schema.BoolAttribute{ + MarkdownDescription: "On grab flag.", + Optional: true, + Computed: true, + }, + "on_download": schema.BoolAttribute{ + MarkdownDescription: "On download flag.", + Optional: true, + Computed: true, + }, + "on_upgrade": schema.BoolAttribute{ + MarkdownDescription: "On upgrade flag.", + Optional: true, + Computed: true, + }, + "on_movie_added": schema.BoolAttribute{ + MarkdownDescription: "On movie added flag.", + Optional: true, + Computed: true, + }, + "on_movie_delete": schema.BoolAttribute{ + MarkdownDescription: "On movie delete flag.", + Required: true, + }, + "on_movie_file_delete": schema.BoolAttribute{ + MarkdownDescription: "On movie file delete flag.", + Optional: true, + Computed: true, + }, + "on_movie_file_delete_for_upgrade": schema.BoolAttribute{ + MarkdownDescription: "On movie file delete for upgrade flag.", + Optional: true, + Computed: true, + }, + "on_health_issue": schema.BoolAttribute{ + MarkdownDescription: "On health issue flag.", + Optional: true, + Computed: true, + }, + "on_health_restored": schema.BoolAttribute{ + MarkdownDescription: "On health restored flag.", + Optional: true, + Computed: true, + }, + "on_manual_interaction_required": schema.BoolAttribute{ + MarkdownDescription: "On manual interaction required flag.", + Optional: true, + Computed: true, + }, + "on_application_update": schema.BoolAttribute{ + MarkdownDescription: "On application update flag.", + Optional: true, + Computed: true, + }, + "include_health_warnings": schema.BoolAttribute{ + MarkdownDescription: "Include health warnings.", + Optional: true, + Computed: true, + }, + "name": schema.StringAttribute{ + MarkdownDescription: "NotificationBoxcar name.", + Required: true, + }, + "tags": schema.SetAttribute{ + MarkdownDescription: "List of associated tags.", + Optional: true, + Computed: true, + ElementType: types.Int64Type, + }, + "id": schema.Int64Attribute{ + MarkdownDescription: "Notification ID.", + Computed: true, + PlanModifiers: []planmodifier.Int64{ + int64planmodifier.UseStateForUnknown(), + }, + }, + // Field values + "notification_type": schema.Int64Attribute{ + MarkdownDescription: "Notification type. `0` Info, `1` Success, `2` Warning, `3` Failure.", + Optional: true, + Computed: true, + Validators: []validator.Int64{ + int64validator.OneOf(0, 1, 2, 3), + }, + }, + "server_url": schema.StringAttribute{ + MarkdownDescription: "Server URL.", + Required: true, + }, + "stateless_urls": schema.StringAttribute{ + MarkdownDescription: "Stateless URLs.", + Optional: true, + Computed: true, + }, + "configuration_key": schema.StringAttribute{ + MarkdownDescription: "Configuration key.", + Optional: true, + Computed: true, + Sensitive: true, + }, + "auth_username": schema.StringAttribute{ + MarkdownDescription: "Username.", + Optional: true, + Computed: true, + }, + "auth_password": schema.StringAttribute{ + MarkdownDescription: "Password.", + Optional: true, + Computed: true, + Sensitive: true, + }, + "field_tags": schema.SetAttribute{ + MarkdownDescription: "Tags and emojis.", + Optional: true, + Computed: true, + ElementType: types.StringType, + }, + }, + } +} + +func (r *NotificationAppriseResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if client := helpers.ResourceConfigure(ctx, req, resp); client != nil { + r.client = client + } +} + +func (r *NotificationAppriseResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + // Retrieve values from plan + var notification *NotificationApprise + + resp.Diagnostics.Append(req.Plan.Get(ctx, ¬ification)...) + + if resp.Diagnostics.HasError() { + return + } + + // Create new NotificationApprise + request := notification.read(ctx) + + response, _, err := r.client.NotificationApi.CreateNotification(ctx).NotificationResource(*request).Execute() + if err != nil { + resp.Diagnostics.AddError(helpers.ClientError, helpers.ParseClientError(helpers.Create, notificationAppriseResourceName, err)) + + return + } + + tflog.Trace(ctx, "created "+notificationAppriseResourceName+": "+strconv.Itoa(int(response.GetId()))) + // Generate resource state struct + notification.write(ctx, response) + resp.Diagnostics.Append(resp.State.Set(ctx, ¬ification)...) +} + +func (r *NotificationAppriseResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + // Get current state + var notification *NotificationApprise + + resp.Diagnostics.Append(req.State.Get(ctx, ¬ification)...) + + if resp.Diagnostics.HasError() { + return + } + + // Get NotificationApprise current value + response, _, err := r.client.NotificationApi.GetNotificationById(ctx, int32(notification.ID.ValueInt64())).Execute() + if err != nil { + resp.Diagnostics.AddError(helpers.ClientError, helpers.ParseClientError(helpers.Read, notificationAppriseResourceName, err)) + + return + } + + tflog.Trace(ctx, "read "+notificationAppriseResourceName+": "+strconv.Itoa(int(response.GetId()))) + // Map response body to resource schema attribute + notification.write(ctx, response) + resp.Diagnostics.Append(resp.State.Set(ctx, ¬ification)...) +} + +func (r *NotificationAppriseResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + // Get plan values + var notification *NotificationApprise + + resp.Diagnostics.Append(req.Plan.Get(ctx, ¬ification)...) + + if resp.Diagnostics.HasError() { + return + } + + // Update NotificationApprise + request := notification.read(ctx) + + response, _, err := r.client.NotificationApi.UpdateNotification(ctx, strconv.Itoa(int(request.GetId()))).NotificationResource(*request).Execute() + if err != nil { + resp.Diagnostics.AddError(helpers.ClientError, helpers.ParseClientError(helpers.Update, notificationAppriseResourceName, err)) + + return + } + + tflog.Trace(ctx, "updated "+notificationAppriseResourceName+": "+strconv.Itoa(int(response.GetId()))) + // Generate resource state struct + notification.write(ctx, response) + resp.Diagnostics.Append(resp.State.Set(ctx, ¬ification)...) +} + +func (r *NotificationAppriseResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var notification *NotificationApprise + + resp.Diagnostics.Append(req.State.Get(ctx, ¬ification)...) + + if resp.Diagnostics.HasError() { + return + } + + // Delete NotificationApprise current value + _, err := r.client.NotificationApi.DeleteNotification(ctx, int32(notification.ID.ValueInt64())).Execute() + if err != nil { + resp.Diagnostics.AddError(helpers.ClientError, helpers.ParseClientError(helpers.Read, notificationAppriseResourceName, err)) + + return + } + + tflog.Trace(ctx, "deleted "+notificationAppriseResourceName+": "+strconv.Itoa(int(notification.ID.ValueInt64()))) + resp.State.RemoveResource(ctx) +} + +func (r *NotificationAppriseResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + helpers.ImportStatePassthroughIntID(ctx, path.Root("id"), req, resp) + tflog.Trace(ctx, "imported "+notificationAppriseResourceName+": "+req.ID) +} + +func (n *NotificationApprise) write(ctx context.Context, notification *radarr.NotificationResource) { + genericNotification := n.toNotification() + genericNotification.write(ctx, notification) + n.fromNotification(genericNotification) +} + +func (n *NotificationApprise) read(ctx context.Context) *radarr.NotificationResource { + return n.toNotification().read(ctx) +} diff --git a/internal/provider/notification_apprise_resource_test.go b/internal/provider/notification_apprise_resource_test.go new file mode 100644 index 00000000..6aa8c42a --- /dev/null +++ b/internal/provider/notification_apprise_resource_test.go @@ -0,0 +1,77 @@ +package provider + +import ( + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccNotificationAppriseResource(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Unauthorized Create + { + Config: testAccNotificationAppriseResourceConfig("resourceAppriseTest", "token123") + testUnauthorizedProvider, + ExpectError: regexp.MustCompile("Client Error"), + }, + // Create and Read testing + { + Config: testAccNotificationAppriseResourceConfig("resourceAppriseTest", "token123"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("radarr_notification_apprise.test", "auth_password", "token123"), + resource.TestCheckResourceAttrSet("radarr_notification_apprise.test", "id"), + ), + }, + // Unauthorized Read + { + Config: testAccNotificationAppriseResourceConfig("resourceAppriseTest", "token123") + testUnauthorizedProvider, + ExpectError: regexp.MustCompile("Client Error"), + }, + // Update and Read testing + { + Config: testAccNotificationAppriseResourceConfig("resourceAppriseTest", "token234"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("radarr_notification_apprise.test", "auth_password", "token234"), + ), + }, + // ImportState testing + { + ResourceName: "radarr_notification_apprise.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"auth_password"}, + }, + // Delete testing automatically occurs in TestCase + }, + }) +} + +func testAccNotificationAppriseResourceConfig(name, token string) string { + return fmt.Sprintf(` + resource "radarr_notification_apprise" "test" { + on_grab = false + on_download = false + on_upgrade = false + on_movie_added = false + on_movie_delete = false + on_movie_file_delete = false + on_movie_file_delete_for_upgrade = false + on_health_issue = false + on_application_update = false + + include_health_warnings = false + name = "%s" + + notification_type = 1 + server_url = "https://apprise.go" + auth_username = "User" + auth_password = "%s" + field_tags = ["warning","skull"] + }`, name, token) +} diff --git a/internal/provider/notification_data_source.go b/internal/provider/notification_data_source.go index a7af91d7..c6cb0e95 100644 --- a/internal/provider/notification_data_source.go +++ b/internal/provider/notification_data_source.go @@ -161,6 +161,10 @@ func (d *NotificationDataSource) Schema(ctx context.Context, req datasource.Sche MarkdownDescription: "Priority.", // TODO: add values in description Computed: true, }, + "notification_type": schema.Int64Attribute{ + MarkdownDescription: "Notification type. `0` Info, `1` Success, `2` Warning, `3` Failure.", + Computed: true, + }, "retry": schema.Int64Attribute{ MarkdownDescription: "Retry.", Computed: true, @@ -333,6 +337,24 @@ func (d *NotificationDataSource) Schema(ctx context.Context, req datasource.Sche MarkdownDescription: "Event.", Computed: true, }, + "stateless_urls": schema.StringAttribute{ + MarkdownDescription: "Stateless URLs.", + Computed: true, + }, + "configuration_key": schema.StringAttribute{ + MarkdownDescription: "Configuration key.", + Computed: true, + Sensitive: true, + }, + "auth_username": schema.StringAttribute{ + MarkdownDescription: "Username.", + Computed: true, + }, + "auth_password": schema.StringAttribute{ + MarkdownDescription: "Password.", + Computed: true, + Sensitive: true, + }, "device_ids": schema.SetAttribute{ MarkdownDescription: "Device IDs.", Computed: true, diff --git a/internal/provider/notification_emby_resource.go b/internal/provider/notification_emby_resource.go index f88b2cc4..9640dba1 100644 --- a/internal/provider/notification_emby_resource.go +++ b/internal/provider/notification_emby_resource.go @@ -55,7 +55,6 @@ type NotificationEmby struct { OnApplicationUpdate types.Bool `tfsdk:"on_application_update"` OnHealthIssue types.Bool `tfsdk:"on_health_issue"` OnHealthRestored types.Bool `tfsdk:"on_health_restored"` - OnManualInteractionRequired types.Bool `tfsdk:"on_manual_interaction_required"` OnMovieDelete types.Bool `tfsdk:"on_movie_delete"` OnRename types.Bool `tfsdk:"on_rename"` OnUpgrade types.Bool `tfsdk:"on_upgrade"` diff --git a/internal/provider/notification_resource.go b/internal/provider/notification_resource.go index 25e5b429..406e2d65 100644 --- a/internal/provider/notification_resource.go +++ b/internal/provider/notification_resource.go @@ -28,8 +28,8 @@ var ( var notificationFields = helpers.Fields{ Bools: []string{"alwaysUpdate", "cleanLibrary", "directMessage", "notify", "requireEncryption", "sendSilently", "useSsl", "updateLibrary", "useEuEndpoint"}, - Strings: []string{"accessToken", "accessTokenSecret", "apiKey", "aPIKey", "appToken", "arguments", "author", "authToken", "authUser", "avatar", "botToken", "channel", "chatId", "consumerKey", "consumerSecret", "deviceNames", "expires", "from", "host", "icon", "mention", "password", "path", "refreshToken", "senderDomain", "senderId", "server", "signIn", "sound", "token", "url", "userKey", "username", "webHookUrl", "serverUrl", "userName", "clickUrl", "mapFrom", "mapTo", "key", "event", "topicId"}, - Ints: []string{"displayTime", "port", "priority", "retry", "expire", "method"}, + Strings: []string{"accessToken", "accessTokenSecret", "apiKey", "aPIKey", "appToken", "arguments", "author", "authToken", "authUser", "avatar", "botToken", "channel", "chatId", "consumerKey", "consumerSecret", "deviceNames", "expires", "from", "host", "icon", "mention", "password", "path", "refreshToken", "senderDomain", "senderId", "server", "signIn", "sound", "token", "url", "userKey", "username", "webHookUrl", "serverUrl", "userName", "clickUrl", "mapFrom", "mapTo", "key", "event", "topicId", "configurationKey", "authUsername", "authPassword", "statelessUrls"}, + Ints: []string{"displayTime", "port", "priority", "retry", "expire", "method", "notificationType"}, StringSlices: []string{"recipients", "to", "cC", "bcc", "topics", "deviceIds", "fieldTags", "channelTags", "devices"}, StringSlicesExceptions: []string{"tags"}, IntSlices: []string{"grabFields", "importFields"}, @@ -102,6 +102,11 @@ type Notification struct { Author types.String `tfsdk:"author"` AuthToken types.String `tfsdk:"auth_token"` AuthUser types.String `tfsdk:"auth_user"` + StatelessURLs types.String `tfsdk:"stateless_urls"` + AuthUsername types.String `tfsdk:"auth_username"` + AuthPassword types.String `tfsdk:"auth_password"` + ConfigurationKey types.String `tfsdk:"configuration_key"` + NotificationType types.Int64 `tfsdk:"notification_type"` DisplayTime types.Int64 `tfsdk:"display_time"` Priority types.Int64 `tfsdk:"priority"` Port types.Int64 `tfsdk:"port"` @@ -302,6 +307,14 @@ func (r *NotificationResource) Schema(ctx context.Context, req resource.SchemaRe int64validator.OneOf(-2, -1, 0, 1, 2, 3, 4, 5, 7, 8), }, }, + "notification_type": schema.Int64Attribute{ + MarkdownDescription: "Notification type. `0` Info, `1` Success, `2` Warning, `3` Failure.", + Optional: true, + Computed: true, + Validators: []validator.Int64{ + int64validator.OneOf(0, 1, 2, 3), + }, + }, "retry": schema.Int64Attribute{ MarkdownDescription: "Retry.", Optional: true, @@ -517,6 +530,28 @@ func (r *NotificationResource) Schema(ctx context.Context, req resource.SchemaRe Optional: true, Computed: true, }, + "stateless_urls": schema.StringAttribute{ + MarkdownDescription: "Stateless URLs.", + Optional: true, + Computed: true, + }, + "configuration_key": schema.StringAttribute{ + MarkdownDescription: "Configuration key.", + Optional: true, + Computed: true, + Sensitive: true, + }, + "auth_username": schema.StringAttribute{ + MarkdownDescription: "Username.", + Optional: true, + Computed: true, + }, + "auth_password": schema.StringAttribute{ + MarkdownDescription: "Password.", + Optional: true, + Computed: true, + Sensitive: true, + }, "device_ids": schema.SetAttribute{ MarkdownDescription: "Device IDs.", Optional: true, diff --git a/internal/provider/notifications_data_source.go b/internal/provider/notifications_data_source.go index 5eb624ea..def11172 100644 --- a/internal/provider/notifications_data_source.go +++ b/internal/provider/notifications_data_source.go @@ -177,6 +177,10 @@ func (d *NotificationsDataSource) Schema(ctx context.Context, req datasource.Sch MarkdownDescription: "Priority.", // TODO: add values in description Computed: true, }, + "notification_type": schema.Int64Attribute{ + MarkdownDescription: "Notification type. `0` Info, `1` Success, `2` Warning, `3` Failure.", + Computed: true, + }, "retry": schema.Int64Attribute{ MarkdownDescription: "Retry.", Computed: true, @@ -349,6 +353,24 @@ func (d *NotificationsDataSource) Schema(ctx context.Context, req datasource.Sch MarkdownDescription: "Event.", Computed: true, }, + "stateless_urls": schema.StringAttribute{ + MarkdownDescription: "Stateless URLs.", + Computed: true, + }, + "configuration_key": schema.StringAttribute{ + MarkdownDescription: "Configuration key.", + Computed: true, + Sensitive: true, + }, + "auth_username": schema.StringAttribute{ + MarkdownDescription: "Username.", + Computed: true, + }, + "auth_password": schema.StringAttribute{ + MarkdownDescription: "Password.", + Computed: true, + Sensitive: true, + }, "device_ids": schema.SetAttribute{ MarkdownDescription: "Device IDs.", Computed: true, diff --git a/internal/provider/provider.go b/internal/provider/provider.go index e3cefe63..4c4a994a 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -209,6 +209,7 @@ func (p *RadarrProvider) Resources(ctx context.Context) []func() resource.Resour // Notifications NewNotificationResource, + NewNotificationAppriseResource, NewNotificationBoxcarResource, NewNotificationCustomScriptResource, NewNotificationDiscordResource,