mcm-cli 1.4.0__py3-none-any.whl → 1.4.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mcm-cli
3
- Version: 1.4.0
3
+ Version: 1.4.1
4
4
  Summary: A command-line interface for Moloco Commerde Media
5
5
  Home-page: https://github.com/moloco-mcm/mcm-cli
6
6
  Author: Moloco MCM Team
7
7
  Author-email: mcm-help@moloco.com
8
8
  License: Apache-2.0 license
9
9
  Classifier: Programming Language :: Python :: 3
10
- Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: License :: OSI Approved :: Apache Software License
11
11
  Classifier: Operating System :: OS Independent
12
12
  Requires-Python: >=3.6
13
13
  Description-Content-Type: text/markdown
@@ -20,6 +20,7 @@ Requires-Dist: pygithub
20
20
  Requires-Dist: python-terraform
21
21
  Requires-Dist: requests
22
22
  Requires-Dist: rich
23
+ Requires-Dist: setuptools
23
24
  Requires-Dist: shortuuid
24
25
  Requires-Dist: toml
25
26
  Requires-Dist: typer
@@ -0,0 +1,32 @@
1
+ mcmcli/__init__.py,sha256=-U6lMZ9_99IXAKwnqnYXYr6NcO6TSmG-kxewgvJjU4k,575
2
+ mcmcli/__main__.py,sha256=wbiwdsy9Sq1Ebv93G6LlnH7wTb2SUT5gRxxFF9w5Hgc,1844
3
+ mcmcli/logging.py,sha256=xjRS5ey1ONx_d34qB1Fetb_SwPysoh2hzNDuNAaYYWQ,1739
4
+ mcmcli/requests.py,sha256=IuySBQ8P_GoGF3f_TRysfgQNOhi2n9M84WK_eRXnoEU,2945
5
+ mcmcli/command/account.py,sha256=FWXmzOLj4rVLVLEv-w0eDVlQVrkONvR1UewZbcTDgE4,24994
6
+ mcmcli/command/admin.py,sha256=05Ti5nMnuL_Ppo8hy2_bMGwfNZGdN6s528Gpi-EnpDg,16036
7
+ mcmcli/command/auth.py,sha256=Ak7ZNEskWPpMoeTJcbYlEpDBgzxn8N33Q2dNf67SsCs,2926
8
+ mcmcli/command/campaign.py,sha256=SU6TrDy6YhqM0JWPzbYWLpXZrz7Ymw31pd168dK2LZk,10638
9
+ mcmcli/command/config.py,sha256=08C5ftAvdvpQ26Z329LqhP8AxTI629LS7Ou6glzrRgw,4396
10
+ mcmcli/command/decision.py,sha256=iLvEDEa2k0LAgoXrOvcdn-HcFRo90E8Dxht_Ls9EGCY,8690
11
+ mcmcli/command/report.py,sha256=N8IMyDZ5QpY11-KkZG-n5_ZzEeh-ME5s2s3wrAKEGjY,5387
12
+ mcmcli/command/wallet.py,sha256=vG2rg7tPwGsV9YB7cpvkiocbqtB1reqXn7dmolFmzD4,11536
13
+ mcmcli/data/account.py,sha256=pe7tPapP6vlUD5D5L5Nh5k2bkWdYOK01Mpt5fBYFnJs,1782
14
+ mcmcli/data/account_user.py,sha256=27nQp52nMma5a3QszSJGqgq5Z0ivIb-nMZcZuhEgbEg,1328
15
+ mcmcli/data/campaign.py,sha256=vUukEsZ9Lzvcqm4Pa8z7vzyt_qOpT_t6_YEXuLubVSQ,1731
16
+ mcmcli/data/decision.py,sha256=bQ5j_PbPRSFa0sY5g9UVqdNzl_2epchcz1lHoDVuV90,2880
17
+ mcmcli/data/error.py,sha256=d6xa_jTXumlA0EzXy2PJQ86ajBb0Pm90fss9R3LuHUc,1094
18
+ mcmcli/data/item.py,sha256=Z2xTRhU8T4vyJADO0l6-XPyQXvb9DX_OAjExhSXpW2A,1091
19
+ mcmcli/data/item_blocking_result.py,sha256=daK4c8--aCe2vRsnTzLBjgKQo0C-zcDH09dC0GgrN7E,1429
20
+ mcmcli/data/platform_user.py,sha256=AC4ps5DdC8XdDpfBMKtVCne2UtnOKtQbVY8D-bLbcIY,1638
21
+ mcmcli/data/report.py,sha256=lJAKQUsaU6g_Kqbx3KpYtBPZ5RSWAJfAmVXxw3KHaUE,2933
22
+ mcmcli/data/seller.py,sha256=40SA7QekM3a3svDrDYLo_QYJ68VUxDO0KeGejJMp4k4,1004
23
+ mcmcli/data/token.py,sha256=11wtyLHCAZHu0LVbNDPa-yipcL6lenxoYIKEI58VzFs,1744
24
+ mcmcli/data/user_join_request.py,sha256=lXMO2hE_VpRg0JofVrYAVM82S-RLFkPrZk8-drvhoDI,1251
25
+ mcmcli/data/wallet.py,sha256=eMUi8N0vJdg_E10TPhSPoZkZtmIG7gHyqgabQ8C5Lg8,3217
26
+ mcm_cli-1.4.1.dist-info/LICENSE,sha256=RFhQPdSOiMTguUX7JSoIuTxA7HVzCbj_p8WU36HjUQQ,10947
27
+ mcm_cli-1.4.1.dist-info/METADATA,sha256=lwdpWx33PEgWxiCl4FBfbqM_CIflw5eLDOLtzCpjK1Y,3056
28
+ mcm_cli-1.4.1.dist-info/NOTICE,sha256=Ldnl2MjRaXPxcldUdbI2NTybq60XAa2LowRhFrRTuiI,76
29
+ mcm_cli-1.4.1.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
30
+ mcm_cli-1.4.1.dist-info/entry_points.txt,sha256=qTHAWZ-ejSiU4t11RYwtAU8ScqhQPDeMVTG9y4wMVLg,60
31
+ mcm_cli-1.4.1.dist-info/top_level.txt,sha256=sh7oqIaqLQlMtKHlxHHgpV2xGMrBMPFWpSp0C6nvJ_Y,7
32
+ mcm_cli-1.4.1.dist-info/RECORD,,
mcmcli/__main__.py CHANGED
@@ -22,8 +22,10 @@ from typing import Optional
22
22
  import mcmcli.command.account
23
23
  import mcmcli.command.admin
24
24
  import mcmcli.command.auth
25
+ import mcmcli.command.campaign
25
26
  import mcmcli.command.config
26
27
  import mcmcli.command.decision
28
+ import mcmcli.command.report
27
29
  import mcmcli.command.wallet
28
30
  import mcmcli.logging
29
31
  import typer
@@ -35,13 +37,15 @@ def version():
35
37
  """
36
38
  Show the tool version
37
39
  """
38
- typer.echo(f"Version: mcm-cli v1.4.0")
40
+ typer.echo(f"Version: mcm-cli v1.4.1")
39
41
 
40
42
  app.add_typer(mcmcli.command.account.app, name="account", help="Ad account management")
41
43
  app.add_typer(mcmcli.command.admin.app, name="admin", help="Platform administration")
42
44
  app.add_typer(mcmcli.command.auth.app, name="auth", help="Authentication management")
45
+ app.add_typer(mcmcli.command.campaign.app, name="campaign", help="Campaign management")
43
46
  app.add_typer(mcmcli.command.config.app, name="config", help="Configurations")
44
47
  app.add_typer(mcmcli.command.decision.app, name="decision", help="Decision command")
48
+ app.add_typer(mcmcli.command.report.app, name="report", help="Report commands")
45
49
  app.add_typer(mcmcli.command.wallet.app, name="wallet", help="Wallet management")
46
50
 
47
51
  if __name__ == "__main__":
mcmcli/command/account.py CHANGED
@@ -13,6 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
  from enum import Enum
16
+ from mcmcli.command.auth import AuthCommand, AuthHeaderName, AuthHeaderValue
16
17
  from mcmcli.data.account import Account, AccountListWrapper
17
18
  from mcmcli.data.account_user import User, UserWrapper, UserListWrapper
18
19
  from mcmcli.data.error import Error
@@ -348,8 +349,7 @@ class AccountCommand:
348
349
  def __init__(
349
350
  self,
350
351
  profile,
351
- auth_command: mcmcli.command.auth.AuthCommand,
352
- token
352
+ auth_command: AuthCommand,
353
353
  ):
354
354
  self.config = mcmcli.command.config.get_config(profile)
355
355
  if (self.config is None):
@@ -362,18 +362,20 @@ class AccountCommand:
362
362
  self.headers = {
363
363
  "accept": "application/json",
364
364
  "content-type": "application/json",
365
- "Authorization": f"Bearer {token}"
366
365
  }
367
366
 
367
+ self.refresh_token()
368
+
368
369
 
369
370
  def refresh_token(
370
371
  self,
371
372
  ) -> None:
372
- _, error, token = self.auth_command.get_token()
373
+ error, auth_header_name, auth_header_value = self.auth_command.get_auth_credential()
373
374
  if error:
374
375
  print(f"ERROR: {error.message}", file=sys.stderr, flush=True)
375
- return
376
- self.headers["Authorization"] = f"Bearer {token.token}"
376
+ sys.exit()
377
+
378
+ self.headers[auth_header_name] = auth_header_value
377
379
 
378
380
 
379
381
  def retry_with_token_refresh(
@@ -760,12 +762,8 @@ class AccountCommand:
760
762
  def _create_account_command(
761
763
  profile: str
762
764
  ) -> Optional[AccountCommand]:
763
- auth = mcmcli.command.auth.AuthCommand(profile)
764
- _, error, token = auth.get_token()
765
- if error:
766
- print(f"ERROR: {error.message}", file=sys.stderr, flush=True)
767
- return None
768
- return AccountCommand(profile, auth, token.token)
765
+ auth = AuthCommand(profile)
766
+ return AccountCommand(profile, auth)
769
767
 
770
768
 
771
769
  def _read_csv_file(
mcmcli/command/admin.py CHANGED
@@ -12,28 +12,33 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  from datetime import datetime, timedelta, timezone
15
- from mcmcli.data.error import Error
15
+ from mcmcli.command.auth import AuthCommand, AuthHeaderName, AuthHeaderValue
16
+ from mcmcli.data.account import Account
16
17
  from mcmcli.data.item_blocking_result import ItemBlockingResult
18
+ from mcmcli.data.campaign import Campaign
19
+ from mcmcli.data.error import Error
20
+ from mcmcli.data.item import Item
21
+ from mcmcli.data.platform_user import PlatformUser, PlatformUserListWrapper, PlatformUserWrapper
17
22
  from mcmcli.requests import CurlString, api_request
18
23
  from typing import Optional
19
24
 
25
+ import csv
20
26
  import mcmcli.command.account
21
27
  import mcmcli.command.auth
28
+ import mcmcli.command.campaign
22
29
  import mcmcli.command.config
23
30
  import mcmcli.command.wallet
24
31
  import mcmcli.requests
25
32
  import sys
26
33
  import typer
27
34
 
35
+ from mcmcli.logging import echo, echo_newline, start_dot_printing, stop_dot_printing, print_error
36
+
28
37
  app = typer.Typer(add_completion=False)
29
38
 
30
39
  def _create_admin_command(profile):
31
- auth = mcmcli.command.auth.AuthCommand(profile)
32
- _, error, token = auth.get_token()
33
- if error:
34
- print(f"ERROR: {error.message}")
35
- return None
36
- return AdminCommand(profile, auth, token.token)
40
+ auth = AuthCommand(profile)
41
+ return AdminCommand(profile, auth)
37
42
 
38
43
  @app.command()
39
44
  def list_wallet_balances(
@@ -48,6 +53,181 @@ def list_wallet_balances(
48
53
  admin.list_wallet_balances()
49
54
 
50
55
 
56
+ @app.command()
57
+ def list_all_campaigns(
58
+ profile: str = "default",
59
+ ):
60
+ """
61
+ List the campaigigns of all of the active ad accounts
62
+ """
63
+ admin = _create_admin_command(profile)
64
+ if admin is None:
65
+ return
66
+ error, account_campaigns = admin.list_all_campaigns()
67
+ if error:
68
+ print(error, file=sys.stderr, flush=True)
69
+ return
70
+
71
+ print("Account IDAccount Title,Campaign ID,Campaign Title,Ad Type,Start,End,Budget Period,Budget Amount,Enabling State,State,Created At,Updated At,Item IDs")
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
+
83
+ @app.command()
84
+ def list_platform_users(
85
+ to_curl: bool = typer.Option(False, help="Generate the curl command instead of executing it."),
86
+ to_json: bool = typer.Option(False, help="Print raw output in json"),
87
+ profile: str = "default",
88
+ ):
89
+ """
90
+ List the users of the platform
91
+ """
92
+ admin = _create_admin_command(profile)
93
+ if admin is None:
94
+ return
95
+
96
+ curl, error, users = admin.list_platform_users(to_curl)
97
+ if to_curl:
98
+ print(curl)
99
+ return
100
+ if error:
101
+ print(error, file=sys.stderr, flush=True)
102
+ return
103
+ if to_json:
104
+ json_dumps = [x.model_dump_json() for x in users]
105
+ print(f"[{','.join(json_dumps)}]")
106
+ return
107
+
108
+ print('User ID,Created At,Updated At,Status,Email,Name,Roles')
109
+ for u in users:
110
+ roles = [f'{x.name} of {x.resource_type} {x.resource_id}' for x in u.roles]
111
+ print(f'{u.id},{u.created_at},{u.updated_at},{u.status},{u.email},{u.name},{';'.join(roles)}')
112
+
113
+
114
+ @app.command()
115
+ def get_platform_user(
116
+ user_email: str = typer.Option(help="User's email address"),
117
+ to_curl: bool = typer.Option(False, help="Generate the curl command instead of executing it."),
118
+ to_json: bool = typer.Option(False, help="Print raw output in json"),
119
+ profile: str = typer.Option("default", help="profile name of the MCM CLI."),
120
+ ):
121
+ """
122
+ Get the email user's profile.
123
+ """
124
+ a = _create_admin_command(profile)
125
+ if a is None:
126
+ return
127
+
128
+ curl, error, user = a.get_platform_user(user_email, to_curl)
129
+ if to_curl:
130
+ print(curl)
131
+ return
132
+ if error:
133
+ print(f"ERROR: {error.message}")
134
+ return
135
+
136
+ if user is not None:
137
+ print(f"{user.model_dump_json()}")
138
+ return
139
+
140
+
141
+ @app.command()
142
+ def list_items(
143
+ account_id: str = typer.Option(help="Ad account ID"),
144
+ profile: str = "default",
145
+ ):
146
+ """
147
+ List the itmes, item status, and attached campaigns of a given ad account
148
+ """
149
+ admin = _create_admin_command(profile)
150
+ if admin is None:
151
+ return
152
+
153
+ error, campaigns = admin.list_campaigns(account_id)
154
+ if error:
155
+ print(f"ERROR: {error.message}")
156
+ return
157
+
158
+ campaign_item_obj = {} # build item list into item object with the item_id as an index
159
+ # print("Campaign ID, Campaign Title, Item ID, Item Title, Item Status")
160
+
161
+ for c in campaigns:
162
+ error, campaign_items = admin.list_campaign_items(account_id, c.id)
163
+ if error:
164
+ print(f"ERROR: {error.message}")
165
+ return
166
+ for ci in campaign_items:
167
+ if ci.id in campaign_item_obj:
168
+ campaign_item_obj[ci.id].append({
169
+ 'campaign_id': c.id,
170
+ 'campaign_title': c.title
171
+ })
172
+ else:
173
+ campaign_item_obj[ci.id] = [{
174
+ 'campaign_id': c.id,
175
+ 'campaign_title': c.title
176
+ }]
177
+ # print(f"{c['id']}, {c['title']}, {ci['id']}, {ci['title']}, {ci['is_active']}")
178
+
179
+ error, items = admin.list_items(account_id)
180
+ if error:
181
+ print(f"ERROR: {error.message}")
182
+
183
+ print("Ad Account ID,Item ID,Is Item Active,Item Title,Campaign ID,Campaign Title")
184
+ for i in items:
185
+ if i.id in campaign_item_obj:
186
+ ci = campaign_item_obj[i.id]
187
+ campaign_id_list = ""
188
+ campaign_title_list = ""
189
+ for c in ci:
190
+ campaign_id_list += f"{c['campaign_id']};"
191
+ campaign_title_list += f"{c['campaign_title']};"
192
+ campaign_id_list = campaign_id_list[:-1]
193
+ campaign_title_list = campaign_title_list[:-1]
194
+
195
+ print(f"{account_id},{i.id},{i.is_active},\"{i.title}\",{campaign_id_list},\"{campaign_title_list}\"")
196
+ else:
197
+ print(f"{account_id},{i.id},{i.is_active},\"{i.title}\",,")
198
+
199
+ @app.command()
200
+ def list_off_campaign_items(
201
+ account_id: str = typer.Option(help="Ad account ID"),
202
+ profile: str = "default",
203
+ ):
204
+ """
205
+ Lists the items that are not in any of campaigns
206
+ """
207
+ admin = _create_admin_command(profile)
208
+ if admin is None:
209
+ return
210
+
211
+ error, items = admin.list_items(account_id)
212
+ if error:
213
+ print(f"ERROR: {error.message}")
214
+ return
215
+ error, campaigns = admin.list_campaigns(account_id)
216
+ if error:
217
+ print(f"ERROR: {error.message}")
218
+ return
219
+
220
+ campaign_item_obj = {} # build item list into item object with the item_id as an index
221
+ for c in campaigns:
222
+ error, campaign_items = admin.list_campaign_items(account_id, c.id)
223
+ for ci in campaign_items:
224
+ campaign_item_obj[ci.id] = ci.title
225
+
226
+ print("Item ID, Item Title")
227
+ for i in items:
228
+ if i.id not in campaign_item_obj and i.is_active:
229
+ print(f"{i.id}, {i.title}")
230
+
51
231
  @app.command()
52
232
  def block_item(
53
233
  item_id: str = typer.Option(help="Item ID"),
@@ -77,26 +257,40 @@ def block_item(
77
257
  print(result.model_dump_json())
78
258
  return
79
259
 
260
+
80
261
  class AdminCommand:
81
262
  def __init__(
82
263
  self,
83
264
  profile,
84
- auth_command: mcmcli.command.auth.AuthCommand,
85
- token
265
+ auth_command: AuthCommand,
86
266
  ):
87
- self.profile = profile
88
- self.auth_command = auth_command
89
267
  self.config = mcmcli.command.config.get_config(profile)
90
- mcmcli.command.config.assert_config_exists(self.config)
268
+ if (self.config is None):
269
+ print(f"ERROR: Failed to load the CLI profile", file=sys.stderr, flush=True)
270
+ sys.exit()
91
271
 
92
- self.token = token
272
+ self.profile = profile
273
+ self.auth_command = auth_command
93
274
  self.api_base_url = f"{self.config['management_api_hostname']}/rmp/mgmt/v1/platforms/{self.config['platform_id']}"
94
275
  self.headers = {
95
276
  "accept": "application/json",
96
277
  "content-type": "application/json",
97
- "Authorization": f"Bearer {token}"
98
278
  }
99
279
 
280
+ self.refresh_token()
281
+
282
+
283
+ def refresh_token(
284
+ self,
285
+ ) -> None:
286
+ error, auth_header_name, auth_header_value = self.auth_command.get_auth_credential()
287
+ if error:
288
+ print(f"ERROR: {error.message}", file=sys.stderr, flush=True)
289
+ sys.exit()
290
+
291
+ self.headers[auth_header_name] = auth_header_value
292
+
293
+
100
294
  def block_item(
101
295
  self,
102
296
  item_id,
@@ -112,13 +306,12 @@ class AdminCommand:
112
306
  _payload = {
113
307
  "items": [{
114
308
  "item_id": item_id,
115
- "seller_id": account_id,
116
309
  "updated_time": _requested_at,
117
310
  "blocked": f'Requested at {_requested_at}',
118
311
  }]
119
312
  }
120
- if account_id is None:
121
- del _payload["items"][0]["seller_id"]
313
+ if account_id is not None:
314
+ _payload["items"][0]["seller_id"] = account_id
122
315
 
123
316
  curl, error, json_obj = api_request('POST', to_curl, _api_url, self.headers, _payload)
124
317
  if curl:
@@ -127,11 +320,52 @@ class AdminCommand:
127
320
  return None, error, None
128
321
  return None, None, ItemBlockingResult(**json_obj)
129
322
 
323
+
324
+ def get_platform_user(
325
+ self,
326
+ user_email,
327
+ to_curl = False,
328
+ ) -> tuple[
329
+ Optional[CurlString],
330
+ Optional[Error],
331
+ Optional[PlatformUser],
332
+ ]:
333
+ _api_url = f"{self.api_base_url}/users/{user_email}"
334
+ curl, error, json_obj = api_request('GET', to_curl, _api_url, self.headers)
335
+ if curl:
336
+ return curl, None, None
337
+ if error:
338
+ return None, error, None
339
+
340
+ ret = PlatformUserWrapper(**json_obj).user
341
+ return None, None, ret
342
+
343
+
344
+ def list_platform_users(
345
+ self,
346
+ to_curl=False,
347
+ ) -> tuple [
348
+ Optional[CurlString],
349
+ Optional[Error],
350
+ list[PlatformUser],
351
+ ]:
352
+ _api_url = f"{self.api_base_url}/users"
353
+
354
+ curl, error, json_obj = api_request('GET', to_curl, _api_url, self.headers)
355
+ if curl:
356
+ return curl, None, []
357
+ if error:
358
+ return None, error, []
359
+
360
+ user_list_wrapper = PlatformUserListWrapper(**json_obj)
361
+ users = user_list_wrapper.users
362
+ return None, None, users
363
+
130
364
  def list_wallet_balances(
131
365
  self
132
366
  ):
133
- ac = mcmcli.command.account.AccountCommand(self.profile, self.auth_command, self.token)
134
- wc = mcmcli.command.wallet.WalletCommand(self.profile, self.auth_command, self.token)
367
+ ac = mcmcli.command.account.AccountCommand(self.profile, self.auth_command)
368
+ wc = mcmcli.command.wallet.WalletCommand(self.profile, self.auth_command)
135
369
  _, error, accounts = ac.list_accounts()
136
370
  if error:
137
371
  print(error, file=sys.stderr, flush=True)
@@ -148,5 +382,105 @@ class AdminCommand:
148
382
  prepaid = w1 if w1.type == 'PRE_PAID' else w0
149
383
  credits = int(credits.balance.amount_micro) / 1000000
150
384
  prepaid = int(prepaid.balance.amount_micro) / 1000000
385
+
151
386
  print(f'"{accounts[id].title}", {id}, {credits}, {prepaid}')
152
387
 
388
+
389
+
390
+ def list_all_campaigns(
391
+ self
392
+ ) -> tuple [
393
+ Optional[Error],
394
+ list[tuple[Account, Campaign]]
395
+ ]:
396
+ ac = mcmcli.command.account.AccountCommand(self.profile, self.auth_command)
397
+ cc = mcmcli.command.campaign.CampaignCommand(self.profile, self.auth_command)
398
+ _, error, accounts = ac.list_accounts()
399
+ if error:
400
+ return error, []
401
+
402
+ echo('Collecting campaigns...')
403
+ return_value = []
404
+ for id in accounts:
405
+ account = accounts[id]
406
+ echo('.')
407
+ if account.state_info.state == "INACTIVE":
408
+ continue
409
+ # print(f'{account.id}, \"{account.title}\"')
410
+ _, error, campaigns = cc.list_campaigns(account.id)
411
+ if error:
412
+ echo_newline(error)
413
+ continue
414
+ for c in campaigns:
415
+ return_value.append((account, c))
416
+
417
+ echo_newline(' done')
418
+ return None, return_value
419
+
420
+
421
+ def list_items(
422
+ self,
423
+ account_id
424
+ ) -> tuple [
425
+ Optional[Error],
426
+ list[Item],
427
+ ]:
428
+ ac = mcmcli.command.account.AccountCommand(self.profile, self.auth_command)
429
+ echo("Gathering the account's items ")
430
+ thread, stopper = start_dot_printing()
431
+ _, error, items = ac.list_account_items(account_id)
432
+ stop_dot_printing(thread, stopper)
433
+ echo_newline(" done")
434
+
435
+ if error:
436
+ return error, []
437
+ if items == []:
438
+ return Error(code=0, message=str("Cannot find items")), []
439
+
440
+ return None, items
441
+
442
+ def list_campaigns(
443
+ self,
444
+ ad_account_id
445
+ ) -> tuple [
446
+ Optional[Error],
447
+ list[Campaign],
448
+ ]:
449
+ cam = mcmcli.command.campaign.CampaignCommand(self.profile, self.auth_command)
450
+
451
+ echo("Gathering the account's campaigns ")
452
+ thread, stopper = start_dot_printing()
453
+ _, error, campaigns = cam.list_campaigns(ad_account_id)
454
+ stop_dot_printing(thread, stopper)
455
+ echo_newline(" done")
456
+
457
+ if error:
458
+ return error, []
459
+ if campaigns == []:
460
+ return Error(code=0, message=str("Cannot find campaigns")), []
461
+
462
+ return None, campaigns
463
+
464
+
465
+ def list_campaign_items(
466
+ self,
467
+ ad_account_id,
468
+ campaign_id
469
+ ) -> tuple [
470
+ Optional[Error],
471
+ list[Item]
472
+ ]:
473
+ cam = mcmcli.command.campaign.CampaignCommand(self.profile, self.auth_command)
474
+
475
+ echo(f"Gathering the items of the campaign {campaign_id} ")
476
+ thread, stopper = start_dot_printing()
477
+ _, error, campaign_items = cam.list_campaign_items(ad_account_id, campaign_id)
478
+ stop_dot_printing(thread, stopper)
479
+ echo_newline(" done")
480
+
481
+ if error:
482
+ return error, []
483
+ if campaign_items == []:
484
+ return Error(code=0, message=str("Cannot find campaign items")), []
485
+
486
+ return None, campaign_items
mcmcli/command/auth.py CHANGED
@@ -21,6 +21,9 @@ import mcmcli.logging
21
21
  import sys
22
22
  import typer
23
23
 
24
+ AuthHeaderName = str
25
+ AuthHeaderValue = str
26
+
24
27
  app = typer.Typer(add_completion=False)
25
28
 
26
29
  #
@@ -79,4 +82,15 @@ class AuthCommand:
79
82
  return None, error, None
80
83
 
81
84
  return None, None, Token(**json_obj)
85
+
86
+ def get_auth_credential(self) -> tuple[Error, AuthHeaderName, AuthHeaderValue]:
87
+ if 'management_api_key' in self.config:
88
+ return None, "x-api-key", self.config['management_api_key']
89
+
90
+ _, error, token = self.get_token(to_curl=False)
91
+ if error:
92
+ return error, None, None
93
+
94
+ else:
95
+ return None, "Authorization", f"Bearer {token.token}"
82
96