From 174877caad7506a1d18d0e2dd479096b21a468f5 Mon Sep 17 00:00:00 2001 From: Fuochi Date: Fri, 9 Dec 2022 08:38:41 +0400 Subject: [PATCH] feat: add notification email resource --- docs/data-sources/notification.md | 8 +- docs/data-sources/notifications.md | 8 +- docs/resources/notification.md | 8 +- docs/resources/notification_email.md | 80 ++++ .../radarr_notification_email/import.sh | 2 + .../radarr_notification_email/resource.tf | 19 + internal/provider/notification_data_source.go | 27 +- .../provider/notification_email_resource.go | 408 ++++++++++++++++++ .../notification_email_resource_test.go | 64 +++ internal/provider/notification_resource.go | 46 +- .../provider/notifications_data_source.go | 27 +- internal/provider/provider.go | 1 + 12 files changed, 642 insertions(+), 56 deletions(-) create mode 100644 docs/resources/notification_email.md create mode 100644 examples/resources/radarr_notification_email/import.sh create mode 100644 examples/resources/radarr_notification_email/resource.tf create mode 100644 internal/provider/notification_email_resource.go create mode 100644 internal/provider/notification_email_resource_test.go diff --git a/docs/data-sources/notification.md b/docs/data-sources/notification.md index fe75e8b9..7c177818 100644 --- a/docs/data-sources/notification.md +++ b/docs/data-sources/notification.md @@ -37,9 +37,9 @@ data "radarr_notification" "example" { - `auth_user` (String) Auth user. - `author` (String) Author. - `avatar` (String) Avatar. -- `bcc` (String) Bcc. +- `bcc` (Set of String) Bcc. - `bot_token` (String) Bot token. -- `cc` (String) Cc. +- `cc` (Set of String) Cc. - `channel` (String) Channel. - `channel_tags` (Set of String) Channel tags. - `chat_id` (String) Chat ID. @@ -48,7 +48,7 @@ data "radarr_notification" "example" { - `config_contract` (String) Notification configuration template. - `consumer_key` (String) Consumer key. - `consumer_secret` (String) Consumer secret. -- `device_ids` (Set of Number) Device IDs. +- `device_ids` (Set of String) Device IDs. - `device_names` (String) Device names. - `devices` (Set of String) Devices. - `direct_message` (Boolean) Direct message flag. @@ -98,7 +98,7 @@ data "radarr_notification" "example" { - `sign_in` (String) Sign in. - `sound` (String) Sound. - `tags` (Set of Number) List of associated tags. -- `to` (String) To. +- `to` (Set of String) To. - `token` (String) Token. - `topics` (Set of String) Devices. - `update_library` (Boolean) Update library flag. diff --git a/docs/data-sources/notifications.md b/docs/data-sources/notifications.md index fb34c63d..c61057b1 100644 --- a/docs/data-sources/notifications.md +++ b/docs/data-sources/notifications.md @@ -40,9 +40,9 @@ Read-Only: - `auth_user` (String) Auth user. - `author` (String) Author. - `avatar` (String) Avatar. -- `bcc` (String) Bcc. +- `bcc` (Set of String) Bcc. - `bot_token` (String) Bot token. -- `cc` (String) Cc. +- `cc` (Set of String) Cc. - `channel` (String) Channel. - `channel_tags` (Set of String) Channel tags. - `chat_id` (String) Chat ID. @@ -51,7 +51,7 @@ Read-Only: - `config_contract` (String) Notification configuration template. - `consumer_key` (String) Consumer key. - `consumer_secret` (String) Consumer secret. -- `device_ids` (Set of Number) Device IDs. +- `device_ids` (Set of String) Device IDs. - `device_names` (String) Device names. - `devices` (Set of String) Devices. - `direct_message` (Boolean) Direct message flag. @@ -102,7 +102,7 @@ Read-Only: - `sign_in` (String) Sign in. - `sound` (String) Sound. - `tags` (Set of Number) List of associated tags. -- `to` (String) To. +- `to` (Set of String) To. - `token` (String) Token. - `topics` (Set of String) Devices. - `update_library` (Boolean) Update library flag. diff --git a/docs/resources/notification.md b/docs/resources/notification.md index de71e152..92b9274c 100644 --- a/docs/resources/notification.md +++ b/docs/resources/notification.md @@ -69,9 +69,9 @@ resource "radarr_notification" "example" { - `auth_user` (String) Auth user. - `author` (String) Author. - `avatar` (String) Avatar. -- `bcc` (String) Bcc. +- `bcc` (Set of String) Bcc. - `bot_token` (String) Bot token. -- `cc` (String) Cc. +- `cc` (Set of String) Cc. - `channel` (String) Channel. - `channel_tags` (Set of String) Channel tags. - `chat_id` (String) Chat ID. @@ -79,7 +79,7 @@ resource "radarr_notification" "example" { - `click_url` (String) Click URL. - `consumer_key` (String) Consumer key. - `consumer_secret` (String) Consumer secret. -- `device_ids` (Set of Number) Device IDs. +- `device_ids` (Set of String) Device IDs. - `device_names` (String) Device names. - `devices` (Set of String) Devices. - `direct_message` (Boolean) Direct message flag. @@ -116,7 +116,7 @@ resource "radarr_notification" "example" { - `sign_in` (String) Sign in. - `sound` (String) Sound. - `tags` (Set of Number) List of associated tags. -- `to` (String) To. +- `to` (Set of String) To. - `token` (String) Token. - `topics` (Set of String) Devices. - `update_library` (Boolean) Update library flag. diff --git a/docs/resources/notification_email.md b/docs/resources/notification_email.md new file mode 100644 index 00000000..473e4a3c --- /dev/null +++ b/docs/resources/notification_email.md @@ -0,0 +1,80 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "radarr_notification_email Resource - terraform-provider-radarr" +subcategory: "Notifications" +description: |- + Notification Email resource. + For more information refer to Notification https://wiki.servarr.com/radarr/settings#connect and Email https://wiki.servarr.com/radarr/supported#email. +--- + +# radarr_notification_email (Resource) + +Notification Email resource. +For more information refer to [Notification](https://wiki.servarr.com/radarr/settings#connect) and [Email](https://wiki.servarr.com/radarr/supported#email). + +## Example Usage + +```terraform +resource "radarr_notification_email" "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" + + server = "http://email-server.net" + port = 587 + from = "from_email@example.com" + to = ["user1@example.com", "user2@example.com"] +} +``` + + +## Schema + +### Required + +- `from` (String) From. +- `include_health_warnings` (Boolean) Include health warnings. +- `name` (String) NotificationEmail name. +- `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_movie_added` (Boolean) On movie added flag. +- `on_movie_delete` (Boolean) On movie delete 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. +- `server` (String) Server. +- `to` (Set of String) To. + +### Optional + +- `bcc` (Set of String) Bcc. +- `cc` (Set of String) Cc. +- `password` (String, Sensitive) Password. +- `port` (Number) Port. +- `require_encryption` (Boolean) Require encryption flag. +- `tags` (Set of Number) List of associated tags. +- `username` (String) Username. + +### 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_email.example 1 +``` diff --git a/examples/resources/radarr_notification_email/import.sh b/examples/resources/radarr_notification_email/import.sh new file mode 100644 index 00000000..2488f481 --- /dev/null +++ b/examples/resources/radarr_notification_email/import.sh @@ -0,0 +1,2 @@ +# import using the API/UI ID +terraform import radarr_notification_email.example 1 \ No newline at end of file diff --git a/examples/resources/radarr_notification_email/resource.tf b/examples/resources/radarr_notification_email/resource.tf new file mode 100644 index 00000000..023027ac --- /dev/null +++ b/examples/resources/radarr_notification_email/resource.tf @@ -0,0 +1,19 @@ +resource "radarr_notification_email" "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" + + server = "http://email-server.net" + port = 587 + from = "from_email@example.com" + to = ["user1@example.com", "user2@example.com"] +} \ No newline at end of file diff --git a/internal/provider/notification_data_source.go b/internal/provider/notification_data_source.go index 7a87545c..edbda140 100644 --- a/internal/provider/notification_data_source.go +++ b/internal/provider/notification_data_source.go @@ -197,18 +197,10 @@ func (d *NotificationDataSource) Schema(ctx context.Context, req datasource.Sche MarkdownDescription: "Instance name.", Computed: true, }, - "bcc": schema.StringAttribute{ - MarkdownDescription: "Bcc.", - Computed: true, - }, "bot_token": schema.StringAttribute{ MarkdownDescription: "Bot token.", Computed: true, }, - "cc": schema.StringAttribute{ - MarkdownDescription: "Cc.", - Computed: true, - }, "channel": schema.StringAttribute{ MarkdownDescription: "Channel.", Computed: true, @@ -285,10 +277,6 @@ func (d *NotificationDataSource) Schema(ctx context.Context, req datasource.Sche MarkdownDescription: "Sound.", Computed: true, }, - "to": schema.StringAttribute{ - MarkdownDescription: "To.", - Computed: true, - }, "token": schema.StringAttribute{ MarkdownDescription: "Token.", Computed: true, @@ -373,6 +361,21 @@ func (d *NotificationDataSource) Schema(ctx context.Context, req datasource.Sche Computed: true, ElementType: types.StringType, }, + "to": schema.SetAttribute{ + MarkdownDescription: "To.", + Computed: true, + ElementType: types.StringType, + }, + "cc": schema.SetAttribute{ + MarkdownDescription: "Cc.", + Computed: true, + ElementType: types.StringType, + }, + "bcc": schema.SetAttribute{ + MarkdownDescription: "Bcc.", + Computed: true, + ElementType: types.StringType, + }, }, } } diff --git a/internal/provider/notification_email_resource.go b/internal/provider/notification_email_resource.go new file mode 100644 index 00000000..22029946 --- /dev/null +++ b/internal/provider/notification_email_resource.go @@ -0,0 +1,408 @@ +package provider + +import ( + "context" + "fmt" + "strconv" + + "github.com/devopsarr/terraform-provider-sonarr/tools" + "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/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "golift.io/starr/radarr" +) + +const ( + notificationEmailResourceName = "notification_email" + NotificationEmailImplementation = "Email" + NotificationEmailConfigContrat = "EmailSettings" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var _ resource.Resource = &NotificationEmailResource{} +var _ resource.ResourceWithImportState = &NotificationEmailResource{} + +func NewNotificationEmailResource() resource.Resource { + return &NotificationEmailResource{} +} + +// NotificationEmailResource defines the notification implementation. +type NotificationEmailResource struct { + client *radarr.Radarr +} + +// NotificationEmail describes the notification data model. +type NotificationEmail struct { + Tags types.Set `tfsdk:"tags"` + To types.Set `tfsdk:"to"` + Cc types.Set `tfsdk:"cc"` + Bcc types.Set `tfsdk:"bcc"` + From types.String `tfsdk:"from"` + Server types.String `tfsdk:"server"` + Name types.String `tfsdk:"name"` + Username types.String `tfsdk:"username"` + Password types.String `tfsdk:"password"` + ID types.Int64 `tfsdk:"id"` + Port types.Int64 `tfsdk:"port"` + RequireEncryption types.Bool `tfsdk:"require_encryption"` + 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"` + OnMovieDelete types.Bool `tfsdk:"on_movie_delete"` + OnUpgrade types.Bool `tfsdk:"on_upgrade"` + OnDownload types.Bool `tfsdk:"on_download"` +} + +func (n NotificationEmail) toNotification() *Notification { + return &Notification{ + Tags: n.Tags, + From: n.From, + To: n.To, + Cc: n.Cc, + Bcc: n.Bcc, + Server: n.Server, + Port: n.Port, + Username: n.Username, + Password: n.Password, + Name: n.Name, + ID: n.ID, + RequireEncryption: n.RequireEncryption, + OnGrab: n.OnGrab, + OnMovieFileDeleteForUpgrade: n.OnMovieFileDeleteForUpgrade, + OnMovieAdded: n.OnMovieAdded, + OnMovieFileDelete: n.OnMovieFileDelete, + IncludeHealthWarnings: n.IncludeHealthWarnings, + OnApplicationUpdate: n.OnApplicationUpdate, + OnHealthIssue: n.OnHealthIssue, + OnMovieDelete: n.OnMovieDelete, + OnUpgrade: n.OnUpgrade, + OnDownload: n.OnDownload, + } +} + +func (n *NotificationEmail) fromNotification(notification *Notification) { + n.Tags = notification.Tags + n.From = notification.From + n.To = notification.To + n.Cc = notification.Cc + n.Bcc = notification.Bcc + n.Server = notification.Server + n.Port = notification.Port + n.Username = notification.Username + n.Password = notification.Password + n.Name = notification.Name + n.ID = notification.ID + n.RequireEncryption = notification.RequireEncryption + 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.OnMovieAdded = notification.OnMovieAdded + n.OnMovieDelete = notification.OnMovieDelete + n.OnUpgrade = notification.OnUpgrade + n.OnDownload = notification.OnDownload +} + +func (r *NotificationEmailResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_" + notificationEmailResourceName +} + +func (r *NotificationEmailResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: "Notification Email resource.\nFor more information refer to [Notification](https://wiki.servarr.com/radarr/settings#connect) and [Email](https://wiki.servarr.com/radarr/supported#email).", + Attributes: map[string]schema.Attribute{ + "on_grab": schema.BoolAttribute{ + MarkdownDescription: "On grab flag.", + Required: true, + }, + "on_download": schema.BoolAttribute{ + MarkdownDescription: "On download flag.", + Required: true, + }, + "on_upgrade": schema.BoolAttribute{ + MarkdownDescription: "On upgrade flag.", + Required: true, + }, + "on_movie_added": schema.BoolAttribute{ + MarkdownDescription: "On movie added flag.", + Required: 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.", + Required: true, + }, + "on_movie_file_delete_for_upgrade": schema.BoolAttribute{ + MarkdownDescription: "On movie file delete for upgrade flag.", + Required: true, + }, + "on_health_issue": schema.BoolAttribute{ + MarkdownDescription: "On health issue flag.", + Required: true, + }, + "on_application_update": schema.BoolAttribute{ + MarkdownDescription: "On application update flag.", + Required: true, + }, + "include_health_warnings": schema.BoolAttribute{ + MarkdownDescription: "Include health warnings.", + Required: true, + }, + "name": schema.StringAttribute{ + MarkdownDescription: "NotificationEmail 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 + "require_encryption": schema.BoolAttribute{ + MarkdownDescription: "Require encryption flag.", + Optional: true, + Computed: true, + }, + "port": schema.Int64Attribute{ + MarkdownDescription: "Port.", + Optional: true, + Computed: true, + }, + "server": schema.StringAttribute{ + MarkdownDescription: "Server.", + Required: true, + }, + "username": schema.StringAttribute{ + MarkdownDescription: "Username.", + Optional: true, + Computed: true, + }, + "password": schema.StringAttribute{ + MarkdownDescription: "Password.", + Optional: true, + Computed: true, + Sensitive: true, + }, + "from": schema.StringAttribute{ + MarkdownDescription: "From.", + Required: true, + }, + "to": schema.SetAttribute{ + MarkdownDescription: "To.", + Required: true, + ElementType: types.StringType, + }, + "cc": schema.SetAttribute{ + MarkdownDescription: "Cc.", + Optional: true, + Computed: true, + ElementType: types.StringType, + }, + "bcc": schema.SetAttribute{ + MarkdownDescription: "Bcc.", + Optional: true, + Computed: true, + ElementType: types.StringType, + }, + }, + } +} + +func (r *NotificationEmailResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*radarr.Radarr) + if !ok { + resp.Diagnostics.AddError( + tools.UnexpectedResourceConfigureType, + fmt.Sprintf("Expected *radarr.Radarr, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = client +} + +func (r *NotificationEmailResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + // Retrieve values from plan + var notification *NotificationEmail + + resp.Diagnostics.Append(req.Plan.Get(ctx, ¬ification)...) + + if resp.Diagnostics.HasError() { + return + } + + // Create new NotificationEmail + request := notification.read(ctx) + + response, err := r.client.AddNotificationContext(ctx, request) + if err != nil { + resp.Diagnostics.AddError(tools.ClientError, fmt.Sprintf("Unable to create %s, got error: %s", notificationEmailResourceName, err)) + + return + } + + tflog.Trace(ctx, "created "+notificationEmailResourceName+": "+strconv.Itoa(int(response.ID))) + // Generate resource state struct + notification.write(ctx, response) + resp.Diagnostics.Append(resp.State.Set(ctx, ¬ification)...) +} + +func (r *NotificationEmailResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + // Get current state + var notification *NotificationEmail + + resp.Diagnostics.Append(req.State.Get(ctx, ¬ification)...) + + if resp.Diagnostics.HasError() { + return + } + + // Get NotificationEmail current value + response, err := r.client.GetNotificationContext(ctx, int(notification.ID.ValueInt64())) + if err != nil { + resp.Diagnostics.AddError(tools.ClientError, fmt.Sprintf("Unable to read %s, got error: %s", notificationEmailResourceName, err)) + + return + } + + tflog.Trace(ctx, "read "+notificationEmailResourceName+": "+strconv.Itoa(int(response.ID))) + // Map response body to resource schema attribute + notification.write(ctx, response) + resp.Diagnostics.Append(resp.State.Set(ctx, ¬ification)...) +} + +func (r *NotificationEmailResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + // Get plan values + var notification *NotificationEmail + + resp.Diagnostics.Append(req.Plan.Get(ctx, ¬ification)...) + + if resp.Diagnostics.HasError() { + return + } + + // Update NotificationEmail + request := notification.read(ctx) + + response, err := r.client.UpdateNotificationContext(ctx, request) + if err != nil { + resp.Diagnostics.AddError(tools.ClientError, fmt.Sprintf("Unable to update %s, got error: %s", notificationEmailResourceName, err)) + + return + } + + tflog.Trace(ctx, "updated "+notificationEmailResourceName+": "+strconv.Itoa(int(response.ID))) + // Generate resource state struct + notification.write(ctx, response) + resp.Diagnostics.Append(resp.State.Set(ctx, ¬ification)...) +} + +func (r *NotificationEmailResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var notification *NotificationEmail + + resp.Diagnostics.Append(req.State.Get(ctx, ¬ification)...) + + if resp.Diagnostics.HasError() { + return + } + + // Delete NotificationEmail current value + err := r.client.DeleteNotificationContext(ctx, notification.ID.ValueInt64()) + if err != nil { + resp.Diagnostics.AddError(tools.ClientError, fmt.Sprintf("Unable to read %s, got error: %s", notificationEmailResourceName, err)) + + return + } + + tflog.Trace(ctx, "deleted "+notificationEmailResourceName+": "+strconv.Itoa(int(notification.ID.ValueInt64()))) + resp.State.RemoveResource(ctx) +} + +func (r *NotificationEmailResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + // resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) + id, err := strconv.Atoi(req.ID) + if err != nil { + resp.Diagnostics.AddError( + tools.UnexpectedImportIdentifier, + fmt.Sprintf("Expected import identifier with format: ID. Got: %q", req.ID), + ) + + return + } + + tflog.Trace(ctx, "imported "+notificationEmailResourceName+": "+strconv.Itoa(id)) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), id)...) +} + +func (n *NotificationEmail) write(ctx context.Context, notification *radarr.NotificationOutput) { + genericNotification := Notification{ + OnGrab: types.BoolValue(notification.OnGrab), + OnDownload: types.BoolValue(notification.OnDownload), + OnUpgrade: types.BoolValue(notification.OnUpgrade), + OnMovieAdded: types.BoolValue(notification.OnMovieAdded), + OnMovieDelete: types.BoolValue(notification.OnMovieDelete), + OnMovieFileDelete: types.BoolValue(notification.OnMovieFileDelete), + OnMovieFileDeleteForUpgrade: types.BoolValue(notification.OnMovieFileDeleteForUpgrade), + OnHealthIssue: types.BoolValue(notification.OnHealthIssue), + OnApplicationUpdate: types.BoolValue(notification.OnApplicationUpdate), + IncludeHealthWarnings: types.BoolValue(notification.IncludeHealthWarnings), + ID: types.Int64Value(notification.ID), + Name: types.StringValue(notification.Name), + } + genericNotification.Tags, _ = types.SetValueFrom(ctx, types.Int64Type, notification.Tags) + genericNotification.writeFields(ctx, notification.Fields) + n.fromNotification(&genericNotification) +} + +func (n *NotificationEmail) read(ctx context.Context) *radarr.NotificationInput { + var tags []int + + tfsdk.ValueAs(ctx, n.Tags, &tags) + + return &radarr.NotificationInput{ + OnGrab: n.OnGrab.ValueBool(), + OnDownload: n.OnDownload.ValueBool(), + OnUpgrade: n.OnUpgrade.ValueBool(), + OnMovieAdded: n.OnMovieAdded.ValueBool(), + OnMovieDelete: n.OnMovieDelete.ValueBool(), + OnMovieFileDelete: n.OnMovieFileDelete.ValueBool(), + OnMovieFileDeleteForUpgrade: n.OnMovieFileDeleteForUpgrade.ValueBool(), + OnHealthIssue: n.OnHealthIssue.ValueBool(), + OnApplicationUpdate: n.OnApplicationUpdate.ValueBool(), + IncludeHealthWarnings: n.IncludeHealthWarnings.ValueBool(), + ConfigContract: NotificationEmailConfigContrat, + Implementation: NotificationEmailImplementation, + ID: n.ID.ValueInt64(), + Name: n.Name.ValueString(), + Tags: tags, + Fields: n.toNotification().readFields(ctx), + } +} diff --git a/internal/provider/notification_email_resource_test.go b/internal/provider/notification_email_resource_test.go new file mode 100644 index 00000000..ca8b5e7d --- /dev/null +++ b/internal/provider/notification_email_resource_test.go @@ -0,0 +1,64 @@ +package provider + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccNotificationEmailResource(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create and Read testing + { + Config: testAccNotificationEmailResourceConfig("resourceEmailTest", "test@email.com"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("radarr_notification_email.test", "from", "test@email.com"), + resource.TestCheckResourceAttrSet("radarr_notification_email.test", "id"), + ), + }, + // Update and Read testing + { + Config: testAccNotificationEmailResourceConfig("resourceEmailTest", "test123@email.com"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("radarr_notification_email.test", "from", "test123@email.com"), + ), + }, + // ImportState testing + { + ResourceName: "radarr_notification_email.test", + ImportState: true, + ImportStateVerify: true, + }, + // Delete testing automatically occurs in TestCase + }, + }) +} + +func testAccNotificationEmailResourceConfig(name, from string) string { + return fmt.Sprintf(` + resource "radarr_notification_email" "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" + + server = "http://email-server.net" + port = 587 + from = "%s" + to = ["test@test.com", "test1@test.com"] + }`, name, from) +} diff --git a/internal/provider/notification_resource.go b/internal/provider/notification_resource.go index edbe5ed2..691eedb9 100644 --- a/internal/provider/notification_resource.go +++ b/internal/provider/notification_resource.go @@ -29,9 +29,9 @@ var _ resource.ResourceWithImportState = &NotificationResource{} var ( notificationBoolFields = []string{"alwaysUpdate", "cleanLibrary", "directMessage", "notify", "requireEncryption", "sendSilently", "useSsl", "updateLibrary", "useEuEndpoint"} - notificationStringFields = []string{"accessToken", "accessTokenSecret", "apiKey", "aPIKey", "appToken", "arguments", "author", "authToken", "authUser", "avatar", "cc", "bcc", "botToken", "channel", "chatId", "consumerKey", "consumerSecret", "deviceNames", "displayTime", "expires", "from", "host", "icon", "instanceName", "mention", "password", "path", "refreshToken", "senderDomain", "senderId", "server", "signIn", "sound", "to", "token", "url", "userKey", "username", "webHookUrl", "serverUrl", "userName", "clickUrl", "mapFrom", "mapTo", "key", "event"} + notificationStringFields = []string{"accessToken", "accessTokenSecret", "apiKey", "aPIKey", "appToken", "arguments", "author", "authToken", "authUser", "avatar", "botToken", "channel", "chatId", "consumerKey", "consumerSecret", "deviceNames", "displayTime", "expires", "from", "host", "icon", "instanceName", "mention", "password", "path", "refreshToken", "senderDomain", "senderId", "server", "signIn", "sound", "token", "url", "userKey", "username", "webHookUrl", "serverUrl", "userName", "clickUrl", "mapFrom", "mapTo", "key", "event"} notificationIntFields = []string{"port", "priority", "retry", "expire", "method"} - notificationStringSliceFields = []string{"recipients", "topics", "deviceIds", "tags", "channelTags", "devices"} + notificationStringSliceFields = []string{"recipients", "to", "cC", "bcc", "topics", "deviceIds", "tags", "channelTags", "devices"} notificationIntSliceFields = []string{"grabFields", "importFields"} ) @@ -54,6 +54,9 @@ type Notification struct { GrabFields types.Set `tfsdk:"grab_fields"` DeviceIds types.Set `tfsdk:"device_ids"` Devices types.Set `tfsdk:"devices"` + To types.Set `tfsdk:"to"` + Cc types.Set `tfsdk:"cc"` + Bcc types.Set `tfsdk:"bcc"` Recipients types.Set `tfsdk:"recipients"` DeviceNames types.String `tfsdk:"device_names"` AccessToken types.String `tfsdk:"access_token"` @@ -69,7 +72,6 @@ type Notification struct { ConsumerKey types.String `tfsdk:"consumer_key"` ChatID types.String `tfsdk:"chat_id"` From types.String `tfsdk:"from"` - Cc types.String `tfsdk:"cc"` Icon types.String `tfsdk:"icon"` Password types.String `tfsdk:"password"` Event types.String `tfsdk:"event"` @@ -83,9 +85,7 @@ type Notification struct { Avatar types.String `tfsdk:"avatar"` URL types.String `tfsdk:"url"` Token types.String `tfsdk:"token"` - To types.String `tfsdk:"to"` Sound types.String `tfsdk:"sound"` - Bcc types.String `tfsdk:"bcc"` SignIn types.String `tfsdk:"sign_in"` Server types.String `tfsdk:"server"` SenderID types.String `tfsdk:"sender_id"` @@ -334,21 +334,11 @@ func (r *NotificationResource) Schema(ctx context.Context, req resource.SchemaRe Optional: true, Computed: true, }, - "bcc": schema.StringAttribute{ - MarkdownDescription: "Bcc.", - Optional: true, - Computed: true, - }, "bot_token": schema.StringAttribute{ MarkdownDescription: "Bot token.", Optional: true, Computed: true, }, - "cc": schema.StringAttribute{ - MarkdownDescription: "Cc.", - Optional: true, - Computed: true, - }, "channel": schema.StringAttribute{ MarkdownDescription: "Channel.", Optional: true, @@ -444,11 +434,6 @@ func (r *NotificationResource) Schema(ctx context.Context, req resource.SchemaRe Optional: true, Computed: true, }, - "to": schema.StringAttribute{ - MarkdownDescription: "To.", - Optional: true, - Computed: true, - }, "token": schema.StringAttribute{ MarkdownDescription: "Token.", Optional: true, @@ -552,6 +537,24 @@ func (r *NotificationResource) Schema(ctx context.Context, req resource.SchemaRe Computed: true, ElementType: types.StringType, }, + "to": schema.SetAttribute{ + MarkdownDescription: "To.", + Optional: true, + Computed: true, + ElementType: types.StringType, + }, + "cc": schema.SetAttribute{ + MarkdownDescription: "Cc.", + Optional: true, + Computed: true, + ElementType: types.StringType, + }, + "bcc": schema.SetAttribute{ + MarkdownDescription: "Bcc.", + Optional: true, + Computed: true, + ElementType: types.StringType, + }, }, } } @@ -722,6 +725,9 @@ func (n *Notification) write(ctx context.Context, notification *radarr.Notificat n.Devices = types.SetValueMust(types.StringType, nil) n.Recipients = types.SetValueMust(types.StringType, nil) n.FieldTags = types.SetValueMust(types.StringType, nil) + n.To = types.SetValueMust(types.StringType, nil) + n.Cc = types.SetValueMust(types.StringType, nil) + n.Bcc = types.SetValueMust(types.StringType, nil) tfsdk.ValueFrom(ctx, notification.Tags, n.Tags.Type(ctx), &n.Tags) n.writeFields(ctx, notification.Fields) } diff --git a/internal/provider/notifications_data_source.go b/internal/provider/notifications_data_source.go index 5f9b6e09..f750db4b 100644 --- a/internal/provider/notifications_data_source.go +++ b/internal/provider/notifications_data_source.go @@ -214,18 +214,10 @@ func (d *NotificationsDataSource) Schema(ctx context.Context, req datasource.Sch MarkdownDescription: "Instance name.", Computed: true, }, - "bcc": schema.StringAttribute{ - MarkdownDescription: "Bcc.", - Computed: true, - }, "bot_token": schema.StringAttribute{ MarkdownDescription: "Bot token.", Computed: true, }, - "cc": schema.StringAttribute{ - MarkdownDescription: "Cc.", - Computed: true, - }, "channel": schema.StringAttribute{ MarkdownDescription: "Channel.", Computed: true, @@ -302,10 +294,6 @@ func (d *NotificationsDataSource) Schema(ctx context.Context, req datasource.Sch MarkdownDescription: "Sound.", Computed: true, }, - "to": schema.StringAttribute{ - MarkdownDescription: "To.", - Computed: true, - }, "token": schema.StringAttribute{ MarkdownDescription: "Token.", Computed: true, @@ -390,6 +378,21 @@ func (d *NotificationsDataSource) Schema(ctx context.Context, req datasource.Sch Computed: true, ElementType: types.StringType, }, + "to": schema.SetAttribute{ + MarkdownDescription: "To.", + Computed: true, + ElementType: types.StringType, + }, + "cc": schema.SetAttribute{ + MarkdownDescription: "Cc.", + Computed: true, + ElementType: types.StringType, + }, + "bcc": schema.SetAttribute{ + MarkdownDescription: "Bcc.", + Computed: true, + ElementType: types.StringType, + }, }, }, }, diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 28ac66a0..f421e1f1 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -176,6 +176,7 @@ func (p *RadarrProvider) Resources(ctx context.Context) []func() resource.Resour NewNotificationResource, NewNotificationBoxcarResource, NewNotificationDiscordResource, + NewNotificationEmailResource, NewNotificationCustomScriptResource, NewNotificationWebhookResource,