Skip to content

Commit 89528f7

Browse files
committed
docs: add documentation for vanities
1 parent ea13944 commit 89528f7

File tree

3 files changed

+156
-24
lines changed

3 files changed

+156
-24
lines changed

.vscode/settings.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,4 @@
44
],
55
"python.testing.unittestEnabled": false,
66
"python.testing.pytestEnabled": true,
7-
"cSpell.words": [
8-
"mypy"
9-
]
107
}

docs/_quarto.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ quartodoc:
104104
- connect.permissions
105105
- connect.tasks
106106
- connect.users
107+
- connect.vanities
107108
- title: Posit Connect Metrics
108109
package: posit
109110
contents:

src/posit/connect/vanities.py

Lines changed: 155 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,42 +8,114 @@
88

99

1010
class Vanity(Resource):
11-
"""Represents a Vanity resource with the ability to destroy itself."""
11+
"""A vanity resource.
12+
13+
Vanities maintain custom URL paths assigned to content.
14+
15+
Warnings
16+
--------
17+
Vanity paths may only contain alphanumeric characters, hyphens, underscores, and slashes.
18+
19+
Vanities cannot have children. For example, if the vanity path "/finance/" exists, the vanity path "/finance/budget/" cannot. But, if "/finance" does not exist, both "/finance/budget/" and "/finance/report" are allowed.
20+
21+
The following vanities are reserved by Connect:
22+
- `/__`
23+
- `/favicon.ico`
24+
- `/connect`
25+
- `/apps`
26+
- `/users`
27+
- `/groups`
28+
- `/setpassword`
29+
- `/user-completion`
30+
- `/confirm`
31+
- `/recent`
32+
- `/reports`
33+
- `/plots`
34+
- `/unpublished`
35+
- `/settings`
36+
- `/metrics`
37+
- `/tokens`
38+
- `/help`
39+
- `/login`
40+
- `/welcome`
41+
- `/register`
42+
- `/resetpassword`
43+
- `/content`
44+
"""
45+
46+
_fuid: str = "content_guid"
47+
"""str : the foreign unique identifier field that points to the owner of this vanity, default is 'content_guid'"""
1248

1349
def __init__(
1450
self,
1551
/,
1652
params: ResourceParameters,
1753
*,
18-
after_destroy: AfterDestroyCallback = lambda: None,
54+
after_destroy: Optional[AfterDestroyCallback] = None,
1955
**kwargs,
2056
):
57+
"""Initialize a Vanity.
58+
59+
Parameters
60+
----------
61+
params : ResourceParameters
62+
after_destroy : AfterDestroyCallback, optional
63+
Called after the Vanity is successfully destroyed, by default None
64+
"""
2165
super().__init__(params, **kwargs)
2266
self._after_destroy = after_destroy
2367

2468
def destroy(self) -> None:
25-
"""Destroy the vanity resource."""
69+
"""Destroy the vanity.
70+
71+
Raises
72+
------
73+
ValueError
74+
If the foreign unique identifier is missing or its value is `None`.
75+
76+
Warnings
77+
--------
78+
This operation is irreversible.
79+
80+
Note
81+
----
82+
This action requires administrator privileges.
83+
"""
2684
fuid = self.get("content_guid")
2785
if fuid is None:
2886
raise ValueError("Missing value for required field: 'content_guid'.")
2987
endpoint = self.params.url + f"v1/content/{fuid}/vanity"
3088
self.params.session.delete(endpoint)
31-
self._after_destroy()
89+
90+
if self._after_destroy:
91+
self._after_destroy()
3292

3393

3494
class Vanities(Resources):
35-
"""Manages a collection of Vanity resources."""
95+
"""Manages a collection of vanities."""
3696

3797
def all(self) -> List[Vanity]:
38-
"""Retrieve all vanity resources."""
98+
"""Retrieve all vanities.
99+
100+
Returns
101+
-------
102+
List[Vanity]
103+
104+
Notes
105+
-----
106+
This action requires administrator privileges.
107+
"""
39108
endpoint = self.params.url + "v1/vanities"
40109
response = self.params.session.get(endpoint)
41110
results = response.json()
42111
return [Vanity(self.params, **result) for result in results]
43112

44113

45114
class VanityMixin(Resource):
46-
"""Mixin class to add vanity management capabilities to a resource."""
115+
"""Mixin class to add a vanity attribute to a resource."""
116+
117+
_uid: str = "guid"
118+
"""str : the unique identifier field for this resource"""
47119

48120
def __init__(self, /, params: ResourceParameters, **kwargs):
49121
super().__init__(params, **kwargs)
@@ -71,37 +143,99 @@ def vanity(self) -> Optional[Vanity]:
71143

72144
@vanity.setter
73145
def vanity(self, value: Union[str, dict]) -> None:
74-
"""Set the vanity using a path or dictionary of attributes."""
146+
"""Set the vanity.
147+
148+
Parameters
149+
----------
150+
value : str or dict
151+
The value can be a string or a dictionary. If provided as a string, it represents the vanity path. If provided as a dictionary, it contains key-value pairs with detailed information about the object.
152+
"""
75153
if isinstance(value, str):
76154
self.set_vanity(path=value)
77155
elif isinstance(value, dict):
78156
self.set_vanity(**value)
79-
self.reset()
157+
self.reset_vanity()
80158

81159
@vanity.deleter
82160
def vanity(self) -> None:
83-
"""Delete the vanity resource."""
161+
"""Destroy the vanity.
162+
163+
Warnings
164+
--------
165+
This operation is irreversible.
166+
167+
Note
168+
----
169+
This action requires administrator privileges.
170+
171+
See Also
172+
--------
173+
reset_vanity
174+
"""
84175
if self._vanity:
85176
self._vanity.destroy()
86-
self.reset()
177+
self.reset_vanity()
87178

88-
def reset(self) -> None:
89-
"""Reset the cached vanity resource."""
179+
def reset_vanity(self) -> None:
180+
"""Unload the cached vanity.
181+
182+
Forces the next access, if any, to query the vanity from the Connect server.
183+
"""
90184
self._vanity = None
91185

92186
@overload
93-
def set_vanity(self, *, path: str) -> None: ...
187+
def set_vanity(self, *, path: str) -> None:
188+
"""Set the vanity.
189+
190+
Parameters
191+
----------
192+
path : str
193+
The vanity path.
194+
195+
Raises
196+
------
197+
ValueError
198+
If the unique identifier field is missing or the value is None.
199+
"""
200+
...
94201

95202
@overload
96-
def set_vanity(self, *, path: str, force: bool) -> None: ...
203+
def set_vanity(self, *, path: str, force: bool) -> None:
204+
"""Set the vanity.
205+
206+
Parameters
207+
----------
208+
path : str
209+
The vanity path.
210+
force : bool
211+
If `True`, overwrite the ownership of this vanity to this resource, default `False`
212+
213+
Raises
214+
------
215+
ValueError
216+
If the unique identifier field is missing or the value is None.
217+
"""
218+
...
97219

98220
@overload
99-
def set_vanity(self, **attributes) -> None: ...
221+
def set_vanity(self, **attributes) -> None:
222+
"""Set the vanity.
223+
224+
Parameters
225+
----------
226+
**attributes : dict, optional
227+
Arbitrary vanity attributes. All attributes are passed as the request body to POST 'v1/content/:guid/vanity'
228+
229+
Possible keys may include:
230+
- `path` : str
231+
- `force` : bool
232+
"""
233+
...
100234

101235
def set_vanity(self, **attributes) -> None:
102-
"""Set or update the vanity resource with given attributes."""
103-
uid = self.get("guid")
104-
if uid is None:
105-
raise ValueError("Missing value for required field: 'guid'.")
106-
endpoint = self.params.url + f"v1/content/{uid}/vanity"
236+
"""Set the vanity."""
237+
v = self.get(self._uid)
238+
if v is None:
239+
raise ValueError(f"Missing value for required field: '{self._uid}'.")
240+
endpoint = self.params.url + f"v1/content/{v}/vanity"
107241
self.params.session.put(endpoint, json=attributes)

0 commit comments

Comments
 (0)