Skip to content

Commit b4c5c1b

Browse files
committed
Added hubs and projects listing.
1 parent bc1786b commit b4c5c1b

File tree

4 files changed

+208
-6
lines changed

4 files changed

+208
-6
lines changed

src/autodesk_forge_sdk/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44

55
from .auth import AuthenticationClient, Scope, get_authorization_url
66
from .auth import TokenProviderInterface, SimpleTokenProvider, OAuthTokenProvider
7-
from .oss import OSSClient
7+
from .dm import OSSClient, DataManagementClient
88
from .md import ModelDerivativeClient, urnify
Lines changed: 193 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
from urllib.parse import quote
77
from .auth import BaseOAuthClient, Scope, TokenProviderInterface
88

9-
BASE_URL = "https://developer.api.autodesk.com/oss/v2"
9+
OSS_BASE_URL = "https://developer.api.autodesk.com/oss/v2"
10+
DATA_MANAGEMENT_BASE_URL = "https://developer.api.autodesk.com/project/v1"
1011
READ_SCOPES = [Scope.BUCKET_READ, Scope.DATA_READ]
1112
WRITE_SCOPES = [Scope.BUCKET_CREATE, Scope.DATA_CREATE, Scope.DATA_WRITE]
1213
DELETE_SCOPES = [Scope.BUCKET_DELETE]
@@ -48,7 +49,7 @@ class OSSClient(BaseOAuthClient):
4849
**Documentation**: https://forge.autodesk.com/en/docs/data/v2/reference/http
4950
"""
5051

51-
def __init__(self, token_provider: TokenProviderInterface(), base_url: str = BASE_URL):
52+
def __init__(self, token_provider: TokenProviderInterface(), base_url: str=OSS_BASE_URL):
5253
"""
5354
Create new instance of the client.
5455
@@ -372,3 +373,193 @@ def delete_object(self, bucket_key: str, object_key: str):
372373
"""
373374
endpoint = "/buckets/{}/objects/{}".format(quote(bucket_key), quote(object_key))
374375
self._delete(endpoint, scopes=DELETE_SCOPES)
376+
377+
378+
class DataManagementClient(BaseOAuthClient):
379+
"""
380+
Forge Data Management data management client.
381+
382+
**Documentation**: https://forge.autodesk.com/en/docs/data/v2/reference/http
383+
"""
384+
385+
def __init__(
386+
self, token_provider: TokenProviderInterface, base_url: str=DATA_MANAGEMENT_BASE_URL):
387+
"""
388+
Create new instance of the client.
389+
390+
Args:
391+
token_provider (autodesk_forge_sdk.auth.TokenProviderInterface):
392+
Provider that will be used to generate access tokens for API calls.
393+
394+
Use `autodesk_forge_sdk.auth.OAuthTokenProvider` if you have your app's client ID
395+
and client secret available, `autodesk_forge_sdk.auth.SimpleTokenProvider`
396+
if you would like to use an existing access token instead, or even your own
397+
implementation of the `autodesk_forge_sdk.auth.TokenProviderInterface` interface.
398+
399+
Note that many APIs in the Forge Data Management service require
400+
a three-legged OAuth token.
401+
base_url (str, optional): Base URL for API calls.
402+
403+
Examples:
404+
```
405+
THREE_LEGGED_TOKEN = os.environ["THREE_LEGGED_TOKEN"]
406+
client = DataManagementClient(SimpleTokenProvider(THREE_LEGGED_TOKEN))
407+
```
408+
"""
409+
BaseOAuthClient.__init__(self, token_provider, base_url)
410+
411+
def _get_paginated(self, url: str, **kwargs) -> list:
412+
json = self._get(url, **kwargs).json()
413+
results = json["data"]
414+
while "links" in json and "next" in json["links"]:
415+
url = json["links"]["next"]["href"]
416+
json = self._get(url, **kwargs).json()
417+
results = results + json["data"]
418+
return results
419+
420+
def get_hubs(self, filter_id: str=None, filter_name: str=None) -> dict:
421+
"""
422+
Return a collection of accessible hubs for this member.
423+
424+
Hubs represent BIM 360 Team hubs, Fusion Team hubs (formerly known as A360 Team hubs),
425+
A360 Personal hubs, or BIM 360 Docs accounts. Team hubs include BIM 360 Team hubs
426+
and Fusion Team hubs (formerly known as A360 Team hubs). Personal hubs include
427+
A360 Personal hubs. Only active hubs are listed.
428+
429+
Note that for BIM 360 Docs, a hub ID corresponds to an account ID in the BIM 360 API.
430+
To convert an account ID into a hub ID you need to add a “b.” prefix. For example,
431+
an account ID of c8b0c73d-3ae9 translates to a hub ID of b.c8b0c73d-3ae9.
432+
433+
**Documentation**: https://forge.autodesk.com/en/docs/data/v2/reference/http/hubs-GET
434+
435+
Args:
436+
filter_id (str, optional): ID to filter the results by.
437+
filter_name (str, optional): Name to filter the results by.
438+
439+
Returns:
440+
dict: Parsed response JSON.
441+
442+
Examples:
443+
```
444+
THREE_LEGGED_TOKEN = os.environ["THREE_LEGGED_TOKEN"]
445+
client = DataManagementClient(SimpleTokenProvider(THREE_LEGGED_TOKEN))
446+
response = client.get_hubs()
447+
print(response.data)
448+
print(response.links)
449+
```
450+
"""
451+
headers = { "Content-Type": "application/vnd.api+json" }
452+
params = {}
453+
if filter_id:
454+
params["filter[id]"] = filter_id
455+
if filter_name:
456+
params["filter[name]"] = filter_name
457+
return self._get("/hubs", scopes=READ_SCOPES, headers=headers, params=params).json()
458+
459+
def get_all_hubs(self, filter_id: str=None, filter_name: str=None) -> dict:
460+
"""
461+
Similar to `get_hubs`, but retrieving all hubs without pagination.
462+
463+
**Documentation**: https://forge.autodesk.com/en/docs/data/v2/reference/http/hubs-GET
464+
465+
Args:
466+
filter_id (str, optional): ID to filter the results by.
467+
filter_name (str, optional): Name to filter the results by.
468+
469+
Returns:
470+
list(dict): List of hubs parsed from the response JSON.
471+
472+
Examples:
473+
```
474+
THREE_LEGGED_TOKEN = os.environ["THREE_LEGGED_TOKEN"]
475+
client = DataManagementClient(SimpleTokenProvider(THREE_LEGGED_TOKEN))
476+
hubs = client.get_all_hubs()
477+
print(hubs)
478+
```
479+
"""
480+
headers = { "Content-Type": "application/vnd.api+json" }
481+
params = {}
482+
if filter_id:
483+
params["filter[id]"] = filter_id
484+
if filter_name:
485+
params["filter[name]"] = filter_name
486+
return self._get_paginated("/hubs", scopes=READ_SCOPES, headers=headers, params=params)
487+
488+
def get_projects(
489+
self, hub_id: str, filter_id: str=None, page_number: int=None, page_limit=None) -> dict:
490+
"""
491+
Return a collection of projects for a given hub_id. A project represents a BIM 360
492+
Team project, a Fusion Team project, a BIM 360 Docs project, or an A360 Personal project.
493+
Multiple projects can be created within a single hub. Only active projects are listed.
494+
495+
Note that for BIM 360 Docs, a hub ID corresponds to an account ID in the BIM 360 API.
496+
To convert an account ID into a hub ID you need to add a “b.” prefix. For example,
497+
an account ID of c8b0c73d-3ae9 translates to a hub ID of b.c8b0c73d-3ae9.
498+
499+
Similarly, for BIM 360 Docs, the project ID in the Data Management API corresponds
500+
to the project ID in the BIM 360 API. To convert a project ID in the BIM 360 API
501+
into a project ID in the Data Management API you need to add a “b.” prefix. For example,
502+
a project ID of c8b0c73d-3ae9 translates to a project ID of b.c8b0c73d-3ae9.
503+
504+
**Documentation**:
505+
https://forge.autodesk.com/en/docs/data/v2/reference/http/hubs-hub_id-projects-GET
506+
507+
Args:
508+
hub_id (str): ID of a hub to list the projects for.
509+
filter_id (str, optional): ID to filter projects by.
510+
page_number (int, optional): Specifies what page to return.
511+
Page numbers are 0-based (the first page is page 0).
512+
page_limit (int, optional): Specifies the maximum number of elements
513+
to return in the page. The default value is 200. The min value is 1.
514+
The max value is 200.
515+
516+
Returns:
517+
dict: Parsed response JSON.
518+
519+
Examples:
520+
```
521+
THREE_LEGGED_TOKEN = os.environ["THREE_LEGGED_TOKEN"]
522+
client = DataManagementClient(SimpleTokenProvider(THREE_LEGGED_TOKEN))
523+
response = client.get_projects("some-hub-id")
524+
print(response.data)
525+
print(response.links)
526+
```
527+
"""
528+
headers = { "Content-Type": "application/vnd.api+json" }
529+
params = {}
530+
if filter_id:
531+
params["filter[id]"] = filter_id
532+
if page_number:
533+
params["page[number]"] = page_number
534+
if page_limit:
535+
params["page[limit]"] = page_limit
536+
endpoint = "/hubs/{}/projects".format(hub_id)
537+
return self._get(endpoint, scopes=READ_SCOPES, headers=headers, params=params).json()
538+
539+
def get_all_projects(self, hub_id: str, filter_id: str=None) -> dict:
540+
"""
541+
Similar to `get_projects`, but retrieving all projects without pagination.
542+
543+
**Documentation**:
544+
https://forge.autodesk.com/en/docs/data/v2/reference/http/hubs-hub_id-projects-GET
545+
546+
Args:
547+
hub_id (str): ID of a hub to list the projects for.
548+
549+
Returns:
550+
list(dict): List of projects parsed from the response JSON.
551+
552+
Examples:
553+
```
554+
THREE_LEGGED_TOKEN = os.environ["THREE_LEGGED_TOKEN"]
555+
client = DataManagementClient(SimpleTokenProvider(THREE_LEGGED_TOKEN))
556+
projects = client.get_all_projects("some-hub-id")
557+
print(projects)
558+
```
559+
"""
560+
headers = { "Content-Type": "application/vnd.api+json" }
561+
params = {}
562+
if filter_id:
563+
params["filter[id]"] = filter_id
564+
endpoint = "/hubs/{}/projects".format(hub_id)
565+
return self._get_paginated(endpoint, scopes=READ_SCOPES, headers=headers, params=params)

tests/context.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'src')))
55
from autodesk_forge_sdk import AuthenticationClient, Scope, get_authorization_url
66
from autodesk_forge_sdk import OAuthTokenProvider, SimpleTokenProvider
7-
from autodesk_forge_sdk import OSSClient, ModelDerivativeClient, urnify
7+
from autodesk_forge_sdk import OSSClient, DataManagementClient
8+
from autodesk_forge_sdk import ModelDerivativeClient, urnify
89

910
FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"]
1011
FORGE_CLIENT_SECRET = os.environ["FORGE_CLIENT_SECRET"]
Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import unittest
2-
from .context import OSSClient, OAuthTokenProvider, FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, FORGE_BUCKET
2+
from .context import OSSClient, DataManagementClient, OAuthTokenProvider, FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, FORGE_BUCKET
33

44
class OSSClientTestSuite(unittest.TestCase):
55
"""Forge Data Management OSS client test cases."""
@@ -41,5 +41,15 @@ def test_upload_object_file(self):
4141
obj = self.client.upload_object(FORGE_BUCKET, 'unittest.py', file)
4242
assert obj
4343

44+
class DataManagementTestSuite(unittest.TestCase):
45+
"""Forge Data Management client test cases."""
46+
47+
def setUp(self):
48+
self.client = DataManagementClient(OAuthTokenProvider(FORGE_CLIENT_ID, FORGE_CLIENT_SECRET))
49+
50+
def test_get_all_hubs(self):
51+
hubs = self.client.get_all_hubs()
52+
self.assertIsNotNone(hubs)
53+
4454
if __name__ == "__main__":
45-
unittest.main()
55+
unittest.main()

0 commit comments

Comments
 (0)