Skip to content

Commit 193a79a

Browse files
asonnenscheinCopilotCopilot
authored
Add default destination support (#1201)
* default destinations sdk and cli support * add tests * yapf * fix type issues * fix parameter name * update cli docs * Update planet/subscription_request.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Use DEFAULT_DESTINATION_REF constant in order_request.py (#1202) * Initial plan * Use DEFAULT_DESTINATION_REF constant in order_request.py Co-authored-by: asonnenschein <3228909+asonnenschein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: asonnenschein <3228909+asonnenschein@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: asonnenschein <3228909+asonnenschein@users.noreply.github.com>
1 parent 0cea292 commit 193a79a

File tree

10 files changed

+571
-7
lines changed

10 files changed

+571
-7
lines changed

docs/cli/cli-destinations.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,19 @@ The `list` command supports filtering on a variety of fields. You can discover a
3131
requesting user, false to exclude them.
3232
* `--can-write`: Set to true to include only destinations the user can
3333
modify, false to exclude them.
34+
* `--is-default`: Set to true to include only the default destination,
35+
false to exclude it.
3436

3537
For example, issue the following command to list destinations that are not archived and you as the user have permission to modify:
3638
```sh
3739
planet destinations list --archived false --can-write true
3840
```
3941

42+
To list only the default destination (if one is set):
43+
```sh
44+
planet destinations list --is-default true
45+
```
46+
4047
### Modify Destinations
4148
The CLI conveniently moves all modify actions to first class commands on the destination. The supported actions are archive, unarchive, rename, and update credentials. To discover all update actions run `planet destinations --help`.
4249

@@ -47,6 +54,31 @@ Credential updating might be done if credentials expire or need to be rotated. F
4754
planet destinations update s3 my-destination-id --access-key-id NEW_ACCESS_KEY --secret-access-key NEW_SECRET_KEY
4855
```
4956

57+
### Manage Default Destinations
58+
Default destinations are globally available to all members of an organization. An organization can have zero or one default destination at any time. Managing default destinations (setting, unsetting) is restricted to organization administrators and destination owners.
59+
60+
#### Set a Default Destination
61+
To set a destination as the default for your organization:
62+
```sh
63+
planet destinations default set my-destination-id
64+
```
65+
66+
#### Get the Current Default Destination
67+
To retrieve the current default destination (if one is set):
68+
```sh
69+
planet destinations default get
70+
```
71+
72+
If no default destination is set, this command will return an error indicating that no default destination is configured.
73+
74+
#### Unset the Default Destination
75+
To remove the current default destination:
76+
```sh
77+
planet destinations default unset
78+
```
79+
80+
This command returns no content on success (HTTP 204). Only organization administrators and destination owners can unset the default destination.
81+
5082
## Using destinations in Subscriptions API
5183
After creating a destination, it can be used as the delivery location for subscriptions. Use the destination reference in the delivery block instead of credentials.
5284

planet/cli/destinations.py

Lines changed: 106 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,18 @@ async def _patch_destination(ctx, destination_id, data, pretty):
3636
raise ClickException(f"Failed to patch destination: {e}")
3737

3838

39-
async def _list_destinations(ctx, archived, is_owner, can_write, pretty):
39+
async def _list_destinations(ctx,
40+
archived,
41+
is_owner,
42+
can_write,
43+
is_default,
44+
pretty):
4045
async with destinations_client(ctx) as cl:
4146
try:
4247
response = await cl.list_destinations(archived,
4348
is_owner,
44-
can_write)
49+
can_write,
50+
is_default)
4551
echo_json(response, pretty)
4652
except Exception as e:
4753
raise ClickException(f"Failed to list destinations: {e}")
@@ -65,6 +71,33 @@ async def _create_destination(ctx, data, pretty):
6571
raise ClickException(f"Failed to create destination: {e}")
6672

6773

74+
async def _set_default_destination(ctx, destination_id, pretty):
75+
async with destinations_client(ctx) as cl:
76+
try:
77+
response = await cl.set_default_destination(destination_id)
78+
echo_json(response, pretty)
79+
except Exception as e:
80+
raise ClickException(f"Failed to set default destination: {e}")
81+
82+
83+
async def _unset_default_destination(ctx, pretty):
84+
async with destinations_client(ctx) as cl:
85+
try:
86+
response = await cl.unset_default_destination()
87+
echo_json(response, pretty)
88+
except Exception as e:
89+
raise ClickException(f"Failed to unset default destination: {e}")
90+
91+
92+
async def _get_default_destination(ctx, pretty):
93+
async with destinations_client(ctx) as cl:
94+
try:
95+
response = await cl.get_default_destination()
96+
echo_json(response, pretty)
97+
except Exception as e:
98+
raise ClickException(f"Failed to get default destination: {e}")
99+
100+
68101
@command(destinations, name="list")
69102
@click.option('--archived',
70103
type=bool,
@@ -82,7 +115,17 @@ async def _create_destination(ctx, data, pretty):
82115
default=None,
83116
help="""Set to true to include only destinations the user can modify,
84117
false to exclude them.""")
85-
async def list_destinations(ctx, archived, is_owner, can_write, pretty):
118+
@click.option('--is-default',
119+
type=bool,
120+
default=None,
121+
help="""Set to true to include only the default destination,
122+
false to exclude it.""")
123+
async def list_destinations(ctx,
124+
archived,
125+
is_owner,
126+
can_write,
127+
is_default,
128+
pretty):
86129
"""
87130
List destinations with optional filters
88131
@@ -93,7 +136,12 @@ async def list_destinations(ctx, archived, is_owner, can_write, pretty):
93136
94137
planet destinations list --archived false --is-owner true --can-write true
95138
"""
96-
await _list_destinations(ctx, archived, is_owner, can_write, pretty)
139+
await _list_destinations(ctx,
140+
archived,
141+
is_owner,
142+
can_write,
143+
is_default,
144+
pretty)
97145

98146

99147
@command(destinations, name="get")
@@ -590,3 +638,57 @@ async def update_s3_compatible(ctx,
590638
data["parameters"]["use_path_style"] = True
591639

592640
await _patch_destination(ctx, destination_id, data, pretty)
641+
642+
643+
@destinations.group()
644+
def default():
645+
"""Commands for interacting with default destinations."""
646+
pass
647+
648+
649+
@command(default, name="set")
650+
@click.argument("destination_id")
651+
async def set_default_destination(ctx, destination_id, pretty):
652+
"""
653+
Set a default destination.
654+
655+
This command sets a specified destination as the default for the organization. Default destinations
656+
are globally available to all members of an organization. An organization can have zero or one default
657+
destination at any time. Ability to set a default destination is restricted to organization
658+
administrators and destination owners.
659+
660+
Example:
661+
662+
planet destinations default set my-destination-id
663+
"""
664+
await _set_default_destination(ctx, destination_id, pretty)
665+
666+
667+
@command(default, name="unset")
668+
async def unset_default_destination(ctx, pretty):
669+
"""
670+
Unset the current default destination.
671+
672+
This command unsets the current default destination. Ability to unset a default destination is restricted
673+
to organization administrators and destination owners. Returns None (HTTP 204, No Content) on success.
674+
675+
Example:
676+
677+
planet destinations default unset
678+
"""
679+
await _unset_default_destination(ctx, pretty)
680+
681+
682+
@command(default, name="get")
683+
async def get_default_destination(ctx, pretty):
684+
"""
685+
Get the current default destination.
686+
687+
This command gets the current default destination for the organization, if one is set. The default
688+
destination is globally available to all members of an organization.
689+
690+
Example:
691+
692+
planet destinations default get
693+
"""
694+
await _get_default_destination(ctx, pretty)

planet/clients/destinations.py

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
T = TypeVar("T")
2828

29+
DEFAULT_DESTINATION_REF = "pl:destinations/default"
30+
2931

3032
class DestinationsClient(_BaseClient):
3133
"""Asynchronous Destinations API client.
@@ -58,14 +60,16 @@ def __init__(self,
5860
async def list_destinations(self,
5961
archived: Optional[bool] = None,
6062
is_owner: Optional[bool] = None,
61-
can_write: Optional[bool] = None) -> Dict:
63+
can_write: Optional[bool] = None,
64+
is_default: Optional[bool] = None) -> Dict:
6265
"""
6366
List all destinations. By default, all non-archived destinations in the requesting user's org are returned.
6467
6568
Args:
6669
archived (bool): If True, include archived destinations.
6770
is_owner (bool): If True, include only destinations owned by the requesting user.
6871
can_write (bool): If True, include only destinations the requesting user can modify.
72+
is_default (bool): If True, include only the default destination.
6973
7074
Returns:
7175
dict: A dictionary containing the list of destinations inside the 'destinations' key.
@@ -81,6 +85,8 @@ async def list_destinations(self,
8185
params["is_owner"] = is_owner
8286
if can_write is not None:
8387
params["can_write"] = can_write
88+
if is_default is not None:
89+
params["is_default"] = is_default
8490

8591
try:
8692
response = await self._session.request(method='GET',
@@ -174,3 +180,75 @@ async def create_destination(self, request: Dict[str, Any]) -> Dict:
174180
else:
175181
dest = response.json()
176182
return dest
183+
184+
async def set_default_destination(self, destination_id: str) -> Dict:
185+
"""
186+
Set an existing destination as the default destination. Default destinations are globally available
187+
to all members of an organization. An organization can have zero or one default destination at any time.
188+
Ability to set a default destination is restricted to organization administrators and destination owners.
189+
190+
Args:
191+
destination_id (str): The ID of the destination to set as default.
192+
193+
Returns:
194+
dict: A dictionary containing the default destination details.
195+
196+
Raises:
197+
APIError: If the API returns an error response.
198+
ClientError: If there is an issue with the client request.
199+
"""
200+
url = f'{self._base_url}/default'
201+
request = {"destination_id": destination_id}
202+
try:
203+
response = await self._session.request(method='PUT',
204+
url=url,
205+
json=request)
206+
except APIError:
207+
raise
208+
except ClientError: # pragma: no cover
209+
raise
210+
else:
211+
return response.json()
212+
213+
async def unset_default_destination(self) -> None:
214+
"""
215+
Unset the current default destination. Ability to unset a default destination is restricted to
216+
organization administrators and destination owners. Returns None (HTTP 204, No Content) on success.
217+
218+
Returns:
219+
None
220+
221+
Raises:
222+
APIError: If the API returns an error response.
223+
ClientError: If there is an issue with the client request.
224+
"""
225+
url = f'{self._base_url}/default'
226+
try:
227+
await self._session.request(method='DELETE', url=url)
228+
except APIError:
229+
raise
230+
except ClientError: # pragma: no cover
231+
raise
232+
233+
async def get_default_destination(self) -> Dict:
234+
"""
235+
Get the current default destination. The default destination is globally available to all members of an
236+
organization.
237+
238+
Returns:
239+
dict: A dictionary containing the default destination details.
240+
241+
Raises:
242+
APIError: If the API returns an error response.
243+
ClientError: If there is an issue with the client request.
244+
"""
245+
url = f'{self._base_url}/default'
246+
try:
247+
response = await self._session.request(method='GET', url=url)
248+
except APIError:
249+
raise
250+
except ClientError: # pragma: no cover
251+
raise
252+
else:
253+
dest = response.json()
254+
return dest

planet/order_request.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from typing import Any, Dict, List, Mapping, Optional, Union
1919

2020
from . import geojson, specs
21+
from .clients.destinations import DEFAULT_DESTINATION_REF
2122
from .exceptions import ClientError
2223

2324
LOGGER = logging.getLogger(__name__)
@@ -392,6 +393,36 @@ def s3_compatible(endpoint: str,
392393
return {'s3_compatible': parameters}
393394

394395

396+
def destination(destination_ref: str,
397+
path_prefix: Optional[str] = None) -> dict:
398+
"""Destinations API configuration.
399+
Parameters:
400+
destination_ref: Reference to an existing Destinations API
401+
destination.
402+
path_prefix: Path prefix for deliveries.
403+
"""
404+
cloud_details: Dict[str, Any] = {'ref': destination_ref}
405+
406+
if path_prefix:
407+
cloud_details['path_prefix'] = path_prefix
408+
409+
return {'destination': cloud_details}
410+
411+
412+
def default_destination(path_prefix: Optional[str] = None) -> dict:
413+
"""Default Destinations API configuration.
414+
415+
Parameters:
416+
path_prefix: Path prefix for deliveries.
417+
"""
418+
parameters: Dict[str, Any] = {'ref': DEFAULT_DESTINATION_REF}
419+
420+
if path_prefix:
421+
parameters['path_prefix'] = path_prefix
422+
423+
return {'destination': parameters}
424+
425+
395426
def _tool(name: str, parameters: dict) -> dict:
396427
"""Create the API spec representation of a tool.
397428

planet/subscription_request.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from typing_extensions import Literal
2020

2121
from . import geojson, specs
22+
from .clients.destinations import DEFAULT_DESTINATION_REF
2223
from .exceptions import ClientError
2324

2425
NOTIFICATIONS_TOPICS = ('delivery.success',
@@ -528,6 +529,36 @@ def s3_compatible(endpoint: str,
528529
return _delivery('s3_compatible', parameters)
529530

530531

532+
def destination(destination_ref: str,
533+
path_prefix: Optional[str] = None) -> dict:
534+
"""Specify a Destinations API destination by its ref.
535+
536+
Parameters:
537+
destination_ref: The ID of the destination to deliver to.
538+
path_prefix: Path prefix for deliveries.
539+
"""
540+
parameters: Dict[str, Any] = {"ref": destination_ref}
541+
542+
if path_prefix:
543+
parameters['path_prefix'] = path_prefix
544+
545+
return _delivery('destination', parameters)
546+
547+
548+
def default_destination(path_prefix: Optional[str] = None) -> dict:
549+
"""Specify the organization's default Destinations API destination.
550+
551+
Parameters:
552+
path_prefix: Path prefix for deliveries.
553+
"""
554+
parameters: Dict[str, Any] = {"ref": DEFAULT_DESTINATION_REF}
555+
556+
if path_prefix:
557+
parameters['path_prefix'] = path_prefix
558+
559+
return _delivery('destination', parameters)
560+
561+
531562
def notifications(url: str, topics: List[str]) -> dict:
532563
"""Specify a subscriptions API notification.
533564

0 commit comments

Comments
 (0)