feat: support customizing guest portal logo and background with unifi_portal_file and unifi_setting_guest_access resources (#74)
* feat: support customizing guest portal logo and background with `unifi_portal_file` and `unifi_setting_guest_access` resources * ci: run acceptance tests on go.mod changes * f
This commit is contained in:
committed by
GitHub
parent
8dd4bfcb97
commit
a133383b43
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -1,9 +1,6 @@
|
|||||||
* text=auto
|
* text=auto
|
||||||
|
|
||||||
*.go diff=golang
|
*.go diff=golang
|
||||||
|
|
||||||
*.sh eol=lf
|
*.sh eol=lf
|
||||||
|
|
||||||
*.jar binary
|
*.jar binary
|
||||||
*.wt binary
|
*.wt binary
|
||||||
*.bson binary
|
*.bson binary
|
||||||
|
|||||||
21
.github/workflows/acctest.yml
vendored
21
.github/workflows/acctest.yml
vendored
@@ -1,14 +1,17 @@
|
|||||||
name: Acceptance Tests
|
name: Acceptance Tests
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
branches:
|
||||||
- "internal/**"
|
- "*"
|
||||||
- "scripts/**"
|
# paths:
|
||||||
- "tools/**"
|
# - "internal/**"
|
||||||
- "main.go"
|
# - "scripts/**"
|
||||||
- "docker-compose.yaml"
|
# - "tools/**"
|
||||||
- ".github/workflows/acctest.yml"
|
# - "main.go"
|
||||||
- "Makefile"
|
# - "docker-compose.yaml"
|
||||||
|
# - ".github/workflows/acctest.yml"
|
||||||
|
# - "Makefile"
|
||||||
|
# - "go.mod"
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- "main"
|
- "main"
|
||||||
@@ -24,6 +27,8 @@ on:
|
|||||||
- "Makefile"
|
- "Makefile"
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "0 13 * * *"
|
- cron: "0 13 * * *"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
|||||||
BIN
internal/provider/acctest/files/testfile.png
Normal file
BIN
internal/provider/acctest/files/testfile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.5 KiB |
BIN
internal/provider/acctest/files/testfile2.jpg
Normal file
BIN
internal/provider/acctest/files/testfile2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
61
internal/provider/acctest/resource_portal_file_test.go
Normal file
61
internal/provider/acctest/resource_portal_file_test.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package acctest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
|
||||||
|
"github.com/hashicorp/terraform-plugin-testing/plancheck"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform-plugin-testing/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccPortalFile_basic(t *testing.T) {
|
||||||
|
|
||||||
|
AcceptanceTest(t, AcceptanceTestCase{
|
||||||
|
CheckDestroy: testAccCheckPortalFileDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: testAccPortalFileConfig("files/testfile.png"),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttr("unifi_portal_file.test", "site", "default"),
|
||||||
|
resource.TestCheckResourceAttrSet("unifi_portal_file.test", "filename"),
|
||||||
|
resource.TestCheckResourceAttrSet("unifi_portal_file.test", "content_type"),
|
||||||
|
resource.TestCheckResourceAttrSet("unifi_portal_file.test", "file_size"),
|
||||||
|
resource.TestCheckResourceAttrSet("unifi_portal_file.test", "md5"),
|
||||||
|
resource.TestCheckResourceAttrSet("unifi_portal_file.test", "url"),
|
||||||
|
),
|
||||||
|
ConfigPlanChecks: pt.CheckResourceActions("unifi_portal_file.test", plancheck.ResourceActionCreate),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Config: testAccPortalFileConfig("files/testfile2.jpg"),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttr("unifi_portal_file.test", "site", "default"),
|
||||||
|
resource.TestCheckResourceAttrSet("unifi_portal_file.test", "filename"),
|
||||||
|
resource.TestCheckResourceAttrSet("unifi_portal_file.test", "content_type"),
|
||||||
|
resource.TestCheckResourceAttrSet("unifi_portal_file.test", "file_size"),
|
||||||
|
resource.TestCheckResourceAttrSet("unifi_portal_file.test", "md5"),
|
||||||
|
resource.TestCheckResourceAttrSet("unifi_portal_file.test", "url"),
|
||||||
|
),
|
||||||
|
ConfigPlanChecks: pt.CheckResourceActions("unifi_portal_file.test", plancheck.ResourceActionReplace),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckPortalFileDestroy(s *terraform.State) error {
|
||||||
|
return pt.CheckDestroy("unifi_portal_file", func(ctx context.Context, site, id string) error {
|
||||||
|
_, err := testClient.GetPortalFile(ctx, site, id)
|
||||||
|
return err
|
||||||
|
})(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccPortalFileConfig(filePath string) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
resource "unifi_portal_file" "test" {
|
||||||
|
file_path = %q
|
||||||
|
}
|
||||||
|
`, filepath.ToSlash(filePath))
|
||||||
|
}
|
||||||
@@ -702,6 +702,15 @@ func TestAccSettingGuestAccess_portalCustomizationPostVersion74(t *testing.T) {
|
|||||||
resource.TestCheckResourceAttr("unifi_setting_guest_access.test", "portal_customization.logo_size", "150"),
|
resource.TestCheckResourceAttr("unifi_setting_guest_access.test", "portal_customization.logo_size", "150"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Config: testAccSettingGuestAccessConfig_portalCustomizationImagesPost74(),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttr("unifi_setting_guest_access.test", "portal_customization.customized", "true"),
|
||||||
|
resource.TestCheckResourceAttr("unifi_setting_guest_access.test", "portal_customization.bg_type", "image"),
|
||||||
|
resource.TestCheckResourceAttrSet("unifi_setting_guest_access.test", "portal_customization.bg_image_file_id"),
|
||||||
|
resource.TestCheckResourceAttrSet("unifi_setting_guest_access.test", "portal_customization.logo_file_id"),
|
||||||
|
),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -758,7 +767,7 @@ func TestAccSettingGuestAccess_portalCustomization(t *testing.T) {
|
|||||||
Config: testAccSettingGuestAccessConfig_basic(),
|
Config: testAccSettingGuestAccessConfig_basic(),
|
||||||
Check: resource.ComposeTestCheckFunc(
|
Check: resource.ComposeTestCheckFunc(
|
||||||
resource.TestCheckResourceAttr("unifi_setting_guest_access.test", "portal_customization.customized", "false"),
|
resource.TestCheckResourceAttr("unifi_setting_guest_access.test", "portal_customization.customized", "false"),
|
||||||
resource.TestCheckResourceAttr("unifi_setting_guest_access.test", "portal_customization.%", "27"),
|
resource.TestCheckResourceAttr("unifi_setting_guest_access.test", "portal_customization.%", "29"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1098,6 +1107,28 @@ resource "unifi_setting_guest_access" "test" {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testAccSettingGuestAccessConfig_portalCustomizationImagesPost74() string {
|
||||||
|
return `
|
||||||
|
resource "unifi_portal_file" "logo" {
|
||||||
|
file_path = "files/testfile.png"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "unifi_portal_file" "background" {
|
||||||
|
file_path = "files/testfile2.jpg"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "unifi_setting_guest_access" "test" {
|
||||||
|
auth = "none"
|
||||||
|
portal_customization = {
|
||||||
|
customized = true
|
||||||
|
bg_type = "image"
|
||||||
|
bg_image_file_id = unifi_portal_file.background.id
|
||||||
|
logo_file_id = unifi_portal_file.logo.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
func testAccSettingGuestAccessConfig_portalCustomizationGallery() string {
|
func testAccSettingGuestAccessConfig_portalCustomizationGallery() string {
|
||||||
return `
|
return `
|
||||||
resource "unifi_setting_guest_access" "test" {
|
resource "unifi_setting_guest_access" "test" {
|
||||||
|
|||||||
179
internal/provider/portal/resource_portal_file.go
Normal file
179
internal/provider/portal/resource_portal_file.go
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
package portal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/filipowm/go-unifi/unifi"
|
||||||
|
"github.com/filipowm/terraform-provider-unifi/internal/provider/base"
|
||||||
|
ut "github.com/filipowm/terraform-provider-unifi/internal/provider/types"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ resource.Resource = &portalFileResource{}
|
||||||
|
_ resource.ResourceWithConfigure = &portalFileResource{}
|
||||||
|
_ resource.ResourceWithImportState = &portalFileResource{}
|
||||||
|
_ base.Resource = &portalFileResource{}
|
||||||
|
)
|
||||||
|
|
||||||
|
type portalFileResource struct {
|
||||||
|
*base.GenericResource[*portalFileModel]
|
||||||
|
}
|
||||||
|
|
||||||
|
type portalFileModel struct {
|
||||||
|
base.Model
|
||||||
|
Filename types.String `tfsdk:"filename"`
|
||||||
|
FilePath types.String `tfsdk:"file_path"`
|
||||||
|
ContentType types.String `tfsdk:"content_type"`
|
||||||
|
FileSize types.Int64 `tfsdk:"file_size"`
|
||||||
|
MD5 types.String `tfsdk:"md5"`
|
||||||
|
URL types.String `tfsdk:"url"`
|
||||||
|
LastModified types.Int64 `tfsdk:"last_modified"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *portalFileModel) Merge(_ context.Context, data interface{}) diag.Diagnostics {
|
||||||
|
var diags diag.Diagnostics
|
||||||
|
portalFile, ok := data.(*unifi.PortalFile)
|
||||||
|
if !ok {
|
||||||
|
diags.AddError("Invalid data type", fmt.Sprintf("Expected *unifi.PortalFile, got: %T", data))
|
||||||
|
return diags
|
||||||
|
}
|
||||||
|
|
||||||
|
m.ID = types.StringValue(portalFile.ID)
|
||||||
|
m.Filename = types.StringValue(portalFile.Filename)
|
||||||
|
m.ContentType = types.StringValue(portalFile.ContentType)
|
||||||
|
m.FileSize = types.Int64Value(int64(portalFile.FileSize))
|
||||||
|
m.MD5 = types.StringValue(portalFile.MD5)
|
||||||
|
m.URL = types.StringValue(portalFile.URL)
|
||||||
|
m.LastModified = types.Int64Value(int64(portalFile.LastModified))
|
||||||
|
|
||||||
|
return diags
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *portalFileModel) AsUnifiModel(_ context.Context) (interface{}, diag.Diagnostics) {
|
||||||
|
// Not used for upload - we don't convert the model to a UniFi model
|
||||||
|
// The file path is used directly for upload
|
||||||
|
return nil, diag.Diagnostics{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPortalFileResource() resource.Resource {
|
||||||
|
return &portalFileResource{
|
||||||
|
GenericResource: base.NewGenericResource(
|
||||||
|
"unifi_portal_file",
|
||||||
|
func() *portalFileModel { return &portalFileModel{} },
|
||||||
|
base.ResourceFunctions{
|
||||||
|
Read: func(ctx context.Context, client *base.Client, site, id string) (interface{}, error) {
|
||||||
|
return client.GetPortalFile(ctx, site, id)
|
||||||
|
},
|
||||||
|
Create: nil, // Custom implementation in CreateWithContext
|
||||||
|
Update: nil, // Portal files cannot be updated, only replaced
|
||||||
|
Delete: func(ctx context.Context, client *base.Client, site, id string) error {
|
||||||
|
return client.DeletePortalFile(ctx, site, id)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *portalFileResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
|
||||||
|
resp.Schema = schema.Schema{
|
||||||
|
MarkdownDescription: "The `unifi_portal_file` resource manages files uploaded to the UniFi guest portal. " +
|
||||||
|
"This resource allows you to upload images that can be used in customizing " +
|
||||||
|
"the UniFi guest portal interface.\n\n" +
|
||||||
|
"**Note:** This resource uploads files to the UniFi controller. The file must exist on the local filesystem " +
|
||||||
|
"where Terraform is executed.",
|
||||||
|
|
||||||
|
Attributes: map[string]schema.Attribute{
|
||||||
|
"id": ut.ID(),
|
||||||
|
"site": ut.SiteAttribute(),
|
||||||
|
"file_path": schema.StringAttribute{
|
||||||
|
MarkdownDescription: "Path to the file on the local filesystem to upload to the UniFi controller. " +
|
||||||
|
"The file must exist and be readable.",
|
||||||
|
Required: true,
|
||||||
|
PlanModifiers: []planmodifier.String{
|
||||||
|
stringplanmodifier.RequiresReplace(),
|
||||||
|
},
|
||||||
|
Validators: []validator.String{
|
||||||
|
stringvalidator.LengthAtLeast(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"filename": schema.StringAttribute{
|
||||||
|
MarkdownDescription: "Name of the file as stored in the UniFi controller.",
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"content_type": schema.StringAttribute{
|
||||||
|
MarkdownDescription: "MIME type of the file.",
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"file_size": schema.Int64Attribute{
|
||||||
|
MarkdownDescription: "Size of the file in bytes.",
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"md5": schema.StringAttribute{
|
||||||
|
MarkdownDescription: "MD5 hash of the file content.",
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"url": schema.StringAttribute{
|
||||||
|
MarkdownDescription: "URL where the file can be accessed on the UniFi controller.",
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"last_modified": schema.Int64Attribute{
|
||||||
|
MarkdownDescription: "Timestamp when the file was last modified.",
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *portalFileResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
|
||||||
|
var data portalFileModel
|
||||||
|
|
||||||
|
// Read Terraform plan data into the model
|
||||||
|
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
|
||||||
|
if resp.Diagnostics.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get file path
|
||||||
|
filePath := data.FilePath.ValueString()
|
||||||
|
if filePath == "" {
|
||||||
|
resp.Diagnostics.AddError("File path is required", "A valid file path must be provided")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if file exists
|
||||||
|
_, err := os.Stat(filePath)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics.AddError("Invalid file path", fmt.Sprintf("Error accessing file: %s", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
site := r.GetClient().ResolveSite(&data)
|
||||||
|
|
||||||
|
portalFile, err := r.GetClient().UploadPortalFile(ctx, site, filePath)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics.AddError("Error uploading file", fmt.Sprintf("Could not upload file: %s", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map response back to model
|
||||||
|
resp.Diagnostics.Append(data.Merge(ctx, portalFile)...)
|
||||||
|
if resp.Diagnostics.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data.Site = types.StringValue(site)
|
||||||
|
|
||||||
|
// Save data into Terraform state
|
||||||
|
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *portalFileResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
|
||||||
|
resp.Diagnostics.AddError("Import is not supported", "The `unifi_portal_file` resource does not support import")
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/filipowm/terraform-provider-unifi/internal/provider/base"
|
"github.com/filipowm/terraform-provider-unifi/internal/provider/base"
|
||||||
"github.com/filipowm/terraform-provider-unifi/internal/provider/dns"
|
"github.com/filipowm/terraform-provider-unifi/internal/provider/dns"
|
||||||
"github.com/filipowm/terraform-provider-unifi/internal/provider/firewall"
|
"github.com/filipowm/terraform-provider-unifi/internal/provider/firewall"
|
||||||
|
"github.com/filipowm/terraform-provider-unifi/internal/provider/portal"
|
||||||
"github.com/filipowm/terraform-provider-unifi/internal/provider/settings"
|
"github.com/filipowm/terraform-provider-unifi/internal/provider/settings"
|
||||||
"github.com/filipowm/terraform-provider-unifi/internal/provider/utils"
|
"github.com/filipowm/terraform-provider-unifi/internal/provider/utils"
|
||||||
"github.com/filipowm/terraform-provider-unifi/internal/provider/validators"
|
"github.com/filipowm/terraform-provider-unifi/internal/provider/validators"
|
||||||
@@ -177,7 +178,7 @@ func (p *unifiProvider) Resources(_ context.Context) []func() resource.Resource
|
|||||||
dns.NewDnsRecordResource,
|
dns.NewDnsRecordResource,
|
||||||
firewall.NewFirewallZoneResource,
|
firewall.NewFirewallZoneResource,
|
||||||
firewall.NewFirewallZonePolicyResource,
|
firewall.NewFirewallZonePolicyResource,
|
||||||
//portal.NewPortalFileResource,
|
portal.NewPortalFileResource,
|
||||||
settings.NewAutoSpeedtestResource,
|
settings.NewAutoSpeedtestResource,
|
||||||
settings.NewCountryResource,
|
settings.NewCountryResource,
|
||||||
settings.NewDpiResource,
|
settings.NewDpiResource,
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ type portalCustomizationModel struct {
|
|||||||
Customized types.Bool `tfsdk:"customized"`
|
Customized types.Bool `tfsdk:"customized"`
|
||||||
AuthenticationText types.String `tfsdk:"authentication_text"`
|
AuthenticationText types.String `tfsdk:"authentication_text"`
|
||||||
BgColor types.String `tfsdk:"bg_color"`
|
BgColor types.String `tfsdk:"bg_color"`
|
||||||
|
BgImageFileId types.String `tfsdk:"bg_image_file_id"`
|
||||||
BgImageTile types.Bool `tfsdk:"bg_image_tile"`
|
BgImageTile types.Bool `tfsdk:"bg_image_tile"`
|
||||||
BgType types.String `tfsdk:"bg_type"`
|
BgType types.String `tfsdk:"bg_type"`
|
||||||
BoxColor types.String `tfsdk:"box_color"`
|
BoxColor types.String `tfsdk:"box_color"`
|
||||||
@@ -110,6 +111,7 @@ type portalCustomizationModel struct {
|
|||||||
ButtonTextColor types.String `tfsdk:"button_text_color"`
|
ButtonTextColor types.String `tfsdk:"button_text_color"`
|
||||||
Languages types.List `tfsdk:"languages"`
|
Languages types.List `tfsdk:"languages"`
|
||||||
LinkColor types.String `tfsdk:"link_color"`
|
LinkColor types.String `tfsdk:"link_color"`
|
||||||
|
LogoFileId types.String `tfsdk:"logo_file_id"`
|
||||||
LogoPosition types.String `tfsdk:"logo_position"`
|
LogoPosition types.String `tfsdk:"logo_position"`
|
||||||
LogoSize types.Int32 `tfsdk:"logo_size"`
|
LogoSize types.Int32 `tfsdk:"logo_size"`
|
||||||
SuccessText types.String `tfsdk:"success_text"`
|
SuccessText types.String `tfsdk:"success_text"`
|
||||||
@@ -129,6 +131,7 @@ func (m *portalCustomizationModel) AttributeTypes() map[string]attr.Type {
|
|||||||
"customized": types.BoolType,
|
"customized": types.BoolType,
|
||||||
"authentication_text": types.StringType,
|
"authentication_text": types.StringType,
|
||||||
"bg_color": types.StringType,
|
"bg_color": types.StringType,
|
||||||
|
"bg_image_file_id": types.StringType,
|
||||||
"bg_image_tile": types.BoolType,
|
"bg_image_tile": types.BoolType,
|
||||||
"bg_type": types.StringType,
|
"bg_type": types.StringType,
|
||||||
"box_color": types.StringType,
|
"box_color": types.StringType,
|
||||||
@@ -143,6 +146,7 @@ func (m *portalCustomizationModel) AttributeTypes() map[string]attr.Type {
|
|||||||
ElemType: types.StringType,
|
ElemType: types.StringType,
|
||||||
},
|
},
|
||||||
"link_color": types.StringType,
|
"link_color": types.StringType,
|
||||||
|
"logo_file_id": types.StringType,
|
||||||
"logo_position": types.StringType,
|
"logo_position": types.StringType,
|
||||||
"logo_size": types.Int32Type,
|
"logo_size": types.Int32Type,
|
||||||
"success_text": types.StringType,
|
"success_text": types.StringType,
|
||||||
@@ -478,6 +482,7 @@ func (d *guestAccessModel) AsUnifiModel(ctx context.Context) (interface{}, diag.
|
|||||||
model.PortalCustomized = portalCustomization.Customized.ValueBool()
|
model.PortalCustomized = portalCustomization.Customized.ValueBool()
|
||||||
model.PortalCustomizedAuthenticationText = portalCustomization.AuthenticationText.ValueString()
|
model.PortalCustomizedAuthenticationText = portalCustomization.AuthenticationText.ValueString()
|
||||||
model.PortalCustomizedBgColor = portalCustomization.BgColor.ValueString()
|
model.PortalCustomizedBgColor = portalCustomization.BgColor.ValueString()
|
||||||
|
model.PortalCustomizedBgImageFilename = portalCustomization.BgImageFileId.ValueString()
|
||||||
model.PortalCustomizedBgImageTile = portalCustomization.BgImageTile.ValueBool()
|
model.PortalCustomizedBgImageTile = portalCustomization.BgImageTile.ValueBool()
|
||||||
model.PortalCustomizedBgType = portalCustomization.BgType.ValueString()
|
model.PortalCustomizedBgType = portalCustomization.BgType.ValueString()
|
||||||
model.PortalCustomizedBoxColor = portalCustomization.BoxColor.ValueString()
|
model.PortalCustomizedBoxColor = portalCustomization.BoxColor.ValueString()
|
||||||
@@ -490,6 +495,7 @@ func (d *guestAccessModel) AsUnifiModel(ctx context.Context) (interface{}, diag.
|
|||||||
model.PortalCustomizedButtonTextColor = portalCustomization.ButtonTextColor.ValueString()
|
model.PortalCustomizedButtonTextColor = portalCustomization.ButtonTextColor.ValueString()
|
||||||
model.PortalCustomizedLanguages = languages
|
model.PortalCustomizedLanguages = languages
|
||||||
model.PortalCustomizedLinkColor = portalCustomization.LinkColor.ValueString()
|
model.PortalCustomizedLinkColor = portalCustomization.LinkColor.ValueString()
|
||||||
|
model.PortalCustomizedLogoFilename = portalCustomization.LogoFileId.ValueString()
|
||||||
model.PortalCustomizedLogoPosition = portalCustomization.LogoPosition.ValueString()
|
model.PortalCustomizedLogoPosition = portalCustomization.LogoPosition.ValueString()
|
||||||
model.PortalCustomizedLogoSize = int(portalCustomization.LogoSize.ValueInt32())
|
model.PortalCustomizedLogoSize = int(portalCustomization.LogoSize.ValueInt32())
|
||||||
model.PortalCustomizedSuccessText = portalCustomization.SuccessText.ValueString()
|
model.PortalCustomizedSuccessText = portalCustomization.SuccessText.ValueString()
|
||||||
@@ -816,6 +822,7 @@ func (d *guestAccessModel) Merge(ctx context.Context, unifiModel interface{}) di
|
|||||||
Customized: types.BoolValue(model.PortalCustomized),
|
Customized: types.BoolValue(model.PortalCustomized),
|
||||||
AuthenticationText: types.StringValue(model.PortalCustomizedAuthenticationText),
|
AuthenticationText: types.StringValue(model.PortalCustomizedAuthenticationText),
|
||||||
BgColor: types.StringValue(model.PortalCustomizedBgColor),
|
BgColor: types.StringValue(model.PortalCustomizedBgColor),
|
||||||
|
BgImageFileId: types.StringValue(model.PortalCustomizedBgImageFilename),
|
||||||
BgImageTile: types.BoolValue(model.PortalCustomizedBgImageTile),
|
BgImageTile: types.BoolValue(model.PortalCustomizedBgImageTile),
|
||||||
BgType: types.StringValue(model.PortalCustomizedBgType),
|
BgType: types.StringValue(model.PortalCustomizedBgType),
|
||||||
BoxColor: types.StringValue(model.PortalCustomizedBoxColor),
|
BoxColor: types.StringValue(model.PortalCustomizedBoxColor),
|
||||||
@@ -828,6 +835,7 @@ func (d *guestAccessModel) Merge(ctx context.Context, unifiModel interface{}) di
|
|||||||
ButtonTextColor: types.StringValue(model.PortalCustomizedButtonTextColor),
|
ButtonTextColor: types.StringValue(model.PortalCustomizedButtonTextColor),
|
||||||
Languages: languages,
|
Languages: languages,
|
||||||
LinkColor: types.StringValue(model.PortalCustomizedLinkColor),
|
LinkColor: types.StringValue(model.PortalCustomizedLinkColor),
|
||||||
|
LogoFileId: types.StringValue(model.PortalCustomizedLogoFilename),
|
||||||
LogoPosition: types.StringValue(model.PortalCustomizedLogoPosition),
|
LogoPosition: types.StringValue(model.PortalCustomizedLogoPosition),
|
||||||
LogoSize: types.Int32Value(int32(model.PortalCustomizedLogoSize)),
|
LogoSize: types.Int32Value(int32(model.PortalCustomizedLogoSize)),
|
||||||
SuccessText: types.StringValue(model.PortalCustomizedSuccessText),
|
SuccessText: types.StringValue(model.PortalCustomizedSuccessText),
|
||||||
@@ -880,14 +888,6 @@ func (g *guestAccessResource) ModifyPlan(_ context.Context, req resource.ModifyP
|
|||||||
resp.Diagnostics.Append(g.RequireMinVersionForPath("7.4", path.Root("portal_customization").AtName("logo_position"), req.Config)...)
|
resp.Diagnostics.Append(g.RequireMinVersionForPath("7.4", path.Root("portal_customization").AtName("logo_position"), req.Config)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func requiredTogetherIfTrue(condition string, attrs ...string) validators.RequiredTogetherIfValidator {
|
|
||||||
var expressions []path.Expression
|
|
||||||
for _, attr := range attrs {
|
|
||||||
expressions = append(expressions, path.MatchRoot(attr))
|
|
||||||
}
|
|
||||||
return validators.RequiredTogetherIf(path.MatchRoot(condition), types.BoolValue(true), expressions...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func requiredTogetherIfStringVal(condition, value string, attrs ...string) validators.RequiredTogetherIfValidator {
|
func requiredTogetherIfStringVal(condition, value string, attrs ...string) validators.RequiredTogetherIfValidator {
|
||||||
var expressions []path.Expression
|
var expressions []path.Expression
|
||||||
for _, attr := range attrs {
|
for _, attr := range attrs {
|
||||||
@@ -904,17 +904,6 @@ func (g *guestAccessResource) ConfigValidators(_ context.Context) []resource.Con
|
|||||||
return []resource.ConfigValidator{
|
return []resource.ConfigValidator{
|
||||||
// Auth validators
|
// Auth validators
|
||||||
requiredTogetherIfStringVal("auth", "custom", "custom_ip"),
|
requiredTogetherIfStringVal("auth", "custom", "custom_ip"),
|
||||||
//requiredTogetherIfStringVal("auth", "facebook_wifi", "facebook_wifi.gateway_id", "facebook_wifi.gateway_name", "facebook_wifi.gateway_secret"),
|
|
||||||
|
|
||||||
// Facebook validators
|
|
||||||
|
|
||||||
// Google validators
|
|
||||||
requiredTogetherIfTrue("google.enabled", "google.client_id", "google.client_secret"),
|
|
||||||
requiredStringValueIfTrue("google.enabled", "auth", "hotspot"),
|
|
||||||
|
|
||||||
// Password validators
|
|
||||||
requiredTogetherIfTrue("password_enabled", "password"),
|
|
||||||
requiredStringValueIfTrue("password_enabled", "auth", "hotspot"),
|
|
||||||
|
|
||||||
// Payment validators
|
// Payment validators
|
||||||
requiredTogetherIfStringVal("payment_gateway", "authorize", "authorize"),
|
requiredTogetherIfStringVal("payment_gateway", "authorize", "authorize"),
|
||||||
@@ -925,21 +914,7 @@ func (g *guestAccessResource) ConfigValidators(_ context.Context) []resource.Con
|
|||||||
requiredTogetherIfStringVal("payment_gateway", "stripe", "stripe"),
|
requiredTogetherIfStringVal("payment_gateway", "stripe", "stripe"),
|
||||||
|
|
||||||
// Portal validators
|
// Portal validators
|
||||||
//requiredTogetherIfStringVal("portal_customized_bg_type", "color", "portal_customized_bg_color"),
|
requiredTogetherIfStringVal("portal_customization.bg_type", "image", "portal_customization.bg_image_file_id"),
|
||||||
//requiredTogetherIfStringVal("portal_customized_bg_type", "gallery", "portal_customized_unsplash_author_name", "portal_customized_unsplash_author_username"),
|
|
||||||
//requiredTogetherIfStringVal("portal_customized_bg_type", "image", "portal_customized_bg_image_filename"),
|
|
||||||
//requiredTogetherIfTrue("portal_customized_bg_image_enabled", "portal_customized_bg_image_filename"),
|
|
||||||
//requiredTogetherIfTrue("portal_customized_logo_enabled", "portal_customized_logo_filename"),
|
|
||||||
//requiredTogetherIfTrue("portal_customized_tos_enabled", "portal_customized_tos"),
|
|
||||||
//requiredTogetherIfTrue("portal_customized_welcome_text_enabled", "portal_customized_welcome_text"),
|
|
||||||
//requiredTogetherIfTrue("portal_use_hostname", "portal_hostname"),
|
|
||||||
|
|
||||||
// RADIUS validators
|
|
||||||
//requiredTogetherIfTrue("radius_disconnect_enabled", "radius_disconnect_port"),
|
|
||||||
//requiredTogetherIfTrue("radius_enabled", "radius_auth_type", "radius_profile_id"),
|
|
||||||
|
|
||||||
// Restricted DNS validators
|
|
||||||
//requiredTogetherIfTrue("restricted_dns_enabled", "restricted_dns_servers"),
|
|
||||||
|
|
||||||
// Voucher validators
|
// Voucher validators
|
||||||
requiredStringValueIfTrue("voucher_enabled", "auth", "hotspot"),
|
requiredStringValueIfTrue("voucher_enabled", "auth", "hotspot"),
|
||||||
@@ -1251,6 +1226,11 @@ func (g *guestAccessResource) Schema(_ context.Context, _ resource.SchemaRequest
|
|||||||
validators.HexColor,
|
validators.HexColor,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"bg_image_file_id": schema.StringAttribute{
|
||||||
|
MarkdownDescription: "ID of the background image portal file. File must exist in controller, use `unifi_portal_file` to manage it.",
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
"bg_image_tile": schema.BoolAttribute{
|
"bg_image_tile": schema.BoolAttribute{
|
||||||
MarkdownDescription: "Tile the background image.",
|
MarkdownDescription: "Tile the background image.",
|
||||||
Optional: true,
|
Optional: true,
|
||||||
@@ -1342,6 +1322,11 @@ func (g *guestAccessResource) Schema(_ context.Context, _ resource.SchemaRequest
|
|||||||
validators.HexColor,
|
validators.HexColor,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"logo_file_id": schema.StringAttribute{
|
||||||
|
MarkdownDescription: "ID of the logo image portal file. File must exist in controller, use `unifi_portal_file` to manage it.",
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
"logo_position": schema.StringAttribute{
|
"logo_position": schema.StringAttribute{
|
||||||
MarkdownDescription: "Position of the logo in the portal. Valid values are: left, center, right.",
|
MarkdownDescription: "Position of the logo in the portal. Valid values are: left, center, right.",
|
||||||
Optional: true,
|
Optional: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user