Skip to content

Commit 1a0b504

Browse files
committed
reworked reconciliation controller to GET/CREATE/UPDATE/DELETE categories by id, added functions descriptions and error checks
1 parent 513b678 commit 1a0b504

File tree

8 files changed

+66
-118
lines changed

8 files changed

+66
-118
lines changed

apis/category/v1alpha1/category_types.go

-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ type CustomAttributes struct {
3434
// CategoryParameters are the configurable fields of a Category.
3535
type CategoryParameters struct {
3636
Name string `json:"name,omitempty"`
37-
ID int `json:"id,omitempty"`
3837
IsActive bool `json:"isActive,omitempty"`
3938
Position int `json:"position,omitempty"`
4039
Level int `json:"level,omitempty"`

apis/category/v1alpha1/groupversion_info.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ limitations under the License.
1616

1717
// Package v1alpha1 contains the v1alpha1 group Sample resources of the Magento provider.
1818
// +kubebuilder:object:generate=true
19-
// +groupName=category.magento.web7.md
19+
// +groupName=magento.web7.md
2020
// +versionName=v1alpha1
2121
package v1alpha1
2222

@@ -27,7 +27,7 @@ import (
2727

2828
// Package type metadata.
2929
const (
30-
Group = "category.magento.web7.md"
30+
Group = "magento.web7.md"
3131
Version = "v1alpha1"
3232
)
3333

examples/provider/config.yaml

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ metadata:
1313
name: category-provider-config
1414
spec:
1515
hostName: ""
16-
scheme: ""
1716
credentials:
1817
source: Secret
1918
secretRef:

examples/sample/category.yaml

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
apiVersion: category.magento.web7.md/v1alpha1
1+
apiVersion: magento.web7.md/v1alpha1
22
kind: Category
33
metadata:
4-
name: test-category
4+
name: example-category
55
spec:
66
forProvider:
7-
name: "Test Category"
8-
is_active: true
9-
include_in_menu: true
7+
name: "Example Category"
8+
level: 2
9+
position: 1
10+
isActive: true
11+
includeInMenu: false
1012
providerConfigRef:
1113
name: category-provider-config

internal/client/categories/categories.go

+32-85
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,42 @@
1+
// Package categories provides functions for interacting with Magento categories.
12
package categories
23

34
import (
45
"encoding/json"
56
"errors"
6-
"fmt"
7-
"net/http"
87
"net/url"
8+
"strconv"
99

10+
"github.com/go-resty/resty/v2"
1011
"github.com/web-seven/provider-magento/apis/category/v1alpha1"
1112

1213
magento "github.com/web-seven/provider-magento/internal/client"
1314
)
1415

16+
// Client is a struct that embeds the magento.Client struct.
1517
type Client struct {
1618
magento.Client
1719
}
1820

19-
func GetCategoryByName(c *magento.Client, categoryName string) (*v1alpha1.Category, error) {
20-
path := fmt.Sprintf("%s/rest/all/V1/categories/list", c.BaseURL)
21+
// categoriesPath is the path for the Magento categories API.
22+
const categoriesPath = "/rest/default/V1/categories/"
2123

24+
// GetCategoryByID retrieves a category by its ID.
25+
func GetCategoryByID(c *magento.Client, id string) (*v1alpha1.Category, error) {
2226
queryParams := map[string]string{
23-
"searchCriteria[filterGroups][0][filters][0][field]": "name",
24-
"searchCriteria[filterGroups][0][filters][0][value]": categoryName,
27+
"searchCriteria[filterGroups][0][filters][0][field]": "entity_id",
28+
"searchCriteria[filterGroups][0][filters][0][value]": id,
2529
}
26-
2730
query := url.Values{}
2831
for key, value := range queryParams {
2932
query.Add(key, value)
3033
}
34+
resp, err := c.Create().R().SetQueryParams(queryParams).Get(categoriesPath + "list")
3135

32-
restyClient, err := c.CreateRestyClient()
3336
if err != nil {
3437
return nil, err
3538
}
3639

37-
resp, err := restyClient.R().
38-
SetHeader("Authorization", "Bearer "+c.AccessToken).
39-
SetQueryParams(queryParams).
40-
Get(path)
41-
if err != nil {
42-
return nil, err
43-
}
4440
var searchResults struct {
4541
Items []v1alpha1.CategoryParameters `json:"items"`
4642
}
@@ -61,106 +57,57 @@ func GetCategoryByName(c *magento.Client, categoryName string) (*v1alpha1.Catego
6157
}
6258
}
6359

64-
func CreateCategory(c *magento.Client, category *v1alpha1.Category) (*v1alpha1.Category, error) {
65-
path := c.BaseURL + "/rest/default/V1/categories"
60+
// CreateCategory creates a new category.
61+
func CreateCategory(c *magento.Client, category *v1alpha1.Category) (*v1alpha1.CategoryObservation, *resty.Response, error) {
6662
requestBody := map[string]interface{}{
6763
"category": category.Spec.ForProvider,
6864
}
69-
restyClient, err := c.CreateRestyClient()
70-
if err != nil {
71-
return nil, err
72-
}
73-
74-
resp, err := restyClient.R().
75-
SetHeader("Authorization", "Bearer "+c.AccessToken).
76-
SetHeader("Content-Type", "application/json").
77-
SetBody(requestBody).
78-
Post(path)
7965

66+
resp, err := c.Create().R().SetHeader("Content-Type", "application/json").SetBody(requestBody).Post(categoriesPath)
8067
if err != nil {
81-
return nil, errors.New("failed to create category: " + err.Error())
82-
}
83-
84-
if resp.StatusCode() != http.StatusOK {
85-
return nil, errors.New("unexpected status code: " + resp.Status() + ": " + string(resp.Body()))
68+
return nil, nil, err
8669
}
8770

88-
var newCategory *v1alpha1.Category
89-
err = json.Unmarshal(resp.Body(), &newCategory)
71+
var categoryObservation *v1alpha1.CategoryObservation
72+
err = json.Unmarshal(resp.Body(), &categoryObservation)
9073
if err != nil {
91-
return nil, errors.New("failed to parse response: " + err.Error())
74+
return nil, nil, err
9275
}
9376

94-
return newCategory, nil
77+
return categoryObservation, resp, nil
9578
}
9679

97-
func UpdateCategoryByName(c *magento.Client, categoryName string, observed *v1alpha1.Category) error {
98-
category, err := GetCategoryByName(c, categoryName)
99-
if err != nil {
100-
return err
101-
}
102-
path := fmt.Sprintf("%s/rest/all/V1/categories/%d", c.BaseURL, category.Spec.ForProvider.ID)
103-
104-
restyClient, err := c.CreateRestyClient()
105-
if err != nil {
106-
return err
107-
}
108-
80+
// UpdateCategoryByID updates a category by its ID.
81+
func UpdateCategoryByID(c *magento.Client, id int, observed *v1alpha1.Category) error {
10982
requestBody := map[string]interface{}{
11083
"category": observed.Spec.ForProvider,
11184
}
11285

113-
resp, err := restyClient.R().
114-
SetHeader("Authorization", "Bearer "+c.AccessToken).
115-
SetHeader("Content-Type", "application/json").
116-
SetBody(requestBody).
117-
Put(path)
86+
_, err := c.Create().R().SetBody(requestBody).Put(categoriesPath + strconv.Itoa(id))
11887
if err != nil {
11988
return err
12089
}
12190

122-
if resp.StatusCode() != http.StatusOK {
123-
return errors.New("failed to update category")
124-
}
125-
12691
return nil
12792
}
12893

129-
func DeleteCategoryByName(c *magento.Client, categoryName string) error {
130-
category, err := GetCategoryByName(c, categoryName)
131-
if err != nil {
132-
return err
133-
}
134-
135-
path := fmt.Sprintf("%s/rest/all/V1/categories/%d", c.BaseURL, category.Spec.ForProvider.ID)
136-
137-
restyClient, err := c.CreateRestyClient()
138-
if err != nil {
139-
return err
140-
}
141-
142-
resp, err := restyClient.R().
143-
SetHeader("Authorization", "Bearer "+c.AccessToken).
144-
Delete(path)
145-
if err != nil {
146-
return err
147-
}
148-
149-
if resp.StatusCode() != http.StatusOK {
150-
return errors.New("failed to delete category")
151-
}
152-
153-
return nil
94+
// DeleteCategoryByID deletes a category by its ID.
95+
func DeleteCategoryByID(c *magento.Client, id int) error {
96+
_, err := c.Create().R().Delete(categoriesPath + strconv.Itoa(id))
97+
return err
15498
}
15599

156-
func IsCategoryUpToDate(name string, observed *v1alpha1.Category, desired *v1alpha1.Category) (bool, error) {
100+
// IsUpToDate checks if the observed category is up to date with the desired category.
101+
func IsUpToDate(observed *v1alpha1.Category, desired *v1alpha1.Category) (bool, error) {
157102
if observed == nil || desired == nil {
158103
return false, errors.New("observed or desired category is nil")
159104
}
160105

161106
if observed.Spec.ForProvider.Name != desired.Spec.ForProvider.Name ||
162-
observed.Spec.ForProvider.IsActive != desired.Spec.ForProvider.IsActive ||
163-
observed.Spec.ForProvider.IncludeInMenu != desired.Spec.ForProvider.IncludeInMenu {
107+
observed.Spec.ForProvider.IncludeInMenu != desired.Spec.ForProvider.IncludeInMenu ||
108+
observed.Spec.ForProvider.ParentID != desired.Spec.ForProvider.ParentID ||
109+
observed.Spec.ForProvider.Position != desired.Spec.ForProvider.Position ||
110+
observed.Spec.ForProvider.Level != desired.Spec.ForProvider.Level {
164111
return false, nil
165112
}
166113

internal/client/client.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ func NewClient(baseURL, accessToken string) *Client {
1919
}
2020

2121
// CreateRestyClient creates a new resty client with configuration from Client
22-
func (c *Client) CreateRestyClient() (*resty.Client, error) {
22+
func (c *Client) Create() *resty.Client {
2323
restyClient := resty.New()
2424
restyClient.SetBaseURL(c.BaseURL)
2525
restyClient.SetAuthToken(c.AccessToken)
2626

27-
return restyClient, nil
27+
return restyClient
2828
}

internal/controller/category/category.go

+21-18
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ package category
1818

1919
import (
2020
"context"
21-
"fmt"
21+
"net/http"
22+
"strconv"
2223

2324
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
2425
"github.com/pkg/errors"
@@ -149,19 +150,26 @@ func (c *external) Observe(ctx context.Context, mg resource.Managed) (managed.Ex
149150
return managed.ExternalObservation{}, errors.New(errNotCategory)
150151
}
151152

152-
fmt.Printf("Observing: %+v", cr)
153-
desired, err := categories.GetCategoryByName(c.service.client, cr.Spec.ForProvider.Name)
153+
externalID := cr.GetAnnotations()["external-id"]
154+
desired, err := categories.GetCategoryByID(c.service.client, externalID)
154155
if err != nil {
155156
return managed.ExternalObservation{
156157
ResourceExists: false,
157158
}, err
158159
}
159160

161+
id, _ := strconv.Atoi(externalID)
160162
if desired != nil {
161163
cr.Status.SetConditions(xpv1.Available())
164+
cr.Status.AtProvider.Name = desired.Spec.ForProvider.Name
165+
cr.Status.AtProvider.ParentID = desired.Spec.ForProvider.ParentID
166+
cr.Status.AtProvider.IsActive = desired.Spec.ForProvider.IsActive
167+
cr.Status.AtProvider.Position = desired.Spec.ForProvider.Position
168+
cr.Status.AtProvider.Level = desired.Spec.ForProvider.Level
169+
cr.Status.AtProvider.ID = id
162170
}
163171

164-
isUpToDate, _ := categories.IsCategoryUpToDate(cr.Spec.ForProvider.Name, cr, desired)
172+
isUpToDate, _ := categories.IsUpToDate(cr, desired)
165173
return managed.ExternalObservation{
166174
ResourceExists: true,
167175
ResourceUpToDate: isUpToDate,
@@ -174,16 +182,16 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext
174182
if !ok {
175183
return managed.ExternalCreation{}, errors.New(errNotCategory)
176184
}
177-
178-
fmt.Printf("Creating: %+v", cr)
179-
180-
_, err := categories.CreateCategory(c.service.client, cr)
185+
cr.SetConditions(xpv1.Creating())
186+
category, resp, err := categories.CreateCategory(c.service.client, cr)
187+
cr.SetAnnotations(map[string]string{"external-id": strconv.Itoa(category.ID)})
188+
if resp.StatusCode() != http.StatusOK {
189+
return managed.ExternalCreation{}, errors.New(resp.String())
190+
}
181191
if err != nil {
182192
return managed.ExternalCreation{}, err
183193
}
184194
return managed.ExternalCreation{
185-
// Optionally return any details that may be required to connect to the
186-
// external resource. These will be stored as the connection secret.
187195
ConnectionDetails: managed.ConnectionDetails{},
188196
}, nil
189197
}
@@ -193,17 +201,13 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext
193201
if !ok {
194202
return managed.ExternalUpdate{}, errors.New(errNotCategory)
195203
}
196-
fmt.Printf("Updating: %+v", cr)
197-
198-
err := categories.UpdateCategoryByName(c.service.client, cr.Spec.ForProvider.Name, cr)
204+
err := categories.UpdateCategoryByID(c.service.client, cr.Status.AtProvider.ID, cr)
199205

200206
if err != nil {
201207
return managed.ExternalUpdate{}, err
202208
}
203209

204210
return managed.ExternalUpdate{
205-
// Optionally return any details that may be required to connect to the
206-
// external resource. These will be stored as the connection secret.
207211
ConnectionDetails: managed.ConnectionDetails{},
208212
}, nil
209213
}
@@ -213,9 +217,8 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error {
213217
if !ok {
214218
return errors.New(errNotCategory)
215219
}
216-
fmt.Printf("Deleting: %+v", cr)
217-
218-
err := categories.DeleteCategoryByName(c.service.client, cr.Spec.ForProvider.Name)
220+
cr.SetConditions(xpv1.Deleting())
221+
err := categories.DeleteCategoryByID(c.service.client, cr.Status.AtProvider.ID)
219222
if err != nil {
220223
return err
221224
}

package/crds/category.magento.web7.md_categories.yaml package/crds/magento.web7.md_categories.yaml

+2-4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ kind: CustomResourceDefinition
44
metadata:
55
annotations:
66
controller-gen.kubebuilder.io/version: v0.12.1
7-
name: categories.category.magento.web7.md
7+
name: categories.magento.web7.md
88
spec:
9-
group: category.magento.web7.md
9+
group: magento.web7.md
1010
names:
1111
categories:
1212
- crossplane
@@ -88,8 +88,6 @@ spec:
8888
- value
8989
type: object
9090
type: array
91-
id:
92-
type: integer
9391
includeInMenu:
9492
type: boolean
9593
isActive:

0 commit comments

Comments
 (0)