mcm-cli 0.471__py3-none-any.whl → 1.0.1__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- {mcm_cli-0.471.dist-info → mcm_cli-1.0.1.dist-info}/METADATA +2 -1
- {mcm_cli-0.471.dist-info → mcm_cli-1.0.1.dist-info}/RECORD +11 -9
- mcmcli/__main__.py +3 -1
- mcmcli/command/decision.py +265 -0
- mcmcli/command/wallet.py +2 -2
- mcmcli/data/decision.py +104 -0
- {mcm_cli-0.471.dist-info → mcm_cli-1.0.1.dist-info}/LICENSE +0 -0
- {mcm_cli-0.471.dist-info → mcm_cli-1.0.1.dist-info}/NOTICE +0 -0
- {mcm_cli-0.471.dist-info → mcm_cli-1.0.1.dist-info}/WHEEL +0 -0
- {mcm_cli-0.471.dist-info → mcm_cli-1.0.1.dist-info}/entry_points.txt +0 -0
- {mcm_cli-0.471.dist-info → mcm_cli-1.0.1.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: mcm-cli
|
3
|
-
Version: 0.
|
3
|
+
Version: 1.0.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
|
@@ -81,6 +81,7 @@ $ mcm --help
|
|
81
81
|
│ account Ad account management │
|
82
82
|
│ auth Authentication management │
|
83
83
|
│ config Configurations │
|
84
|
+
│ decision Decision command │
|
84
85
|
│ version Show the tool version │
|
85
86
|
│ wallet Wallet management │
|
86
87
|
╰──────────────────────────────────────────────────────────────────╯
|
@@ -1,21 +1,23 @@
|
|
1
1
|
mcmcli/__init__.py,sha256=-U6lMZ9_99IXAKwnqnYXYr6NcO6TSmG-kxewgvJjU4k,575
|
2
|
-
mcmcli/__main__.py,sha256=
|
2
|
+
mcmcli/__main__.py,sha256=Ky33jkUC1pB1BELZU1BQY2_7G_MfAkXaewQb1Z1Zaw0,1473
|
3
3
|
mcmcli/logging.py,sha256=xjRS5ey1ONx_d34qB1Fetb_SwPysoh2hzNDuNAaYYWQ,1739
|
4
4
|
mcmcli/requests.py,sha256=50N_LiWIWr8-3EPs_yR9f4uEQf8rQ68s_FoMYRhgjzI,2343
|
5
5
|
mcmcli/command/account.py,sha256=EtcYZsC5LL5ue-hKsZZl3_0oZ09nJdVi774yqiTykl8,14712
|
6
6
|
mcmcli/command/auth.py,sha256=QLdr_XFW5BVw9r4a7Kjj5BTBXpSux3AWI9eI03S8aiA,2480
|
7
7
|
mcmcli/command/config.py,sha256=sdzge-l_Yi2P_TlTgSLqShcGyPCzpW3QJzctpIvc-g4,4195
|
8
|
-
mcmcli/command/
|
8
|
+
mcmcli/command/decision.py,sha256=Zjbmt71OVU-oL8Itt9O-SvwT9Lbxw-PAgRZaIgiXi-E,8411
|
9
|
+
mcmcli/command/wallet.py,sha256=0h09ccx0lgmQUdAdaAdvjMvXCJ4qyeJXjovZMGZWcbg,8984
|
9
10
|
mcmcli/data/account.py,sha256=pe7tPapP6vlUD5D5L5Nh5k2bkWdYOK01Mpt5fBYFnJs,1782
|
10
11
|
mcmcli/data/account_user.py,sha256=27nQp52nMma5a3QszSJGqgq5Z0ivIb-nMZcZuhEgbEg,1328
|
12
|
+
mcmcli/data/decision.py,sha256=bQ5j_PbPRSFa0sY5g9UVqdNzl_2epchcz1lHoDVuV90,2880
|
11
13
|
mcmcli/data/error.py,sha256=d6xa_jTXumlA0EzXy2PJQ86ajBb0Pm90fss9R3LuHUc,1094
|
12
14
|
mcmcli/data/seller.py,sha256=40SA7QekM3a3svDrDYLo_QYJ68VUxDO0KeGejJMp4k4,1004
|
13
15
|
mcmcli/data/token.py,sha256=11wtyLHCAZHu0LVbNDPa-yipcL6lenxoYIKEI58VzFs,1744
|
14
16
|
mcmcli/data/wallet.py,sha256=W-CksF9SPqiv3jZg07Wy8ehVUP5Ot1Gbq2LEGNQCOC8,1906
|
15
|
-
mcm_cli-0.
|
16
|
-
mcm_cli-0.
|
17
|
-
mcm_cli-0.
|
18
|
-
mcm_cli-0.
|
19
|
-
mcm_cli-0.
|
20
|
-
mcm_cli-0.
|
21
|
-
mcm_cli-0.
|
17
|
+
mcm_cli-1.0.1.dist-info/LICENSE,sha256=RFhQPdSOiMTguUX7JSoIuTxA7HVzCbj_p8WU36HjUQQ,10947
|
18
|
+
mcm_cli-1.0.1.dist-info/METADATA,sha256=YK3oZIzaU9UjXZ-bq1IWqEpd2-oc3p9MHNkv5Le6cTc,3018
|
19
|
+
mcm_cli-1.0.1.dist-info/NOTICE,sha256=Ldnl2MjRaXPxcldUdbI2NTybq60XAa2LowRhFrRTuiI,76
|
20
|
+
mcm_cli-1.0.1.dist-info/WHEEL,sha256=Wyh-_nZ0DJYolHNn1_hMa4lM7uDedD_RGVwbmTjyItk,91
|
21
|
+
mcm_cli-1.0.1.dist-info/entry_points.txt,sha256=qTHAWZ-ejSiU4t11RYwtAU8ScqhQPDeMVTG9y4wMVLg,60
|
22
|
+
mcm_cli-1.0.1.dist-info/top_level.txt,sha256=sh7oqIaqLQlMtKHlxHHgpV2xGMrBMPFWpSp0C6nvJ_Y,7
|
23
|
+
mcm_cli-1.0.1.dist-info/RECORD,,
|
mcmcli/__main__.py
CHANGED
@@ -20,6 +20,7 @@
|
|
20
20
|
import mcmcli.command.account
|
21
21
|
import mcmcli.command.auth
|
22
22
|
import mcmcli.command.config
|
23
|
+
import mcmcli.command.decision
|
23
24
|
import mcmcli.command.wallet
|
24
25
|
import mcmcli.logging
|
25
26
|
import typer
|
@@ -31,11 +32,12 @@ def version():
|
|
31
32
|
"""
|
32
33
|
Show the tool version
|
33
34
|
"""
|
34
|
-
typer.echo(f"Version: mcm-cli
|
35
|
+
typer.echo(f"Version: mcm-cli v1.0.1")
|
35
36
|
|
36
37
|
app.add_typer(mcmcli.command.account.app, name="account", help="Ad account management")
|
37
38
|
app.add_typer(mcmcli.command.auth.app, name="auth", help="Authentication management")
|
38
39
|
app.add_typer(mcmcli.command.config.app, name="config", help="Configurations")
|
40
|
+
app.add_typer(mcmcli.command.decision.app, name="decision", help="Decision command")
|
39
41
|
app.add_typer(mcmcli.command.wallet.app, name="wallet", help="Wallet management")
|
40
42
|
|
41
43
|
if __name__ == "__main__":
|
@@ -0,0 +1,265 @@
|
|
1
|
+
# Copyright 2023 Moloco, Inc
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
from mcmcli.data.error import Error
|
16
|
+
from mcmcli.data.decision import DecidedCreative, DecidedCreativeBulkList, DecidedItemList
|
17
|
+
from mcmcli.requests import CurlString, api_request
|
18
|
+
from typing import Any, Callable, Dict, Optional, Tuple, TypeVar
|
19
|
+
|
20
|
+
import json
|
21
|
+
import mcmcli.command.auth
|
22
|
+
import mcmcli.command.config
|
23
|
+
import mcmcli.logging
|
24
|
+
import sys
|
25
|
+
import typer
|
26
|
+
|
27
|
+
MAX_NUM_ITEMS_PER_PAGE = 5000
|
28
|
+
|
29
|
+
app = typer.Typer(add_completion=False)
|
30
|
+
|
31
|
+
@app.command()
|
32
|
+
def decide_items(
|
33
|
+
inventory_id: str = typer.Option(help="Ad inventory ID"),
|
34
|
+
num_items: int = typer.Option(help="Number of items requested for the inventory."),
|
35
|
+
items: str = typer.Option(None, help="The main item ids of the page. For example, homepage inventories don't have any main items, and product-detail-page inventories have one main item."),
|
36
|
+
location_filter: str = typer.Option(None, help="Location filter value"),
|
37
|
+
to_curl: bool = typer.Option(False, help="Generate the curl command instead of executing it."),
|
38
|
+
profile: str = typer.Option("default", help="profile name of the MCM CLI."),
|
39
|
+
):
|
40
|
+
"""
|
41
|
+
Request item decision by auction.
|
42
|
+
"""
|
43
|
+
d = DecisionCommand(profile)
|
44
|
+
|
45
|
+
curl, error, ret = d.decide_items(inventory_id, num_items, items, location_filter, to_curl)
|
46
|
+
if to_curl:
|
47
|
+
print(curl)
|
48
|
+
return
|
49
|
+
if error:
|
50
|
+
print(f"ERROR: {error.message}")
|
51
|
+
return
|
52
|
+
if ret is None:
|
53
|
+
print(f"ERROR: Unknown error")
|
54
|
+
return
|
55
|
+
|
56
|
+
print(ret.model_dump_json())
|
57
|
+
return
|
58
|
+
|
59
|
+
|
60
|
+
@app.command()
|
61
|
+
def decide_creative(
|
62
|
+
inventory_id: str = typer.Option(help="Ad inventory ID"),
|
63
|
+
items: str = typer.Option(None, help="The main item ids of the page. For example, homepage inventories don't have any main items, and product-detail-page inventories have one main item."),
|
64
|
+
location_filter: str = typer.Option(None, help="Location filter value"),
|
65
|
+
to_curl: bool = typer.Option(False, help="Generate the curl command instead of executing it."),
|
66
|
+
profile: str = typer.Option("default", help="profile name of the MCM CLI."),
|
67
|
+
):
|
68
|
+
"""
|
69
|
+
Request item decision by creative auction.
|
70
|
+
"""
|
71
|
+
d = DecisionCommand(profile)
|
72
|
+
|
73
|
+
curl, error, ret = d.decide_creative(inventory_id, items, location_filter, to_curl)
|
74
|
+
if to_curl:
|
75
|
+
print(curl)
|
76
|
+
return
|
77
|
+
if error:
|
78
|
+
print(f"ERROR: {error.message}")
|
79
|
+
return
|
80
|
+
if ret is None:
|
81
|
+
print(f"ERROR: Unknown error")
|
82
|
+
return
|
83
|
+
|
84
|
+
print(ret.model_dump_json())
|
85
|
+
return
|
86
|
+
|
87
|
+
|
88
|
+
@app.command()
|
89
|
+
def decide_creative_bulk(
|
90
|
+
inventory_id_list: str = typer.Option(help="Ad inventory IDs separated by comma(,)"),
|
91
|
+
items: str = typer.Option(None, help="The main item ids of the page. For example, homepage inventories don't have any main items, and product-detail-page inventories have one main item."),
|
92
|
+
location_filter: str = typer.Option(None, help="Location filter value"),
|
93
|
+
to_curl: bool = typer.Option(False, help="Generate the curl command instead of executing it."),
|
94
|
+
profile: str = typer.Option("default", help="profile name of the MCM CLI."),
|
95
|
+
):
|
96
|
+
"""
|
97
|
+
Request item decision by creative auction for multiple inventories.
|
98
|
+
"""
|
99
|
+
d = DecisionCommand(profile)
|
100
|
+
|
101
|
+
curl, error, ret = d.decide_creative_bulk(inventory_id_list, items, location_filter, to_curl)
|
102
|
+
if to_curl:
|
103
|
+
print(curl)
|
104
|
+
return
|
105
|
+
if error:
|
106
|
+
print(f"ERROR: {error.message}")
|
107
|
+
return
|
108
|
+
if ret is None:
|
109
|
+
print(f"ERROR: Unknown error")
|
110
|
+
return
|
111
|
+
|
112
|
+
print(ret.model_dump_json())
|
113
|
+
return
|
114
|
+
|
115
|
+
|
116
|
+
|
117
|
+
class DecisionCommand:
|
118
|
+
def __init__(
|
119
|
+
self,
|
120
|
+
profile,
|
121
|
+
):
|
122
|
+
self.config = mcmcli.command.config.get_config(profile)
|
123
|
+
if (self.config is None):
|
124
|
+
print(f"ERROR: Failed to load the CLI profile", file=sys.stderr, flush=True)
|
125
|
+
sys.exit()
|
126
|
+
|
127
|
+
self.profile = profile
|
128
|
+
self.api_base_url = f"{self.config['decision_api_hostname']}/rmp/decision/v1/platforms/{self.config['platform_id']}"
|
129
|
+
self.headers = {
|
130
|
+
"accept": "application/json",
|
131
|
+
"content-type": "application/json",
|
132
|
+
"x-api-key": self.config['decision_api_key']
|
133
|
+
}
|
134
|
+
|
135
|
+
def decide_items(
|
136
|
+
self,
|
137
|
+
inventory_id,
|
138
|
+
num_items,
|
139
|
+
items,
|
140
|
+
location_filter,
|
141
|
+
to_curl,
|
142
|
+
) -> tuple[
|
143
|
+
Optional[CurlString],
|
144
|
+
Optional[Error],
|
145
|
+
Optional[DecidedItemList],
|
146
|
+
]:
|
147
|
+
_api_url = f"{self.api_base_url}/auction"
|
148
|
+
_payload = {
|
149
|
+
"request_id": "request-1",
|
150
|
+
"inventory": {
|
151
|
+
"inventory_id": inventory_id,
|
152
|
+
"num_items": num_items
|
153
|
+
},
|
154
|
+
"user": {
|
155
|
+
"user_id": "user-1"
|
156
|
+
},
|
157
|
+
"device": {
|
158
|
+
"persistent_id": "persistent-device-1"
|
159
|
+
},
|
160
|
+
}
|
161
|
+
if items:
|
162
|
+
_payload["inventory"]["items"] = items.split(',')
|
163
|
+
|
164
|
+
if location_filter:
|
165
|
+
_payload["filtering"] = {
|
166
|
+
"location": {
|
167
|
+
"locations": location_filter.split(',')
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
171
|
+
curl, error, json_obj = api_request('POST', to_curl, _api_url, self.headers, _payload)
|
172
|
+
if curl:
|
173
|
+
return curl, None, None
|
174
|
+
if error:
|
175
|
+
return None, error, None
|
176
|
+
|
177
|
+
decided_items = DecidedItemList(**json_obj)
|
178
|
+
return None, None, decided_items
|
179
|
+
|
180
|
+
|
181
|
+
def decide_creative(
|
182
|
+
self,
|
183
|
+
inventory_id,
|
184
|
+
items,
|
185
|
+
location_filter,
|
186
|
+
to_curl
|
187
|
+
) -> tuple[
|
188
|
+
Optional[CurlString],
|
189
|
+
Optional[Error],
|
190
|
+
Optional[DecidedCreative],
|
191
|
+
]:
|
192
|
+
_api_url = f"{self.api_base_url}/creative-auction"
|
193
|
+
_payload = {
|
194
|
+
"request_id": "request-1",
|
195
|
+
"inventory": {
|
196
|
+
"inventory_id": inventory_id
|
197
|
+
},
|
198
|
+
"user": {
|
199
|
+
"user_id": "user-1"
|
200
|
+
},
|
201
|
+
"device": {
|
202
|
+
"persistent_id": "persistent-device-1"
|
203
|
+
},
|
204
|
+
}
|
205
|
+
if items:
|
206
|
+
_payload["inventory"]["items"] = items.split(',')
|
207
|
+
|
208
|
+
if location_filter:
|
209
|
+
_payload["filtering"] = {
|
210
|
+
"location": {
|
211
|
+
"locations": location_filter.split(',')
|
212
|
+
}
|
213
|
+
}
|
214
|
+
|
215
|
+
curl, error, json_obj = api_request('POST', to_curl, _api_url, self.headers, _payload)
|
216
|
+
if curl:
|
217
|
+
return curl, None, None
|
218
|
+
if error:
|
219
|
+
return None, error, None
|
220
|
+
|
221
|
+
decided_creative = DecidedCreative(**json_obj)
|
222
|
+
return None, None, decided_creative
|
223
|
+
|
224
|
+
|
225
|
+
def decide_creative_bulk(
|
226
|
+
self,
|
227
|
+
inventory_id_list,
|
228
|
+
items,
|
229
|
+
location_filter,
|
230
|
+
to_curl
|
231
|
+
) -> tuple[
|
232
|
+
Optional[CurlString],
|
233
|
+
Optional[Error],
|
234
|
+
Optional[DecidedCreativeBulkList],
|
235
|
+
]:
|
236
|
+
_api_url = f"{self.api_base_url}/creative-auction-bulk"
|
237
|
+
_payload = {
|
238
|
+
"request_id": "request-1",
|
239
|
+
"inventories": list(map(lambda x: { "inventory_id": x }, inventory_id_list.split(','))),
|
240
|
+
"user": {
|
241
|
+
"user_id": "user-1"
|
242
|
+
},
|
243
|
+
"device": {
|
244
|
+
"persistent_id": "persistent-device-1"
|
245
|
+
},
|
246
|
+
}
|
247
|
+
if items:
|
248
|
+
for inventory in _payload["inventories"]:
|
249
|
+
inventory["items"] = items.split(',')
|
250
|
+
|
251
|
+
if location_filter:
|
252
|
+
_payload["filtering"] = {
|
253
|
+
"location": {
|
254
|
+
"locations": location_filter.split(',')
|
255
|
+
}
|
256
|
+
}
|
257
|
+
|
258
|
+
curl, error, json_obj = api_request('POST', to_curl, _api_url, self.headers, _payload)
|
259
|
+
if curl:
|
260
|
+
return curl, None, None
|
261
|
+
if error:
|
262
|
+
return None, error, None
|
263
|
+
|
264
|
+
return None, None, DecidedCreativeBulkList(**json_obj)
|
265
|
+
|
mcmcli/command/wallet.py
CHANGED
@@ -127,7 +127,7 @@ def deposit(
|
|
127
127
|
credits_amount = float(credits_amount_micro) / float(1000000)
|
128
128
|
pre_paid_amount = float(pre_paid_amount_micro) / float(1000000)
|
129
129
|
|
130
|
-
print(f"
|
130
|
+
print(f"Funds have been deposited into the wallet. The current balance for ad account ID {account_id} is {pre_paid_amount} in PRE_PAID and {credits_amount} in CREDITS.")
|
131
131
|
return
|
132
132
|
|
133
133
|
@app.command()
|
@@ -178,7 +178,7 @@ def withdraw(
|
|
178
178
|
credits_amount = float(credits_amount_micro) / float(1000000)
|
179
179
|
pre_paid_amount = float(pre_paid_amount_micro) / float(1000000)
|
180
180
|
|
181
|
-
print(f"
|
181
|
+
print(f"Funds were withdrawn out of the wallet. The current balance of ad account ID {account_id} is {pre_paid_amount} for PRE_PAID and {credits_amount} for CREDITS.")
|
182
182
|
return
|
183
183
|
|
184
184
|
class WalletCommand:
|
mcmcli/data/decision.py
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# Copyright 2023 Moloco, Inc
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
from pydantic import BaseModel
|
16
|
+
from typing import Optional
|
17
|
+
|
18
|
+
#
|
19
|
+
# API response dataclasses
|
20
|
+
#
|
21
|
+
# Item decision API's response example:
|
22
|
+
#
|
23
|
+
# {
|
24
|
+
# "request_id": "request-1",
|
25
|
+
# "decided_items": [
|
26
|
+
# {
|
27
|
+
# "item_id": "1111833",
|
28
|
+
# "auction_result": {
|
29
|
+
# "ad_account_id": "2444",
|
30
|
+
# "campaign_id": "zWHhpyNbzYcy5FAy",
|
31
|
+
# "win_price": {
|
32
|
+
# "currency": "USD",
|
33
|
+
# "amount_micro": "500000000"
|
34
|
+
# },
|
35
|
+
# "campaign_text_entry": ""
|
36
|
+
# },
|
37
|
+
# "imp_trackers": [
|
38
|
+
# "https://myplatform-evt.rmp-api.moloco.com/t/i/MYPLATFORM_TEST?source=2X0op"
|
39
|
+
# ],
|
40
|
+
# "click_trackers": [
|
41
|
+
# "https://myplatform-evt.rmp-api.moloco.com/t/c/MYPLATFORM_TEST?source=2X0opp"
|
42
|
+
# ],
|
43
|
+
# "track_id": "2X0op"
|
44
|
+
# }
|
45
|
+
# ]
|
46
|
+
# }
|
47
|
+
|
48
|
+
class MicroPrice(BaseModel):
|
49
|
+
currency: str
|
50
|
+
amount_micro: str
|
51
|
+
|
52
|
+
class AuctionResult(BaseModel):
|
53
|
+
ad_account_id: str
|
54
|
+
campaign_id: str
|
55
|
+
win_price: Optional[MicroPrice]
|
56
|
+
campaign_text_entry: Optional[str]
|
57
|
+
|
58
|
+
class DecidedItem(BaseModel):
|
59
|
+
item_id: str
|
60
|
+
auction_result: Optional[AuctionResult]
|
61
|
+
imp_trackers: list[str]
|
62
|
+
click_trackers: list[str]
|
63
|
+
track_id: Optional[str]
|
64
|
+
|
65
|
+
class DecidedItemList(BaseModel):
|
66
|
+
request_id: str
|
67
|
+
decided_items: list[DecidedItem]
|
68
|
+
|
69
|
+
class CreativeBanner(BaseModel):
|
70
|
+
creative_id: str
|
71
|
+
image_url: str
|
72
|
+
imp_trackers: list[str]
|
73
|
+
click_trackers: list[str]
|
74
|
+
|
75
|
+
class CreativeItem(BaseModel):
|
76
|
+
item_id: str
|
77
|
+
imp_trackers: list[str]
|
78
|
+
click_trackers: list[str]
|
79
|
+
|
80
|
+
class LandingUrl(BaseModel):
|
81
|
+
id: str
|
82
|
+
url: str
|
83
|
+
|
84
|
+
class DecidedCreative(BaseModel):
|
85
|
+
request_id: str
|
86
|
+
auction_result: Optional[AuctionResult]
|
87
|
+
banner: Optional[CreativeBanner]
|
88
|
+
items: list[CreativeItem]
|
89
|
+
landing_url:Optional[LandingUrl]
|
90
|
+
|
91
|
+
class CreativeBannerWrapper(BaseModel):
|
92
|
+
banner: CreativeBanner
|
93
|
+
|
94
|
+
class DecidedCreativeBulk(BaseModel):
|
95
|
+
inventory_id: str
|
96
|
+
auction_result: Optional[AuctionResult]
|
97
|
+
creatives: list[CreativeBannerWrapper]
|
98
|
+
items: list[DecidedItem]
|
99
|
+
landing_url: Optional[LandingUrl]
|
100
|
+
|
101
|
+
class DecidedCreativeBulkList(BaseModel):
|
102
|
+
request_id: str
|
103
|
+
results: list[DecidedCreativeBulk]
|
104
|
+
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|