Skip to content

Commit

Permalink
Merge pull request #92 from cloudblue/LITE-22859_tier_templates_type_…
Browse files Browse the repository at this point in the history
…issue

Lite 22859 tier templates type issue
  • Loading branch information
marcserrat authored Apr 11, 2022
2 parents d61817c + 86486c0 commit 44081c5
Show file tree
Hide file tree
Showing 2 changed files with 192 additions and 79 deletions.
147 changes: 78 additions & 69 deletions connect/cli/plugins/product/sync/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# This file is part of the Ingram Micro Cloud Blue Connect connect-cli.
# Copyright (c) 2019-2021 Ingram Micro. All Rights Reserved.

from collections import namedtuple
from collections import defaultdict, namedtuple

from tqdm import trange

Expand All @@ -18,90 +18,99 @@


class TemplatesSynchronizer(ProductSynchronizer):
def sync(self): # noqa: CCR001

def __init__(self, client, silent):
super().__init__(client, silent)
self._action_handlers = {
'create': self._action_create,
'update': self._action_update,
'delete': self._action_delete,
}

def sync(self):
ws = self._wb["Templates"]
errors = {}
skipped_count = 0
created_items = []
updated_items = []
deleted_items = []
success_action_count = defaultdict(int)

row_indexes = trange(
2, ws.max_row + 1, disable=self._silent, leave=True, bar_format=DEFAULT_BAR_FORMAT,
)
for row_idx in row_indexes:
data = _RowData(*[ws.cell(row_idx, col_idx).value for col_idx in range(1, 9)])
row_indexes.set_description(f'Processing Template {data.id or data.title}')
if data.action == '-':
skipped_count += 1
continue
row_errors = self._validate_row(data)
if row_errors:
errors[row_idx] = row_errors
continue
template_data = {
'name': data.title,
'scope': data.scope,
'body': data.content,
'type': data.type,
}
if data.scope == 'asset':
template_data['title'] = data.title
if data.action == 'create':
row_indexes.set_description(f"Creating template {data[1]}")
try:
template = self._create_template(template_data)
created_items.append(template)
self._update_sheet_row(ws, row_idx, template)
continue
except Exception as e:
errors[row_idx] = [str(e)]
continue
try:
current = self._client.products[self._product_id].templates[data.id].get()
except ClientError as e:
if data.action == 'delete':
if e.status_code == 404:
deleted_items.append(data)
continue
errors[row_idx] = [str(e)]
continue
errors[row_idx] = [
f'Cannot {data.action} template {data.id} since does not exist in the product.'
'Create it instead',
]
continue
if current['type'] != data.type or current['scope'] != data.scope:
errors[row_idx] = [
f'Switching scope or type is not supported. '
f'Original scope {current["scope"]}, requested scope {data.scope}. '
f'Original type {current["type"]}, requested type {data.type}',
]
continue
try:
if data.action == 'update':
template = self._update_template(data.id, template_data)
updated_items.append(template)
self._update_sheet_row(ws, row_idx, template)
if data.action == 'delete':
self._client.products[self._product_id].templates[data.id].delete()
deleted_items.append(data)

if data.action != '-':
self._process_row(data, ws, row_indexes, row_idx)
success_action_count[data.action] += 1
except Exception as e:
errors[row_idx] = [str(e)]
errors[row_idx] = str(e).split('\n')

return (
skipped_count,
len(created_items),
len(updated_items),
len(deleted_items),
success_action_count['-'],
success_action_count['create'],
success_action_count['update'],
success_action_count['delete'],
errors,
)

def _create_template(self, template_data):
return self._client.products[self._product_id].templates.create(template_data)
def _process_row(self, data, ws, row_indexes, row_idx):
row_errors = self._validate_row(data)
if row_errors:
raise Exception('\n'.join(row_errors))
template = self._action_handlers[data.action](data, row_indexes)
if template:
self._update_sheet_row(ws, row_idx, template)

def _action_create(self, data, row_indexes):
row_indexes.set_description(f"Creating template {data.title}")
payload = self._row_to_payload(data)
return self._client.products[self._product_id].templates.create(payload)

def _update_template(self, tl_id, template_data):
return self._client.products[self._product_id].templates[tl_id].update(template_data)
def _action_update(self, data, row_indexes):
row_indexes.set_description(f"Updating template {data.id}")

try:
current = self._client.products[self._product_id].templates[data.id].get()
except ClientError as e:
if e.status_code == 404:
raise Exception(
f'Cannot update template {data.id} since does not exist in the product. '
'Create it instead',
) from e
raise e

payload = self._row_to_payload(data)
# check not changing scope or type before update
if current.get('type') != payload.get('type') or current['scope'] != payload['scope']:
raise Exception(
f'Switching scope or type is not supported. '
f'Original scope {current["scope"]}, requested scope {payload["scope"]}. '
f'Original type {current.get("type")}, requested type {payload.get("type")}',
)
return self._client.products[self._product_id].templates[data.id].update(payload)

def _action_delete(self, data, row_indexes):
row_indexes.set_description(f"Deleting template {data.id}")
try:
self._client.products[self._product_id].templates[data.id].delete()
except ClientError as e:
# if the template doesn't exist, perform as success deletion
if e.status_code != 404:
raise

@staticmethod
def _row_to_payload(data):
template_payload = {
'name': data.title,
'scope': data.scope,
'body': data.content,
}
if data.scope == 'asset':
template_payload.update({
'title': data.title,
'type': data.type,
})
return template_payload

@staticmethod
def _update_sheet_row(ws, row_idx, template):
Expand Down
124 changes: 114 additions & 10 deletions tests/plugins/product/sync/test_template.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from responses import matchers

from connect.cli.plugins.product.sync.templates import TemplatesSynchronizer
from connect.client import ConnectClient

Expand Down Expand Up @@ -213,6 +215,56 @@ def test_create_template_error(fs, get_sync_templates_env, mocked_templates_resp
assert errors == {2: ['500 Internal Server Error']}


def test_create_template_for_tier_scope_ignore_type(
fs, get_sync_templates_env, mocked_templates_response, mocked_responses
):
get_sync_templates_env['Templates']['C2'] = 'create'
get_sync_templates_env['Templates']['A2'] = None
get_sync_templates_env['Templates']['D2'] = 'tier1'
get_sync_templates_env['Templates']['E2'] = 'fulfillment'

get_sync_templates_env.save(f'{fs.root_path}/test.xlsx')

synchronizer = TemplatesSynchronizer(
client=ConnectClient(
use_specs=False,
api_key='ApiKey SU:123',
endpoint='https://localhost/public/v1',
),
silent=True,
)

mocked_responses.add(
method='POST',
url='https://localhost/public/v1/products/PRD-276-377-545/templates',
match=[
matchers.json_params_matcher({
'name': 'Template 1',
'scope': 'tier1',
'body': (
'# Template 1\n\n'
'This is **template 1** with the following parameters:\n\n'
'1. t0_o_email = {{ t0_o_email }}\n'
'2. t0_f_password = {{ t0_f_password }}\n'
'3. t0_f_text = {{ t0_f_text }}\n\n'
'Have a nice day!'
),
}),
],
json=mocked_templates_response[0],
)

synchronizer.open(f'{fs.root_path}/test.xlsx', 'Templates')

skipped, created, updated, deleted, errors = synchronizer.sync()

assert skipped == 0
assert created == 1
assert updated == 0
assert deleted == 0
assert errors == {}


def test_update_template_not_exists(
fs,
get_sync_templates_env,
Expand Down Expand Up @@ -247,7 +299,7 @@ def test_update_template_not_exists(
assert updated == 0
assert deleted == 0
assert errors == {
2: ['Cannot update template TL-551-876-782 since does not exist in the product.Create it '
2: ['Cannot update template TL-551-876-782 since does not exist in the product. Create it '
'instead'],
}

Expand All @@ -272,7 +324,7 @@ def test_delete_template_not_exists(
)

mocked_responses.add(
method='GET',
method='DELETE',
url='https://localhost/public/v1/products/PRD-276-377-545/templates/TL-551-876-782',
status=404,
)
Expand Down Expand Up @@ -308,7 +360,7 @@ def test_delete_template_500(
)

mocked_responses.add(
method='GET',
method='DELETE',
url='https://localhost/public/v1/products/PRD-276-377-545/templates/TL-551-876-782',
status=500,
)
Expand All @@ -324,7 +376,7 @@ def test_delete_template_500(
assert errors == {2: ['500 Internal Server Error']}


def test_delete_template(fs, get_sync_templates_env, mocked_templates_response, mocked_responses):
def test_delete_template(fs, get_sync_templates_env, mocked_responses):
get_sync_templates_env['Templates']['C2'] = 'delete'

get_sync_templates_env.save(f'{fs.root_path}/test.xlsx')
Expand All @@ -338,12 +390,6 @@ def test_delete_template(fs, get_sync_templates_env, mocked_templates_response,
silent=True,
)

mocked_responses.add(
method='GET',
url='https://localhost/public/v1/products/PRD-276-377-545/templates/TL-551-876-782',
json=mocked_templates_response[0],
)

mocked_responses.add(
method='DELETE',
url='https://localhost/public/v1/products/PRD-276-377-545/templates/TL-551-876-782',
Expand Down Expand Up @@ -481,3 +527,61 @@ def test_update_template_exception(
assert updated == 0
assert deleted == 0
assert errors == {2: ['500 Internal Server Error']}


def test_update_template_for_tier_scope_ignore_type(
fs,
get_sync_templates_env,
mocked_templates_response,
mocked_responses,
):
get_sync_templates_env['Templates']['C2'] = 'update'
get_sync_templates_env['Templates']['D2'] = 'tier1'
get_sync_templates_env['Templates']['E2'] = 'fulfillment'

get_sync_templates_env.save(f'{fs.root_path}/test.xlsx')

synchronizer = TemplatesSynchronizer(
client=ConnectClient(
use_specs=False,
api_key='ApiKey SU:123',
endpoint='https://localhost/public/v1',
),
silent=True,
)

mocked_responses.add(
method='GET',
url='https://localhost/public/v1/products/PRD-276-377-545/templates/TL-551-876-782',
json=mocked_templates_response[1],
)

mocked_responses.add(
method='PUT',
url='https://localhost/public/v1/products/PRD-276-377-545/templates/TL-551-876-782',
match=[
matchers.json_params_matcher({
'name': 'Template 1',
'scope': 'tier1',
'body': (
'# Template 1\n\n'
'This is **template 1** with the following parameters:\n\n'
'1. t0_o_email = {{ t0_o_email }}\n'
'2. t0_f_password = {{ t0_f_password }}\n'
'3. t0_f_text = {{ t0_f_text }}\n\n'
'Have a nice day!'
),
}),
],
json=mocked_templates_response[1],
)

synchronizer.open(f'{fs.root_path}/test.xlsx', 'Templates')

skipped, created, updated, deleted, errors = synchronizer.sync()

assert skipped == 0
assert created == 0
assert updated == 1
assert deleted == 0
assert errors == {}

0 comments on commit 44081c5

Please sign in to comment.