Control panels
Control panels allow you to configure the global site setup. The @controlpanels
endpoint allows you to list all existing control panels.
Listing Control Panels
A list of all existing control panels in the portal can be retrieved by sending a GET
request to the @controlpanels
endpoint:
GET /@controlpanels HTTP/1.1
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImZ1bGxuYW1lIjoiQWRtaW4iLCJpYXQiOjE2NDkzMTI0NDl9.RS1Ny_r0v7vIylFfK6q0JVJrkiDuTOh9iG9IL8xbzAk
Or use the client directly:
import { Client } from '@robgietema/nick';
const cli = Client.initialize({ apiPath: 'http://localhost:8080' });
const login = await cli.login({ username: 'admin', password: 'admin' });
const { data } = await cli.getControlpanels();
Response:
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"@id": "http://localhost:8080/@controlpanels/dexterity-types",
"group": "Content",
"title": "Content Types"
},
{
"@id": "http://localhost:8080/@controlpanels/language",
"group": "General",
"title": "Language"
},
{
"@id": "http://localhost:8080/@controlpanels/mail",
"group": "General",
"title": "Mail"
},
{
"@id": "http://localhost:8080/@controlpanels/navigation",
"group": "General",
"title": "Navigation"
},
{
"@id": "http://localhost:8080/@controlpanels/site",
"group": "General",
"title": "Site"
}
]
The following fields are returned:
@id
: hypermedia link to the control paneltitle
: the title of the control panelgroup
: the group in which the control panel should appear, for example, General, Content, Users, Security, Advanced, or Add-on Configuration.
Retrieve a single Control Panel
To retrieve a single control panel, send a GET
request to the URL of the control panel:
GET /@controlpanels/mail HTTP/1.1
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImZ1bGxuYW1lIjoiQWRtaW4iLCJpYXQiOjE2NDkzMTI0NDl9.RS1Ny_r0v7vIylFfK6q0JVJrkiDuTOh9iG9IL8xbzAk
Or use the client directly:
import { Client } from '@robgietema/nick';
const cli = Client.initialize({ apiPath: 'http://localhost:8080' });
const login = await cli.login({ username: 'admin', password: 'admin' });
const { data } = await cli.getControlpanel({ path: '/mail' });
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"@id": "http://localhost:8080/@controlpanels/mail",
"group": "General",
"title": "Mail",
"data": {
"host": "localhost",
"pass": "",
"port": 25,
"user": "",
"debug": true,
"secure": true,
"email_from_name": "Webmaster",
"email_from_address": "webmaster@nickcms.org"
},
"schema": {
"required": ["host", "port", "email_from_name", "email_from_address"],
"fieldsets": [
{
"id": "default",
"title": "Default",
"fields": [
"host",
"port",
"secure",
"user",
"pass",
"email_from_name",
"email_from_address",
"debug"
],
"behavior": "plone"
}
],
"properties": {
"host": {
"type": "string",
"title": "SMTP server",
"default": "localhost",
"description": "The address of your local SMTP (outgoing e-mail) server. Usually 'localhost', unless you use an external server to send e-mail."
},
"pass": {
"type": "string",
"title": "ESMTP password",
"widget": "password",
"description": "The password for the ESMTP user account."
},
"port": {
"type": "integer",
"title": "SMTP port",
"default": 25,
"description": "The port of your local SMTP (outgoing e-mail) server. Usually '25'."
},
"user": {
"type": "string",
"title": "ESMTP username",
"description": "Username for authentication to your e-mail server. Not required unless you are using ESMTP."
},
"debug": {
"type": "boolean",
"title": "Debug",
"description": "If enabled the mail is send to a test server."
},
"secure": {
"type": "boolean",
"title": "Secure",
"description": "If enabled the mail is send using a secure connection."
},
"email_from_name": {
"type": "string",
"title": "Site 'From' name",
"description": "Plone generates e-mail using this name as the e-mail sender."
},
"email_from_address": {
"type": "string",
"title": "Site 'From' address",
"description": "Plone generates e-mail using this address as the e-mail return address. It is also used as the destination address for the site-wide contact form and the 'Send test e-mail' feature."
}
}
}
}
The following fields are returned:
@id
: hypermedia link to the control paneltitle
: title of the control panelgroup
: group name of the control panelschema
: JSON Schema of the control paneldata
: current values of the control panel
Updating a Control Panel
To update the settings on a control panel, send a PATCH
request to control panel resource:
PATCH /@controlpanels/mail HTTP/1.1
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImZ1bGxuYW1lIjoiQWRtaW4iLCJpYXQiOjE2NDkzMTI0NDl9.RS1Ny_r0v7vIylFfK6q0JVJrkiDuTOh9iG9IL8xbzAk
Content-Type: application/json
{
"host": "mail.someserver.com",
"port": 25
}
Or use the client directly:
import { Client } from '@robgietema/nick';
const cli = Client.initialize({ apiPath: 'http://localhost:8080' });
const login = await cli.login({ username: 'admin', password: 'admin' });
const { data } = await cli.updateControlpanel({
token: login.data.token,
path: '/@controlpanels/mail',
data: {
host: 'mail.someserver.com',
port: 25,
},
});
A successful response to a PATCH
request will be indicated by a 204 No Content response:
HTTP/1.1 204 No Content
Control Panels not based on schemas
Control panels which are not based on schemas have a custom @controlpanels/:panel
endpoint implementation.
Content Types
@controlpanels/dexterity-types
is a custom control panel endpoint that will allow you to add, remove, and configure available types
.
Reading or writing content types require the Manage Site
permission.
Verb | URL | Action |
---|---|---|
GET |
/@controlpanels/dexterity-types |
List configurable content types |
POST |
/@controlpanels/dexterity-types |
Creates a new content type |
GET |
/@controlpanels/dexterity-types/{type-id} |
Get the current state of the content type |
PATCH |
/@controlpanels/dexterity-types/{type-id} |
Update the content type details |
DELETE |
/@controlpanels/dexterity-types/{type-id} |
Remove the content type |
Listing Content Types
To list the available content types, send a GET
request to @controlpanels/dexterity-types
GET /@controlpanels/dexterity-types HTTP/1.1
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImZ1bGxuYW1lIjoiQWRtaW4iLCJpYXQiOjE2NDkzMTI0NDl9.RS1Ny_r0v7vIylFfK6q0JVJrkiDuTOh9iG9IL8xbzAk
Or use the client directly:
import { Client } from '@robgietema/nick';
const cli = Client.initialize({ apiPath: 'http://localhost:8080' });
const login = await cli.login({ username: 'admin', password: 'admin' });
const { data } = await cli.getControlpanel({ path: '/dexterity-types' });
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"@id": "http://localhost:8080/@controlpanels/dexterity-types",
"items": [
{
"@id": "http://localhost:8080/@controlpanels/dexterity-types/File",
"@type": "File",
"title": "File",
"description": "Lets you upload a file to the site.",
"id": "File",
"count": 0,
"meta_type": "File"
},
{
"@id": "http://localhost:8080/@controlpanels/dexterity-types/Folder",
"@type": "Folder",
"title": "Folder",
"description": "",
"id": "Folder",
"count": 3,
"meta_type": "Folder"
},
{
"@id": "http://localhost:8080/@controlpanels/dexterity-types/Image",
"@type": "Image",
"title": "Image",
"description": "Images can be referenced in pages or displayed in an album.",
"id": "Image",
"count": 0,
"meta_type": "Image"
},
{
"@id": "http://localhost:8080/@controlpanels/dexterity-types/Page",
"@type": "Page",
"title": "Page",
"description": "",
"id": "Page",
"count": 1,
"meta_type": "Page"
},
{
"@id": "http://localhost:8080/@controlpanels/dexterity-types/Site",
"@type": "Site",
"title": "Site",
"description": "",
"id": "Site",
"count": 1,
"meta_type": "Site"
}
],
"title": "Content Types",
"group": "Content"
}
The following fields are returned:
@id
: hypermedia link to the control paneltitle
: title of the control panelgroup
: group name of the control panelitems
: list of configurable content types
Creating a new type with POST
To create a new content type, send a POST
request to the /@controlpanels/dexterity-types
endpoint:
POST /@controlpanels/dexterity-types HTTP/1.1
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImZ1bGxuYW1lIjoiQWRtaW4iLCJpYXQiOjE2NDkzMTI0NDl9.RS1Ny_r0v7vIylFfK6q0JVJrkiDuTOh9iG9IL8xbzAk
Content-Type: application/json
{
"title": "My Type",
"description": "Type Description"
}
Or use the client directly:
import { Client } from '@robgietema/nick';
const cli = Client.initialize({ apiPath: 'http://localhost:8080' });
const login = await cli.login({ username: 'admin', password: 'admin' });
const { data } = await cli.createControlpanelType({
token: login.data.token,
path: '/controlpanels/dexterity-types',
data: {
title: 'My Type',
description: 'Type Description',
},
});
Response:
HTTP/1.1 201 Created
Content-Type: application/json
{
"@id": "http://localhost:8080/@controlpanels/dexterity-types/My Type",
"title": "My Type",
"description": "Type Description",
"schema": {
"fieldsets": [
{
"fields": [
"title",
"description",
"allowed_content_types",
"filter_content_types"
],
"id": "default",
"title": "Default"
},
{
"fields": [
"basic",
"blocks",
"categorization",
"dates",
"dublin_core",
"exclude_from_nav",
"ownership",
"preview_image_link",
"short_name",
"versioning"
],
"id": "behaviors",
"title": "Behaviors"
}
],
"properties": {
"allowed_content_types": {
"additionalItems": true,
"description": "",
"factory": "Multiple Choice",
"items": {
"description": "",
"factory": "Choice",
"title": "",
"type": "string",
"vocabulary": {
"@id": "http://localhost:8080/@vocabularies/types"
}
},
"title": "Allowed Content Types",
"type": "array",
"uniqueItems": true
},
"description": {
"description": "",
"factory": "Text",
"title": "Description",
"type": "string",
"widget": "textarea"
},
"filter_content_types": {
"factory": "Yes/No",
"title": "Filter Contained Types",
"description": "Items of this type can act as a folder containing other items. What content types should be allowed inside?",
"type": "boolean"
},
"title": {
"description": "",
"factory": "Text line (String)",
"title": "Type Name",
"type": "string"
},
"basic": {
"description": "Adds title and description fields.",
"factory": "Yes/No",
"title": "Basic metadata",
"type": "boolean"
},
"blocks": {
"description": "Enables Volto Blocks support",
"factory": "Yes/No",
"title": "Blocks",
"type": "boolean"
},
"categorization": {
"description": "Adds keywords and language fields.",
"factory": "Yes/No",
"title": "Categorization",
"type": "boolean"
},
"dates": {
"description": "Adds effective and expiration dates.",
"factory": "Yes/No",
"title": "Dates",
"type": "boolean"
},
"dublin_core": {
"description": "Adds standard metadatafields",
"factory": "Yes/No",
"title": "Dublin Core metadata",
"type": "boolean"
},
"exclude_from_nav": {
"description": "If selected, this item will not appear in the navigation tree.",
"factory": "Yes/No",
"title": "Exclude from navigation",
"type": "boolean"
},
"ownership": {
"description": "Adds ownership and rights fields.",
"factory": "Yes/No",
"title": "Ownership",
"type": "boolean"
},
"preview_image_link": {
"description": "Gives the ability to rename an item from its edit form.",
"factory": "Yes/No",
"title": "Preview Image Link",
"type": "boolean"
},
"short_name": {
"description": "Gives the ability to rename an item from its edit form.",
"factory": "Yes/No",
"title": "Short name",
"type": "boolean"
},
"versioning": {
"description": "Versioning support",
"factory": "Yes/No",
"title": "Versioning",
"type": "boolean"
}
},
"required": [
"title",
"filter_content_types"
]
},
"data": {
"title": "My Type",
"description": "Type Description",
"allowed_content_types": [],
"filter_content_types": false,
"basic": false,
"blocks": false,
"categorization": false,
"dates": false,
"dublin_core": false,
"exclude_from_nav": false,
"ownership": false,
"preview_image_link": false,
"short_name": false,
"versioning": false
}
}
Reading a type with GET
After a successful POST
, access the content type by sending a GET
request to the endpoint /@controlpanels/dexterity-types/{type-id}
:
GET /@controlpanels/dexterity-types/Page HTTP/1.1
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImZ1bGxuYW1lIjoiQWRtaW4iLCJpYXQiOjE2NDkzMTI0NDl9.RS1Ny_r0v7vIylFfK6q0JVJrkiDuTOh9iG9IL8xbzAk
Or use the client directly:
import { Client } from '@robgietema/nick';
const cli = Client.initialize({ apiPath: 'http://localhost:8080' });
const login = await cli.login({ username: 'admin', password: 'admin' });
const { data } = await cli.getControlpanelType({
token: login.data.token,
path: '/controlpanels/dexterity-types/Page',
});
Response:
import { Client } from '@robgietema/nick';
const cli = Client.initialize({ apiPath: 'http://localhost:8080' });
const login = await cli.login({ username: 'admin', password: 'admin' });
const { data } = await cli.getControlpanelType({
token: login.data.token,
path: '/controlpanels/dexterity-types/Page',
});
Updating a type with PATCH
To update an existing content type, send a PATCH
request to the server.
PATCH
allows to provide just a subset of the resource, that is, the values you actually want to change:
PATCH /@controlpanels/dexterity-types/Page HTTP/1.1
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImZ1bGxuYW1lIjoiQWRtaW4iLCJpYXQiOjE2NDkzMTI0NDl9.RS1Ny_r0v7vIylFfK6q0JVJrkiDuTOh9iG9IL8xbzAk
Content-Type: application/json
{
"description": "Some Description",
"preview_image_link": true
}
Or use the client directly:
import { Client } from '@robgietema/nick';
const cli = Client.initialize({ apiPath: 'http://localhost:8080' });
const login = await cli.login({ username: 'admin', password: 'admin' });
const { data } = await cli.updateControlpanelType({
token: login.data.token,
path: '/controlpanels/dexterity-types/Page',
data: {
description: "Some Description",
preview_image_link: true
},
});
Response:
HTTP/1.1 204 No Content
Removing a type with DELETE
Delete an existing content type by sending a DELETE
request to the URL of an existing content type:
DELETE /@controlpanels/dexterity-types/File HTTP/1.1
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImZ1bGxuYW1lIjoiQWRtaW4iLCJpYXQiOjE2NDkzMTI0NDl9.RS1Ny_r0v7vIylFfK6q0JVJrkiDuTOh9iG9IL8xbzAk
Or use the client directly:
import { Client } from '@robgietema/nick';
const cli = Client.initialize({ apiPath: 'http://localhost:8080' });
const login = await cli.login({ username: 'admin', password: 'admin' });
const { data } = await cli.deleteControlpanelType({
token: login.data.token,
path: '/controlpanels/dexterity-types/File',
});
Response:
HTTP/1.1 204 No Content