mcm-cli 1.4.0__py3-none-any.whl → 1.4.2__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- {mcm_cli-1.4.0.dist-info → mcm_cli-1.4.2.dist-info}/METADATA +3 -2
- mcm_cli-1.4.2.dist-info/RECORD +32 -0
- mcmcli/__main__.py +5 -1
- mcmcli/command/account.py +10 -12
- mcmcli/command/admin.py +352 -19
- mcmcli/command/auth.py +14 -0
- mcmcli/command/campaign.py +317 -0
- mcmcli/command/config.py +2 -0
- mcmcli/command/decision.py +4 -0
- mcmcli/command/report.py +150 -0
- mcmcli/command/wallet.py +37 -36
- mcmcli/data/campaign.py +86 -0
- mcmcli/data/platform_user.py +64 -0
- mcmcli/data/report.py +110 -0
- mcmcli/data/user_join_request.py +44 -0
- mcm_cli-1.4.0.dist-info/RECORD +0 -26
- {mcm_cli-1.4.0.dist-info → mcm_cli-1.4.2.dist-info}/LICENSE +0 -0
- {mcm_cli-1.4.0.dist-info → mcm_cli-1.4.2.dist-info}/NOTICE +0 -0
- {mcm_cli-1.4.0.dist-info → mcm_cli-1.4.2.dist-info}/WHEEL +0 -0
- {mcm_cli-1.4.0.dist-info → mcm_cli-1.4.2.dist-info}/entry_points.txt +0 -0
- {mcm_cli-1.4.0.dist-info → mcm_cli-1.4.2.dist-info}/top_level.txt +0 -0
@@ -1,13 +1,13 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: mcm-cli
|
3
|
-
Version: 1.4.
|
3
|
+
Version: 1.4.2
|
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 ::
|
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=8rr--sz02pkM_Z6u90JYm8f1s6sbHmgXF82xfIF6rqg,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=2GC0B3oqQsT5N5mHUyezgZvzPkB4-oGtddguOWfdLJs,15980
|
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=-HR-SbEfe44Ys_UXnYr9HRG0TPcGkO2k61iEsz9uET0,2284
|
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.2.dist-info/LICENSE,sha256=RFhQPdSOiMTguUX7JSoIuTxA7HVzCbj_p8WU36HjUQQ,10947
|
27
|
+
mcm_cli-1.4.2.dist-info/METADATA,sha256=6Y7vHnYzLC2-4-7AHMDyL2mprCj0BKVMCUAP8sOGob8,3056
|
28
|
+
mcm_cli-1.4.2.dist-info/NOTICE,sha256=Ldnl2MjRaXPxcldUdbI2NTybq60XAa2LowRhFrRTuiI,76
|
29
|
+
mcm_cli-1.4.2.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
30
|
+
mcm_cli-1.4.2.dist-info/entry_points.txt,sha256=qTHAWZ-ejSiU4t11RYwtAU8ScqhQPDeMVTG9y4wMVLg,60
|
31
|
+
mcm_cli-1.4.2.dist-info/top_level.txt,sha256=sh7oqIaqLQlMtKHlxHHgpV2xGMrBMPFWpSp0C6nvJ_Y,7
|
32
|
+
mcm_cli-1.4.2.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.
|
40
|
+
typer.echo(f"Version: mcm-cli v1.4.2")
|
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:
|
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
|
-
|
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
|
-
|
376
|
-
|
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 =
|
764
|
-
|
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.
|
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 =
|
32
|
-
|
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,182 @@ 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 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
|
+
|
84
|
+
@app.command()
|
85
|
+
def list_platform_users(
|
86
|
+
to_curl: bool = typer.Option(False, help="Generate the curl command instead of executing it."),
|
87
|
+
to_json: bool = typer.Option(False, help="Print raw output in json"),
|
88
|
+
profile: str = "default",
|
89
|
+
):
|
90
|
+
"""
|
91
|
+
List the users of the platform
|
92
|
+
"""
|
93
|
+
admin = _create_admin_command(profile)
|
94
|
+
if admin is None:
|
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
|
108
|
+
|
109
|
+
print('User ID,Created At,Updated At,Status,Email,Name,Roles')
|
110
|
+
for u in users:
|
111
|
+
roles = [f'{x.name} of {x.resource_type} {x.resource_id}' for x in u.roles]
|
112
|
+
print(f'{u.id},{u.created_at},{u.updated_at},{u.status},{u.email},{u.name},{';'.join(roles)}')
|
113
|
+
|
114
|
+
|
115
|
+
@app.command()
|
116
|
+
def get_platform_user(
|
117
|
+
user_email: str = typer.Option(help="User's email address"),
|
118
|
+
to_curl: bool = typer.Option(False, help="Generate the curl command instead of executing it."),
|
119
|
+
to_json: bool = typer.Option(False, help="Print raw output in json"),
|
120
|
+
profile: str = typer.Option("default", help="profile name of the MCM CLI."),
|
121
|
+
):
|
122
|
+
"""
|
123
|
+
Get the email user's profile.
|
124
|
+
"""
|
125
|
+
a = _create_admin_command(profile)
|
126
|
+
if a is None:
|
127
|
+
return
|
128
|
+
|
129
|
+
curl, error, user = a.get_platform_user(user_email, to_curl)
|
130
|
+
if to_curl:
|
131
|
+
print(curl)
|
132
|
+
return
|
133
|
+
if error:
|
134
|
+
print(f"ERROR: {error.message}")
|
135
|
+
return
|
136
|
+
|
137
|
+
if user is not None:
|
138
|
+
print(f"{user.model_dump_json()}")
|
139
|
+
return
|
140
|
+
|
141
|
+
|
142
|
+
@app.command()
|
143
|
+
def list_items(
|
144
|
+
account_id: str = typer.Option(help="Ad account ID"),
|
145
|
+
profile: str = "default",
|
146
|
+
):
|
147
|
+
"""
|
148
|
+
List the itmes, item status, and attached campaigns of a given ad account
|
149
|
+
"""
|
150
|
+
admin = _create_admin_command(profile)
|
151
|
+
if admin is None:
|
152
|
+
return
|
153
|
+
|
154
|
+
error, campaigns = admin.list_campaigns(account_id)
|
155
|
+
if error:
|
156
|
+
print(f"ERROR: {error.message}")
|
157
|
+
return
|
158
|
+
|
159
|
+
campaign_item_obj = {} # build item list into item object with the item_id as an index
|
160
|
+
# print("Campaign ID, Campaign Title, Item ID, Item Title, Item Status")
|
161
|
+
|
162
|
+
for c in campaigns:
|
163
|
+
error, campaign_items = admin.list_campaign_items(account_id, c.id)
|
164
|
+
if error:
|
165
|
+
print(f"ERROR: {error.message}")
|
166
|
+
return
|
167
|
+
for ci in campaign_items:
|
168
|
+
if ci.id in campaign_item_obj:
|
169
|
+
campaign_item_obj[ci.id].append({
|
170
|
+
'campaign_id': c.id,
|
171
|
+
'campaign_title': c.title
|
172
|
+
})
|
173
|
+
else:
|
174
|
+
campaign_item_obj[ci.id] = [{
|
175
|
+
'campaign_id': c.id,
|
176
|
+
'campaign_title': c.title
|
177
|
+
}]
|
178
|
+
# print(f"{c['id']}, {c['title']}, {ci['id']}, {ci['title']}, {ci['is_active']}")
|
179
|
+
|
180
|
+
error, items = admin.list_items(account_id)
|
181
|
+
if error:
|
182
|
+
print(f"ERROR: {error.message}")
|
183
|
+
|
184
|
+
print("Ad Account ID,Item ID,Is Item Active,Item Title,Campaign ID,Campaign Title")
|
185
|
+
for i in items:
|
186
|
+
if i.id in campaign_item_obj:
|
187
|
+
ci = campaign_item_obj[i.id]
|
188
|
+
campaign_id_list = ""
|
189
|
+
campaign_title_list = ""
|
190
|
+
for c in ci:
|
191
|
+
campaign_id_list += f"{c['campaign_id']};"
|
192
|
+
campaign_title_list += f"{c['campaign_title']};"
|
193
|
+
campaign_id_list = campaign_id_list[:-1]
|
194
|
+
campaign_title_list = campaign_title_list[:-1]
|
195
|
+
|
196
|
+
print(f"{account_id},{i.id},{i.is_active},\"{i.title}\",{campaign_id_list},\"{campaign_title_list}\"")
|
197
|
+
else:
|
198
|
+
print(f"{account_id},{i.id},{i.is_active},\"{i.title}\",,")
|
199
|
+
|
200
|
+
@app.command()
|
201
|
+
def list_off_campaign_items(
|
202
|
+
account_id: str = typer.Option(help="Ad account ID"),
|
203
|
+
profile: str = "default",
|
204
|
+
):
|
205
|
+
"""
|
206
|
+
Lists the items that are not in any of campaigns
|
207
|
+
"""
|
208
|
+
admin = _create_admin_command(profile)
|
209
|
+
if admin is None:
|
210
|
+
return
|
211
|
+
|
212
|
+
error, items = admin.list_items(account_id)
|
213
|
+
if error:
|
214
|
+
print(f"ERROR: {error.message}")
|
215
|
+
return
|
216
|
+
error, campaigns = admin.list_campaigns(account_id)
|
217
|
+
if error:
|
218
|
+
print(f"ERROR: {error.message}")
|
219
|
+
return
|
220
|
+
|
221
|
+
campaign_item_obj = {} # build item list into item object with the item_id as an index
|
222
|
+
for c in campaigns:
|
223
|
+
error, campaign_items = admin.list_campaign_items(account_id, c.id)
|
224
|
+
for ci in campaign_items:
|
225
|
+
campaign_item_obj[ci.id] = ci.title
|
226
|
+
|
227
|
+
print("Item ID, Item Title")
|
228
|
+
for i in items:
|
229
|
+
if i.id not in campaign_item_obj and i.is_active:
|
230
|
+
print(f"{i.id}, {i.title}")
|
231
|
+
|
51
232
|
@app.command()
|
52
233
|
def block_item(
|
53
234
|
item_id: str = typer.Option(help="Item ID"),
|
@@ -77,26 +258,40 @@ def block_item(
|
|
77
258
|
print(result.model_dump_json())
|
78
259
|
return
|
79
260
|
|
261
|
+
|
80
262
|
class AdminCommand:
|
81
263
|
def __init__(
|
82
264
|
self,
|
83
265
|
profile,
|
84
|
-
auth_command:
|
85
|
-
token
|
266
|
+
auth_command: AuthCommand,
|
86
267
|
):
|
87
|
-
self.profile = profile
|
88
|
-
self.auth_command = auth_command
|
89
268
|
self.config = mcmcli.command.config.get_config(profile)
|
90
|
-
|
269
|
+
if (self.config is None):
|
270
|
+
print(f"ERROR: Failed to load the CLI profile", file=sys.stderr, flush=True)
|
271
|
+
sys.exit()
|
91
272
|
|
92
|
-
self.
|
273
|
+
self.profile = profile
|
274
|
+
self.auth_command = auth_command
|
93
275
|
self.api_base_url = f"{self.config['management_api_hostname']}/rmp/mgmt/v1/platforms/{self.config['platform_id']}"
|
94
276
|
self.headers = {
|
95
277
|
"accept": "application/json",
|
96
278
|
"content-type": "application/json",
|
97
|
-
"Authorization": f"Bearer {token}"
|
98
279
|
}
|
99
280
|
|
281
|
+
self.refresh_token()
|
282
|
+
|
283
|
+
|
284
|
+
def refresh_token(
|
285
|
+
self,
|
286
|
+
) -> None:
|
287
|
+
error, auth_header_name, auth_header_value = self.auth_command.get_auth_credential()
|
288
|
+
if error:
|
289
|
+
print(f"ERROR: {error.message}", file=sys.stderr, flush=True)
|
290
|
+
sys.exit()
|
291
|
+
|
292
|
+
self.headers[auth_header_name] = auth_header_value
|
293
|
+
|
294
|
+
|
100
295
|
def block_item(
|
101
296
|
self,
|
102
297
|
item_id,
|
@@ -112,13 +307,12 @@ class AdminCommand:
|
|
112
307
|
_payload = {
|
113
308
|
"items": [{
|
114
309
|
"item_id": item_id,
|
115
|
-
"seller_id": account_id,
|
116
310
|
"updated_time": _requested_at,
|
117
311
|
"blocked": f'Requested at {_requested_at}',
|
118
312
|
}]
|
119
313
|
}
|
120
|
-
if account_id is None:
|
121
|
-
|
314
|
+
if account_id is not None:
|
315
|
+
_payload["items"][0]["seller_id"] = account_id
|
122
316
|
|
123
317
|
curl, error, json_obj = api_request('POST', to_curl, _api_url, self.headers, _payload)
|
124
318
|
if curl:
|
@@ -127,11 +321,52 @@ class AdminCommand:
|
|
127
321
|
return None, error, None
|
128
322
|
return None, None, ItemBlockingResult(**json_obj)
|
129
323
|
|
324
|
+
|
325
|
+
def get_platform_user(
|
326
|
+
self,
|
327
|
+
user_email,
|
328
|
+
to_curl = False,
|
329
|
+
) -> tuple[
|
330
|
+
Optional[CurlString],
|
331
|
+
Optional[Error],
|
332
|
+
Optional[PlatformUser],
|
333
|
+
]:
|
334
|
+
_api_url = f"{self.api_base_url}/users/{user_email}"
|
335
|
+
curl, error, json_obj = api_request('GET', to_curl, _api_url, self.headers)
|
336
|
+
if curl:
|
337
|
+
return curl, None, None
|
338
|
+
if error:
|
339
|
+
return None, error, None
|
340
|
+
|
341
|
+
ret = PlatformUserWrapper(**json_obj).user
|
342
|
+
return None, None, ret
|
343
|
+
|
344
|
+
|
345
|
+
def list_platform_users(
|
346
|
+
self,
|
347
|
+
to_curl=False,
|
348
|
+
) -> tuple [
|
349
|
+
Optional[CurlString],
|
350
|
+
Optional[Error],
|
351
|
+
list[PlatformUser],
|
352
|
+
]:
|
353
|
+
_api_url = f"{self.api_base_url}/users"
|
354
|
+
|
355
|
+
curl, error, json_obj = api_request('GET', to_curl, _api_url, self.headers)
|
356
|
+
if curl:
|
357
|
+
return curl, None, []
|
358
|
+
if error:
|
359
|
+
return None, error, []
|
360
|
+
|
361
|
+
user_list_wrapper = PlatformUserListWrapper(**json_obj)
|
362
|
+
users = user_list_wrapper.users
|
363
|
+
return None, None, users
|
364
|
+
|
130
365
|
def list_wallet_balances(
|
131
366
|
self
|
132
367
|
):
|
133
|
-
ac = mcmcli.command.account.AccountCommand(self.profile, self.auth_command
|
134
|
-
wc = mcmcli.command.wallet.WalletCommand(self.profile, self.auth_command
|
368
|
+
ac = mcmcli.command.account.AccountCommand(self.profile, self.auth_command)
|
369
|
+
wc = mcmcli.command.wallet.WalletCommand(self.profile, self.auth_command)
|
135
370
|
_, error, accounts = ac.list_accounts()
|
136
371
|
if error:
|
137
372
|
print(error, file=sys.stderr, flush=True)
|
@@ -148,5 +383,103 @@ class AdminCommand:
|
|
148
383
|
prepaid = w1 if w1.type == 'PRE_PAID' else w0
|
149
384
|
credits = int(credits.balance.amount_micro) / 1000000
|
150
385
|
prepaid = int(prepaid.balance.amount_micro) / 1000000
|
386
|
+
|
151
387
|
print(f'"{accounts[id].title}", {id}, {credits}, {prepaid}')
|
152
388
|
|
389
|
+
|
390
|
+
|
391
|
+
def list_all_campaigns(
|
392
|
+
self
|
393
|
+
) -> tuple [
|
394
|
+
Optional[Error],
|
395
|
+
list[tuple[Account, Campaign]]
|
396
|
+
]:
|
397
|
+
ac = mcmcli.command.account.AccountCommand(self.profile, self.auth_command)
|
398
|
+
cc = mcmcli.command.campaign.CampaignCommand(self.profile, self.auth_command)
|
399
|
+
_, error, accounts = ac.list_accounts()
|
400
|
+
if error:
|
401
|
+
return error, []
|
402
|
+
|
403
|
+
echo('Collecting campaigns...')
|
404
|
+
return_value = []
|
405
|
+
for id in accounts:
|
406
|
+
account = accounts[id]
|
407
|
+
echo('.')
|
408
|
+
# print(f'{account.id}, \"{account.title}\"')
|
409
|
+
_, error, campaigns = cc.list_campaigns(account.id)
|
410
|
+
if error:
|
411
|
+
echo_newline(error)
|
412
|
+
continue
|
413
|
+
for c in campaigns:
|
414
|
+
return_value.append((account, c))
|
415
|
+
|
416
|
+
echo_newline(' done')
|
417
|
+
return None, return_value
|
418
|
+
|
419
|
+
|
420
|
+
def list_items(
|
421
|
+
self,
|
422
|
+
account_id
|
423
|
+
) -> tuple [
|
424
|
+
Optional[Error],
|
425
|
+
list[Item],
|
426
|
+
]:
|
427
|
+
ac = mcmcli.command.account.AccountCommand(self.profile, self.auth_command)
|
428
|
+
echo("Gathering the account's items ")
|
429
|
+
thread, stopper = start_dot_printing()
|
430
|
+
_, error, items = ac.list_account_items(account_id)
|
431
|
+
stop_dot_printing(thread, stopper)
|
432
|
+
echo_newline(" done")
|
433
|
+
|
434
|
+
if error:
|
435
|
+
return error, []
|
436
|
+
if items == []:
|
437
|
+
return Error(code=0, message=str("Cannot find items")), []
|
438
|
+
|
439
|
+
return None, items
|
440
|
+
|
441
|
+
def list_campaigns(
|
442
|
+
self,
|
443
|
+
ad_account_id
|
444
|
+
) -> tuple [
|
445
|
+
Optional[Error],
|
446
|
+
list[Campaign],
|
447
|
+
]:
|
448
|
+
cam = mcmcli.command.campaign.CampaignCommand(self.profile, self.auth_command)
|
449
|
+
|
450
|
+
echo("Gathering the account's campaigns ")
|
451
|
+
thread, stopper = start_dot_printing()
|
452
|
+
_, error, campaigns = cam.list_campaigns(ad_account_id)
|
453
|
+
stop_dot_printing(thread, stopper)
|
454
|
+
echo_newline(" done")
|
455
|
+
|
456
|
+
if error:
|
457
|
+
return error, []
|
458
|
+
if campaigns == []:
|
459
|
+
return Error(code=0, message=str("Cannot find campaigns")), []
|
460
|
+
|
461
|
+
return None, campaigns
|
462
|
+
|
463
|
+
|
464
|
+
def list_campaign_items(
|
465
|
+
self,
|
466
|
+
ad_account_id,
|
467
|
+
campaign_id
|
468
|
+
) -> tuple [
|
469
|
+
Optional[Error],
|
470
|
+
list[Item]
|
471
|
+
]:
|
472
|
+
cam = mcmcli.command.campaign.CampaignCommand(self.profile, self.auth_command)
|
473
|
+
|
474
|
+
echo(f"Gathering the items of the campaign {campaign_id} ")
|
475
|
+
thread, stopper = start_dot_printing()
|
476
|
+
_, error, campaign_items = cam.list_campaign_items(ad_account_id, campaign_id)
|
477
|
+
stop_dot_printing(thread, stopper)
|
478
|
+
echo_newline(" done")
|
479
|
+
|
480
|
+
if error:
|
481
|
+
return error, []
|
482
|
+
if campaign_items == []:
|
483
|
+
return Error(code=0, message=str("Cannot find campaign items")), []
|
484
|
+
|
485
|
+
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
|
|