canonicalwebteam.store-api 5.0.0__py3-none-any.whl → 6.0.0__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.
- canonicalwebteam/store_api/base.py +68 -0
- canonicalwebteam/store_api/dashboard.py +647 -0
- canonicalwebteam/store_api/{store.py → devicegw.py} +126 -78
- canonicalwebteam/store_api/publishergw.py +832 -0
- {canonicalwebteam_store_api-5.0.0.dist-info → canonicalwebteam_store_api-6.0.0.dist-info}/METADATA +7 -7
- canonicalwebteam_store_api-6.0.0.dist-info/RECORD +11 -0
- {canonicalwebteam_store_api-5.0.0.dist-info → canonicalwebteam_store_api-6.0.0.dist-info}/WHEEL +1 -1
- canonicalwebteam/store_api/publisher.py +0 -420
- canonicalwebteam/store_api/stores/__init__.py +0 -0
- canonicalwebteam/store_api/stores/charmstore.py +0 -525
- canonicalwebteam/store_api/stores/snapstore.py +0 -770
- canonicalwebteam_store_api-5.0.0.dist-info/RECORD +0 -12
- /canonicalwebteam/{store_api/exceptions.py → exceptions.py} +0 -0
- {canonicalwebteam_store_api-5.0.0.dist-info → canonicalwebteam_store_api-6.0.0.dist-info}/LICENSE +0 -0
|
@@ -1,770 +0,0 @@
|
|
|
1
|
-
from os import getenv
|
|
2
|
-
|
|
3
|
-
import requests
|
|
4
|
-
|
|
5
|
-
from canonicalwebteam.store_api.store import Store
|
|
6
|
-
from canonicalwebteam.store_api.publisher import Publisher
|
|
7
|
-
|
|
8
|
-
SNAPSTORE_API_URL = getenv("SNAPSTORE_API_URL", "https://api.snapcraft.io/")
|
|
9
|
-
SNAPSTORE_DASHBOARD_API_URL = getenv(
|
|
10
|
-
"SNAPSTORE_DASHBOARD_API_URL", "https://dashboard.snapcraft.io/"
|
|
11
|
-
)
|
|
12
|
-
SNAPSTORE_PUBLISHERWG_API_URL = getenv(
|
|
13
|
-
"SNAPSTORE_PUBLISHERWG_API_URL", "https://api.charmhub.io/"
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class SnapStore(Store):
|
|
18
|
-
def __init__(self, session=requests.Session(), store=None):
|
|
19
|
-
super().__init__(session, store)
|
|
20
|
-
|
|
21
|
-
self.config = {
|
|
22
|
-
1: {
|
|
23
|
-
"base_url": f"{SNAPSTORE_API_URL}api/v1/snaps/",
|
|
24
|
-
"headers": {"X-Ubuntu-Series": "16"},
|
|
25
|
-
},
|
|
26
|
-
2: {
|
|
27
|
-
"base_url": f"{SNAPSTORE_API_URL}v2/snaps/",
|
|
28
|
-
"headers": {"Snap-Device-Series": "16"},
|
|
29
|
-
},
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if store:
|
|
33
|
-
self.config[1]["headers"].update({"X-Ubuntu-Store": store})
|
|
34
|
-
self.config[2]["headers"].update({"Snap-Device-Store": store})
|
|
35
|
-
|
|
36
|
-
def get_item_details(
|
|
37
|
-
self,
|
|
38
|
-
name,
|
|
39
|
-
fields=[
|
|
40
|
-
"title",
|
|
41
|
-
"summary",
|
|
42
|
-
"description",
|
|
43
|
-
"license",
|
|
44
|
-
"contact",
|
|
45
|
-
"website",
|
|
46
|
-
"publisher",
|
|
47
|
-
"media",
|
|
48
|
-
"download",
|
|
49
|
-
"version",
|
|
50
|
-
"created-at",
|
|
51
|
-
"confinement",
|
|
52
|
-
"categories",
|
|
53
|
-
"trending",
|
|
54
|
-
"unlisted",
|
|
55
|
-
"links",
|
|
56
|
-
],
|
|
57
|
-
api_version=1,
|
|
58
|
-
):
|
|
59
|
-
return super(SnapStore, self).get_item_details(
|
|
60
|
-
name, None, fields, api_version
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
def find(
|
|
64
|
-
self,
|
|
65
|
-
query="",
|
|
66
|
-
category="",
|
|
67
|
-
architecture="",
|
|
68
|
-
publisher="",
|
|
69
|
-
featured="false",
|
|
70
|
-
fields=[],
|
|
71
|
-
):
|
|
72
|
-
"""
|
|
73
|
-
Documentation: https://api.snapcraft.io/docs/search.html#snaps_find
|
|
74
|
-
Endpoint: [GET] https://api.snapcraft.io/v2/snaps/find
|
|
75
|
-
"""
|
|
76
|
-
url = self.get_endpoint_url("find", 2)
|
|
77
|
-
headers = self.config[2].get("headers")
|
|
78
|
-
params = {
|
|
79
|
-
"q": query,
|
|
80
|
-
"category": category,
|
|
81
|
-
"architecture": architecture,
|
|
82
|
-
"publisher": publisher,
|
|
83
|
-
"featured": featured,
|
|
84
|
-
}
|
|
85
|
-
if fields:
|
|
86
|
-
params["fields"] = ",".join(fields)
|
|
87
|
-
response = self.session.get(url, params=params, headers=headers)
|
|
88
|
-
return self.process_response(response)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
class SnapPublisher(Publisher):
|
|
92
|
-
def __init__(self, session=requests.Session()):
|
|
93
|
-
super().__init__(session)
|
|
94
|
-
|
|
95
|
-
self.config = {
|
|
96
|
-
1: {"base_url": f"{SNAPSTORE_DASHBOARD_API_URL}dev/api/"},
|
|
97
|
-
2: {"base_url": f"{SNAPSTORE_DASHBOARD_API_URL}api/v2/"},
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
def get_macaroon(self, permissions):
|
|
101
|
-
"""
|
|
102
|
-
Return a bakery v2 macaroon from the publisher API to be discharged
|
|
103
|
-
Documemntation:
|
|
104
|
-
https://dashboard.snapcraft.io/docs/reference/v1/macaroon.html
|
|
105
|
-
Endpoint: [POST] https://dashboard.snapcraft.iodev/api/acl
|
|
106
|
-
"""
|
|
107
|
-
response = self.session.post(
|
|
108
|
-
url=self.get_endpoint_url("tokens", 2),
|
|
109
|
-
json={"permissions": permissions},
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
return self.process_response(response)["macaroon"]
|
|
113
|
-
|
|
114
|
-
def whoami(self, session):
|
|
115
|
-
"""
|
|
116
|
-
Get the authenticated user details.
|
|
117
|
-
Documentation:
|
|
118
|
-
https://dashboard.snapcraft.io/docs/reference/v2/en/tokens.html#api-tokens-whoami
|
|
119
|
-
Endpoint: [GET] https://dashboard.snapcraft.io/api/v2/tokens/whoami
|
|
120
|
-
"""
|
|
121
|
-
response = self.session.get(
|
|
122
|
-
url=self.get_endpoint_url("tokens/whoami", 2),
|
|
123
|
-
headers=self._get_authorization_header(session),
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
return self.process_response(response)
|
|
127
|
-
|
|
128
|
-
def get_dashboard_endpoint_url(self, endpoint):
|
|
129
|
-
return f"{SNAPSTORE_DASHBOARD_API_URL}api/v2/{endpoint}"
|
|
130
|
-
|
|
131
|
-
def get_publisherwg_endpoint_url(self, endpoint):
|
|
132
|
-
return f"{SNAPSTORE_PUBLISHERWG_API_URL}v1/{endpoint}"
|
|
133
|
-
|
|
134
|
-
def _get_publisherwg_authorization_header(self, session):
|
|
135
|
-
return {"Authorization": f"Macaroon {session['developer_token']}"}
|
|
136
|
-
|
|
137
|
-
def exchange_dashboard_macaroons(self, session):
|
|
138
|
-
"""
|
|
139
|
-
Exchange dashboard.snapcraft.io SSO discharged macaroons
|
|
140
|
-
Documentation:
|
|
141
|
-
https://api.charmhub.io/docs/default.html#exchange_dashboard_macaroons
|
|
142
|
-
Endpoint: [POST] https://api.charmhub.io/v1/tokens/dashboard/exchange
|
|
143
|
-
"""
|
|
144
|
-
response = self.session.post(
|
|
145
|
-
url=self.get_publisherwg_endpoint_url("tokens/dashboard/exchange"),
|
|
146
|
-
headers=self._get_authorization_header(session),
|
|
147
|
-
json={},
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
return self.process_response(response)["macaroon"]
|
|
151
|
-
|
|
152
|
-
def get_collaborators(self, session, name):
|
|
153
|
-
"""
|
|
154
|
-
Get collaborators (accepted invites) for the given package.
|
|
155
|
-
Documentation:
|
|
156
|
-
https://api.charmhub.io/docs/collaborator.html#get_collaborators
|
|
157
|
-
Endpoint: [GET]
|
|
158
|
-
https://api.charmhub.io/v1/snap/{snap_name}/collaborators
|
|
159
|
-
"""
|
|
160
|
-
response = self.session.get(
|
|
161
|
-
url=self.get_publisherwg_endpoint_url(
|
|
162
|
-
f"snap/{name}/collaborators"
|
|
163
|
-
),
|
|
164
|
-
headers=self._get_publisherwg_authorization_header(session),
|
|
165
|
-
)
|
|
166
|
-
return self.process_response(response)
|
|
167
|
-
|
|
168
|
-
def get_pending_invites(self, session, name):
|
|
169
|
-
"""
|
|
170
|
-
Get pending collaborator invites for the given package.
|
|
171
|
-
Documentation:
|
|
172
|
-
https://api.charmhub.io/docs/collaborator.html#get_pending_invites
|
|
173
|
-
Endpoint: [GET]
|
|
174
|
-
https://api.charmhub.io/v1/snap/{snap_name}/collaborators/invites
|
|
175
|
-
"""
|
|
176
|
-
response = self.session.get(
|
|
177
|
-
url=self.get_publisherwg_endpoint_url(
|
|
178
|
-
f"snap/{name}/collaborators/invites"
|
|
179
|
-
),
|
|
180
|
-
headers=self._get_publisherwg_authorization_header(session),
|
|
181
|
-
)
|
|
182
|
-
return self.process_response(response)
|
|
183
|
-
|
|
184
|
-
def invite_collaborators(self, session, name, emails):
|
|
185
|
-
"""
|
|
186
|
-
Invite one or more collaborators for a package.
|
|
187
|
-
Documentation:
|
|
188
|
-
https://api.charmhub.io/docs/collaborator.html#invite_collaborators
|
|
189
|
-
Endpoint: [POST]
|
|
190
|
-
https://api.charmhub.io/v1/snap/{snap_name}/collaborators/invites
|
|
191
|
-
"""
|
|
192
|
-
payload = {"invites": []}
|
|
193
|
-
|
|
194
|
-
for email in emails:
|
|
195
|
-
payload["invites"].append({"email": email})
|
|
196
|
-
|
|
197
|
-
response = self.session.post(
|
|
198
|
-
url=self.get_publisherwg_endpoint_url(
|
|
199
|
-
f"snap/{name}/collaborators/invites"
|
|
200
|
-
),
|
|
201
|
-
headers=self._get_publisherwg_authorization_header(session),
|
|
202
|
-
json=payload,
|
|
203
|
-
)
|
|
204
|
-
return self.process_response(response)
|
|
205
|
-
|
|
206
|
-
def revoke_invites(self, session, name, emails):
|
|
207
|
-
"""
|
|
208
|
-
Revoke invites to the specified emails for the package.
|
|
209
|
-
Documentation:
|
|
210
|
-
https://api.charmhub.io/docs/collaborator.html#revoke_invites
|
|
211
|
-
Endpoint: [POST]
|
|
212
|
-
https://api.charmhub.io/v1/snap/{snap_name}/collaborators/invites/revoke
|
|
213
|
-
"""
|
|
214
|
-
payload = {"invites": []}
|
|
215
|
-
|
|
216
|
-
for email in emails:
|
|
217
|
-
payload["invites"].append({"email": email})
|
|
218
|
-
|
|
219
|
-
response = self.session.post(
|
|
220
|
-
url=self.get_publisherwg_endpoint_url(
|
|
221
|
-
f"snap/{name}/collaborators/invites/revoke"
|
|
222
|
-
),
|
|
223
|
-
headers=self._get_publisherwg_authorization_header(session),
|
|
224
|
-
json=payload,
|
|
225
|
-
)
|
|
226
|
-
return self.process_response(response)
|
|
227
|
-
|
|
228
|
-
def accept_invite(self, session, name, token):
|
|
229
|
-
"""
|
|
230
|
-
Accept a collaborator invite.
|
|
231
|
-
Documentation:
|
|
232
|
-
https://api.charmhub.io/docs/collaborator.html#accept_invite
|
|
233
|
-
Endpoint: [POST]
|
|
234
|
-
https://api.charmhub.io/v1/snap/{snap_name}/collaborators/invites/accept
|
|
235
|
-
"""
|
|
236
|
-
response = self.session.post(
|
|
237
|
-
url=self.get_publisherwg_endpoint_url(
|
|
238
|
-
f"snap/{name}/collaborators/invites/accept"
|
|
239
|
-
),
|
|
240
|
-
headers=self._get_publisherwg_authorization_header(session),
|
|
241
|
-
json={"token": token},
|
|
242
|
-
)
|
|
243
|
-
return self.process_response(response)
|
|
244
|
-
|
|
245
|
-
def reject_invite(self, session, name, token):
|
|
246
|
-
"""
|
|
247
|
-
Reject a collaborator invite.
|
|
248
|
-
Documentation:
|
|
249
|
-
https://api.charmhub.io/docs/collaborator.html#reject_invite
|
|
250
|
-
Endpoint: [POST]
|
|
251
|
-
https://api.charmhub.io/v1/snap/{snap_name}/collaborators/invites/reject
|
|
252
|
-
"""
|
|
253
|
-
response = self.session.post(
|
|
254
|
-
url=self.get_publisherwg_endpoint_url(
|
|
255
|
-
f"snap/{name}/collaborators/invites/reject"
|
|
256
|
-
),
|
|
257
|
-
headers=self._get_publisherwg_authorization_header(session),
|
|
258
|
-
json={"token": token},
|
|
259
|
-
)
|
|
260
|
-
return self.process_response(response)
|
|
261
|
-
|
|
262
|
-
def create_track(
|
|
263
|
-
self,
|
|
264
|
-
session,
|
|
265
|
-
snap_name,
|
|
266
|
-
track_name,
|
|
267
|
-
version_pattern=None,
|
|
268
|
-
auto_phasing_percentage=None,
|
|
269
|
-
):
|
|
270
|
-
"""
|
|
271
|
-
Create a track for a snap base on the snap's guardrail pattern.
|
|
272
|
-
Documentation: https://api.charmhub.io/docs/default.html#create_tracks
|
|
273
|
-
Endpoint: [POST] https://api.charmhub.io/v1/snap/{snap_name}/tracks
|
|
274
|
-
Args:
|
|
275
|
-
publisher_auth: Serialized macaroon to consume the API.
|
|
276
|
-
snap_name: Name of the snap
|
|
277
|
-
track_name: Name of the track
|
|
278
|
-
version_pattern: Version pattern for the track (optional)
|
|
279
|
-
auto_phasing_percentage: phasing percentage for track (optional)
|
|
280
|
-
"""
|
|
281
|
-
payload = {
|
|
282
|
-
"name": track_name,
|
|
283
|
-
"version-pattern": version_pattern,
|
|
284
|
-
"automatic-phasing-percentage": auto_phasing_percentage,
|
|
285
|
-
}
|
|
286
|
-
response = self.session.post(
|
|
287
|
-
url=self.get_publisherwg_endpoint_url(f"snap/{snap_name}/tracks"),
|
|
288
|
-
headers=self._get_publisherwg_authorization_header(session),
|
|
289
|
-
json=[payload],
|
|
290
|
-
)
|
|
291
|
-
return response
|
|
292
|
-
|
|
293
|
-
def get_package_metadata(self, publisher_auth, package_type, snap_name):
|
|
294
|
-
"""
|
|
295
|
-
Get general metadata for a package.
|
|
296
|
-
Documentation:
|
|
297
|
-
https://api.charmhub.io/docs/default.html#package_metadata
|
|
298
|
-
Endpoint: [GET] https://api.charmhub.io/v1/{package_type}/{snap_name}
|
|
299
|
-
Args:
|
|
300
|
-
publisher_auth: Serialized macaroon to consume the API.
|
|
301
|
-
package_type: Type of packages to obtain.
|
|
302
|
-
Returns:
|
|
303
|
-
Package general metadata
|
|
304
|
-
"""
|
|
305
|
-
response = self.session.get(
|
|
306
|
-
url=self.get_publisherwg_endpoint_url(
|
|
307
|
-
f"{package_type}/{snap_name}"
|
|
308
|
-
),
|
|
309
|
-
headers=self._get_publisherwg_authorization_header(publisher_auth),
|
|
310
|
-
)
|
|
311
|
-
return response.json()
|
|
312
|
-
|
|
313
|
-
def unregister_package_name(self, publisher_auth, snap_name):
|
|
314
|
-
"""
|
|
315
|
-
Unregister a package name.
|
|
316
|
-
Documentation: https://api.charmhub.io/docs/default.html#register_name
|
|
317
|
-
Endpoint: [DELETE] https://api.charmhub.io/v1/snap/{snap_name}
|
|
318
|
-
|
|
319
|
-
Args:
|
|
320
|
-
publisher_auth: Serialized macaroon to consume the API.
|
|
321
|
-
name: Name of the package to unregister
|
|
322
|
-
Returns:
|
|
323
|
-
The package name ID if successful
|
|
324
|
-
Otherwise, returns an error list
|
|
325
|
-
"""
|
|
326
|
-
url = self.get_publisherwg_endpoint_url(f"snap/{snap_name}")
|
|
327
|
-
response = self.session.delete(
|
|
328
|
-
url=url,
|
|
329
|
-
headers=self._get_authorization_header(publisher_auth),
|
|
330
|
-
)
|
|
331
|
-
return response
|
|
332
|
-
|
|
333
|
-
def get_validation_sets(self, publisher_auth):
|
|
334
|
-
"""
|
|
335
|
-
Return a list of validation sets for the current account
|
|
336
|
-
Documentation:
|
|
337
|
-
https://dashboard.snapcraft.io/docs/reference/v2/en/validation-sets.html
|
|
338
|
-
Endpoint: [GET] https://dashboard.snapcraft.io/api/v2/validation-sets
|
|
339
|
-
"""
|
|
340
|
-
url = self.get_dashboard_endpoint_url("validation-sets")
|
|
341
|
-
response = self.session.get(
|
|
342
|
-
url, headers=self._get_authorization_header(publisher_auth)
|
|
343
|
-
)
|
|
344
|
-
return self.process_response(response)
|
|
345
|
-
|
|
346
|
-
def get_validation_set(self, publisher_auth, validation_set_id):
|
|
347
|
-
"""
|
|
348
|
-
Return a validation set for the current account
|
|
349
|
-
Documentation:
|
|
350
|
-
https://dashboard.snapcraft.io/docs/reference/v2/en/validation-sets.html
|
|
351
|
-
Endpoint:
|
|
352
|
-
[GET] https://dashboard.snapcraft.io/api/v2/validation-sets/{id}
|
|
353
|
-
"""
|
|
354
|
-
url = self.get_dashboard_endpoint_url(
|
|
355
|
-
f"validation-sets/{validation_set_id}?sequence=all"
|
|
356
|
-
)
|
|
357
|
-
response = self.session.get(
|
|
358
|
-
url, headers=self._get_authorization_header(publisher_auth)
|
|
359
|
-
)
|
|
360
|
-
return self.process_response(response)
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
class SnapStoreAdmin(SnapPublisher):
|
|
364
|
-
def get_endpoint_url(self, endpoint, api_version=2):
|
|
365
|
-
return super().get_endpoint_url(f"stores/{endpoint}", api_version)
|
|
366
|
-
|
|
367
|
-
def get_stores(self, session, roles=["admin", "review", "view", "access"]):
|
|
368
|
-
"""Return a list a stores with the given roles
|
|
369
|
-
Documentation:
|
|
370
|
-
https://dashboard.snapcraft.io/docs/reference/v1/account.html#get--dev-api-account
|
|
371
|
-
Endpoint: [GET] https://dashboard.snapcraft.io/dev/api/account
|
|
372
|
-
|
|
373
|
-
:return: A list of stores
|
|
374
|
-
"""
|
|
375
|
-
headers = self._get_authorization_header(session)
|
|
376
|
-
|
|
377
|
-
response = self.session.get(
|
|
378
|
-
url=super().get_endpoint_url("account", 1), headers=headers
|
|
379
|
-
)
|
|
380
|
-
|
|
381
|
-
account_info = self.process_response(response)
|
|
382
|
-
stores = account_info.get("stores", [])
|
|
383
|
-
user_stores = []
|
|
384
|
-
|
|
385
|
-
for store in stores:
|
|
386
|
-
if not set(roles).isdisjoint(store["roles"]):
|
|
387
|
-
user_stores.append(store)
|
|
388
|
-
|
|
389
|
-
return user_stores
|
|
390
|
-
|
|
391
|
-
def get_store(self, session, store_id):
|
|
392
|
-
"""Return a store where the user is an admin
|
|
393
|
-
Documentation:
|
|
394
|
-
https://dashboard.snapcraft.io/docs/reference/v2/en/stores.html#list-the-details-of-a-brand-store
|
|
395
|
-
Endpoint: [GET]
|
|
396
|
-
https://dashboard.snapcraft.io/api/v2/stores/{store_id}
|
|
397
|
-
|
|
398
|
-
:return: Store details
|
|
399
|
-
"""
|
|
400
|
-
headers = self._get_authorization_header(session)
|
|
401
|
-
|
|
402
|
-
response = self.session.get(
|
|
403
|
-
url=self.get_endpoint_url(store_id), headers=headers
|
|
404
|
-
)
|
|
405
|
-
|
|
406
|
-
return self.process_response(response)["store"]
|
|
407
|
-
|
|
408
|
-
def get_store_snaps(
|
|
409
|
-
self, session, store_id, query=None, allowed_for_inclusion=None
|
|
410
|
-
):
|
|
411
|
-
"""
|
|
412
|
-
Documentation:
|
|
413
|
-
https://dashboard.snapcraft.io/docs/reference/v2/en/stores.html#get
|
|
414
|
-
Endpoint: [GET]
|
|
415
|
-
https://dashboard.snapcraft.io/api/v2/stores/{store_id}/snaps
|
|
416
|
-
"""
|
|
417
|
-
headers = self._get_authorization_header(session)
|
|
418
|
-
params = {}
|
|
419
|
-
|
|
420
|
-
if query:
|
|
421
|
-
params["q"] = query
|
|
422
|
-
|
|
423
|
-
if allowed_for_inclusion:
|
|
424
|
-
params["allowed-for-inclusion"] = allowed_for_inclusion
|
|
425
|
-
|
|
426
|
-
response = self.session.get(
|
|
427
|
-
url=self.get_endpoint_url(f"{store_id}/snaps"),
|
|
428
|
-
params=params,
|
|
429
|
-
headers=headers,
|
|
430
|
-
)
|
|
431
|
-
|
|
432
|
-
return self.process_response(response).get("snaps", [])
|
|
433
|
-
|
|
434
|
-
def get_store_members(self, session, store_id):
|
|
435
|
-
"""
|
|
436
|
-
Documentation:
|
|
437
|
-
https://dashboard.snapcraft.io/docs/reference/v2/en/stores.html#list-the-details-of-a-brand-store
|
|
438
|
-
Endpoint: [GET] https://dashboard.snapcraft.io/api/v2/stores/{store_id}
|
|
439
|
-
"""
|
|
440
|
-
headers = self._get_authorization_header(session)
|
|
441
|
-
|
|
442
|
-
response = self.session.get(
|
|
443
|
-
url=self.get_endpoint_url(f"{store_id}"),
|
|
444
|
-
headers=headers,
|
|
445
|
-
)
|
|
446
|
-
|
|
447
|
-
return self.process_response(response).get("users", [])
|
|
448
|
-
|
|
449
|
-
def update_store_members(self, session, store_id, members):
|
|
450
|
-
"""
|
|
451
|
-
Documentation:
|
|
452
|
-
https://dashboard.snapcraft.io/docs/reference/v2/en/stores.html#add-remove-or-edit-users-roles
|
|
453
|
-
Endpoint: [POST]
|
|
454
|
-
https://dashboard.snapcraft.io/api/v2/stores/{store_id}/users
|
|
455
|
-
"""
|
|
456
|
-
headers = self._get_authorization_header(session)
|
|
457
|
-
|
|
458
|
-
response = self.session.post(
|
|
459
|
-
url=self.get_endpoint_url(f"{store_id}/users"),
|
|
460
|
-
headers=headers,
|
|
461
|
-
json=members,
|
|
462
|
-
)
|
|
463
|
-
|
|
464
|
-
return self.process_response(response)
|
|
465
|
-
|
|
466
|
-
def invite_store_members(self, session, store_id, members):
|
|
467
|
-
"""
|
|
468
|
-
Documentation:
|
|
469
|
-
https://dashboard.snapcraft.io/docs/reference/v2/en/stores.html#manage-store-invitations
|
|
470
|
-
Endpoint: [POST]
|
|
471
|
-
https://dashboard.snapcraft.io/api/v2/stores/{store_id}/invites
|
|
472
|
-
"""
|
|
473
|
-
headers = self._get_authorization_header(session)
|
|
474
|
-
|
|
475
|
-
response = self.session.post(
|
|
476
|
-
url=self.get_endpoint_url(f"{store_id}/invites"),
|
|
477
|
-
headers=headers,
|
|
478
|
-
json=members,
|
|
479
|
-
)
|
|
480
|
-
|
|
481
|
-
return self.process_response(response)
|
|
482
|
-
|
|
483
|
-
def change_store_settings(self, session, store_id, settings):
|
|
484
|
-
"""
|
|
485
|
-
Documentation:
|
|
486
|
-
https://dashboard.snapcraft.io/docs/reference/v2/en/stores.html#change-store-settings
|
|
487
|
-
Endpoint: [PUT]
|
|
488
|
-
https://dashboard.snapcraft.io/api/v2/stores/{store_id}/settings
|
|
489
|
-
"""
|
|
490
|
-
headers = self._get_authorization_header(session)
|
|
491
|
-
|
|
492
|
-
response = self.session.put(
|
|
493
|
-
url=self.get_endpoint_url(f"{store_id}/settings"),
|
|
494
|
-
headers=headers,
|
|
495
|
-
json=settings,
|
|
496
|
-
)
|
|
497
|
-
|
|
498
|
-
return self.process_response(response)
|
|
499
|
-
|
|
500
|
-
def update_store_snaps(self, session, store_id, snaps):
|
|
501
|
-
"""
|
|
502
|
-
Documentation:
|
|
503
|
-
https://dashboard.snapcraft.io/docs/reference/v2/en/stores.html#post
|
|
504
|
-
Endpoint: [POST]
|
|
505
|
-
https://dashboard.snapcraft.io/api/v2/stores/{store_id}/snaps
|
|
506
|
-
"""
|
|
507
|
-
headers = self._get_authorization_header(session)
|
|
508
|
-
|
|
509
|
-
response = self.session.post(
|
|
510
|
-
url=self.get_endpoint_url(f"{store_id}/snaps"),
|
|
511
|
-
headers=headers,
|
|
512
|
-
json=snaps,
|
|
513
|
-
)
|
|
514
|
-
|
|
515
|
-
return self.process_response(response)
|
|
516
|
-
|
|
517
|
-
def update_store_invites(self, session, store_id, invites):
|
|
518
|
-
"""
|
|
519
|
-
Documentation:
|
|
520
|
-
https://dashboard.snapcraft.io/docs/reference/v2/en/stores.html#manage-store-invitations
|
|
521
|
-
Endpoint: [PUT]
|
|
522
|
-
https://dashboard.snapcraft.io/api/v2/stores/{store_id}/invites
|
|
523
|
-
"""
|
|
524
|
-
headers = self._get_authorization_header(session)
|
|
525
|
-
|
|
526
|
-
response = self.session.put(
|
|
527
|
-
url=self.get_endpoint_url(f"{store_id}/invites"),
|
|
528
|
-
headers=headers,
|
|
529
|
-
json=invites,
|
|
530
|
-
)
|
|
531
|
-
|
|
532
|
-
return self.process_response(response)
|
|
533
|
-
|
|
534
|
-
def get_store_invites(self, session, store_id):
|
|
535
|
-
"""
|
|
536
|
-
Documentation:
|
|
537
|
-
https://dashboard.snapcraft.io/docs/reference/v2/en/stores.html#list-the-details-of-a-brand-store
|
|
538
|
-
Endpoint: [GET] https://dashboard.snapcraft.io/api/v2/stores/{store_id}
|
|
539
|
-
"""
|
|
540
|
-
headers = self._get_authorization_header(session)
|
|
541
|
-
|
|
542
|
-
response = self.session.get(
|
|
543
|
-
url=self.get_endpoint_url(f"{store_id}"),
|
|
544
|
-
headers=headers,
|
|
545
|
-
)
|
|
546
|
-
|
|
547
|
-
return self.process_response(response).get("invites", [])
|
|
548
|
-
|
|
549
|
-
# MODEL SERVICE ADMIN
|
|
550
|
-
def get_store_models(self, session, store_id):
|
|
551
|
-
"""
|
|
552
|
-
Documentation:
|
|
553
|
-
https://api.charmhub.io/docs/model-service-admin.html#read_models
|
|
554
|
-
Endpoint: [GET] https://api.charmhub.io/v1/brand/{store_id}/model
|
|
555
|
-
"""
|
|
556
|
-
response = self.session.get(
|
|
557
|
-
url=self.get_publisherwg_endpoint_url(f"brand/{store_id}/model"),
|
|
558
|
-
headers=self._get_publisherwg_authorization_header(session),
|
|
559
|
-
)
|
|
560
|
-
|
|
561
|
-
return self.process_response(response)
|
|
562
|
-
|
|
563
|
-
def create_store_model(self, session, store_id, name, api_key=None):
|
|
564
|
-
"""
|
|
565
|
-
Documentation:
|
|
566
|
-
https://api.charmhub.io/docs/model-service-admin.html#create_model
|
|
567
|
-
Endpoint: [POST] https://api.charmhub.io/v1/brand/{store_id}/model
|
|
568
|
-
"""
|
|
569
|
-
if api_key:
|
|
570
|
-
payload = {"name": name, "api-key": api_key, "series": "16"}
|
|
571
|
-
else:
|
|
572
|
-
payload = {"name": name, "series": "16"}
|
|
573
|
-
response = self.session.post(
|
|
574
|
-
url=self.get_publisherwg_endpoint_url(f"brand/{store_id}/model"),
|
|
575
|
-
headers=self._get_publisherwg_authorization_header(session),
|
|
576
|
-
json=payload,
|
|
577
|
-
)
|
|
578
|
-
|
|
579
|
-
return self.process_response(response)
|
|
580
|
-
|
|
581
|
-
def update_store_model(self, session, store_id, model_name, api_key):
|
|
582
|
-
"""
|
|
583
|
-
Doucumentation:
|
|
584
|
-
https://api.charmhub.io/docs/model-service-admin.html#update_model
|
|
585
|
-
Endpoint: [PATCH]
|
|
586
|
-
https://api.charmhub.io/v1/brand/{store_id}/model/{model_name}
|
|
587
|
-
"""
|
|
588
|
-
response = self.session.patch(
|
|
589
|
-
url=self.get_publisherwg_endpoint_url(
|
|
590
|
-
f"brand/{store_id}/model/{model_name}"
|
|
591
|
-
),
|
|
592
|
-
headers=self._get_publisherwg_authorization_header(session),
|
|
593
|
-
json={"api-key": api_key},
|
|
594
|
-
)
|
|
595
|
-
|
|
596
|
-
return self.process_response(response)
|
|
597
|
-
|
|
598
|
-
def get_store_model_policies(self, session, store_id, model_name):
|
|
599
|
-
"""
|
|
600
|
-
Documentation:
|
|
601
|
-
https://api.charmhub.io/docs/model-service-admin.html#read_serial_policies
|
|
602
|
-
Endpoint: [GET]
|
|
603
|
-
https://api.charmhub.io/v1/brand/{store_id}/model/<model_name>/serial_policy
|
|
604
|
-
"""
|
|
605
|
-
response = self.session.get(
|
|
606
|
-
url=self.get_publisherwg_endpoint_url(
|
|
607
|
-
f"brand/{store_id}/model/{model_name}/serial_policy"
|
|
608
|
-
),
|
|
609
|
-
headers=self._get_publisherwg_authorization_header(session),
|
|
610
|
-
)
|
|
611
|
-
|
|
612
|
-
return self.process_response(response)
|
|
613
|
-
|
|
614
|
-
def create_store_model_policy(
|
|
615
|
-
self, session, store_id, model_name, signing_key
|
|
616
|
-
):
|
|
617
|
-
"""
|
|
618
|
-
Documentation:
|
|
619
|
-
https://api.charmhub.io/docs/model-service-admin.html#create_serial_policy
|
|
620
|
-
Endpoint: [POST]
|
|
621
|
-
https://api.charmhub.io/v1/brand/{store_id}/model/{model_name}/serial_policy
|
|
622
|
-
"""
|
|
623
|
-
response = self.session.post(
|
|
624
|
-
url=self.get_publisherwg_endpoint_url(
|
|
625
|
-
f"brand/{store_id}/model/{model_name}/serial_policy"
|
|
626
|
-
),
|
|
627
|
-
headers=self._get_publisherwg_authorization_header(session),
|
|
628
|
-
json={"signing-key-sha3-384": signing_key},
|
|
629
|
-
)
|
|
630
|
-
|
|
631
|
-
return self.process_response(response)
|
|
632
|
-
|
|
633
|
-
def delete_store_model_policy(
|
|
634
|
-
self, session, store_id, model_name, revision
|
|
635
|
-
):
|
|
636
|
-
"""
|
|
637
|
-
Documentation:
|
|
638
|
-
https://api.charmhub.io/docs/model-service-admin.html#delete_serial_policy
|
|
639
|
-
Endpoint: [DELETE]
|
|
640
|
-
https://api.charmhub.io/v1/brand/{store_id}/model/{model_name}/serial_policy/{serial_policy_revision}
|
|
641
|
-
"""
|
|
642
|
-
response = self.session.delete(
|
|
643
|
-
url=self.get_publisherwg_endpoint_url(
|
|
644
|
-
f"brand/{store_id}/model/{model_name}/serial_policy/{revision}"
|
|
645
|
-
),
|
|
646
|
-
headers=self._get_publisherwg_authorization_header(session),
|
|
647
|
-
)
|
|
648
|
-
|
|
649
|
-
return response
|
|
650
|
-
|
|
651
|
-
def get_store_signing_keys(self, session, store_id):
|
|
652
|
-
"""
|
|
653
|
-
Documentation:
|
|
654
|
-
https://api.charmhub.io/docs/model-service-admin.html#read_signing_keys
|
|
655
|
-
Endpoint: [GET] https://api.charmhub.io/v1/brand/{store_id}/signing_key
|
|
656
|
-
"""
|
|
657
|
-
headers = self._get_publisherwg_authorization_header(session)
|
|
658
|
-
url = self.get_publisherwg_endpoint_url(
|
|
659
|
-
f"brand/{store_id}/signing_key"
|
|
660
|
-
)
|
|
661
|
-
response = self.session.get(
|
|
662
|
-
url=url,
|
|
663
|
-
headers=headers,
|
|
664
|
-
)
|
|
665
|
-
return self.process_response(response)
|
|
666
|
-
|
|
667
|
-
def create_store_signing_key(self, session, store_id, name):
|
|
668
|
-
"""
|
|
669
|
-
Documentation:
|
|
670
|
-
https://api.charmhub.io/docs/model-service-admin.html#create_signing_key
|
|
671
|
-
Endpoint: [POST]
|
|
672
|
-
https://api.charmhub.io/v1/brand/{store_id}/signing_key
|
|
673
|
-
"""
|
|
674
|
-
headers = self._get_publisherwg_authorization_header(session)
|
|
675
|
-
url = self.get_publisherwg_endpoint_url(
|
|
676
|
-
f"brand/{store_id}/signing_key"
|
|
677
|
-
)
|
|
678
|
-
response = self.session.post(
|
|
679
|
-
url=url,
|
|
680
|
-
headers=headers,
|
|
681
|
-
json={"name": name},
|
|
682
|
-
)
|
|
683
|
-
return self.process_response(response)
|
|
684
|
-
|
|
685
|
-
def delete_store_signing_key(
|
|
686
|
-
self, session, store_id, signing_key_sha3_384
|
|
687
|
-
):
|
|
688
|
-
"""
|
|
689
|
-
Documentation:
|
|
690
|
-
https://api.charmhub.io/docs/model-service-admin.html#delete_signing_key
|
|
691
|
-
Endpoint: [DELETE]
|
|
692
|
-
https://api.charmhub.io/v1/brand/{store_id}/signing_key/<signing_key_sha3_384}
|
|
693
|
-
"""
|
|
694
|
-
headers = self._get_publisherwg_authorization_header(session)
|
|
695
|
-
url = self.get_publisherwg_endpoint_url(
|
|
696
|
-
f"brand/{store_id}/signing_key/{signing_key_sha3_384}"
|
|
697
|
-
)
|
|
698
|
-
response = self.session.delete(
|
|
699
|
-
url=url,
|
|
700
|
-
headers=headers,
|
|
701
|
-
)
|
|
702
|
-
|
|
703
|
-
return response
|
|
704
|
-
|
|
705
|
-
def get_brand(self, session, store_id):
|
|
706
|
-
"""
|
|
707
|
-
Documentation:
|
|
708
|
-
https://api.charmhub.io/docs/model-service-admin.html#read_brand
|
|
709
|
-
Endpoint: [GET] https://api.charmhub.io/v1/brand/{store_id}
|
|
710
|
-
"""
|
|
711
|
-
headers = self._get_publisherwg_authorization_header(session)
|
|
712
|
-
url = self.get_publisherwg_endpoint_url(f"brand/{store_id}")
|
|
713
|
-
response = self.session.get(
|
|
714
|
-
url=url,
|
|
715
|
-
headers=headers,
|
|
716
|
-
)
|
|
717
|
-
|
|
718
|
-
return self.process_response(response)
|
|
719
|
-
|
|
720
|
-
# FEATURED SNAPS AUTOMATION
|
|
721
|
-
def delete_featured_snaps(self, session, snaps):
|
|
722
|
-
"""
|
|
723
|
-
Documentation: (link to spec)
|
|
724
|
-
https://docs.google.com/document/d/1UAybxuZyErh3ayqb4nzL3T4BbvMtnmKKEPu-ixcCj_8
|
|
725
|
-
Endpoint: [DELETE] https://api.charmhub.io/v1/snap/featured
|
|
726
|
-
"""
|
|
727
|
-
headers = self._get_publisherwg_authorization_header(session)
|
|
728
|
-
url = self.get_publisherwg_endpoint_url("snap/featured")
|
|
729
|
-
response = self.session.delete(
|
|
730
|
-
url=url,
|
|
731
|
-
headers=headers,
|
|
732
|
-
json=snaps,
|
|
733
|
-
)
|
|
734
|
-
return response
|
|
735
|
-
|
|
736
|
-
def update_featured_snaps(self, session, snaps):
|
|
737
|
-
"""
|
|
738
|
-
Documentation: (link to spec)
|
|
739
|
-
https://docs.google.com/document/d/1UAybxuZyErh3ayqb4nzL3T4BbvMtnmKKEPu-ixcCj_8
|
|
740
|
-
Endpoint: [PUT] https://api.charmhub.io/v1/snap/featured
|
|
741
|
-
"""
|
|
742
|
-
headers = self._get_publisherwg_authorization_header(session)
|
|
743
|
-
url = self.get_publisherwg_endpoint_url("snap/featured")
|
|
744
|
-
response = self.session.put(
|
|
745
|
-
url=url,
|
|
746
|
-
headers=headers,
|
|
747
|
-
json=snaps,
|
|
748
|
-
)
|
|
749
|
-
return response
|
|
750
|
-
|
|
751
|
-
def get_featured_snaps(self, session, api_version=1, fields="snap_id"):
|
|
752
|
-
"""
|
|
753
|
-
Documentation: (link to spec)
|
|
754
|
-
https://docs.google.com/document/d/1UAybxuZyErh3ayqb4nzL3T4BbvMtnmKKEPu-ixcCj_8/edit
|
|
755
|
-
Endpoint: https://api.snapcraft.io/api/v1/snaps/search
|
|
756
|
-
"""
|
|
757
|
-
url = f"{SNAPSTORE_API_URL}api/v1/snaps/search"
|
|
758
|
-
headers = self.config[api_version].get("headers")
|
|
759
|
-
|
|
760
|
-
params = {
|
|
761
|
-
"scope": "wide",
|
|
762
|
-
"arch": "wide",
|
|
763
|
-
"confinement": "strict,classic,devmode",
|
|
764
|
-
"fields": fields,
|
|
765
|
-
"section": "featured",
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
return self.process_response(
|
|
769
|
-
self.session.get(url, params=params, headers=headers)
|
|
770
|
-
)
|