Merge ~jsseidel/maas:jsseidel-notifications-api-annotations into maas:master

Proposed by Spencer Seidel
Status: Merged
Approved by: Spencer Seidel
Approved revision: b949cc38bfe0e4724d17e0be0f57901b4d18d086
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~jsseidel/maas:jsseidel-notifications-api-annotations
Merge into: maas:master
Diff against target: 345 lines (+260/-28)
2 files modified
src/maasserver/api/examples/notifications.json (+132/-0)
src/maasserver/api/notification.py (+128/-28)
Reviewer Review Type Date Requested Status
MAAS Lander Approve
Mike Pontillo (community) Approve
Review via email: mp+361144@code.launchpad.net

Commit message

Added API annotations and examples to notifications.

To post a comment you must log in.
Revision history for this message
Mike Pontillo (mpontillo) wrote :

I'm good with this branch. Just a few comments below; I'll leave it up to you regarding whether or not you think action is required on them.

review: Approve
Revision history for this message
Spencer Seidel (jsseidel) :
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b jsseidel-notifications-api-annotations lp:~jsseidel/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: b949cc38bfe0e4724d17e0be0f57901b4d18d086

review: Approve
Revision history for this message
Spencer Seidel (jsseidel) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/api/examples/notifications.json b/src/maasserver/api/examples/notifications.json
2new file mode 100644
3index 0000000..1010eb3
4--- /dev/null
5+++ b/src/maasserver/api/examples/notifications.json
6@@ -0,0 +1,132 @@
7+{
8+ "notifications-read": [
9+ {
10+ "ident": "dhcp_disabled_all_vlans",
11+ "user": null,
12+ "users": false,
13+ "admins": true,
14+ "message": "DHCP is not enabled on any VLAN. This will prevent machines from being able to PXE boot, unless an external DHCP server is being used.",
15+ "context": {},
16+ "category": "warning",
17+ "id": 1,
18+ "resource_uri": "/MAAS/api/2.0/notifications/1/"
19+ },
20+ {
21+ "ident": null,
22+ "user": null,
23+ "users": false,
24+ "admins": true,
25+ "message": "Attention admins! Core critical! Meltdown imminent! Evacuate habitat immediately!",
26+ "context": {
27+ "name-oeIkwE": "value-cY9eNX"
28+ },
29+ "category": "error",
30+ "id": 2,
31+ "resource_uri": "/MAAS/api/2.0/notifications/2/"
32+ },
33+ {
34+ "ident": null,
35+ "user": {
36+ "is_superuser": true,
37+ "username": "admin",
38+ "email": "NN7ER2rH6x@example.com",
39+ "is_local": true,
40+ "resource_uri": "/MAAS/api/2.0/users/admin/"
41+ },
42+ "users": false,
43+ "admins": false,
44+ "message": "Greetings, {name}! Get away from the habitat for the weekend and visit the Mare Nubium with MAAS Tours. Use the code METAL to claim a special gift!",
45+ "context": {
46+ "name": "Admin"
47+ },
48+ "category": "info",
49+ "id": 5,
50+ "resource_uri": "/MAAS/api/2.0/notifications/5/"
51+ },
52+ {
53+ "ident": "maas-import-pxe-files script",
54+ "user": null,
55+ "users": false,
56+ "admins": true,
57+ "message": "Boot image import process not started. Machines will not be able to\nprovision without boot images. Visit the\n<a href=\"http://localhost:5240/MAAS/#/images\">boot images</a> page to start the import.\n",
58+ "context": {},
59+ "category": "error",
60+ "id": 1409,
61+ "resource_uri": "/MAAS/api/2.0/notifications/1409/"
62+ },
63+ {
64+ "ident": "clusters",
65+ "user": null,
66+ "users": false,
67+ "admins": true,
68+ "message": "One rack controller is not yet connected to the region. Visit the <a href=\"/MAAS/#/controllers\">rack controllers page</a> for more information.",
69+ "context": {},
70+ "category": "error",
71+ "id": 1410,
72+ "resource_uri": "/MAAS/api/2.0/notifications/1410/"
73+ },
74+ {
75+ "ident": "controller_out_of_date_mfhrw8",
76+ "user": null,
77+ "users": false,
78+ "admins": true,
79+ "message": "Controller <a href='#/node/controller/{system_id}'>{hostname}</a> is running an older version of MAAS (less than 2.3.0).",
80+ "context": {
81+ "hostname": "happy-region",
82+ "latest_version": "",
83+ "system_id": "mfhrw8"
84+ },
85+ "category": "warning",
86+ "id": 1411,
87+ "resource_uri": "/MAAS/api/2.0/notifications/1411/"
88+ },
89+ {
90+ "ident": "controller_out_of_date_ekf6cn",
91+ "user": null,
92+ "users": false,
93+ "admins": true,
94+ "message": "Controller <a href='#/node/controller/{system_id}'>{hostname}</a> is running an older version of MAAS (less than 2.3.0).",
95+ "context": {
96+ "hostname": "happy-rack",
97+ "latest_version": "",
98+ "system_id": "ekf6cn"
99+ },
100+ "category": "warning",
101+ "id": 1412,
102+ "resource_uri": "/MAAS/api/2.0/notifications/1412/"
103+ }
104+ ],
105+ "notifications-create": {
106+ "ident": null,
107+ "user": null,
108+ "users": true,
109+ "admins": false,
110+ "message": "This is a test message.",
111+ "context": {},
112+ "category": "info",
113+ "id": 1413,
114+ "resource_uri": "/MAAS/api/2.0/notifications/1413/"
115+ },
116+ "notifications-read-by-id": {
117+ "ident": null,
118+ "user": null,
119+ "users": true,
120+ "admins": false,
121+ "message": "This is a test message.",
122+ "context": {},
123+ "category": "info",
124+ "id": 1414,
125+ "resource_uri": "/MAAS/api/2.0/notifications/1414/"
126+ },
127+ "notifications-update": {
128+ "ident": null,
129+ "user": null,
130+ "users": true,
131+ "admins": false,
132+ "message": "This is an updated test message.",
133+ "context": {},
134+ "category": "info",
135+ "id": 1414,
136+ "resource_uri": "/MAAS/api/2.0/notifications/1414/"
137+ }
138+}
139diff --git a/src/maasserver/api/notification.py b/src/maasserver/api/notification.py
140index 6def843..edf059f 100644
141--- a/src/maasserver/api/notification.py
142+++ b/src/maasserver/api/notification.py
143@@ -44,36 +44,58 @@ class NotificationsHandler(OperationsHandler):
144 return ('notifications_handler', [])
145
146 def read(self, request):
147- """List notifications relevant to the invoking user.
148+ """@description-title List notifications
149+ @description List notifications relevant to the invoking user.
150
151 Notifications that have been dismissed are *not* returned.
152+
153+ @success (http-status-code) "server-success" 200
154+ @success (json) "success-json" A JSON object containing a list of
155+ notification objects.
156+ @success-example "success-json" [exkey=notifications-read] placeholder
157+ text
158 """
159 return Notification.objects.find_for_user(request.user).order_by('id')
160
161 @admin_method
162 def create(self, request):
163- """Create a notification.
164+ """@description-title Create a notification
165+ @description Create a new notification.
166
167 This is available to admins *only*.
168
169- :param message: The message for this notification. May contain basic
170- HTML; this will be sanitised before display.
171- :param context: Optional JSON context. The root object *must* be an
172- object (i.e. a mapping). The values herein can be referenced by
173- `message` with Python's "format" (not %) codes.
174- :param category: Optional category. Choose from: error, warning,
175- success, or info. Defaults to info.
176-
177- :param ident: Optional unique identifier for this notification.
178- :param user: Optional user ID this notification is intended for. By
179- default it will not be targeted to any individual user.
180- :param users: Optional boolean, true to notify all users, defaults to
181- false, i.e. not targeted to all users.
182- :param admins: Optional boolean, true to notify all admins, defaults to
183- false, i.e. not targeted to all admins.
184-
185- Note: if neither user nor users nor admins is set, the notification
186- will not be seen by anyone.
187+ Note: One of the ``user``, ``users`` or ``admins`` parameters must be
188+ set to True for the notification to be visible to anyone.
189+
190+ @param (string) "message" [required=true] The message for this
191+ notification. May contain basic HTML, such as formatting. This string
192+ will be sanitised before display so that it doesn't break MAAS HTML.
193+
194+ @param (string) "context" [required=false] Optional JSON context. The
195+ root object *must* be an object (i.e. a mapping). The values herein can
196+ be referenced by ``message`` with Python's "format" (not %) codes.
197+
198+ @param (string) "category" [required=false] Choose from: ``error``,
199+ ``warning``, ``success``, or ``info``. Defaults to ``info``.
200+
201+ @param (string) "ident" [required=false] Unique identifier for this
202+ notification.
203+
204+ @param (string) "user" [required=false] User ID this notification is
205+ intended for. By default it will not be targeted to any individual
206+ user.
207+
208+ @param (boolean) "users" [required=false] True to notify all users,
209+ defaults to false, i.e. not targeted to all users.
210+
211+ @param (boolean) "admins" [required=false] True to notify all admins,
212+ defaults to false, i.e. not targeted to all admins.
213+
214+ @success (http-status-code) "server-success" 200
215+ @success (json) "success-json" A JSON object containing a new
216+ notification object.
217+ @success-example "success-json" [exkey=notifications-create]
218+ placeholder text
219 """
220 form = NotificationForm(data=request.data)
221 if form.is_valid():
222@@ -92,7 +114,22 @@ class NotificationHandler(OperationsHandler):
223 fields = DISPLAYED_NOTIFICATION_FIELDS
224
225 def read(self, request, id):
226- """Read a specific notification."""
227+ """@description-title Read a notification
228+ @description Read a notification with the given id.
229+
230+ @param (int) "{id}" [required=true] The notification id.
231+
232+ @success (http-status-code) "server-success" 200
233+ @success (json) "success-json" A JSON object containing the requested
234+ notification object.
235+ @success-example "success-json" [exkey=notifications-read-by-id]
236+ placeholder text
237+
238+ @error (http-status-code) "404" 404
239+ @error (content) "not-found" The requested notification is not found.
240+ @error-example "not-found"
241+ Not Found
242+ """
243 notification = get_object_or_404(Notification, id=id)
244 if notification.is_relevant_to(request.user):
245 return notification
246@@ -103,9 +140,50 @@ class NotificationHandler(OperationsHandler):
247
248 @admin_method
249 def update(self, request, id):
250- """Update a specific notification.
251+ """@description-title Update a notification
252+ @description Update a notification with a given id.
253+
254+ This is available to admins *only*.
255+
256+ Note: One of the ``user``, ``users`` or ``admins`` parameters must be
257+ set to True for the notification to be visible to anyone.
258+
259+ @param (int) "{id}" [required=true] The notification id.
260
261- See `NotificationsHandler.create` for field information.
262+ @param (string) "message" [required=true] The message for this
263+ notification. May contain basic HTML, such as formatting. This string
264+ will be sanitised before display so that it doesn't break MAAS HTML.
265+
266+ @param (string) "context" [required=false] Optional JSON context. The
267+ root object *must* be an object (i.e. a mapping). The values herein can
268+ be referenced by ``message`` with Python's "format" (not %) codes.
269+
270+ @param (string) "category" [required=false] Choose from: ``error``,
271+ ``warning``, ``success``, or ``info``. Defaults to ``info``.
272+
273+ @param (string) "ident" [required=false] Unique identifier for this
274+ notification.
275+
276+ @param (string) "user" [required=false] User ID this notification is
277+ intended for. By default it will not be targeted to any individual
278+ user.
279+
280+ @param (boolean) "users" [required=false] True to notify all users,
281+ defaults to false, i.e. not targeted to all users.
282+
283+ @param (boolean) "admins" [required=false] True to notify all admins,
284+ defaults to false, i.e. not targeted to all admins.
285+
286+ @success (http-status-code) "server-success" 200
287+ @success (json) "success-json" A JSON object containing the updated
288+ notification object.
289+ @success-example "success-json" [exkey=notifications-update]
290+ placeholder text
291+
292+ @error (http-status-code) "404" 404
293+ @error (content) "not-found" The requested notification is not found.
294+ @error-example "not-found"
295+ Not Found
296 """
297 notification = get_object_or_404(Notification, id=id)
298 form = NotificationForm(
299@@ -117,19 +195,41 @@ class NotificationHandler(OperationsHandler):
300
301 @admin_method
302 def delete(self, request, id):
303- """Delete a specific notification."""
304+ """@description-title Delete a notification
305+ @description Delete a notification with a given id.
306+
307+ @param (int) "{id}" [required=true] The notification id.
308+
309+ @success (http-status-code) "server-success" 204
310+
311+ @error (http-status-code) "404" 404
312+ @error (content) "not-found" The requested notification is not found.
313+ @error-example "not-found"
314+ Not Found
315+ """
316 notification = get_object_or_404(Notification, id=id)
317 notification.delete()
318 return rc.DELETED
319
320 @operation(idempotent=False)
321 def dismiss(self, request, id):
322- """Dismiss a specific notification.
323-
324- Returns HTTP 403 FORBIDDEN if this notification is not relevant
325- (targeted) to the invoking user.
326+ """@description-title Dismiss a notification
327+ @description Dismiss a notification with the given id.
328
329 It is safe to call multiple times for the same notification.
330+
331+ @param (int) "{id}" [required=true] The notification id.
332+
333+ @success (http-status-code) "server-success" 200
334+
335+ @error (http-status-code) "403" 403
336+ @error (content) "no-perms" The notification is not relevant to the
337+ invoking user.
338+
339+ @error (http-status-code) "404" 404
340+ @error (content) "not-found" The requested notification is not found.
341+ @error-example "not-found"
342+ Not Found
343 """
344 notification = get_object_or_404(Notification, id=id)
345 if notification.is_relevant_to(request.user):

Subscribers

People subscribed via source and target branches