Skip to content

Commit ff2c593

Browse files
authored
Merge pull request #46 from cloudblue/LITE-30057-invited-accounts-can-not-create-schedule-tasks
LITE-30057 Invited accounts can not create schedule tasks
2 parents fadf953 + 0d1ae56 commit ff2c593

File tree

9 files changed

+199
-89
lines changed

9 files changed

+199
-89
lines changed

connect_bi_reporter/events.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
from connect.eaas.core.decorators import event, variables
77
from connect.eaas.core.extension import EventsApplicationBase
88
from connect.eaas.core.responses import BackgroundResponse
9+
from connect.eaas.core.inject.models import Context
10+
from connect_extension_utils.connect_services.base import get_extension_owner_client
911

1012
from connect_bi_reporter.uploads.tasks import UploadTaskApplicationMixin
1113
from connect_bi_reporter.scheduler import genererate_default_recurring_schedule_task
@@ -45,9 +47,15 @@ def handle_installation_status_change(self, request):
4547
f"This extension has been installed by {account}: "
4648
f"id={request['id']}, environment={request['environment']['id']}",
4749
)
50+
client = get_extension_owner_client(self.logger)
4851
return genererate_default_recurring_schedule_task(
49-
self.installation_client,
50-
self.context,
52+
client,
53+
Context(
54+
extension_id=self.context.extension_id,
55+
environment_id=self.context.environment_id,
56+
installation_id=request['id'],
57+
account_id=request['owner']['id'],
58+
),
5159
self.logger,
5260
BackgroundResponse,
5361
)

connect_bi_reporter/scheduler.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
from connect.eaas.core.inject.models import Context
99

1010
from connect_bi_reporter.connect_services.devops import create_schedule_task, get_schedule_tasks
11-
from connect_bi_reporter.constants import DEFAULT_RECURRING_EAAS_SCHEDULE_TASK_DATA
11+
from connect_bi_reporter.constants import (
12+
CREATE_UPLOADS_METHOD_NAME,
13+
DEFAULT_RECURRING_EAAS_SCHEDULE_TASK_DATA,
14+
)
1215

1316

1417
class TriggerTypeEnum(str, enum.Enum):
@@ -121,7 +124,11 @@ def genererate_default_recurring_schedule_task(
121124
):
122125
try:
123126
scheduler = Scheduler(client, context, logger)
124-
schedule_tasks = scheduler.get_schedule_tasks()
127+
schedule_tasks = [
128+
task for task in scheduler.get_schedule_tasks()
129+
if task['method'] == CREATE_UPLOADS_METHOD_NAME
130+
and task['parameter']['installation_id'] == context.installation_id
131+
]
125132
if schedule_tasks:
126133
task_ids = ', '.join(task['id'] for task in schedule_tasks)
127134
logger.info(
@@ -136,11 +143,12 @@ def genererate_default_recurring_schedule_task(
136143
datetime.utcnow() + timedelta(days=1)
137144
).replace(hour=0, minute=0, second=0, microsecond=0)
138145
method_payload = {
139-
'method': 'create_uploads',
146+
'method': CREATE_UPLOADS_METHOD_NAME,
140147
'name': f'Create Uploads - {context.account_id}',
141148
'description': 'Create Uploads for recurrent processing.',
142149
'parameter': {
143150
'installation_id': context.installation_id,
151+
'account_id': context.account_id,
144152
},
145153
}
146154
trigger_data = {

connect_bi_reporter/settings/api/views.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from connect.eaas.core.decorators import router
66
from connect.eaas.core.inject.common import get_call_context, get_logger
77
from connect.eaas.core.inject.models import Context
8-
from connect.eaas.core.inject.synchronous import get_installation_client
8+
from connect.eaas.core.inject.synchronous import get_extension_client
99
from connect_extension_utils.api.errors import Http404
1010
from fastapi import Depends, status
1111

@@ -24,14 +24,18 @@ class SettingsWebAppMixin:
2424
)
2525
def get_create_upload_task_info(
2626
self,
27-
client: ConnectClient = Depends(get_installation_client),
27+
client: ConnectClient = Depends(get_extension_client),
2828
context: Context = Depends(get_call_context),
2929
logger: Logger = Depends(get_logger),
3030
):
3131
scheduler = Scheduler(client, context, logger)
3232

33-
task = scheduler.get_schedule_task_by_method_name(CREATE_UPLOADS_METHOD_NAME)
33+
tasks = [
34+
task for task in scheduler.get_schedule_tasks()
35+
if task['method'] == CREATE_UPLOADS_METHOD_NAME
36+
and task['parameter']['installation_id'] == context.installation_id
37+
]
3438

35-
if not task:
39+
if not tasks:
3640
raise Http404(obj_id=CREATE_UPLOADS_METHOD_NAME)
37-
return EaasScheduleTaskSchema(**task)
41+
return EaasScheduleTaskSchema(**tasks[0])

connect_bi_reporter/uploads/tasks.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
ScheduledExecutionResponse,
99
)
1010
from connect_extension_utils.db.models import get_db_ctx_manager
11+
from connect_extension_utils.connect_services.base import get_extension_owner_client
1112
from sqlalchemy.exc import DBAPIError
1213

1314
from connect_bi_reporter.connect_services.reports import download_report
@@ -26,28 +27,38 @@ class UploadTaskApplicationMixin:
2627
'Create Upload objects base on Connect Report files',
2728
)
2829
def create_uploads(self, schedule):
29-
if 'installation_id' not in schedule['parameter']:
30-
return ScheduledExecutionResponse.fail(output='Parameter installation_id is missing.')
30+
missing_params = [
31+
param for param in ['installation_id', 'account_id']
32+
if param not in schedule['parameter']
33+
]
34+
if missing_params:
35+
params = ', '.join(missing_params)
36+
return ScheduledExecutionResponse.fail(
37+
output=f'The following required schedule parameters are missing: `{params}`.',
38+
)
3139

3240
installation_id = schedule['parameter']['installation_id']
41+
account_id = schedule['parameter']['account_id']
42+
43+
extension_owner_client = get_extension_owner_client(self.logger)
44+
installation_client = self.get_installation_admin_client(installation_id)
3345
try:
34-
client = self.get_installation_admin_client(installation_id)
35-
installation = client('devops').installations[installation_id].get()
46+
3647
with get_db_ctx_manager(self.config) as db:
3748
feeds = db.query(Feed).filter(
38-
Feed.account_id == installation['owner']['id'],
49+
Feed.account_id == account_id,
3950
Feed.status == FeedStatusChoices.enabled,
4051
).all()
4152
if not feeds:
4253
self.logger.info(Info.no_feeds_to_process)
4354
return ScheduledExecutionResponse.done()
44-
uploads = create_uploads(db, client, self.logger, feeds)
45-
scheduler = Scheduler(client, self.context, self.logger)
55+
uploads = create_uploads(db, installation_client, self.logger, feeds)
56+
scheduler = Scheduler(extension_owner_client, self.context, self.logger)
4657
create_process_upload_tasks(
4758
uploads,
4859
scheduler,
49-
installation_id=installation['id'],
50-
account_id=installation['owner']['id'],
60+
installation_id=installation_id,
61+
account_id=account_id,
5162
)
5263
except (ClientError, DBAPIError) as exc:
5364
output = Errors.connect_client_error

docker-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ services:
3636
DATABASE_URL: postgresql+psycopg2://postgres:1q2w3e@db/bi_reporter
3737
depends_on:
3838
- db
39+
links:
40+
- "db_ram:db"
3941

4042
connect_bi_reporter_test:
4143
container_name: connect_bi_reporter_test

tests/conftest.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from pytest_factoryboy import register
1010
from connect.client import AsyncConnectClient, ConnectClient
1111
from connect.eaas.core.inject.models import Context
12+
from connect.eaas.core.inject.common import get_call_context
1213
from connect_extension_utils.db.models import get_db
1314

1415
from .factories import CredentialFactory, FeedFactory, UploadFactory
@@ -46,8 +47,13 @@ def logger(mocker):
4647

4748

4849
@pytest.fixture
49-
def common_context():
50-
return Context(call_type='user', user_id='UR-000-000-000', account_id='PA-000-000')
50+
def common_context(installation):
51+
return Context(
52+
call_type='user',
53+
user_id='UR-000-000-000',
54+
account_id='PA-000-000',
55+
installation_id=installation['id'],
56+
)
5157

5258

5359
@pytest.fixture(autouse=True)
@@ -64,10 +70,11 @@ def mocked_context(config):
6470

6571

6672
@pytest.fixture
67-
def api_client(test_client_factory, dbsession):
73+
def api_client(test_client_factory, dbsession, common_context):
6874
client = test_client_factory(ConnectBiReporterWebApplication)
6975
client.app.dependency_overrides = {
7076
get_db: lambda: dbsession,
77+
get_call_context: lambda: common_context,
7178
}
7279
yield client
7380

@@ -217,7 +224,9 @@ def eaas_schedule_task():
217224
"name": "Create Uploads - PA-065-102",
218225
"description": "Create Uploads for recurrent processing.",
219226
"method": "create_uploads",
220-
"parameter": {},
227+
"parameter": {
228+
"installation_id": "EIN-8436-7221-8308",
229+
},
221230
"trigger": {
222231
"type": "recurring",
223232
"start": "2024-01-10T09:35:03+00:00",

tests/test_events.py

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
# Copyright (c) 2024, Ingram Micro
44
# All rights reserved.
55
#
6+
from datetime import datetime, timedelta
7+
68
from connect.client import ClientError
79
from connect.eaas.core.inject.models import Context
810

@@ -11,33 +13,53 @@
1113

1214
def test_handle_installation_status_installed_create_task(
1315
connect_client,
14-
client_mocker_factory,
1516
logger,
1617
installation,
1718
eaas_schedule_task,
19+
mocker,
1820
):
1921
config = {}
20-
client_mocker = client_mocker_factory(base_url=connect_client.endpoint)
22+
mocker.patch(
23+
'connect_bi_reporter.events.get_extension_owner_client',
24+
return_value=connect_client,
25+
)
26+
start = datetime.utcnow()
27+
string_start_date = (
28+
start + timedelta(days=1)
29+
).replace(hour=0, minute=0, second=0, microsecond=0).isoformat()
30+
p_datetime = mocker.patch(
31+
'connect_bi_reporter.scheduler.datetime',
32+
)
33+
p_datetime.utcnow.return_value = start
34+
p_get_connect_task = mocker.patch(
35+
'connect_bi_reporter.scheduler.get_schedule_tasks',
36+
return_value=[],
37+
)
38+
p_create_connect_task = mocker.patch(
39+
'connect_bi_reporter.scheduler.create_schedule_task',
40+
return_value=eaas_schedule_task,
41+
)
2142
ctx = Context(
2243
installation_id=installation['id'],
2344
environment_id=installation['environment']['id'],
2445
extension_id=installation['environment']['extension']['id'],
2546
account_id=installation['environment']['extension']['owner']['id'],
2647
)
27-
(
28-
client_mocker.ns('devops')
29-
.services[ctx.extension_id]
30-
.environments[ctx.environment_id]
31-
.schedules.all().mock(
32-
return_value=[],
33-
)
34-
)
35-
(
36-
client_mocker.ns('devops')
37-
.services[ctx.extension_id]
38-
.environments[ctx.environment_id]
39-
.schedules.create(return_value=eaas_schedule_task)
40-
)
48+
task_payload = {
49+
'description': 'Create Uploads for recurrent processing.',
50+
'method': 'create_uploads',
51+
'name': f'Create Uploads - {ctx.account_id}',
52+
'parameter': {
53+
'installation_id': ctx.installation_id,
54+
'account_id': ctx.account_id,
55+
},
56+
'trigger': {
57+
'amount': 1,
58+
'start': string_start_date,
59+
'type': 'recurring',
60+
'unit': 'days',
61+
},
62+
}
4163
ext = ConnectBiReporterEventsApplication(
4264
connect_client,
4365
logger,
@@ -46,6 +68,9 @@ def test_handle_installation_status_installed_create_task(
4668
installation_client=connect_client,
4769
)
4870
result = ext.handle_installation_status_change(installation)
71+
p_get_connect_task.assert_called_once_with(connect_client, ctx)
72+
p_create_connect_task.assert_called_once_with(connect_client, ctx, task_payload)
73+
4974
assert result.status == 'success'
5075
assert logger.method_calls[0].args[0] == (
5176
f'This extension has been installed by Provider '
@@ -59,27 +84,30 @@ def test_handle_installation_status_installed_create_task(
5984

6085
def test_handle_installation_status_installed_task_already_exists(
6186
connect_client,
62-
client_mocker_factory,
6387
logger,
6488
installation,
6589
eaas_schedule_task,
90+
mocker,
6691
):
6792
config = {}
68-
client_mocker = client_mocker_factory(base_url=connect_client.endpoint)
93+
mocker.patch(
94+
'connect_bi_reporter.events.get_extension_owner_client',
95+
return_value=connect_client,
96+
)
97+
p_get_connect_task = mocker.patch(
98+
'connect_bi_reporter.scheduler.get_schedule_tasks',
99+
return_value=[eaas_schedule_task],
100+
)
101+
p_create_connect_task = mocker.patch(
102+
'connect_bi_reporter.scheduler.create_schedule_task',
103+
)
69104
ctx = Context(
70105
installation_id=installation['id'],
71106
environment_id=installation['environment']['id'],
72107
extension_id=installation['environment']['extension']['id'],
73108
account_id=installation['environment']['extension']['owner']['id'],
74109
)
75-
(
76-
client_mocker.ns('devops')
77-
.services[ctx.extension_id]
78-
.environments[ctx.environment_id]
79-
.schedules.all().mock(
80-
return_value=[eaas_schedule_task],
81-
)
82-
)
110+
83111
ext = ConnectBiReporterEventsApplication(
84112
connect_client,
85113
logger,
@@ -88,6 +116,8 @@ def test_handle_installation_status_installed_task_already_exists(
88116
installation_client=connect_client,
89117
)
90118
result = ext.handle_installation_status_change(installation)
119+
p_get_connect_task.assert_called_once_with(connect_client, ctx)
120+
p_create_connect_task.assert_not_called()
91121
assert result.status == 'success'
92122
assert logger.method_calls[0].args[0] == (
93123
f'This extension has been installed by Provider '

tests/test_scheduler.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,29 @@ def test_scheduler(connect_client, logger, mocker, eaas_schedule_task, installat
9292
@pytest.mark.parametrize(
9393
'response_type, mocker_return_value, expected_response',
9494
(
95-
(None, {'return_value': [{'id': 'test'}]}, None),
95+
(None, {
96+
'return_value': [
97+
{
98+
'id': 'some',
99+
'method': 'create_uploads',
100+
'parameter': {
101+
'installation_id': 'EIN-8436-7221-8308',
102+
},
103+
},
104+
],
105+
}, None),
96106
(None, {'side_effect': ClientError(message='Bad!', status_code=500)}, None),
97-
(BackgroundResponse, {'return_value': [{'id': 'test'}]}, 'success'),
107+
(BackgroundResponse, {
108+
'return_value': [
109+
{
110+
'id': 'some',
111+
'method': 'create_uploads',
112+
'parameter': {
113+
'installation_id': 'EIN-8436-7221-8308',
114+
},
115+
},
116+
],
117+
}, 'success'),
98118
(
99119
BackgroundResponse,
100120
{'side_effect': ClientError(message='Bad!', status_code=500)},
@@ -110,6 +130,7 @@ def test_genererate_default_recurring_schedule_task(
110130
response_type,
111131
mocker_return_value,
112132
expected_response,
133+
113134
):
114135
ctx = Context(
115136
installation_id=installation['id'],

0 commit comments

Comments
 (0)