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