Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: association_type resource #46

Merged
merged 1 commit into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions docs/resources/association_type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "akeneo_association_type Resource - terraform-provider-akeneo"
subcategory: ""
description: |-
Akeneo association type resource
---

# akeneo_association_type (Resource)

Akeneo association type resource



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `code` (String) Association type code

### Optional

- `is_quantified` (Boolean) Whether the association type is a quantified association
- `is_two_way` (Boolean) Whether the association type is a two-way association
- `labels` (Map of String) Label definition per locale
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
module github.com/0xfrej/terraform-provider-akeneo

go 1.22.0
toolchain go1.22.9
go 1.22.7

toolchain go1.23.2

require (
github.com/ezifyio/go-akeneo v1.0.28
Expand Down
48 changes: 48 additions & 0 deletions internal/akeneox/association.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package akeneox

import (
"fmt"

goakeneo "github.com/ezifyio/go-akeneo"
)

const (
associationTypesSinglePath = "/api/rest/v1/association-types/%s"
)

type AssociationTypeService struct {
client *goakeneo.Client
}

func NewAssociationTypeClient(client *goakeneo.Client) *AssociationTypeService {
return &AssociationTypeService{
client: client,
}
}

func (a *AssociationTypeService) UpdateAssociationTypes(association AssociationType) error {
err := a.client.PATCH(
fmt.Sprintf(associationTypesSinglePath, association.Code),
nil,
association,
nil,
)
if err != nil {
return err
}
return nil
}

func (a *AssociationTypeService) GetAssociationType(code string) (*AssociationType, error) {
response := new(AssociationType)
err := a.client.GET(
fmt.Sprintf(associationTypesSinglePath, code),
nil,
nil,
response,
)
if err != nil {
return nil, err
}
return response, nil
}
7 changes: 7 additions & 0 deletions internal/akeneox/entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,10 @@ type MeasurementFamilyPatchResponse struct {
Message string `json:"message,omitempty"`
Errors []goakeneo.ValidationError `json:"errors,omitempty"`
}

type AssociationType struct {
Code string `json:"code,omitempty" mapstructure:"code"`
Labels map[string]string `json:"labels,omitempty" mapstructure:"labels"`
IsQuantified *bool `json:"is_quantified,omitempty" mapstructure:"is_quantified"`
IsTwoWay *bool `json:"is_two_way,omitempty" mapstructure:"is_two_way"`
}
278 changes: 278 additions & 0 deletions internal/provider/association_type_resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
package provider

import (
"context"
"fmt"

"github.com/0xfrej/terraform-provider-akeneo/internal/akeneox"
"github.com/0xfrej/terraform-provider-akeneo/internal/validator/stringvalidatorx"
"github.com/hashicorp/terraform-plugin-framework-validators/mapvalidator"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)

// Ensure provider defined types fully satisfy framework interfaces.
var _ resource.Resource = &AssociationTypeResource{}
var _ resource.ResourceWithImportState = &AssociationTypeResource{}
var _ resource.ResourceWithConfigure = &AssociationTypeResource{}

func NewAssociationTypeResource() resource.Resource {
return &AssociationTypeResource{}
}

// AssociationTypeResource defines the resource implementation.
type AssociationTypeResource struct {
client *akeneox.AssociationTypeService
}

// AssociationTypeResourceModel describes the resource data model.
type AssociationTypeResourceModel struct {
Code types.String `tfsdk:"code"`
Labels types.Map `tfsdk:"labels"`
IsQuantified types.Bool `tfsdk:"is_quantified"`
IsTwoWay types.Bool `tfsdk:"is_two_way"`
}

func (r *AssociationTypeResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_association_type"
}

func (r *AssociationTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "Akeneo association type resource",

Attributes: map[string]schema.Attribute{
"code": schema.StringAttribute{
Description: "Association type code",
Required: true,
},
"labels": schema.MapAttribute{
Description: "Label definition per locale",
Optional: true,
ElementType: types.StringType,
Validators: []validator.Map{
mapvalidator.KeysAre(stringvalidatorx.IsLocaleCode()),
},
},
"is_quantified": schema.BoolAttribute{
Description: "Whether the association type is a quantified association",
Optional: true,
},
"is_two_way": schema.BoolAttribute{
Description: "Whether the association type is a two-way association",
Optional: true,
},
},
}
}

func (r *AssociationTypeResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}

data, ok := req.ProviderData.(*ResourceData)

if !ok {
resp.Diagnostics.AddError(
"Unexpected Resource Configure Type",
fmt.Sprintf("Expected *ResourceData, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)
return
}

if data.Client == nil {
resp.Diagnostics.AddError(
"Missing client instance",
"Client instance pointer passed to Configure is required, got nil",
)
return
}

r.client = akeneox.NewAssociationTypeClient(data.Client)
}

func (r *AssociationTypeResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data AssociationTypeResourceModel

// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)

if resp.Diagnostics.HasError() {
return
}

apiData := r.mapToApiObject(ctx, &resp.Diagnostics, &data)

if resp.Diagnostics.HasError() {
return
}

err := r.client.UpdateAssociationTypes(*apiData)
if err != nil {
resp.Diagnostics.AddError(
"Error while creating a association type",
"An unexpected error occurred when creating association type. \n\n"+
"Akeneo API Error: "+err.Error(),
)
return
}

if resp.Diagnostics.HasError() {
return
}

// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *AssociationTypeResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data AssociationTypeResourceModel

// Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)

if resp.Diagnostics.HasError() {
return
}

attrData, err := r.client.GetAssociationType(data.Code.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Error while reading an association type",
"An unexpected error occurred when reading association type. \n\n"+
"Akeneo API Error: "+err.Error(),
)
return
}

if resp.Diagnostics.HasError() {
return
}

r.mapToTfObject(&resp.Diagnostics, &data, attrData)

if resp.Diagnostics.HasError() {
return
}

// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *AssociationTypeResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data AssociationTypeResourceModel

// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)

if resp.Diagnostics.HasError() {
return
}

apiData := r.mapToApiObject(ctx, &resp.Diagnostics, &data)

if resp.Diagnostics.HasError() {
return
}
err := r.client.UpdateAssociationTypes(*apiData)
if err != nil {
resp.Diagnostics.AddError(
"Error while creating a association type",
"An unexpected error occurred when creating association type. \n\n"+
"Akeneo API Error: "+err.Error(),
)
return
}

if resp.Diagnostics.HasError() {
return
}

// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *AssociationTypeResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
//var data AssociationTypeResourceModel
//
//// Read Terraform prior state data into the model
//resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
//
//if resp.Diagnostics.HasError() {
// return
//}

resp.Diagnostics.AddError(
"This resource does not support deletes",
"This resource does not support deletes. The Akeneo API does not support deletes for association types.",
)
}

func (r *AssociationTypeResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("code"), req, resp)
}

func (r *AssociationTypeResource) mapToApiObject(ctx context.Context, diags *diag.Diagnostics, data *AssociationTypeResourceModel) *akeneox.AssociationType {
a := akeneox.AssociationType{
Code: data.Code.ValueString(),
}

if !(data.Labels.IsNull() || data.Labels.IsUnknown()) {
elements := make(map[string]types.String, len(data.Labels.Elements()))
diags.Append(data.Labels.ElementsAs(ctx, &elements, false)...)
labels := make(map[string]string)
for locale, label := range elements {
labels[locale] = label.ValueString()
}
a.Labels = labels
}

if !(data.IsQuantified.IsNull() || data.IsQuantified.IsUnknown()) {
v := data.IsQuantified.ValueBool()
a.IsQuantified = &v
}

if !(data.IsTwoWay.IsNull() || data.IsTwoWay.IsUnknown()) {
v := data.IsTwoWay.ValueBool()
a.IsTwoWay = &v
}

if diags.HasError() {
return nil
}

return &a
}

func (r *AssociationTypeResource) mapToTfObject(respDiags *diag.Diagnostics, data *AssociationTypeResourceModel, apiData *akeneox.AssociationType) {
data.Code = types.StringValue(apiData.Code)

if len(apiData.Labels) > 0 {
elements := make(map[string]attr.Value, len(apiData.Labels))

for k, v := range apiData.Labels {
elements[k] = types.StringValue(v)
}

mapVal, diags := types.MapValue(types.StringType, elements)
if diags.HasError() {
respDiags.Append(diags...)
}
data.Labels = mapVal
}

if apiData.IsQuantified != nil {
data.IsQuantified = types.BoolValue(*apiData.IsQuantified)
}

if apiData.IsTwoWay != nil {
data.IsQuantified = types.BoolValue(*apiData.IsTwoWay)
}
}
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ func (p *AkeneoProvider) Resources(ctx context.Context) []func() resource.Resour
NewMeasurementFamilyResource,
NewChannelResource,
NewCategoryResource,
NewAssociationTypeResource,
}
}

Expand Down