mcm-cli 1.4.0__py3-none-any.whl → 1.4.1__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.
@@ -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