From b10369047b63d1ba1b8d56030ceb1c6b904eb0c4 Mon Sep 17 00:00:00 2001 From: Mike Mondragon Date: Mon, 9 May 2022 17:05:32 -0700 Subject: [PATCH 1/8] Data Source "okta_theme" Data Source "okta_themes" --- examples/okta_theme/README.md | 8 ++ examples/okta_theme/datasource.tf | 11 +++ examples/okta_themes/README.md | 8 ++ examples/okta_themes/datasource.tf | 6 ++ okta/data_source_okta_theme.go | 57 +++++++++++++ okta/data_source_okta_theme_test.go | 39 +++++++++ okta/data_source_okta_themes.go | 46 ++++++++++ okta/data_source_okta_themes_test.go | 30 +++++++ okta/provider.go | 4 + okta/theme.go | 120 +++++++++++++++++++++++++++ website/docs/d/theme.html.markdown | 52 ++++++++++++ website/docs/d/themes.html.markdown | 33 ++++++++ website/okta.erb | 6 ++ 13 files changed, 420 insertions(+) create mode 100644 examples/okta_theme/README.md create mode 100644 examples/okta_theme/datasource.tf create mode 100644 examples/okta_themes/README.md create mode 100644 examples/okta_themes/datasource.tf create mode 100644 okta/data_source_okta_theme.go create mode 100644 okta/data_source_okta_theme_test.go create mode 100644 okta/data_source_okta_themes.go create mode 100644 okta/data_source_okta_themes_test.go create mode 100644 okta/theme.go create mode 100644 website/docs/d/theme.html.markdown create mode 100644 website/docs/d/themes.html.markdown diff --git a/examples/okta_theme/README.md b/examples/okta_theme/README.md new file mode 100644 index 000000000..0cbd5ee24 --- /dev/null +++ b/examples/okta_theme/README.md @@ -0,0 +1,8 @@ +# okta_theme + +This resource represents a theme of a brand for an Okta organization. More +information can be found in the +[Theme](https://developer.okta.com/docs/reference/api/brands/#theme-response-object) +API documentation. + +- Example [datastore.tf](./datasource.tf) diff --git a/examples/okta_theme/datasource.tf b/examples/okta_theme/datasource.tf new file mode 100644 index 000000000..d24ca16de --- /dev/null +++ b/examples/okta_theme/datasource.tf @@ -0,0 +1,11 @@ +data "okta_brands" "test" { +} + +data "okta_themes" "test" { + brand_id = tolist(data.okta_brands.test.brands)[0].id +} + +data "okta_theme" "test" { + brand_id = tolist(data.okta_brands.test.brands)[0].id + theme_id = tolist(data.okta_themes.test.themes)[0].id +} diff --git a/examples/okta_themes/README.md b/examples/okta_themes/README.md new file mode 100644 index 000000000..4e6082d44 --- /dev/null +++ b/examples/okta_themes/README.md @@ -0,0 +1,8 @@ +# okta_themes + +This resource represents a themes of a brand for an Okta organization. More +information can be found in the +[Theme](https://developer.okta.com/docs/reference/api/brands/#get-themes) +API documentation. + +- Example [datastore.tf](./datasource.tf) diff --git a/examples/okta_themes/datasource.tf b/examples/okta_themes/datasource.tf new file mode 100644 index 000000000..3e1ff438e --- /dev/null +++ b/examples/okta_themes/datasource.tf @@ -0,0 +1,6 @@ +data "okta_brands" "test" { +} + +data "okta_themes" "test" { + brand_id = tolist(data.okta_brands.test.brands)[0].id +} diff --git a/okta/data_source_okta_theme.go b/okta/data_source_okta_theme.go new file mode 100644 index 000000000..7f65903c6 --- /dev/null +++ b/okta/data_source_okta_theme.go @@ -0,0 +1,57 @@ +package okta + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceTheme() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceThemeRead, + Schema: buildSchema( + map[string]*schema.Schema{ + "brand_id": { + Type: schema.TypeString, + Required: true, + Description: "Brand ID", + }, + "theme_id": { + Type: schema.TypeString, + Required: true, + Description: "Theme ID", + }, + }, + themeDataSourceSchema, + ), + } +} + +func dataSourceThemeRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + bid, ok := d.GetOk("brand_id") + if !ok { + return diag.Errorf("brand_id required for email template") + } + brandID := bid.(string) + + tid, ok := d.GetOk("theme_id") + if !ok { + return diag.Errorf("theme_id required for theme") + } + themeID := tid.(string) + + theme, _, err := getOktaClientFromMetadata(m).Brand.GetBrandTheme(ctx, brandID, themeID) + if err != nil { + return diag.Errorf("failed to get email template: %v", err) + } + + d.SetId(theme.Id) + rawMap := flattenTheme(brandID, themeID, theme) + err = setNonPrimitives(d, rawMap) + if err != nil { + return diag.Errorf("failed to set theme properties: %v", err) + } + + return nil +} diff --git a/okta/data_source_okta_theme_test.go b/okta/data_source_okta_theme_test.go new file mode 100644 index 000000000..6a4991216 --- /dev/null +++ b/okta/data_source_okta_theme_test.go @@ -0,0 +1,39 @@ +package okta + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccDataSourceOktaTheme_read(t *testing.T) { + ri := acctest.RandInt() + mgr := newFixtureManager(theme) + config := mgr.GetFixtures("datasource.tf", ri, t) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProvidersFactories, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.okta_theme.test", "id"), + resource.TestCheckResourceAttrSet("data.okta_theme.test", "logo"), + resource.TestCheckResourceAttrSet("data.okta_theme.test", "favicon"), + // resource.TestCheckResourceAttrSet("data.okta_theme.test", "background_image"), // background image is null by default, skip check + resource.TestCheckResourceAttrSet("data.okta_theme.test", "primary_color_hex"), + resource.TestCheckResourceAttrSet("data.okta_theme.test", "primary_color_contrast_hex"), + resource.TestCheckResourceAttrSet("data.okta_theme.test", "secondary_color_hex"), + resource.TestCheckResourceAttrSet("data.okta_theme.test", "secondary_color_contrast_hex"), + resource.TestCheckResourceAttrSet("data.okta_theme.test", "sign_in_page_touch_point_variant"), + resource.TestCheckResourceAttrSet("data.okta_theme.test", "end_user_dashboard_touch_point_variant"), + resource.TestCheckResourceAttrSet("data.okta_theme.test", "error_page_touch_point_variant"), + resource.TestCheckResourceAttrSet("data.okta_theme.test", "email_template_touch_point_variant"), + resource.TestCheckResourceAttrSet("data.okta_theme.test", "links"), + ), + }, + }, + }) +} diff --git a/okta/data_source_okta_themes.go b/okta/data_source_okta_themes.go new file mode 100644 index 000000000..7f9464999 --- /dev/null +++ b/okta/data_source_okta_themes.go @@ -0,0 +1,46 @@ +package okta + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceThemes() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceThemesRead, + Schema: themesDataSourceSchema, + } +} + +func dataSourceThemesRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + var err error + brandID, ok := d.GetOk("brand_id") + if !ok { + return diag.Errorf("brand_id required for themes: %v", err) + } + + themes, _, err := getOktaClientFromMetadata(m).Brand.ListBrandThemes(ctx, brandID.(string)) + if err != nil { + return diag.Errorf("failed to list brand themes: %v", err) + } + + d.SetId(fmt.Sprintf("themes-%s", brandID.(string))) + arr := make([]interface{}, len(themes)) + for i, theme := range themes { + rawMap := flattenTheme("", "", theme) + arr[i] = rawMap + } + + themesDataSource := &schema.Resource{ + Schema: themeDataSourceSchema, + } + err = d.Set("themes", schema.NewSet(schema.HashResource(themesDataSource), arr)) + if err != nil { + return diag.Errorf("failed to set themes: %v", err) + } + + return nil +} diff --git a/okta/data_source_okta_themes_test.go b/okta/data_source_okta_themes_test.go new file mode 100644 index 000000000..9d4952a6a --- /dev/null +++ b/okta/data_source_okta_themes_test.go @@ -0,0 +1,30 @@ +package okta + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccDataSourceOktaThemes_read(t *testing.T) { + ri := acctest.RandInt() + mgr := newFixtureManager(themes) + config := mgr.GetFixtures("datasource.tf", ri, t) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProvidersFactories, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.okta_themes.test", "themes.#"), + resource.TestCheckResourceAttr("data.okta_themes.test", "themes.#", "1"), + resource.TestCheckResourceAttrSet("data.okta_themes.test", "themes.0.id"), + resource.TestCheckResourceAttrSet("data.okta_themes.test", "themes.0.links"), + ), + }, + }, + }) +} diff --git a/okta/provider.go b/okta/provider.go index 0354d5566..8f47f257f 100644 --- a/okta/provider.go +++ b/okta/provider.go @@ -114,6 +114,8 @@ const ( securityNotificationEmails = "okta_security_notification_emails" templateEmail = "okta_template_email" templateSms = "okta_template_sms" + theme = "okta_theme" + themes = "okta_themes" threatInsightSettings = "okta_threat_insight_settings" trustedOrigin = "okta_trusted_origin" trustedOrigins = "okta_trusted_origins" @@ -381,6 +383,8 @@ func Provider() *schema.Provider { networkZone: dataSourceNetworkZone(), policy: dataSourcePolicy(), roleSubscription: dataSourceRoleSubscription(), + theme: dataSourceTheme(), + themes: dataSourceThemes(), trustedOrigins: dataSourceTrustedOrigins(), user: dataSourceUser(), userProfileMappingSource: dataSourceUserProfileMappingSource(), diff --git a/okta/theme.go b/okta/theme.go new file mode 100644 index 000000000..5b819fdc3 --- /dev/null +++ b/okta/theme.go @@ -0,0 +1,120 @@ +package okta + +import ( + "encoding/json" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +var themesDataSourceSchema = map[string]*schema.Schema{ + "brand_id": { + Type: schema.TypeString, + Required: true, + Description: "Brand ID", + }, + "themes": { + Type: schema.TypeSet, + Computed: true, + Description: "List of `okta_them` belonging to the brand in the organization", + Elem: &schema.Resource{ + Schema: themeDataSourceSchema, + }, + }, +} + +var themeDataSourceSchema = map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the theme", + }, + "logo": { + Type: schema.TypeString, + Computed: true, + Description: "Logo URL", + }, + "favicon": { + Type: schema.TypeString, + Computed: true, + Description: "Favicon URL", + }, + "background_image": { + Type: schema.TypeString, + Computed: true, + Description: "Background image URL", + }, + "primary_color_hex": { + Type: schema.TypeString, + Computed: true, + Description: "Primary color hex code", + }, + "primary_color_contrast_hex": { + Type: schema.TypeString, + Computed: true, + Description: "Primary color contrast hex code", + }, + "secondary_color_hex": { + Type: schema.TypeString, + Computed: true, + Description: "Secondary color hex code", + }, + "secondary_color_contrast_hex": { + Type: schema.TypeString, + Computed: true, + Description: "Secondary color contrast hex code", + }, + "sign_in_page_touch_point_variant": { + Type: schema.TypeString, + Computed: true, + Description: "Variant for the Okta Sign-In Page (`OKTA_DEFAULT`, `BACKGROUND_SECONDARY_COLOR`, `BACKGROUND_IMAGE`)", + }, + "end_user_dashboard_touch_point_variant": { + Type: schema.TypeString, + Computed: true, + Description: "Variant for the Okta End-User Dashboard (`OKTA_DEFAULT`, `WHITE_LOGO_BACKGROUND`, `FULL_THEME`, `LOGO_ON_FULL_WHITE_BACKGROUND`)", + }, + "error_page_touch_point_variant": { + Type: schema.TypeString, + Computed: true, + Description: "Variant for the error page (`OKTA_DEFAULT`, `BACKGROUND_SECONDARY_COLOR`, `BACKGROUND_IMAGE`)", + }, + "email_template_touch_point_variant": { + Type: schema.TypeString, + Computed: true, + Description: "Variant for email templates (`OKTA_DEFAULT`, `FULL_THEME`)", + }, + "links": { + Type: schema.TypeString, + Computed: true, + Description: "Link relations for this object - JSON HAL - Discoverable resources related to the email template", + }, +} + +func flattenTheme(brandID, themeID string, theme *okta.ThemeResponse) map[string]interface{} { + attrs := map[string]interface{}{} + + attrs["id"] = theme.Id + if brandID != "" { + attrs["brand_id"] = brandID + } + if themeID != "" { + attrs["theme_id"] = themeID + } + attrs["logo"] = theme.Logo + attrs["favicon"] = theme.Favicon + attrs["background_image"] = theme.BackgroundImage + attrs["primary_color_hex"] = theme.PrimaryColorHex + attrs["primary_color_contrast_hex"] = theme.PrimaryColorContrastHex + attrs["secondary_color_hex"] = theme.SecondaryColorHex + attrs["secondary_color_contrast_hex"] = theme.SecondaryColorContrastHex + attrs["sign_in_page_touch_point_variant"] = theme.SignInPageTouchPointVariant + attrs["end_user_dashboard_touch_point_variant"] = theme.EndUserDashboardTouchPointVariant + attrs["error_page_touch_point_variant"] = theme.ErrorPageTouchPointVariant + attrs["email_template_touch_point_variant"] = theme.EmailTemplateTouchPointVariant + + links, _ := json.Marshal(theme.Links) + attrs["links"] = string(links) + + return attrs +} diff --git a/website/docs/d/theme.html.markdown b/website/docs/d/theme.html.markdown new file mode 100644 index 000000000..54d4205a3 --- /dev/null +++ b/website/docs/d/theme.html.markdown @@ -0,0 +1,52 @@ +--- +layout: 'okta' +page_title: 'Okta: okta_theme' +sidebar_current: 'docs-okta-datasource-theme' +description: |- + Get a single Theme of a Brand of an Okta Organization. +--- + +# okta_theme + +Use this data source to retrieve a +[Theme](https://developer.okta.com/docs/reference/api/brands/#theme-response-object) +of a brand for an Okta orgnanization. + +## Example Usage + +```hcl +data "okta_brands" "test" { +} + +data "okta_themes" "test" { + brand_id = tolist(data.okta_brands.test.brands)[0].id +} + +data "okta_theme" "test" { + brand_id = tolist(data.okta_brands.test.brands)[0].id + theme_id = tolist(data.okta_themes.test.themes)[0].id +} +``` + +## Arguments Reference + +- `brand_id` - (Required) Brand ID +- `theme_id` - (Required) Theme ID + +## Attributes Reference + +Related Okta API [Theme Response Object](https://developer.okta.com/docs/reference/api/brands/#theme-response-object) + +- `id` - Theme URL +- `logo` - Logo URL +- `favicon` - Favicon URL +- `background_image` - Background image URL +- `primary_color_hex` - Primary color hex code +- `primary_color_contrast_hex` - Primary color contrast hex code +- `secondary_color_hex` - Secondary color hex code +- `secondary_color_contrast_hex` Secondary color contrast hex code +- `sign_in_page_touch_point_variant` - (Enum) Variant for the Okta Sign-In Page (`OKTA_DEFAULT`, `BACKGROUND_SECONDARY_COLOR`, `BACKGROUND_IMAGE`) +- `end_user_dashboard_touch_point_variant` - (Enum) Variant for the Okta End-User Dashboard (`OKTA_DEFAULT`, `WHITE_LOGO_BACKGROUND`, `FULL_THEME`, `LOGO_ON_FULL_WHITE_BACKGROUND`) +- `error_page_touch_point_variant` - (Enum) Variant for the error page (`OKTA_DEFAULT`, `BACKGROUND_SECONDARY_COLOR`, `BACKGROUND_IMAGE`) +- `email_template_touch_point_variant` - (Enum) Variant for email templates (`OKTA_DEFAULT`, `FULL_THEME`) +- `links` - Link relations for this object - JSON HAL - Discoverable resources related to the brand diff --git a/website/docs/d/themes.html.markdown b/website/docs/d/themes.html.markdown new file mode 100644 index 000000000..08e7e0004 --- /dev/null +++ b/website/docs/d/themes.html.markdown @@ -0,0 +1,33 @@ +--- +layout: 'okta' +page_title: 'Okta: okta_themes' +sidebar_current: 'docs-okta-datasource-themes' +description: |- +Get Themes of a Brand of an Okta Organization. +--- + + +# okta_themes + +Use this data source to retrieve +[Themes](https://developer.okta.com/docs/reference/api/brands/#theme-response-object) +of a brand for an Okta orgnanization. + +## Example Usage + +```hcl +data "okta_brands" "test" { +} + +data "okta_themes" "example" { + brand_id = tolist(data.okta_brands.test.brands)[0].id +} +``` + +## Argument Reference + +- `brand_id` - (Required) Brand ID + +## Attribute Reference + +- `themes` - List of `okta_theme` belonging to the brand. diff --git a/website/okta.erb b/website/okta.erb index a8382a2e2..757048493 100644 --- a/website/okta.erb +++ b/website/okta.erb @@ -88,6 +88,12 @@ > okta_policy + > + okta_theme + + > + okta_themes + > okta_user From 15bbfcf9ea2a9412b239f03c609e419d8011c26e Mon Sep 17 00:00:00 2001 From: Mike Mondragon Date: Tue, 10 May 2022 11:06:16 -0700 Subject: [PATCH 2/8] DRY up brand/brands --- okta/brand.go | 33 ++++++++++------------------- okta/data_source_okta_brand.go | 11 +++++++++- okta/data_source_okta_brand_test.go | 2 +- okta/data_source_okta_brands.go | 13 ++---------- website/docs/d/brand.html.markdown | 2 ++ 5 files changed, 26 insertions(+), 35 deletions(-) diff --git a/okta/brand.go b/okta/brand.go index 5b93ff886..80fb59cf1 100644 --- a/okta/brand.go +++ b/okta/brand.go @@ -53,10 +53,10 @@ func suppressDuringCreate(k, old, new string, d *schema.ResourceData) bool { } var brandDataSourceSchema = map[string]*schema.Schema{ - "brand_id": { + "id": { Type: schema.TypeString, - Required: true, - Description: "Brand ID", + Computed: true, + Description: "The ID of the Brand", }, "custom_privacy_policy_url": { Type: schema.TypeString, @@ -76,31 +76,20 @@ var brandDataSourceSchema = map[string]*schema.Schema{ } var brandsDataSourceSchema = map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, + "brands": { + Type: schema.TypeSet, Computed: true, - Description: "Brand ID", - }, - "custom_privacy_policy_url": { - Type: schema.TypeString, - Computed: true, - Description: "Custom privacy policy URL", - }, - "links": { - Type: schema.TypeString, - Computed: true, - Description: "Link relations for this object - JSON HAL - Discoverable resources related to the brand", - }, - "remove_powered_by_okta": { - Type: schema.TypeBool, - Computed: true, - Description: `Removes "Powered by Okta" from the Okta-hosted sign-in page and "© 2021 Okta, Inc." from the Okta End-User Dashboard`, + Description: "List of `okta_brand` belonging to the organization", + Elem: &schema.Resource{ + Schema: brandDataSourceSchema, + }, }, } func flattenBrand(brand *okta.Brand) map[string]interface{} { attrs := map[string]interface{}{} - // NOTE: explicitly set defaults on brand + + attrs["id"] = brand.Id attrs["custom_privacy_policy_url"] = "" if brand.CustomPrivacyPolicyUrl != "" { attrs["custom_privacy_policy_url"] = brand.CustomPrivacyPolicyUrl diff --git a/okta/data_source_okta_brand.go b/okta/data_source_okta_brand.go index a6eeaecb3..3f6b13252 100644 --- a/okta/data_source_okta_brand.go +++ b/okta/data_source_okta_brand.go @@ -11,7 +11,16 @@ import ( func dataSourceBrand() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceBrandRead, - Schema: brandDataSourceSchema, + Schema: buildSchema( + map[string]*schema.Schema{ + "brand_id": { + Type: schema.TypeString, + Required: true, + Description: "Brand ID", + }, + }, + brandDataSourceSchema, + ), } } diff --git a/okta/data_source_okta_brand_test.go b/okta/data_source_okta_brand_test.go index 70c2943b8..b57b3d21a 100644 --- a/okta/data_source_okta_brand_test.go +++ b/okta/data_source_okta_brand_test.go @@ -20,7 +20,7 @@ func TestAccDataSourceOktaBrand_read(t *testing.T) { Config: config, Destroy: false, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.okta_brand.example", "brand_id"), + resource.TestCheckResourceAttrSet("data.okta_brand.example", "id"), resource.TestCheckResourceAttrSet("data.okta_brand.example", "links"), ), }, diff --git a/okta/data_source_okta_brands.go b/okta/data_source_okta_brands.go index 65671acdb..7cb71ee2c 100644 --- a/okta/data_source_okta_brands.go +++ b/okta/data_source_okta_brands.go @@ -10,16 +10,7 @@ import ( func dataSourceBrands() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceBrandsRead, - Schema: map[string]*schema.Schema{ - "brands": { - Type: schema.TypeSet, - Computed: true, - Description: "List of `okta_brand` belonging to the organization", - Elem: &schema.Resource{ - Schema: brandsDataSourceSchema, - }, - }, - }, + Schema: brandsDataSourceSchema, } } @@ -37,7 +28,7 @@ func dataSourceBrandsRead(ctx context.Context, d *schema.ResourceData, m interfa arr[i] = rawMap } brandDataSource := &schema.Resource{ - Schema: brandResourceSchema, + Schema: brandDataSourceSchema, } _ = d.Set("brands", schema.NewSet(schema.HashResource(brandDataSource), arr)) diff --git a/website/docs/d/brand.html.markdown b/website/docs/d/brand.html.markdown index 7a56c33d0..a505b5cfa 100644 --- a/website/docs/d/brand.html.markdown +++ b/website/docs/d/brand.html.markdown @@ -27,6 +27,8 @@ data "okta_brand" "test" { ## Attributes Reference +- `id` - Brand ID + - `custom_privacy_policy_url` - Custom privacy policy URL - `links` - Link relations for this object - JSON HAL - Discoverable resources related to the brand From b93bee96ad66103363768ae51442205b59f50588 Mon Sep 17 00:00:00 2001 From: Mike Mondragon Date: Tue, 10 May 2022 13:24:24 -0700 Subject: [PATCH 3/8] Refine email_template/email_templates --- okta/data_source_okta_email_template.go | 11 ++++++++++- okta/data_source_okta_email_templates.go | 11 ++++++++++- okta/email_template.go | 10 ---------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/okta/data_source_okta_email_template.go b/okta/data_source_okta_email_template.go index cbb9534a0..fc9354585 100644 --- a/okta/data_source_okta_email_template.go +++ b/okta/data_source_okta_email_template.go @@ -12,7 +12,16 @@ import ( func dataSourceEmailTemplate() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceEmailTemplateRead, - Schema: emailTemplateDataSourceSchema, + Schema: buildSchema( + map[string]*schema.Schema{ + "brand_id": { + Type: schema.TypeString, + Required: true, + Description: "Brand ID", + }, + }, + emailTemplateDataSourceSchema, + ), } } diff --git a/okta/data_source_okta_email_templates.go b/okta/data_source_okta_email_templates.go index 5f31952fa..17c24b12b 100644 --- a/okta/data_source_okta_email_templates.go +++ b/okta/data_source_okta_email_templates.go @@ -12,7 +12,16 @@ import ( func dataSourceEmailTemplates() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceEmailTemplatesRead, - Schema: emailTemplatesDataSourceSchema, + Schema: buildSchema( + map[string]*schema.Schema{ + "brand_id": { + Type: schema.TypeString, + Required: true, + Description: "Brand ID", + }, + }, + emailTemplatesDataSourceSchema, + ), } } diff --git a/okta/email_template.go b/okta/email_template.go index 4162db622..ee9fd8aed 100644 --- a/okta/email_template.go +++ b/okta/email_template.go @@ -8,11 +8,6 @@ import ( ) var emailTemplatesDataSourceSchema = map[string]*schema.Schema{ - "brand_id": { - Type: schema.TypeString, - Required: true, - Description: "Brand ID", - }, "email_templates": { Type: schema.TypeSet, Computed: true, @@ -24,11 +19,6 @@ var emailTemplatesDataSourceSchema = map[string]*schema.Schema{ } var emailTemplateDataSourceSchema = map[string]*schema.Schema{ - "brand_id": { - Type: schema.TypeString, - Required: true, - Description: "Brand ID", - }, "name": { Type: schema.TypeString, Required: true, From e1dad183e337af69fd12d6344538a4e38f35317e Mon Sep 17 00:00:00 2001 From: Mike Mondragon Date: Tue, 10 May 2022 13:53:35 -0700 Subject: [PATCH 4/8] Refine email_customization/email_customizations --- .../okta_email_customization/datasource.tf | 4 +- okta/data_source_okta_email_customization.go | 23 ++++++++++- ...ta_source_okta_email_customization_test.go | 2 +- okta/data_source_okta_email_customizations.go | 18 ++++++++- ...a_source_okta_email_customizations_test.go | 2 +- okta/email_customization.go | 38 ++----------------- okta/resource_okta_email_customization.go | 6 +-- .../docs/d/email_customization.html.markdown | 4 +- 8 files changed, 49 insertions(+), 48 deletions(-) diff --git a/examples/okta_email_customization/datasource.tf b/examples/okta_email_customization/datasource.tf index a7aa80d55..70d76ab22 100644 --- a/examples/okta_email_customization/datasource.tf +++ b/examples/okta_email_customization/datasource.tf @@ -7,7 +7,7 @@ data "okta_email_customizations" "forgot_password" { } data "okta_email_customization" "forgot_password_en" { - customization_id = tolist(data.okta_email_customizations.forgot_password.email_customizations)[0].id brand_id = tolist(data.okta_brands.test.brands)[0].id template_name = "ForgotPassword" -} \ No newline at end of file + customization_id = tolist(data.okta_email_customizations.forgot_password.email_customizations)[0].id +} diff --git a/okta/data_source_okta_email_customization.go b/okta/data_source_okta_email_customization.go index b0079aa9c..439e7ff58 100644 --- a/okta/data_source_okta_email_customization.go +++ b/okta/data_source_okta_email_customization.go @@ -11,7 +11,26 @@ import ( func dataSourceEmailCustomization() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceEmailCustomizationRead, - Schema: emailCustomizationDataSourceSchema, + Schema: buildSchema( + map[string]*schema.Schema{ + "brand_id": { + Type: schema.TypeString, + Required: true, + Description: "Brand ID", + }, + "template_name": { + Type: schema.TypeString, + Required: true, + Description: "Template Name", + }, + "customization_id": { + Type: schema.TypeString, + Required: true, + Description: "The ID of the customization", + }, + }, + emailCustomizationDataSourceSchema, + ), } } @@ -37,7 +56,7 @@ func dataSourceEmailCustomizationRead(ctx context.Context, d *schema.ResourceDat } d.SetId(fmt.Sprintf("email_customization-%s-%s-%s", customization.Id, templateName.(string), brandID.(string))) - rawMap := flattenEmailCustomization(brandID.(string), templateName.(string), true, customization) + rawMap := flattenEmailCustomization(customization) err = setNonPrimitives(d, rawMap) if err != nil { return diag.Errorf("failed to set email customization properties: %v", err) diff --git a/okta/data_source_okta_email_customization_test.go b/okta/data_source_okta_email_customization_test.go index 0e391dea5..2b01f1493 100644 --- a/okta/data_source_okta_email_customization_test.go +++ b/okta/data_source_okta_email_customization_test.go @@ -27,7 +27,7 @@ func TestAccDataSourceOktaEmailCustomization_read(t *testing.T) { resource.TestCheckResourceAttrSet("data.okta_email_customization.forgot_password_en", "language"), resource.TestCheckResourceAttr("data.okta_email_customization.forgot_password_en", "language", "en"), resource.TestCheckResourceAttrSet("data.okta_email_customization.forgot_password_en", "is_default"), - resource.TestCheckResourceAttr("data.okta_email_customization.forgot_password_en", "is_default", "false"), + resource.TestCheckResourceAttr("data.okta_email_customization.forgot_password_en", "is_default", "true"), resource.TestCheckResourceAttrSet("data.okta_email_customization.forgot_password_en", "subject"), resource.TestCheckResourceAttr("data.okta_email_customization.forgot_password_en", "subject", "Stuff"), resource.TestCheckResourceAttrSet("data.okta_email_customization.forgot_password_en", "body"), diff --git a/okta/data_source_okta_email_customizations.go b/okta/data_source_okta_email_customizations.go index b88c932d8..acdacb4c4 100644 --- a/okta/data_source_okta_email_customizations.go +++ b/okta/data_source_okta_email_customizations.go @@ -11,7 +11,21 @@ import ( func dataSourceEmailCustomizations() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceEmailCustomizationsRead, - Schema: emailCustomizationsDataSourceSchema, + Schema: buildSchema( + map[string]*schema.Schema{ + "brand_id": { + Type: schema.TypeString, + Required: true, + Description: "Brand ID", + }, + "template_name": { + Type: schema.TypeString, + Required: true, + Description: "Template Name", + }, + }, + emailCustomizationsDataSourceSchema, + ), } } @@ -35,7 +49,7 @@ func dataSourceEmailCustomizationsRead(ctx context.Context, d *schema.ResourceDa d.SetId(fmt.Sprintf("email_customizations-%s-%s", templateName, brandID.(string))) arr := make([]interface{}, len(customizations)) for i, customization := range customizations { - rawMap := flattenEmailCustomization(brandID.(string), templateName.(string), true, customization) + rawMap := flattenEmailCustomization(customization) arr[i] = rawMap } diff --git a/okta/data_source_okta_email_customizations_test.go b/okta/data_source_okta_email_customizations_test.go index 67b47d1d6..bc672b20c 100644 --- a/okta/data_source_okta_email_customizations_test.go +++ b/okta/data_source_okta_email_customizations_test.go @@ -26,7 +26,7 @@ func TestAccDataSourceOktaEmailCustomizations_read(t *testing.T) { resource.TestCheckResourceAttrSet("data.okta_email_customizations.forgot_password", "email_customizations.0.language"), resource.TestCheckResourceAttr("data.okta_email_customizations.forgot_password", "email_customizations.0.language", "en"), resource.TestCheckResourceAttrSet("data.okta_email_customizations.forgot_password", "email_customizations.0.is_default"), - resource.TestCheckResourceAttr("data.okta_email_customizations.forgot_password", "email_customizations.0.is_default", "false"), + resource.TestCheckResourceAttr("data.okta_email_customizations.forgot_password", "email_customizations.0.is_default", "true"), resource.TestCheckResourceAttrSet("data.okta_email_customizations.forgot_password", "email_customizations.0.subject"), resource.TestCheckResourceAttr("data.okta_email_customizations.forgot_password", "email_customizations.0.subject", "Stuff"), resource.TestCheckResourceAttrSet("data.okta_email_customizations.forgot_password", "email_customizations.0.body"), diff --git a/okta/email_customization.go b/okta/email_customization.go index a206f7e96..7591c8d42 100644 --- a/okta/email_customization.go +++ b/okta/email_customization.go @@ -10,16 +10,6 @@ import ( ) var emailCustomizationsDataSourceSchema = map[string]*schema.Schema{ - "brand_id": { - Type: schema.TypeString, - Required: true, - Description: "Brand ID", - }, - "template_name": { - Type: schema.TypeString, - Required: true, - Description: "Template Name", - }, "email_customizations": { Type: schema.TypeSet, Computed: true, @@ -32,26 +22,11 @@ var emailCustomizationsDataSourceSchema = map[string]*schema.Schema{ } var emailCustomizationDataSourceSchema = map[string]*schema.Schema{ - "customization_id": { - Type: schema.TypeString, - Required: true, - Description: "The ID of the customization", - }, "id": { Type: schema.TypeString, Computed: true, Description: "The ID of the customization", }, - "brand_id": { - Type: schema.TypeString, - Required: true, - Description: "Brand ID", - }, - "template_name": { - Type: schema.TypeString, - Required: true, - Description: "Template Name", - }, "links": { Type: schema.TypeString, Computed: true, @@ -122,14 +97,9 @@ var emailCustomizationResourceSchema = map[string]*schema.Schema{ }, } -func flattenEmailCustomization(brandId, templateName string, isDataSource bool, emailCustomization *okta.EmailTemplateCustomization) map[string]interface{} { +func flattenEmailCustomization(emailCustomization *okta.EmailTemplateCustomization) map[string]interface{} { attrs := map[string]interface{}{} - if isDataSource { - attrs["customization_id"] = emailCustomization.Id - } attrs["id"] = emailCustomization.Id - attrs["brand_id"] = brandId - attrs["template_name"] = templateName attrs["language"] = emailCustomization.Language attrs["is_default"] = false if emailCustomization.IsDefault != nil { @@ -147,10 +117,8 @@ func hashEmailCustomization(v interface{}) int { var buf bytes.Buffer m := v.(map[string]interface{}) buf.WriteString(fmt.Sprintf( - "%s-%s-%s-%s-%s-", - m["customization_id"].(string), - m["brand_id"].(string), - m["template_name"].(string), + "%s-%s-%s-", + m["id"].(string), m["language"].(string), m["subject"].(string), )) diff --git a/okta/resource_okta_email_customization.go b/okta/resource_okta_email_customization.go index dfe7340b4..d95fad501 100644 --- a/okta/resource_okta_email_customization.go +++ b/okta/resource_okta_email_customization.go @@ -52,7 +52,7 @@ func resourceEmailCustomizationCreate(ctx context.Context, d *schema.ResourceDat } d.SetId(customization.Id) - rawMap := flattenEmailCustomization(brandID.(string), templateName.(string), false, customization) + rawMap := flattenEmailCustomization(customization) err = setNonPrimitives(d, rawMap) if err != nil { return diag.Errorf("failed to set new email customization properties: %v", err) @@ -76,7 +76,7 @@ func resourceEmailCustomizationRead(ctx context.Context, d *schema.ResourceData, return nil } - rawMap := flattenEmailCustomization(etcr.brandID, etcr.templateName, false, customization) + rawMap := flattenEmailCustomization(customization) err = setNonPrimitives(d, rawMap) if err != nil { return diag.Errorf("failed to set email customization properties: %v", err) @@ -111,7 +111,7 @@ func resourceEmailCustomizationUpdate(ctx context.Context, d *schema.ResourceDat } d.SetId(customization.Id) - rawMap := flattenEmailCustomization(etcr.brandID, etcr.templateName, false, customization) + rawMap := flattenEmailCustomization(customization) err = setNonPrimitives(d, rawMap) if err != nil { return diag.Errorf("failed to set email customization properties: %v", err) diff --git a/website/docs/d/email_customization.html.markdown b/website/docs/d/email_customization.html.markdown index 283441e51..4090215f4 100644 --- a/website/docs/d/email_customization.html.markdown +++ b/website/docs/d/email_customization.html.markdown @@ -24,17 +24,17 @@ data "okta_email_customizations" "forgot_password" { } data "okta_email_customization" "forgot_password_en" { - customization_id = tolist(data.okta_email_customizations.forgot_password.email_customizations)[0].id brand_id = tolist(data.okta_brands.test.brands)[0].id template_name = "ForgotPassword" + customization_id = tolist(data.okta_email_customizations.forgot_password.email_customizations)[0].id } ``` ## Arguments Reference -- `customization_id` - (Required) Customization ID - `brand_id` - (Required) Brand ID - `template_name` - (Required) Template Name +- `customization_id` - (Required) Customization ID ## Attributes Reference From 723e11456c91256e9cda0230da3924d5f99e67aa Mon Sep 17 00:00:00 2001 From: Mike Mondragon Date: Thu, 12 May 2022 12:50:00 -0700 Subject: [PATCH 5/8] Refactor local image file functions to be DRY --- okta/app.go | 28 +--------------------------- okta/app_test.go | 2 +- okta/utils.go | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/okta/app.go b/okta/app.go index 8d74bf17d..a3624bad4 100644 --- a/okta/app.go +++ b/okta/app.go @@ -2,15 +2,10 @@ package okta import ( "context" - "crypto/sha256" - "encoding/hex" "encoding/json" "errors" "fmt" - "io" - "log" "net/http" - "os" "strings" "sync" "time" @@ -92,7 +87,7 @@ var ( DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { return new == "" }, - StateFunc: logoStateFunc, + StateFunc: localFileStateFunc, }, "logo_url": { Type: schema.TypeString, @@ -724,24 +719,3 @@ func setAppUsersIDsAndGroupsIDs(ctx context.Context, d *schema.ResourceData, cli } return nil } - -func computeFileHash(filename string) string { - file, err := os.Open(filename) - if err != nil { - return "" - } - h := sha256.New() - if _, err := io.Copy(h, file); err != nil { - log.Fatal(err) - } - _ = file.Close() - return hex.EncodeToString(h.Sum(nil)) -} - -func logoStateFunc(val interface{}) string { - logoPath := val.(string) - if logoPath == "" { - return "" - } - return computeFileHash(logoPath) -} diff --git a/okta/app_test.go b/okta/app_test.go index 68f5b0e3c..5719f79f9 100644 --- a/okta/app_test.go +++ b/okta/app_test.go @@ -26,7 +26,7 @@ func TestLogoStateFunc(t *testing.T) { }, } for _, c := range cases { - result := logoStateFunc(c.input) + result := localFileStateFunc(c.input) if result != c.expected { t.Errorf("Error matching logo, expected %q, got %q, for file %q", c.expected, result, c.input) } diff --git a/okta/utils.go b/okta/utils.go index 1f0ca4e21..0a835e453 100644 --- a/okta/utils.go +++ b/okta/utils.go @@ -2,11 +2,15 @@ package okta import ( "context" + "crypto/sha256" + "encoding/hex" "encoding/json" "errors" "fmt" "io" + "log" "net/http" + "os" "strconv" "strings" "unicode" @@ -404,3 +408,39 @@ func buildEnum(ae []interface{}, elemType string) ([]interface{}, error) { } return enum, nil } + +// localFileStateFunc - helper for schema.Schema StateFunc checking if a the +// blob of a local file has changed - is not file path dependant. +func localFileStateFunc(val interface{}) string { + filePath := val.(string) + if filePath == "" { + return "" + } + return computeFileHash(filePath) +} + +// computeFileHash - equivalent to `shasum -a 256 filepath` +func computeFileHash(filename string) string { + file, err := os.Open(filename) + if err != nil { + return "" + } + h := sha256.New() + if _, err := io.Copy(h, file); err != nil { + log.Fatal(err) + } + _ = file.Close() + return hex.EncodeToString(h.Sum(nil)) +} + +// suppressDuringCreateFunc - attribute has changed assume this is a create and +// treat the properties as readers not caring about what would otherwise apear +// to be drift. +func suppressDuringCreateFunc(attribute string) func(k, old, new string, d *schema.ResourceData) bool { + return func(k, old, new string, d *schema.ResourceData) bool { + if d.HasChange(attribute) { + return true + } + return old == new + } +} From b5cdc5dd03a2a145f06afe2e05f3247596bd3dcf Mon Sep 17 00:00:00 2001 From: Mike Mondragon Date: Thu, 12 May 2022 12:54:01 -0700 Subject: [PATCH 6/8] DRY'd up to utils --- okta/brand.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/okta/brand.go b/okta/brand.go index 80fb59cf1..f3974ae9e 100644 --- a/okta/brand.go +++ b/okta/brand.go @@ -28,7 +28,7 @@ var brandResourceSchema = map[string]*schema.Schema{ Type: schema.TypeString, Optional: true, Description: "Custom privacy policy URL", - DiffSuppressFunc: suppressDuringCreate, + DiffSuppressFunc: suppressDuringCreateFunc("brand_id"), }, "links": { Type: schema.TypeString, @@ -40,18 +40,10 @@ var brandResourceSchema = map[string]*schema.Schema{ Optional: true, Default: false, Description: `Removes "Powered by Okta" from the Okta-hosted sign-in page and "© 2021 Okta, Inc." from the Okta End-User Dashboard`, - DiffSuppressFunc: suppressDuringCreate, + DiffSuppressFunc: suppressDuringCreateFunc("brand_id"), }, } -func suppressDuringCreate(k, old, new string, d *schema.ResourceData) bool { - // If brand_id has changed assume this is create and treat the properties as readers not caring about what would otherwise apear to be drift. - if d.HasChange("brand_id") { - return true - } - return old == new -} - var brandDataSourceSchema = map[string]*schema.Schema{ "id": { Type: schema.TypeString, From 2aa4f31bdd473816c84116416d076b9ce260a931 Mon Sep 17 00:00:00 2001 From: Mike Mondragon Date: Thu, 12 May 2022 13:15:31 -0700 Subject: [PATCH 7/8] Resource "okta_theme" --- examples/okta_theme/README.md | 4 + examples/okta_theme/basic.tf | 21 ++ examples/okta_theme/delete-images.tf | 22 ++ examples/okta_theme/import.tf | 11 + examples/okta_theme/okta_background_image.png | Bin 0 -> 1283 bytes examples/okta_theme/okta_favicon.png | Bin 0 -> 828 bytes examples/okta_theme/okta_logo.png | Bin 0 -> 6992 bytes examples/okta_theme/updated.tf | 18 ++ okta/data_source_okta_theme.go | 2 +- okta/data_source_okta_theme_test.go | 6 +- okta/data_source_okta_themes.go | 2 +- okta/provider.go | 1 + okta/resource_okta_theme.go | 219 ++++++++++++++++++ okta/resource_okta_theme_test.go | 137 +++++++++++ okta/theme.go | 131 ++++++++++- website/docs/d/theme.html.markdown | 14 +- website/docs/d/themes.html.markdown | 2 +- website/docs/r/brand.html.markdown | 4 + website/docs/r/theme.html.markdown | 88 +++++++ 19 files changed, 657 insertions(+), 25 deletions(-) create mode 100644 examples/okta_theme/basic.tf create mode 100644 examples/okta_theme/delete-images.tf create mode 100644 examples/okta_theme/import.tf create mode 100644 examples/okta_theme/okta_background_image.png create mode 100644 examples/okta_theme/okta_favicon.png create mode 100644 examples/okta_theme/okta_logo.png create mode 100644 examples/okta_theme/updated.tf create mode 100644 okta/resource_okta_theme.go create mode 100644 okta/resource_okta_theme_test.go create mode 100644 website/docs/r/theme.html.markdown diff --git a/examples/okta_theme/README.md b/examples/okta_theme/README.md index 0cbd5ee24..0106cde36 100644 --- a/examples/okta_theme/README.md +++ b/examples/okta_theme/README.md @@ -6,3 +6,7 @@ information can be found in the API documentation. - Example [datastore.tf](./datasource.tf) +- Example [basic.tf](./basic.tf) +- Example [updated.tf](./updated.tf) +- Example [import.tf](./import.tf) +- Example [delete-images.tf](./delete-images.tf) diff --git a/examples/okta_theme/basic.tf b/examples/okta_theme/basic.tf new file mode 100644 index 000000000..6479d0435 --- /dev/null +++ b/examples/okta_theme/basic.tf @@ -0,0 +1,21 @@ +# This example is part of the test harness. The okta_theme resource state has +# already been imported via import.tf + +data "okta_brands" "test" { +} + +resource "okta_theme" "example" { + brand_id = tolist(data.okta_brands.test.brands)[0].id + + logo = "../examples/okta_theme/okta_logo.png" + favicon = "../examples/okta_theme/okta_favicon.png" + background_image = "../examples/okta_theme/okta_background_image.png" + primary_color_hex = "#1662dd" + primary_color_contrast_hex = "#ffffff" + secondary_color_hex = "#ebebed" + secondary_color_contrast_hex = "#000000" + sign_in_page_touch_point_variant = "OKTA_DEFAULT" + end_user_dashboard_touch_point_variant = "OKTA_DEFAULT" + error_page_touch_point_variant = "OKTA_DEFAULT" + email_template_touch_point_variant = "OKTA_DEFAULT" +} diff --git a/examples/okta_theme/delete-images.tf b/examples/okta_theme/delete-images.tf new file mode 100644 index 000000000..21adc1254 --- /dev/null +++ b/examples/okta_theme/delete-images.tf @@ -0,0 +1,22 @@ +# This example is part of the test harness. The okta_theme resource state has +# already been imported via import.tf + +data "okta_brands" "test" { +} + +resource "okta_theme" "example" { + brand_id = tolist(data.okta_brands.test.brands)[0].id + + logo = "" + favicon = "" + background_image = "" + + primary_color_hex = "#1662ff" + primary_color_contrast_hex = "#ffffff" + secondary_color_hex = "#fbfbfd" + secondary_color_contrast_hex = "#000000" + sign_in_page_touch_point_variant = "OKTA_DEFAULT" + end_user_dashboard_touch_point_variant = "OKTA_DEFAULT" + error_page_touch_point_variant = "OKTA_DEFAULT" + email_template_touch_point_variant = "OKTA_DEFAULT" +} diff --git a/examples/okta_theme/import.tf b/examples/okta_theme/import.tf new file mode 100644 index 000000000..df8dd83d5 --- /dev/null +++ b/examples/okta_theme/import.tf @@ -0,0 +1,11 @@ +data "okta_brands" "test" { +} + +data "okta_themes" "test" { + brand_id = tolist(data.okta_brands.test.brands)[0].id +} + +resource "okta_theme" "example" { + brand_id = tolist(data.okta_brands.test.brands)[0].id + theme_id = tolist(data.okta_themes.test.themes)[0].id +} diff --git a/examples/okta_theme/okta_background_image.png b/examples/okta_theme/okta_background_image.png new file mode 100644 index 0000000000000000000000000000000000000000..766b92950facad700f746016e309bf8579551ea6 GIT binary patch literal 1283 zcmV+e1^oJnP)#%PT3T@#Io ziHgxTnwXl18Y76N5gU-26e-Zs3$V*=VXy44JG*l`28eqZ&g|^kCj8%a&gFOJo9}YI zr4|+zz*dOZ66#ihsj_AxgcJmLK@KMbj+Z0_u@vF3&`t|OQILS}{)023JTbdEbSpL< z;O3&dC?N$Qv~DqifEJeWc}xfDZLLj?Z4QR{2HpL3>4A2 z+y4AfZ@t?DiyEL97$J0LG5JNGe=NZ15evjJ#Mzc@&mE~T8pyK22%)}_(C5AWlpvP_ z&1r9~^{q2Lx1Gg~;=Ni?(D#1@KmB?7e^UVf*8|*p-8cQARHDO@+SJNd{Q+6ISL%j>@yy3RPVpJF<<#Jnr1;q{GvYnJYre*3SGx!1 zQDI0F#4$qX(%|A;Bwb_|15F&Lx3%oH*Sbsw8pe~-jd||RiKstZEZBOk2HW>k`aI_B zlLD^}#?t4zuCJ!?4g~=?@_^%9`;MJe#{3vX2#B(BIXOvb{A+_7@twNu}WYArjt zzxt)ex6@RyqT;r*@1EV|vNG7wR7M`0jA6hLPMBW8$6U3IId^OaN$Qs}Z>90o6SZ2Y za_Dv}>teaRZZ9OYoVoLm$8M%|sT+E<$x-jd8{EH~O8ysDIj~lWp-A{xv$I6%y4#b7 z8|~Pkcv9k0k{TRIh}hXx6^x_g*WFNl*yKx65XWxIE=udyj&hXUeX~enQykkg>>1`Vyr8)eRoj6#Co{@eAW=G1 zQP8z%{Cq1*S&ft$yt~G%^(A|TmjrF=sWiQu`e$YZJLIt&DonH*T;pKfb^~_7s6TOe zER1w-T~2%#t^eAIKdXLw2LSj}Ebenu+@xF)aVV1s@5 zP8_>3l~F$VX{vuT)Um&M-_8n~nT7z!3Yv@XgOjn|kx(e1SrZ`yXIeZ|-fI=I?5iPuloZ;ls?FEJGH#?uWgyYLmJ zEHM;3-%;1vzzbN`EF?O;=p`b zEH76B02)1}H&6Q-v|BfwZgHb;>mHc@`)*t-AF1TD(5D`8cOLeb*b&UW3 literal 0 HcmV?d00001 diff --git a/examples/okta_theme/okta_favicon.png b/examples/okta_theme/okta_favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..b0190d1153f4aa1bf1c93a29a21177cf9a85a0ce GIT binary patch literal 828 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>-pV@q~bq&jJygtWhF;A#~PpDH#YGd_|n8(pS zrq=k1+n%<+yI8^0H~DwJ#;2x4LGFOQ#gT^FzKMK#^|m%h*2h%m*xq|TqW?4Qc_Mgc z^);mop!-!zTq89-8f8yaN z4Aam!<$wB&=hGktW@T=@WNu+)VeiQz%)$yT4JL7El@#&;eiL#QMHul-~&xMbNy;m6` zb8&F!sg>oVb$zmTa!7oprgQcrUx01A9oHCr`1uI`bmXLpz2faT4z92Rv?d;^EUm6+W@z z4MN(~&)g&x|M0pDu02s=J|bS_;@1({q7$dY;Mw9B)dGt|p#HUqDD}~arbD1Vx8;0r zlJX`E8X_8W=-UYOUP3~mo5-sMM(qt-5Hpv6+V3v_4J6Q~oGn_(FZ0e!D@BESsWt@) zw(tWY%syHE>X_7RRoq~=5+tDz439qaJ+m6lcw}g;s{N5HAR=|F`nXqM+N;d|$qBKx z7o2C~=;^mij|w4$2{HvEx$cQ)<4xs?D4OS5y-c~k^lg{jA9>BTf19t}uzndq@K&Nf zd@DB}?vV!rDJ0zD)x7F`6R_tg5`D)FpgNfdlQ_@p=)Gi1E4g}IeJqHeu^YP9XSNX} z3W~NF94GE`5>V%8oQD&ms6ulWl;>n2>XJDUEAMOUvo7o4u4GsuWQl{o=Dz;Mpp9x zTYaeov>-3{qb(f~4~8J*FoXY{)qHTc?C(Yz)B;ebkZhpZgg|SDkVPqt9-HQhI=8lfiTDKOxb(tY>ZJFI{&bVE0=* z$g-yor=P>ZHJ+m6$0{}%M;f$|HFP;pyxZqW_7X=&Avw%uvB-yW)Dm-QKya#rDQ3Yi zEvs;v2U?4!x*b`oju+zF4n865&{wOrW4yv7zYEqvN~`ePi5o26L2A|Yv_0*$<6+4U zHRW;JgVOfBLks&8PQHIMc~3fhHVv?u5U|%~q~3MVJI0$?*-PMmnP`%?f{b@nWX zg&p%nnT?^TM9-t%o8$_0#(FiF?2>TUOv=-&p1yWn7}&^adcksGGtD50qBB?3R!=es zK{)G8=lo#E^r;44aHfsZ8>S5H>K_toyZdUuhCa9IW%^vO>^h{4(HrJg2Kl)YuU6G7 z*j5~WFaf_qr(4rKJmc2vdE&ZCg2j;A&D!8SiIfTuA$4vP(cDr!|9Es{q#$C6;3&^G z9F}bMV2UO-qU+1N!@}``oO7CHwlu7nZ%=Z!C-dk{*H_u(dF!m=m9N{bEN9NZ9;VG2 zzO9-;DE*_8We)Y#>X@vs?i;FwyK}oZ`oJh*5MJ|6-ja`PTfX;(W0DjVs%_p7?ljl@ zegEi1&mDHpjVo9mxSQA#6;NJ3N)%)Jo!d#X5G=CDw-ph6qAV5rV1&8j*hH)mSv=bm zjur`#(*!IJ_*?zqG-pe6U9Uo2xJp-fP|*3+d;SP9t19BMmUj zKK1jbc0)91Z~#{>?O>?5Y;MUoI$ltlT0TeM!+0Z;e%7|}4SwCm9|imgdt#>eeqdg~ zMG7Wf=pK5Tgnz3hx=+F-(QI$5@QJM|ZL|3$pz6d=;V6Av&(WnQ?7Eg3XRK;@N13?s6L^?|du&blWVh$e9jG;u4 zMpfs=WOm~;ZF)raWNirrG9T~@X&cDr#D<&`YX^*;T>b!eU(kq9T`5Pmf+rBsR-Rty zm_v)6j|h9k)r&6T;t1E$6scL#`=)`#yxY&mPF|BSjd`ZKzI?zCA0R|j_dR&Y z(`%gzwRF;G2-ny_9#yxF^uiAAHz#4(miD#IhAsqmX)HCG-WNs z)@+@-m^G()xvd%Q^M!!$rE^E`xK6E=7aeaoM)GOr4sGw53$4#{OnPsd`?PG6&c|9;tG2sB&RTFMM?ZZ(gb5V(K{N$o?)Ur95D>t4Tsy z_fu4uWH8*6ulrH{G^=rZo&{==@{5=}0ojh3jLu)E@t;QE@Dn>0$5a^=WD@~o`C5ru z-6P3$+aVWuG2$Bkixk78=iT(O!U3Sru%A!Hc%GS;@3z7JLnyw~JWD`)vg+e-Ms(fz z({J1mjVQ8wx3GwoJTH>1?ryMB{mHrJP--Aul^8BrkIzSvQQqF!q^EW2Bl$4f_kYB) zzhh<#TuT?KE2kHik>wjw{L8>f5qe{8NTB?w8J? zr^P?2j-MJ1ttSy!XYmY;b+$z=UV{Xtzlu%8%#7i&XMuyRYk{;aj$flu>VjOYS8V6T z+8){Dk8a~$XFARvgx#IqRks$~S>Jwu=`bt$QU7$h`19!*{h_qS(<{57)OiI*RiduX z=2}<9Xzt#dwUi)Vca3+p6b`u&R-yum&xt?4nTC^on5maer{Ho z#Q6n}6(|FVS}lQ3s--SAD_y=*;3wbXST<^FMM!V*vFrDa_GOT)x`q_2pyWzbv{2(s zP!7&#?`8XWrr#jEsrGoFOwdGjgxIdg(a;%oW)&BX?F%LS@&mj-d8IVFtBDf`8iXMt z-5L)J^$d{06GHe_Zkq*wWk)hxpf`{81lq5IV9e|xh%iJXBKFc+{&$P-it>*jk_7Y2 z*m-xW;IN|m`5R5y#cA< zO6!{F7Q5YV7-op#B@2`d`Vv~klD~VV`smmw#HW~=UChrjd!z?q|4!6x_OmS^OE^m^ z8@Rd@U6}sxb&)xdw!cFyB{0m@9`q;gG6Y6DzyxK7mb2W5yG}5nJietGu*>QM6O1*j z2HH$*cFR4-S~;KU# zN6uw=@T`#cShd=yG4MXQ4mpI}szHSF-^Q13_J({d&I;;hO6-Ee-b$hM(T0K=2QpJk z;|CFrOBG&psoZJYGQRmB=QQr_H=)$fwS-b>23)HT>`6AXsupKD*f$lI%ik)X4bjHj z#b|N2E~eec)s9*{TBQ#?DZi2D#dPC_6#@kt2wxUkGP{GYT1r|Kk^0b?cb*f+g<>o- zESntUM{-k4UIsNV3A{rBc-H&RcE}_Iq5@eA@UyJ24+5TeWu{Rp?{KU|c># z{F=LV7;U)aa7K36Qqc&!;p=AXyHgbwmeYJ<-OgS2DCrilhlSUFFDsj2x*Pz=ZXp-U z*SFS_Mo##aG!N^kW<7C>%^=?ch?!Zc4E02Z>L=Blu=2M+W4yhAR7J62ComACD#;{vwqdJCuQ^NI{0#6GlF+y$g?^Vayh$lF)e$Bb-sraWYWBqFHVsbPI zgAKd&|NB?`nTYdymT2RG{pTqJKvV3|fZsF^Zb>5`C_MFg;#&t;H6uxUS?L{FO>inyCBcblk( zwBbQZrp+Hv0?3EsR%_H2NKWoV?m_OShlPeCnfXzk^&ilaI-A$aDtZ&NMX&!48n^;(vaoQAx>@ww*DrV70XL9?sA}}1g{^WC zv@e>T1usFYEBMpz4{VvSK|&AZtSV=IB<~0BqwV-L&ll)lsHhO1dUV7$PH;iOYY}r% zG!;GUW+Dz`=7W%L5w!w9eBlibmuavuffQQzpZ$URb&M}_mvTrwobX<`XPq49A^wKP zbQ1uWLI$F&(TnE>@ydxfBy5Wmnx&RMfRYAyooQk4i}-W_5rnez{q~xr3;;$Im;)Axk#EQ!*WFFRTrRS-zWqdk;g~c zwVptdx(x;7`!}PG-$M{aFTAKcy!|1ozLNNSNVtQgeLuMNCMbYW9b)*_p-6Bwz8Rza)%CBAgB^1K6QJClv0 z>*4+&qw*I&KULaF0MjbmaJ^W_K@>FoD%+t_U;bp}S?Sk38+g(^MCRItQjD(Rl&99#Lko+L z(0G~27V~m<@-;HuHv#53yUsbm|2b|M;-^mb9lGQ3?aX$t)bF7N{WNEky|U1+AU~KC z4>Xa0Tk&ITP0MR0J0U~|;QH@f#!EeRC2YY9VVTUxXwqQ$7f}ehw2DhUU&xD{Isx;Y zdj%DHI(=v-NJuFc+1G_x+=3fzr#2N1kgGZ0TPt2ePK-{+>Yc~J4w#7#-P6CyN`j5` zqO3Z#_C1`hItH<6+2O6)R^VfBFyi>dBU=OW+3vZgKUw(ex*YhA&h;;gc-HzI&lhw< zOIF3)k1#gglSnYh>I78<3G%%?)yC0GGJGJk(oawX zZmNP>kB(NaDQ9lUI-%#tYlJuX-iu}R>DUNa=HK_*Km5 zK;bYQg5Bs_@-z8B;MfUiXYO(Ktrt~B#?jp0k0#AYFr8-Y$YliuM58`NYGJcmHo(=# z!R?wcBEx-Hu2$V#P{uS9YSR`VL_P8~t{?c!)fM9vERokoCCHU6KW}ogBAo6vN!YWn zCBFxph%jf+X!Jb~#Bx|yE&a(Qk?{x&Rw9uG*5BEdk7cgt2pc*Vqdr( zl~uhlY;d@EZjT?4yZI|~kGLM>#-uRwkUKAHa0nvyp>FMC34ea;bm$jf+#JZPg1%j{ zO=>ASVIOZhp`DvL*WkP2I9|LpKKfjb$!gdfF1VH{vo}hA{hyiyp=cUjlWcMJY`+19 zO;D=qzpwAVw(8;X+M;2=)i_iwS>?(M;&w@u5q<@X`zm|aH7OV$Yd!FOJkbV|~JbP|hFEwk~^?8gvOSX;=f>rSB6kC+AiW{^+ zw5D~WdspmP-FG7EG3^fK^HRS}e>#I$`!*VLu>V4mi-n}YiL74#=9-~!tYPyudO?9= zE&wn(a(AK>$o+MS8_TFj_*U*cR$sL4oyk!9!4Q6ATsab#eolrqc7Ic#d4V!seq2-w9ovEM#?Jz>9bZPx?+x#erpfvBSS}yC zv+$m4`C$xCfVEQqVx%W4s0r6zfMC_I&^by>j8H+6W@oV_f{2$sex4sbH9BD*lfO5X z%yqT9I{s9Lrd>MpL&%ko)_KEVP@9&dW&y24;A+vcWkiS7H#Ok%&UE4>cvk!b$_=?+ z#XLG`zgohpP5rPhiRMwyaO0l;4X;n}!|F{F%Q>)MW+KI0`v>ZdvsZEPEe8mTZ0XQX z0SlNO$Oh}ey5LST-LNY`gqiil&7<6RvQzdTukWZcoCkit_jOGOvaPo31T#B*(|+`R zDLxvGkMS=(XnfExb2d@G`{$cC3 zYSncpP9-vjfDD(ks=NN_A$x2)oD{89V(wd(s*KblJb2;+H$3XaHK{hrpEGPI z0(Y6_JhDTsW`35Xf7WDnB!+@{Z}#cDoI!7U9GQ|l`0VcdEZ+f~Ts2z-x|5ze#cVOo zNFHDuZkH0R{f!PakQc9HK*_oQbG095j=IoS*vg{t*GAz|SN38-&TZTy(f2TtM~9$;F4z6HP|^N-r|`WZ z;cCLOde!4}Iq-u$xfVT__7^~#qP87cEY9c+gZzF7NVFD-0?qCB-gPp<;+5NGII}-Xcx`7o^Br{#t^av+{Nnw4KBMXOXyFvfNc&dpR^uIy~^88 zdIiQ5!Kf+zJ_0d}__xjg)qY+HgJ&4MY}f7YeacbI99-v)fbLHXlsL&U?j6i)*z)q%;Da=2GQHUjb)~3w99OOXa_gEcUE3y4mJD ze$NCM{8WgNM#QRmInR%Ng-2scs_*G4Ap@SlQm8Y;y3sirSSbHnM@0b-q?0#Qmei zS%-pgEO*De;184Le%5y51RYR(SO$ipu+o;A8F(kuxP-4#X?6==ykz2adY%)jg|jW?ziK#8PTv~e2qg^(_LYe& zvbO0_uT@>+&16@6AgBc@ui^wm%uE>HIT`;k>&7G=%o^B-9J6)2<-#WSTE=@pRNHT2 zL;pqDYCj2h*6dib=kpxMG^1N@(EqpP@e}%#=)W5(f~jG^>BpE0f{0}_=4;qU70LOl z<*r!%9LVy;x3mv#%KDQ;ZHm=?4}*~22j2B$ z+wUF*UM;`HJOVz3lNFG2$1d4)?GALqGGe;_qG1_NE`--tUseOm5jQapD{I!!H;sRz z@41V(3sA=4Jd=BW{rBFd2&puC+SAp&eR9&jEMwE^pZ=sf)5dJvJ;cGeyHl^X3r/") + } + brandID := parts[0] + themeID := parts[1] + + theme, _, err := getOktaClientFromMetadata(m).Brand.GetBrandTheme(ctx, brandID, themeID) + if err != nil { + return nil, fmt.Errorf("failed to get theme: %v", err) + } + + d.SetId(theme.Id) + rawMap := flattenTheme(brandID, theme) + err = setNonPrimitives(d, rawMap) + if err != nil { + return nil, fmt.Errorf("failed to set theme properties: %v", err) + } + + return []*schema.ResourceData{d}, nil +} + +func handleThemeLogo(ctx context.Context, d *schema.ResourceData, m interface{}, brandID, themeID string) error { + _, newPath := d.GetChange("logo") + if newPath == "" { + _, err := getOktaClientFromMetadata(m).Brand.DeleteBrandThemeLogo(ctx, brandID, themeID) + return err + } + _, _, err := getOktaClientFromMetadata(m).Brand.UploadBrandThemeLogo(ctx, brandID, themeID, newPath.(string)) + return err +} + +func handleThemeFavicon(ctx context.Context, d *schema.ResourceData, m interface{}, brandID, themeID string) error { + _, newPath := d.GetChange("favicon") + if newPath == "" { + _, err := getOktaClientFromMetadata(m).Brand.DeleteBrandThemeFavicon(ctx, brandID, themeID) + return err + } + _, _, err := getOktaClientFromMetadata(m).Brand.UploadBrandThemeFavicon(ctx, brandID, themeID, newPath.(string)) + return err +} + +func handleThemeBackgroundImage(ctx context.Context, d *schema.ResourceData, m interface{}, brandID, themeID string) error { + _, newPath := d.GetChange("background_image") + if newPath == "" { + _, err := getOktaClientFromMetadata(m).Brand.DeleteBrandThemeBackgroundImage(ctx, brandID, themeID) + return err + } + _, _, err := getOktaClientFromMetadata(m).Brand.UploadBrandThemeBackgroundImage(ctx, brandID, themeID, newPath.(string)) + return err +} diff --git a/okta/resource_okta_theme_test.go b/okta/resource_okta_theme_test.go new file mode 100644 index 000000000..c8183894c --- /dev/null +++ b/okta/resource_okta_theme_test.go @@ -0,0 +1,137 @@ +package okta + +import ( + "errors" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccResourceOktaTheme_import_update(t *testing.T) { + ri := acctest.RandInt() + mgr := newFixtureManager(theme) + config := mgr.GetFixtures("basic.tf", ri, t) + updatedConfig := mgr.GetFixtures("updated.tf", ri, t) + importConfig := mgr.GetFixtures("import.tf", ri, t) + deleteImagesConfig := mgr.GetFixtures("delete-images.tf", ri, t) + + // okta_theme is read and update only, so set up the test by importing the theme first + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProvidersFactories, + CheckDestroy: func(s *terraform.State) error { + // theme api doens't have real delete for a theme + return nil + }, + Steps: []resource.TestStep{ + { + // this is set up only for import state test, ignore check as import.tf is for testing + ExpectNonEmptyPlan: true, + Config: importConfig, + }, + { + ResourceName: "okta_theme.example", + ImportState: true, + ImportStateIdFunc: func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources["okta_theme.example"] + if !ok { + return "", fmt.Errorf("failed to find %s", "okta_theme.example") + } + + brandID := rs.Primary.Attributes["brand_id"] + themeID := rs.Primary.Attributes["theme_id"] + + return fmt.Sprintf("%s/%s", brandID, themeID), nil + }, + ImportStateCheck: func(s []*terraform.InstanceState) error { + // import should only net one theme + if len(s) != 1 { + return errors.New("failed to import into resource into state") + } + // simple check + if len(s[0].Attributes["links"]) <= 2 { + return fmt.Errorf("there should more than two attributes set on the instance %+v", s[0].Attributes) + + } + return nil + }, + }, + { + Config: config, + Destroy: false, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("okta_theme.example", "id"), + resource.TestCheckResourceAttrSet("okta_theme.example", "logo_url"), + resource.TestCheckResourceAttrSet("okta_theme.example", "favicon_url"), + // resource.TestCheckResourceAttrSet("okta_theme.example", "background_image_url"), // background image is null on new orgs, skip check + resource.TestCheckResourceAttrSet("okta_theme.example", "primary_color_hex"), + resource.TestCheckResourceAttr("okta_theme.example", "primary_color_hex", "#1662dd"), + resource.TestCheckResourceAttrSet("okta_theme.example", "primary_color_contrast_hex"), + resource.TestCheckResourceAttrSet("okta_theme.example", "secondary_color_hex"), + resource.TestCheckResourceAttr("okta_theme.example", "secondary_color_hex", "#ebebed"), + resource.TestCheckResourceAttrSet("okta_theme.example", "secondary_color_contrast_hex"), + resource.TestCheckResourceAttrSet("okta_theme.example", "sign_in_page_touch_point_variant"), + resource.TestCheckResourceAttr("okta_theme.example", "sign_in_page_touch_point_variant", "OKTA_DEFAULT"), + resource.TestCheckResourceAttrSet("okta_theme.example", "end_user_dashboard_touch_point_variant"), + resource.TestCheckResourceAttr("okta_theme.example", "end_user_dashboard_touch_point_variant", "OKTA_DEFAULT"), + resource.TestCheckResourceAttrSet("okta_theme.example", "error_page_touch_point_variant"), + resource.TestCheckResourceAttr("okta_theme.example", "error_page_touch_point_variant", "OKTA_DEFAULT"), + resource.TestCheckResourceAttrSet("okta_theme.example", "email_template_touch_point_variant"), + resource.TestCheckResourceAttr("okta_theme.example", "email_template_touch_point_variant", "OKTA_DEFAULT"), + resource.TestCheckResourceAttrSet("okta_theme.example", "links"), + ), + }, + { + Config: updatedConfig, + Destroy: false, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("okta_theme.example", "id"), + resource.TestCheckResourceAttrSet("okta_theme.example", "logo_url"), + resource.TestCheckResourceAttrSet("okta_theme.example", "favicon_url"), + //resource.TestCheckResourceAttrSet("okta_theme.example", "background_image_url"), // background_image_url not present when dashboard is OKTA_DEFAULT + resource.TestCheckResourceAttrSet("okta_theme.example", "primary_color_hex"), + resource.TestCheckResourceAttr("okta_theme.example", "primary_color_hex", "#1662ff"), + resource.TestCheckResourceAttrSet("okta_theme.example", "primary_color_contrast_hex"), + resource.TestCheckResourceAttrSet("okta_theme.example", "secondary_color_hex"), + resource.TestCheckResourceAttr("okta_theme.example", "secondary_color_hex", "#fbfbfd"), + resource.TestCheckResourceAttrSet("okta_theme.example", "secondary_color_contrast_hex"), + resource.TestCheckResourceAttrSet("okta_theme.example", "sign_in_page_touch_point_variant"), + resource.TestCheckResourceAttr("okta_theme.example", "sign_in_page_touch_point_variant", "OKTA_DEFAULT"), + resource.TestCheckResourceAttrSet("okta_theme.example", "end_user_dashboard_touch_point_variant"), + resource.TestCheckResourceAttr("okta_theme.example", "end_user_dashboard_touch_point_variant", "OKTA_DEFAULT"), + resource.TestCheckResourceAttrSet("okta_theme.example", "error_page_touch_point_variant"), + resource.TestCheckResourceAttr("okta_theme.example", "error_page_touch_point_variant", "OKTA_DEFAULT"), + resource.TestCheckResourceAttrSet("okta_theme.example", "email_template_touch_point_variant"), + resource.TestCheckResourceAttr("okta_theme.example", "email_template_touch_point_variant", "OKTA_DEFAULT"), + resource.TestCheckResourceAttrSet("okta_theme.example", "links"), + ), + }, + { + Config: deleteImagesConfig, + Destroy: false, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("okta_theme.example", "id"), + + // TODO find a better way to test delete of logo, favicon, background image, given: + // Deletes a Theme logo. The org then uses the Okta default logo. + // Deletes a Theme favicon. The org then uses the Okta default favicon. + // Deletes a Theme background image + // However, this still has fair coverage of delete as if their a failure the plan will fail. + /* + resource.TestCheckResourceAttrSet("okta_theme.example", "logo_url"), + resource.TestCheckResourceAttr("okta_theme.example", "logo_url", ""), + resource.TestCheckResourceAttrSet("okta_theme.example", "favicon_url"), + resource.TestCheckResourceAttr("okta_theme.example", "favicon_url", ""), + resource.TestCheckResourceAttrSet("okta_theme.example", "background_image_url"), + resource.TestCheckResourceAttr("okta_theme.example", "background_image_url", ""), + */ + + resource.TestCheckResourceAttrSet("okta_theme.example", "links"), + ), + }, + }, + }) +} diff --git a/okta/theme.go b/okta/theme.go index 5b819fdc3..105b71da7 100644 --- a/okta/theme.go +++ b/okta/theme.go @@ -7,6 +7,119 @@ import ( "github.com/okta/okta-sdk-golang/v2/okta" ) +var themeResourceSchema = map[string]*schema.Schema{ + "brand_id": { + Type: schema.TypeString, + Required: true, + Description: "Brand ID", + }, + "theme_id": { + Type: schema.TypeString, + Optional: true, + Description: "Theme ID - Note: Okta API for theme only reads and updates therefore the okta_theme resource needs to act as a quasi data source. Do this by setting theme_id.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Brand ID", + }, + "logo": { + Type: schema.TypeString, + Optional: true, + Description: "Path to local file", + DiffSuppressFunc: suppressDuringCreateFunc("theme_id"), + StateFunc: localFileStateFunc, + }, + "logo_url": { + Type: schema.TypeString, + Computed: true, + Description: "Logo URL", + }, + "favicon": { + Type: schema.TypeString, + Optional: true, + Description: "Path to local file", + DiffSuppressFunc: suppressDuringCreateFunc("theme_id"), + StateFunc: localFileStateFunc, + }, + "favicon_url": { + Type: schema.TypeString, + Computed: true, + Description: "Favicon URL", + }, + "background_image": { + Type: schema.TypeString, + Optional: true, + Description: "Path to local file", + DiffSuppressFunc: suppressDuringCreateFunc("theme_id"), + StateFunc: localFileStateFunc, + }, + "background_image_url": { + Type: schema.TypeString, + Computed: true, + Description: "Background image URL", + }, + "primary_color_hex": { + Type: schema.TypeString, + //Required: true, + Optional: true, + Description: "Primary color hex code", + DiffSuppressFunc: suppressDuringCreateFunc("theme_id"), + }, + "primary_color_contrast_hex": { + Type: schema.TypeString, + Optional: true, + Description: "Primary color contrast hex code", + DiffSuppressFunc: suppressDuringCreateFunc("theme_id"), + }, + "secondary_color_hex": { + Type: schema.TypeString, + //Required: true, + Optional: true, + Description: "Secondary color hex code", + DiffSuppressFunc: suppressDuringCreateFunc("theme_id"), + }, + "secondary_color_contrast_hex": { + Type: schema.TypeString, + Optional: true, + Description: "Secondary color contrast hex code", + DiffSuppressFunc: suppressDuringCreateFunc("theme_id"), + }, + "sign_in_page_touch_point_variant": { + Type: schema.TypeString, + //Required: true, + Optional: true, + Description: "Variant for the Okta Sign-In Page (`OKTA_DEFAULT`, `BACKGROUND_SECONDARY_COLOR`, `BACKGROUND_IMAGE`)", + DiffSuppressFunc: suppressDuringCreateFunc("theme_id"), + }, + "end_user_dashboard_touch_point_variant": { + Type: schema.TypeString, + //Required: true, + Optional: true, + Description: "Variant for the Okta End-User Dashboard (`OKTA_DEFAULT`, `WHITE_LOGO_BACKGROUND`, `FULL_THEME`, `LOGO_ON_FULL_WHITE_BACKGROUND`)", + DiffSuppressFunc: suppressDuringCreateFunc("theme_id"), + }, + "error_page_touch_point_variant": { + Type: schema.TypeString, + //Required: true, + Optional: true, + Description: "Variant for the error page (`OKTA_DEFAULT`, `BACKGROUND_SECONDARY_COLOR`, `BACKGROUND_IMAGE`)", + DiffSuppressFunc: suppressDuringCreateFunc("theme_id"), + }, + "email_template_touch_point_variant": { + Type: schema.TypeString, + //Required: true, + Optional: true, + Description: "Variant for email templates (`OKTA_DEFAULT`, `FULL_THEME`)", + DiffSuppressFunc: suppressDuringCreateFunc("theme_id"), + }, + "links": { + Type: schema.TypeString, + Computed: true, + Description: "Link relations for this object - JSON HAL - Discoverable resources related to the email template", + }, +} + var themesDataSourceSchema = map[string]*schema.Schema{ "brand_id": { Type: schema.TypeString, @@ -29,17 +142,17 @@ var themeDataSourceSchema = map[string]*schema.Schema{ Computed: true, Description: "The ID of the theme", }, - "logo": { + "logo_url": { Type: schema.TypeString, Computed: true, Description: "Logo URL", }, - "favicon": { + "favicon_url": { Type: schema.TypeString, Computed: true, Description: "Favicon URL", }, - "background_image": { + "background_image_url": { Type: schema.TypeString, Computed: true, Description: "Background image URL", @@ -91,19 +204,17 @@ var themeDataSourceSchema = map[string]*schema.Schema{ }, } -func flattenTheme(brandID, themeID string, theme *okta.ThemeResponse) map[string]interface{} { +func flattenTheme(brandID string, theme *okta.ThemeResponse) map[string]interface{} { attrs := map[string]interface{}{} attrs["id"] = theme.Id if brandID != "" { attrs["brand_id"] = brandID } - if themeID != "" { - attrs["theme_id"] = themeID - } - attrs["logo"] = theme.Logo - attrs["favicon"] = theme.Favicon - attrs["background_image"] = theme.BackgroundImage + + attrs["logo_url"] = theme.Logo + attrs["favicon_url"] = theme.Favicon + attrs["background_image_url"] = theme.BackgroundImage attrs["primary_color_hex"] = theme.PrimaryColorHex attrs["primary_color_contrast_hex"] = theme.PrimaryColorContrastHex attrs["secondary_color_hex"] = theme.SecondaryColorHex diff --git a/website/docs/d/theme.html.markdown b/website/docs/d/theme.html.markdown index 54d4205a3..829acb531 100644 --- a/website/docs/d/theme.html.markdown +++ b/website/docs/d/theme.html.markdown @@ -18,13 +18,9 @@ of a brand for an Okta orgnanization. data "okta_brands" "test" { } -data "okta_themes" "test" { - brand_id = tolist(data.okta_brands.test.brands)[0].id -} - data "okta_theme" "test" { - brand_id = tolist(data.okta_brands.test.brands)[0].id - theme_id = tolist(data.okta_themes.test.themes)[0].id + brand_id = tolist(data.okta_brands.test.brands)[0].id + theme_id = tolist(data.okta_themes.test.themes)[0].id } ``` @@ -38,9 +34,9 @@ data "okta_theme" "test" { Related Okta API [Theme Response Object](https://developer.okta.com/docs/reference/api/brands/#theme-response-object) - `id` - Theme URL -- `logo` - Logo URL -- `favicon` - Favicon URL -- `background_image` - Background image URL +- `logo_url` - Logo URL +- `favicon_url` - Favicon URL +- `background_image_url` - Background image URL - `primary_color_hex` - Primary color hex code - `primary_color_contrast_hex` - Primary color contrast hex code - `secondary_color_hex` - Secondary color hex code diff --git a/website/docs/d/themes.html.markdown b/website/docs/d/themes.html.markdown index 08e7e0004..273c45a0f 100644 --- a/website/docs/d/themes.html.markdown +++ b/website/docs/d/themes.html.markdown @@ -20,7 +20,7 @@ data "okta_brands" "test" { } data "okta_themes" "example" { - brand_id = tolist(data.okta_brands.test.brands)[0].id + brand_id = tolist(data.okta_brands.test.brands)[0].id } ``` diff --git a/website/docs/r/brand.html.markdown b/website/docs/r/brand.html.markdown index 245a550d9..0648e9c8b 100644 --- a/website/docs/r/brand.html.markdown +++ b/website/docs/r/brand.html.markdown @@ -10,10 +10,14 @@ description: |- This resource allows you to get and update an Okta [Brand](https://developer.okta.com/docs/reference/api/brands/#brand-object). +Brands are can only be updated through the Okta API. Therefore this resource +only gets and updates a brand. + ## Example Usage ```hcl # resource has been imported into current state +# $ terraform import okta_brand.example resource "okta_brand" "example" { agree_to_custom_privacy_policy = true custom_privacy_policy_url = "https://example.com/privacy-policy" diff --git a/website/docs/r/theme.html.markdown b/website/docs/r/theme.html.markdown new file mode 100644 index 000000000..7e4514784 --- /dev/null +++ b/website/docs/r/theme.html.markdown @@ -0,0 +1,88 @@ +--- +layout: 'okta' +page_title: 'Okta: okta_theme' +sidebar_current: 'docs-okta-resource-theme' +description: |- + Gets, updates, a single Theme of a Brand of an Okta Organization. +--- + +# okta_theme + +This resource allows you to get and update an Okta +[Theme](https://developer.okta.com/docs/reference/api/brands/#theme-object). + +Themes are can only be updated through the Okta API. Therefore this resource +only gets and updates a theme. + +## Example Usage + +```hcl +data "okta_brands" "test" { +} + +# resource has been imported into current state: +# $ terraform import okta_theme.example +resource "okta_theme" "example" { + brand_id = tolist(data.okta_brands.test.brands)[0].id + logo = "path/to/logo.png" + favicon = "path/to/favicon.png" + background_image = "path/to/background.png" + primary_color_hex = "#1662dd" + secondary_color_hex = "#ebebed" + sign_in_page_touch_point_variant = "OKTA_DEFAULT" + end_user_dashboard_touch_point_variant = "OKTA_DEFAULT" + error_page_touch_point_variant = "OKTA_DEFAULT" + email_template_touch_point_variant = "OKTA_DEFAULT" +} +``` + +## Arguments Reference + +- `brand_id` - (Required) Brand ID +- `theme_id` - (Optional) Theme ID, used for read (faux-create) + +## Attributes Reference + +Related Okta API [Theme Response Object](https://developer.okta.com/docs/reference/api/brands/#theme-response-object) + +- `id` - (Read-Only) Theme URL +- `logo` - (Optional) Local path to logo file. Setting the value to the blank string `""` will delete the logo on the theme at Okta but will not delete the local file. +- `logo_url` - (Read-Only) Logo URL +- `favicon` - (Optional) Local path to favicon file. Setting the value to the blank string `""` will delete the favicon on the theme at Okta but will not delete the local file. +- `favicon_url` - (Read-Only) Favicon URL +- `background_image` - (Optional) Local path to background image file. Setting the value to the blank string `""` will delete the favicon on the theme at Okta but will not delete the local file. +- `background_image_url` - (Read-Only) Background image URL +- `primary_color_hex` - (Required) Primary color hex code +- `primary_color_contrast_hex` - (Optional) Primary color contrast hex code +- `secondary_color_hex` - (Required) Secondary color hex code +- `secondary_color_contrast_hex` (Optional) Secondary color contrast hex code +- `sign_in_page_touch_point_variant` - (Required) Variant for the Okta Sign-In Page. Valid values: (`OKTA_DEFAULT`, `BACKGROUND_SECONDARY_COLOR`, `BACKGROUND_IMAGE`) +- `end_user_dashboard_touch_point_variant` - (Required) Variant for the Okta End-User Dashboard. Valid values: (`OKTA_DEFAULT`, `WHITE_LOGO_BACKGROUND`, `FULL_THEME`, `LOGO_ON_FULL_WHITE_BACKGROUND`) +- `error_page_touch_point_variant` - (Required) Variant for the error page. Valid values: (`OKTA_DEFAULT`, `BACKGROUND_SECONDARY_COLOR`, `BACKGROUND_IMAGE`) +- `email_template_touch_point_variant` - (Required) Variant for email templates. Valid values: (`OKTA_DEFAULT`, `FULL_THEME`) +- `links` - Link relations for this object - JSON HAL - (Read-Only) Discoverable resources related to the brand + +[Variants for the Okta Sign-In Page](https://developer.okta.com/docs/reference/api/brands/#variants-for-the-okta-sign-in-page): + +| Enum Value | Description | +| ----------- | ------------- | +| OKTA_DEFAULT | Use the Okta logo, Okta favicon with no background image, and the Okta colors on the Okta Sign-In Page. | +| BACKGROUND_SECONDARY_COLOR | Use the logo and favicon from Theme with the secondaryColorHex as the background color for the Okta Sign-In Page. | +| BACKGROUND_IMAGE | Use the logo, favicon, and background image from Theme. | + +[Variants for the Okta End-User Dashboard](https://developer.okta.com/docs/reference/api/brands/#variants-for-the-okta-end-user-dashboard): + +| Enum Value | Description | +| ----------- | ------------- | +| OKTA_DEFAULT | Use the Okta logo and Okta favicon with a white background color for the logo and the side navigation bar background color. | +| WHITE_LOGO_BACKGROUND | Use the logo from Theme with a white background color for the logo, use favicon from Theme, and use primaryColorHex for the side navigation bar background color. | +| FULL_THEME | Use the logo from Theme, primaryColorHex for the logo and the side navigation bar background color, and use favicon from Theme | +| LOGO_ON_FULL_WHITE_BACKGROUND | Use the logo from Theme, white background color for the logo and the side navigation bar background color, and use favicon from Theme | + +## Import + +An Okta Brand can be imported via the ID. + +``` +$ terraform import okta_theme.example <brand id>/<theme id> +``` From 2ea0bc97dec299ed8f74caf56baba03dadfca641 Mon Sep 17 00:00:00 2001 From: Mike Mondragon Date: Fri, 13 May 2022 12:52:28 -0700 Subject: [PATCH 8/8] Tidy grammar --- website/docs/r/theme.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/theme.html.markdown b/website/docs/r/theme.html.markdown index 7e4514784..f2f4e8eb3 100644 --- a/website/docs/r/theme.html.markdown +++ b/website/docs/r/theme.html.markdown @@ -11,8 +11,8 @@ description: |- This resource allows you to get and update an Okta [Theme](https://developer.okta.com/docs/reference/api/brands/#theme-object). -Themes are can only be updated through the Okta API. Therefore this resource -only gets and updates a theme. +Themes can only be updated through the Okta API. Therefore this resource only +gets and updates a theme. ## Example Usage