mcm-cli 1.6.0__py3-none-any.whl → 1.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mcm_cli-1.6.0.dist-info → mcm_cli-1.7.0.dist-info}/METADATA +1 -1
- {mcm_cli-1.6.0.dist-info → mcm_cli-1.7.0.dist-info}/RECORD +11 -11
- mcmcli/__main__.py +1 -1
- mcmcli/command/admin.py +130 -69
- mcmcli/command/campaign.py +4 -4
- mcmcli/command/decision.py +17 -16
- {mcm_cli-1.6.0.dist-info → mcm_cli-1.7.0.dist-info}/LICENSE +0 -0
- {mcm_cli-1.6.0.dist-info → mcm_cli-1.7.0.dist-info}/NOTICE +0 -0
- {mcm_cli-1.6.0.dist-info → mcm_cli-1.7.0.dist-info}/WHEEL +0 -0
- {mcm_cli-1.6.0.dist-info → mcm_cli-1.7.0.dist-info}/entry_points.txt +0 -0
- {mcm_cli-1.6.0.dist-info → mcm_cli-1.7.0.dist-info}/top_level.txt +0 -0
@@ -1,13 +1,13 @@
|
|
1
1
|
mcmcli/__init__.py,sha256=-U6lMZ9_99IXAKwnqnYXYr6NcO6TSmG-kxewgvJjU4k,575
|
2
|
-
mcmcli/__main__.py,sha256=
|
2
|
+
mcmcli/__main__.py,sha256=r1C_-MzJ3UISn0P0SKNlEDQCECf4VSvioELtlePMvRA,1844
|
3
3
|
mcmcli/logging.py,sha256=xjRS5ey1ONx_d34qB1Fetb_SwPysoh2hzNDuNAaYYWQ,1739
|
4
4
|
mcmcli/requests.py,sha256=IuySBQ8P_GoGF3f_TRysfgQNOhi2n9M84WK_eRXnoEU,2945
|
5
5
|
mcmcli/command/account.py,sha256=FWXmzOLj4rVLVLEv-w0eDVlQVrkONvR1UewZbcTDgE4,24994
|
6
|
-
mcmcli/command/admin.py,sha256=
|
6
|
+
mcmcli/command/admin.py,sha256=0uB5djhbdjy3HMIQ0r3bfcmYyBfwZo_F9mgWavPnr3E,18514
|
7
7
|
mcmcli/command/auth.py,sha256=Ak7ZNEskWPpMoeTJcbYlEpDBgzxn8N33Q2dNf67SsCs,2926
|
8
|
-
mcmcli/command/campaign.py,sha256=
|
8
|
+
mcmcli/command/campaign.py,sha256=eHE_i1lRlUuU1GeVMwXkJgBU_zOgU-b9Wo0SYC9TK7M,15444
|
9
9
|
mcmcli/command/config.py,sha256=08C5ftAvdvpQ26Z329LqhP8AxTI629LS7Ou6glzrRgw,4396
|
10
|
-
mcmcli/command/decision.py,sha256=
|
10
|
+
mcmcli/command/decision.py,sha256=3eCz4360q37vxNZVBUEDEVKGEqatjMA1nKswQh8GXsA,8993
|
11
11
|
mcmcli/command/report.py,sha256=N8IMyDZ5QpY11-KkZG-n5_ZzEeh-ME5s2s3wrAKEGjY,5387
|
12
12
|
mcmcli/command/wallet.py,sha256=vG2rg7tPwGsV9YB7cpvkiocbqtB1reqXn7dmolFmzD4,11536
|
13
13
|
mcmcli/data/account.py,sha256=pe7tPapP6vlUD5D5L5Nh5k2bkWdYOK01Mpt5fBYFnJs,1782
|
@@ -23,10 +23,10 @@ mcmcli/data/seller.py,sha256=40SA7QekM3a3svDrDYLo_QYJ68VUxDO0KeGejJMp4k4,1004
|
|
23
23
|
mcmcli/data/token.py,sha256=11wtyLHCAZHu0LVbNDPa-yipcL6lenxoYIKEI58VzFs,1744
|
24
24
|
mcmcli/data/user_join_request.py,sha256=lXMO2hE_VpRg0JofVrYAVM82S-RLFkPrZk8-drvhoDI,1251
|
25
25
|
mcmcli/data/wallet.py,sha256=eMUi8N0vJdg_E10TPhSPoZkZtmIG7gHyqgabQ8C5Lg8,3217
|
26
|
-
mcm_cli-1.
|
27
|
-
mcm_cli-1.
|
28
|
-
mcm_cli-1.
|
29
|
-
mcm_cli-1.
|
30
|
-
mcm_cli-1.
|
31
|
-
mcm_cli-1.
|
32
|
-
mcm_cli-1.
|
26
|
+
mcm_cli-1.7.0.dist-info/LICENSE,sha256=RFhQPdSOiMTguUX7JSoIuTxA7HVzCbj_p8WU36HjUQQ,10947
|
27
|
+
mcm_cli-1.7.0.dist-info/METADATA,sha256=_9mCAcpzeBGhL5404uuUTscJqqAiwFfb5pmnkzjam9U,3056
|
28
|
+
mcm_cli-1.7.0.dist-info/NOTICE,sha256=Ldnl2MjRaXPxcldUdbI2NTybq60XAa2LowRhFrRTuiI,76
|
29
|
+
mcm_cli-1.7.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
30
|
+
mcm_cli-1.7.0.dist-info/entry_points.txt,sha256=qTHAWZ-ejSiU4t11RYwtAU8ScqhQPDeMVTG9y4wMVLg,60
|
31
|
+
mcm_cli-1.7.0.dist-info/top_level.txt,sha256=sh7oqIaqLQlMtKHlxHHgpV2xGMrBMPFWpSp0C6nvJ_Y,7
|
32
|
+
mcm_cli-1.7.0.dist-info/RECORD,,
|
mcmcli/__main__.py
CHANGED
@@ -37,7 +37,7 @@ def version():
|
|
37
37
|
"""
|
38
38
|
Show the tool version
|
39
39
|
"""
|
40
|
-
typer.echo(f"Version: mcm-cli v1.
|
40
|
+
typer.echo(f"Version: mcm-cli v1.7.0")
|
41
41
|
|
42
42
|
app.add_typer(mcmcli.command.account.app, name="account", help="Ad account management")
|
43
43
|
app.add_typer(mcmcli.command.admin.app, name="admin", help="Platform administration")
|
mcmcli/command/admin.py
CHANGED
@@ -27,8 +27,11 @@ import mcmcli.command.account
|
|
27
27
|
import mcmcli.command.auth
|
28
28
|
import mcmcli.command.campaign
|
29
29
|
import mcmcli.command.config
|
30
|
+
import mcmcli.command.decision
|
30
31
|
import mcmcli.command.wallet
|
31
32
|
import mcmcli.requests
|
33
|
+
import random
|
34
|
+
import requests
|
32
35
|
import sys
|
33
36
|
import typer
|
34
37
|
|
@@ -40,76 +43,90 @@ def _create_admin_command(profile):
|
|
40
43
|
auth = AuthCommand(profile)
|
41
44
|
return AdminCommand(profile, auth)
|
42
45
|
|
43
|
-
@app.command()
|
44
|
-
def list_wallet_balances(
|
45
|
-
profile: str = typer.Option("default", help="profile name of the MCM CLI."),
|
46
|
-
):
|
47
|
-
"""
|
48
|
-
List the wallet balances of all of the ad accounts
|
49
|
-
"""
|
50
|
-
admin = _create_admin_command(profile)
|
51
|
-
if admin is None:
|
52
|
-
return
|
53
|
-
admin.list_wallet_balances()
|
54
|
-
|
55
46
|
|
56
47
|
@app.command()
|
57
|
-
def
|
58
|
-
|
48
|
+
def block_item(
|
49
|
+
item_id: str = typer.Option(help="Item ID"),
|
50
|
+
account_id: str = typer.Option(None, help="The Ad Account ID is applicable only for MSPI catalogs. If this value is provided, only the item associated with the specified seller ID will be removed from ad serving. If it is not provided, the specified item will be removed for all sellers in the MSPI catalog."),
|
51
|
+
to_curl: bool = typer.Option(False, help="Generate the curl command instead of executing it."),
|
52
|
+
profile: str = typer.Option("default", help="Profile name of the MCM CLI."),
|
59
53
|
):
|
60
54
|
"""
|
61
|
-
|
55
|
+
Item Kill Switch Command.
|
56
|
+
This API immediately blocks an item or an ad account item from appearing in ads by marking it as `blocked`.
|
62
57
|
"""
|
58
|
+
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ")
|
59
|
+
|
60
|
+
# print(f"invoked block_item(item_id={item_id}, account_id={account_id}, blocked='Requested at {timestamp}')");
|
63
61
|
admin = _create_admin_command(profile)
|
64
62
|
if admin is None:
|
65
63
|
return
|
66
|
-
|
64
|
+
|
65
|
+
curl, error, result = admin.block_item(item_id=item_id, account_id=account_id, to_curl=to_curl)
|
66
|
+
if curl:
|
67
|
+
print(curl)
|
68
|
+
return
|
67
69
|
if error:
|
68
|
-
print(error, file=sys.stderr, flush=True)
|
70
|
+
print(f"ERROR: {error.message}", file=sys.stderr, flush=True)
|
69
71
|
return
|
72
|
+
|
73
|
+
print(result.model_dump_json())
|
74
|
+
return
|
70
75
|
|
71
|
-
print("Account ID,Account Title,Campaign ID,Campaign Title,Ad Type,Start,End,Budget Period,Budget Amount,Enabling State,State,Created At,Updated At")
|
72
|
-
for account_campaign in account_campaigns:
|
73
|
-
a, c = account_campaign
|
74
|
-
|
75
|
-
print(f'"{a.id}","{a.title}",', end="", flush=True)
|
76
|
-
print(f'"{c.id}","{c.title}","{c.ad_type}",', end="", flush=True)
|
77
|
-
print(f'"{c.schedule.start}","{c.schedule.end}",', end="", flush=True)
|
78
|
-
print(f'"{c.budget.period}","{int(c.budget.amount.amount_micro) / 1000000}",', end="", flush=True)
|
79
|
-
print(f'"{c.enabling_state}","{c.state}",', end="", flush=True)
|
80
|
-
print(f'"{c.created_at}","{c.updated_at}",', end="", flush=True)
|
81
|
-
# print(f'"{";".join(c.catalog_item_ids)}"')
|
82
|
-
print("", flush=True)
|
83
76
|
|
84
77
|
@app.command()
|
85
|
-
def
|
86
|
-
|
87
|
-
|
88
|
-
|
78
|
+
def generate_sample_data(
|
79
|
+
ad_inventory_id: str = typer.Option(help="The ad inventory ID to use when calling the Decision API."),
|
80
|
+
num_iterations: int = typer.Option(100, help="How many times to call the Decision API."),
|
81
|
+
warn: bool = typer.Option(True, help="Shows a warning message before running. Use `--no-warn` if you want to skip the warning."),
|
82
|
+
profile: str = typer.Option("default", help="Profile Name – The MCM CLI configuration profile to use."),
|
89
83
|
):
|
90
84
|
"""
|
91
|
-
|
85
|
+
Generate sample impressions and clicks. This command invokes the Decision APIs, and posts the impression
|
86
|
+
and click trackers to generate sample data in the platform.
|
92
87
|
"""
|
93
|
-
|
94
|
-
|
95
|
-
return
|
96
|
-
|
97
|
-
curl, error, users = admin.list_platform_users(to_curl)
|
98
|
-
if to_curl:
|
99
|
-
print(curl)
|
100
|
-
return
|
101
|
-
if error:
|
102
|
-
print(error, file=sys.stderr, flush=True)
|
103
|
-
return
|
104
|
-
if to_json:
|
105
|
-
json_dumps = [x.model_dump_json() for x in users]
|
106
|
-
print(f"[{','.join(json_dumps)}]")
|
107
|
-
return
|
88
|
+
if warn:
|
89
|
+
typer.confirm("This will generate sample impressions and clicks. Are you sure you want to continue?", abort=True)
|
108
90
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
91
|
+
# Initialize DecisionCommand
|
92
|
+
d = mcmcli.command.decision.DecisionCommand(profile)
|
93
|
+
|
94
|
+
print(f"Invoking the Decision API {num_iterations} times to generate sample impressions and clicks...", end='', flush=True)
|
95
|
+
thread, stopper = start_dot_printing()
|
96
|
+
|
97
|
+
for i in range(num_iterations):
|
98
|
+
# Call Decision API to get trackers
|
99
|
+
_, error, decided_items = d.decide_items(ad_inventory_id)
|
100
|
+
if error:
|
101
|
+
print_error(f"Error calling Decision API: {error.message}")
|
102
|
+
continue
|
103
|
+
|
104
|
+
if not decided_items or not decided_items.decided_items or len(decided_items.decided_items) == 0:
|
105
|
+
print_error("The Decision API returned an empty response.")
|
106
|
+
continue
|
107
|
+
|
108
|
+
for item in decided_items.decided_items:
|
109
|
+
# Post impression tracker
|
110
|
+
for imp_url in item.imp_trackers:
|
111
|
+
try:
|
112
|
+
requests.post(imp_url)
|
113
|
+
except requests.RequestException as e:
|
114
|
+
print(f"[{i}] Failed to post imp tracker: {imp_url} - Error: {e}")
|
115
|
+
|
116
|
+
# Post to click trackers with 20% probability
|
117
|
+
if random.random() >= 0.8:
|
118
|
+
continue
|
119
|
+
for click_url in item.click_trackers:
|
120
|
+
try:
|
121
|
+
requests.post(click_url)
|
122
|
+
except requests.RequestException as e:
|
123
|
+
print(f"[{i}] Failed to post imp tracker: {click_url} - Error: {e}")
|
124
|
+
|
125
|
+
print('.', end='', flush=True)
|
126
|
+
|
127
|
+
stop_dot_printing(thread, stopper)
|
128
|
+
print("\nDone generating sample data!")
|
129
|
+
return
|
113
130
|
|
114
131
|
|
115
132
|
@app.command()
|
@@ -139,6 +156,35 @@ def get_platform_user(
|
|
139
156
|
return
|
140
157
|
|
141
158
|
|
159
|
+
@app.command()
|
160
|
+
def list_all_campaigns(
|
161
|
+
profile: str = "default",
|
162
|
+
):
|
163
|
+
"""
|
164
|
+
List the campaigigns of all of the active ad accounts
|
165
|
+
"""
|
166
|
+
admin = _create_admin_command(profile)
|
167
|
+
if admin is None:
|
168
|
+
return
|
169
|
+
error, account_campaigns = admin.list_all_campaigns()
|
170
|
+
if error:
|
171
|
+
print(error, file=sys.stderr, flush=True)
|
172
|
+
return
|
173
|
+
|
174
|
+
print("Account ID,Account Title,Campaign ID,Campaign Title,Ad Type,Start,End,Budget Period,Budget Amount,Enabling State,State,Created At,Updated At")
|
175
|
+
for account_campaign in account_campaigns:
|
176
|
+
a, c = account_campaign
|
177
|
+
|
178
|
+
print(f'"{a.id}","{a.title}",', end="", flush=True)
|
179
|
+
print(f'"{c.id}","{c.title}","{c.ad_type}",', end="", flush=True)
|
180
|
+
print(f'"{c.schedule.start}","{c.schedule.end}",', end="", flush=True)
|
181
|
+
print(f'"{c.budget.period}","{int(c.budget.amount.amount_micro) / 1000000}",', end="", flush=True)
|
182
|
+
print(f'"{c.enabling_state}","{c.state}",', end="", flush=True)
|
183
|
+
print(f'"{c.created_at}","{c.updated_at}",', end="", flush=True)
|
184
|
+
# print(f'"{";".join(c.catalog_item_ids)}"')
|
185
|
+
print("", flush=True)
|
186
|
+
|
187
|
+
|
142
188
|
@app.command()
|
143
189
|
def list_items(
|
144
190
|
account_id: str = typer.Option(help="Ad account ID"),
|
@@ -197,6 +243,7 @@ def list_items(
|
|
197
243
|
else:
|
198
244
|
print(f"{account_id},{i.id},{i.is_active},\"{i.title}\",,")
|
199
245
|
|
246
|
+
|
200
247
|
@app.command()
|
201
248
|
def list_off_campaign_items(
|
202
249
|
account_id: str = typer.Option(help="Ad account ID"),
|
@@ -229,34 +276,48 @@ def list_off_campaign_items(
|
|
229
276
|
if i.id not in campaign_item_obj and i.is_active:
|
230
277
|
print(f"{i.id}, {i.title}")
|
231
278
|
|
279
|
+
|
232
280
|
@app.command()
|
233
|
-
def
|
234
|
-
item_id: str = typer.Option(help="Item ID"),
|
235
|
-
account_id: str = typer.Option(None, help="The Ad Account ID is applicable only for MSPI catalogs. If this value is provided, only the item associated with the specified seller ID will be removed from ad serving. If it is not provided, the specified item will be removed for all sellers in the MSPI catalog."),
|
281
|
+
def list_platform_users(
|
236
282
|
to_curl: bool = typer.Option(False, help="Generate the curl command instead of executing it."),
|
237
|
-
|
283
|
+
to_json: bool = typer.Option(False, help="Print raw output in json"),
|
284
|
+
profile: str = "default",
|
238
285
|
):
|
239
286
|
"""
|
240
|
-
|
241
|
-
This API immediately blocks an item or an ad account item from appearing in ads by marking it as “blocked.”
|
287
|
+
List the users of the platform
|
242
288
|
"""
|
243
|
-
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ")
|
244
|
-
|
245
|
-
# print(f"invoked block_item(item_id={item_id}, account_id={account_id}, blocked='Requested at {timestamp}')");
|
246
289
|
admin = _create_admin_command(profile)
|
247
290
|
if admin is None:
|
248
291
|
return
|
249
|
-
|
250
|
-
curl, error,
|
251
|
-
if
|
292
|
+
|
293
|
+
curl, error, users = admin.list_platform_users(to_curl)
|
294
|
+
if to_curl:
|
252
295
|
print(curl)
|
253
296
|
return
|
254
297
|
if error:
|
255
|
-
print(
|
298
|
+
print(error, file=sys.stderr, flush=True)
|
256
299
|
return
|
257
|
-
|
258
|
-
|
259
|
-
|
300
|
+
if to_json:
|
301
|
+
json_dumps = [x.model_dump_json() for x in users]
|
302
|
+
print(f"[{','.join(json_dumps)}]")
|
303
|
+
return
|
304
|
+
|
305
|
+
print('User ID,Created At,Updated At,Status,Email,Name,Roles')
|
306
|
+
for u in users:
|
307
|
+
roles = [f'{x.name} of {x.resource_type} {x.resource_id}' for x in u.roles]
|
308
|
+
print(f'{u.id},{u.created_at},{u.updated_at},{u.status},{u.email},{u.name},{';'.join(roles)}')
|
309
|
+
|
310
|
+
@app.command()
|
311
|
+
def list_wallet_balances(
|
312
|
+
profile: str = typer.Option("default", help="profile name of the MCM CLI."),
|
313
|
+
):
|
314
|
+
"""
|
315
|
+
List the wallet balances of all of the ad accounts
|
316
|
+
"""
|
317
|
+
admin = _create_admin_command(profile)
|
318
|
+
if admin is None:
|
319
|
+
return
|
320
|
+
admin.list_wallet_balances()
|
260
321
|
|
261
322
|
|
262
323
|
class AdminCommand:
|
mcmcli/command/campaign.py
CHANGED
@@ -110,7 +110,7 @@ def update_campaign(
|
|
110
110
|
target_roas: int = typer.Option(None, help='Target ROAS (%) – Applies only to campaigns with the Optimize ROAS goal type.'),
|
111
111
|
target_cpc: float = typer.Option(None, help='Target CPC – Set in the platform currency. Applies only to campaigns with the Manual CPC goal type.'),
|
112
112
|
budget_period: BudgetPeriod = typer.Option(None, help='Budget Period – Choose between DAILY or WEEKLY.'),
|
113
|
-
budget_amount:
|
113
|
+
budget_amount: float = typer.Option(None, help='Budget Amount – Set the spending limit for the chosen period.'),
|
114
114
|
profile: str = typer.Option("default", help="Profile Name – The MCM CLI configuration profile to use."),
|
115
115
|
):
|
116
116
|
"""
|
@@ -148,6 +148,9 @@ def update_campaign(
|
|
148
148
|
raise typer.BadParameter(f"The campaign goal type is not FIXED_CPC and cannot update the target CPC. Ad Account ID = {account_id}, Campaign ID = {campaign_id}")
|
149
149
|
goal['optimize_fixed_cpc']['target_cpc']['amount_micro'] = int(target_cpc * 1_000_000)
|
150
150
|
|
151
|
+
# Remove 'daily_budget' as it's unnecessary
|
152
|
+
c.root.pop("daily_budget", None)
|
153
|
+
|
151
154
|
_, error, c = command.update_campaign(c)
|
152
155
|
if error:
|
153
156
|
print(f"ERROR: {error.message}", file=sys.stderr, flush=True)
|
@@ -320,9 +323,6 @@ class CampaignCommand:
|
|
320
323
|
if campaign is None:
|
321
324
|
return Error(code=0, message="invalid campaign info"), None
|
322
325
|
|
323
|
-
# Remove 'daily_budget' as it's unnecessary
|
324
|
-
campaign.root.pop("daily_budget", None)
|
325
|
-
|
326
326
|
_api_url = f"{self.api_base_url}/ad-accounts/{campaign.root['ad_account_id']}/campaigns/{campaign.root['id']}"
|
327
327
|
_payload = {
|
328
328
|
"campaign": campaign.model_dump()
|
mcmcli/command/decision.py
CHANGED
@@ -21,6 +21,7 @@ import json
|
|
21
21
|
import mcmcli.command.auth
|
22
22
|
import mcmcli.command.config
|
23
23
|
import mcmcli.logging
|
24
|
+
import random
|
24
25
|
import sys
|
25
26
|
import typer
|
26
27
|
|
@@ -139,10 +140,10 @@ class DecisionCommand:
|
|
139
140
|
def decide_items(
|
140
141
|
self,
|
141
142
|
inventory_id,
|
142
|
-
num_items,
|
143
|
-
items,
|
144
|
-
location_filter,
|
145
|
-
to_curl,
|
143
|
+
num_items = 5,
|
144
|
+
items = False,
|
145
|
+
location_filter = None,
|
146
|
+
to_curl = False,
|
146
147
|
) -> tuple[
|
147
148
|
Optional[CurlString],
|
148
149
|
Optional[Error],
|
@@ -156,10 +157,10 @@ class DecisionCommand:
|
|
156
157
|
"num_items": num_items
|
157
158
|
},
|
158
159
|
"user": {
|
159
|
-
"user_id": "user-
|
160
|
+
"user_id": f"mcmcli-user-{random.randint(100_000, 999_999)}"
|
160
161
|
},
|
161
162
|
"device": {
|
162
|
-
"persistent_id": "
|
163
|
+
"persistent_id": f"mcmcli-device-{random.randint(100_000, 999_999)}"
|
163
164
|
},
|
164
165
|
}
|
165
166
|
if items:
|
@@ -185,9 +186,9 @@ class DecisionCommand:
|
|
185
186
|
def decide_creative(
|
186
187
|
self,
|
187
188
|
inventory_id,
|
188
|
-
items,
|
189
|
-
location_filter,
|
190
|
-
to_curl
|
189
|
+
items = False,
|
190
|
+
location_filter = None,
|
191
|
+
to_curl = False,
|
191
192
|
) -> tuple[
|
192
193
|
Optional[CurlString],
|
193
194
|
Optional[Error],
|
@@ -200,10 +201,10 @@ class DecisionCommand:
|
|
200
201
|
"inventory_id": inventory_id
|
201
202
|
},
|
202
203
|
"user": {
|
203
|
-
"user_id": "user-
|
204
|
+
"user_id": f"mcmcli-user-{random.randint(100_000, 999_999)}"
|
204
205
|
},
|
205
206
|
"device": {
|
206
|
-
"persistent_id": "
|
207
|
+
"persistent_id": f"mcmcli-device-{random.randint(100_000, 999_999)}"
|
207
208
|
},
|
208
209
|
}
|
209
210
|
if items:
|
@@ -229,9 +230,9 @@ class DecisionCommand:
|
|
229
230
|
def decide_creative_bulk(
|
230
231
|
self,
|
231
232
|
inventory_id_list,
|
232
|
-
items,
|
233
|
-
location_filter,
|
234
|
-
to_curl
|
233
|
+
items = False,
|
234
|
+
location_filter = None,
|
235
|
+
to_curl = False,
|
235
236
|
) -> tuple[
|
236
237
|
Optional[CurlString],
|
237
238
|
Optional[Error],
|
@@ -242,10 +243,10 @@ class DecisionCommand:
|
|
242
243
|
"request_id": "request-1",
|
243
244
|
"inventories": list(map(lambda x: { "inventory_id": x }, inventory_id_list.split(','))),
|
244
245
|
"user": {
|
245
|
-
"user_id": "user-
|
246
|
+
"user_id": f"mcmcli-user-{random.randint(100_000, 999_999)}"
|
246
247
|
},
|
247
248
|
"device": {
|
248
|
-
"persistent_id": "
|
249
|
+
"persistent_id": f"mcmcli-device-{random.randint(100_000, 999_999)}"
|
249
250
|
},
|
250
251
|
}
|
251
252
|
if items:
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|