Skip to main content

Petstore: Users

The Users page (/console/users) is the petstore's server-mode CRUD example: a table of user accounts with a status filter, an add dialog in the ribbon, and Edit and Delete row actions. Its one lesson beyond the plain table is the password. It is write-only: it can be set from the form, but nothing the server sends ever contains it.

The table​

The table pages, sorts and filters on the server. UsersRest.query runs the DataTables request through DataTablesQuery.run and answers a malformed search expression with a 200 error envelope, as the other server-mode pages do. The ribbon has a deselectable "User status" option group ($eq(ACTIVE) and $eq(INACTIVE) on the userStatus column), the "+ Add user" dialog button and a refresh button. The row actions are Edit, which opens the same form in a dialog, and Delete, which confirms first and is styled as dangerous.

The write-only password​

Every read goes through a UserView record that has username, first name, last name and status, and no password field. The query runs over UserView through its own InMemoryBeanQueryContext, so the password is neither searchable nor serialized. GET /console/users/{username} returns the same view. The result toast of a create or an update carries a UserView too.

The dialog is built by GET /console/users/form as a ModalDef with a FormDef:

CasePassword field
Add (no username query parameter)Required, with the help text "Write-only; it is never shown again"
Edit (?username=)Optional, never pre-filled, with the help text "Leave blank to keep the current password"

The field is a masked password input and never carries a value. On update, a field left out of the body keeps its stored value, and a null or blank password keeps the stored password. Both the plain body and the dialog envelope ({fields: {...}}) are accepted.

RouteDoesErrors
POST /console/users/queryOne page of UserView rows
POST /console/usersCreates a user400 blank username, 409 username taken
PUT /console/users/{username}Updates a user404 unknown user, 400 unknown status
DELETE /console/users/{username}Deletes a user404 unknown user

Each write calls ConsoleWrites.actor(req). With the petstore.secure setting on, a write without the demo bearer token is a 401, and the audit entry names the actor. See Petstore: Secure for the demo tokens.

Template​

rowActions: [
{ id: 'edit', label: 'Edit', form: '/console/users/form?username={username}', present: 'dialog',
endpoint: '/console/users/{username}', method: 'PUT', onSuccess: 'redraw' },
{ id: 'delete', label: 'Delete', endpoint: '/console/users/{username}', method: 'DELETE',
confirm: "Delete user '{username}'?", confirmLabel: 'Delete', tone: 'danger', onSuccess: 'redraw' }
]

Builder twin​

.rowActions(
RowAction.create("edit").label("Edit").form("/console/users/form?username={username}").present(Present.DIALOG)
.endpoint("/console/users/{username}").method(Method.PUT).onSuccess(OnSuccess.REDRAW),
RowAction.create("delete").label("Delete").endpoint("/console/users/{username}").method(Method.DELETE)
.confirm("Delete user '{username}'?").confirmLabel("Delete").tone(Tone.DANGER).onSuccess(OnSuccess.REDRAW))

Source: UsersRest in juneau-petstore/juneau-petstore-core/src/main/java/org/apache/juneau/petstore/console/users/; UsersPageBuilders in .../console/pages/; users.ftlh under .../console/templates/.

Tests: UsersRest_Test.

See also​