Confluence cloud provides three types of entity properties for storing data:
Users can access entity and app properties using the REST APIs. For this reason, never store user personal data, any sensitive data or configuration information using entity properties or app properties. Your app has to handle storage and permissions for security-sensitive information.
Content properties are a key-value storage associated with a piece of Confluence content, and are one of the forms of persistence available to you as an app developer. The Confluence content that you can store content properties against are:
Content properties can be referenced in the following conditions to decide whether or not to show a web fragment:
content_property_exists
content_property_equal_to
content_property_equal_to_context
content_property_contains_any
content_property_contains_all
content_property_contains_context
content_property_contains_any_user_group
space_property_exists
space_property_equal_to
space_property_equal_to_context
space_property_contains_any
space_property_contains_all
space_property_contains_context
space_property_contains_any_user_group
Content properties have the following limitations:
It is important to note that content properties are unique in that they provide a mechanism to
handle concurrent edits. The version
field in the request and response ensures that two requests
cannot update the same version of the entity properties data. Attempting to do so will result in a
HTTP error.
GET content properties
To retrieve any existing content properties for a piece of content, perform a GET on the endpoint /rest/api/content/{content_ID}/property
.
1 2# Retrieves content properties associated with a piece of content with ID 12345 curl -u admin@example.com:api_token -X GET "https://your-domain.atlassian.net/wiki/rest/api/content/12345/property" | python -mjson.tool
POST new content properties
To add content properties to a piece of Confluence content, perform a POST to the same endpoint. The key in your content property can be an arbitrary string (like "myprop"), whereas the value must be structured JSON.
1 2# Stores a JSON document under the key "myprop" against content with ID 12345 curl --request PUT \ --user email@example.com:<api_token> \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --data '{ "key": "my-property", "version": { "number": 1 }, "value": {"party": { "attendees": ["andrew","becky","charlie","dave"], "attendeeCount": 4 }} }' \ --url 'https://your-domain.atlassian.net/wiki/rest/api/content/12345/property/my-property'
Note that the structure of the payload in this request is different from entity and app properties. The differences are:
To update that property in the future you would need to bump the version number from 1
to 2
,
like so:
1 2curl --request PUT \ --user email@example.com:<api_token> \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --data '{ "key": "my-property", "version": { "number": 2 }, "value": {"party": { "attendees": ["andrew","becky","charlie","dave", "evie"], "attendeeCount": 5 }} }' \ --url 'https://your-domain.atlassian.net/wiki/rest/api/content/12345/property/my-property'
DELETE content properties
To delete a content property, perform a DELETE on the endpoint /rest/api/content/<CONTENT_ID>/property/<KEY>
.
1 2# Removes JSON document associated with key "myprop from content with ID 12345 curl -i -u admin@example.com:api_token -X DELETE "https://your-domain.atlassian.net/wiki/rest/api/content/12345/property/myprop"
Content properties are available as an expansion on the content resource. This allows content properties to be retrieved in the same REST call as fetching the content itself. This expansion is available from any resource that returns content, including the CQL search resource.
GET content properties as an expansion on content
1 2# fetch properties at the same time as fetching content, note the expand=metadata.properties.myprop curl -u admin@example.com:api_token -X GET "https://your-domain.atlassian.net/wiki/rest/api/content/12345?expand=metadata.properties.myprop" | python -mjson.tool { id: "12345", type: "page", status: "current", title: "New in the platform team? Read me first", metadata: { _expandable: { currentuser: "", labels: "" properties: { my-property: { "id": "507f1f77bcf86cd799439011", "editDate": "2000-01-01T11:00:00.000+11:00", "version": { "number": 2 }, "value": {"party": { "attendees": ["andrew","becky","charlie","dave", "evie"], "attendeeCount": 5 }} } } } } }
To allow searching of content properties using CQL, you can enable indexing of data stored as content properties by defining an index schema. You can define an exclusive index schema for each content property key; then, whenever a content property is saved, Confluence checks if a schema was defined for its key. If a schema exists, indexable values are extracted from content property values and stored in an index. There can only be one index schema definition for a content property key, so any duplicates will be disabled. In the case of offending keys, an appropriate log message will be available.
When defining an index schema for content properties, you need to provide a set of extraction expressions and field type pairs, which are used to retrieve a specific value from a JSON document and transform it into the desired representation. Supported index field types are: string
, text
number
, and date
.
See the below JSON document and its index schema as an example:
Example content property value
1 2{ "id": "507f1f77bcf86cd799439011", "editDate": "2000-01-01T11:00:00.000+11:00", "description": "If you have any questions please address them to admin@example.com", "content": { "likes": 5, "tags": ["cql", "confluence"] } }
Use dot-notation to access an embedded field in a document (as shown below). After successful validation, all extracted values are stored inside an index and you can address them in CQL queries.
Putting it all together, here's a sample index schema definition:
atlassian-connect.json
Example Connect app index schema definition
1 2"confluenceContentProperties": [{ "name": { "value" :"Attachments index", "i18n": "attachments.index" }, "keyConfigurations": [{ "propertyKey" : "attachments", "extractions" : [{ "objectName" : "id", "type" : "string" }] }] }]
Field type doesn't only specify how data is stored in the index, but also determines which CQL operators are available in your query.
Type | Description | Supported CQL operators |
---|---|---|
string | Entire extracted value will be indexed as a single token, without any filtering. When extraction expression evaluates to a JSON array, each element will be indexed separately. Enables searching for an exact value, e.g. unique identifier. | IN, NOT IN, =, != |
text | Extracted value will be tokenized before indexing, allowing searching for a particular words. | ~, !~ |
number | Extracted number will be indexed as a double value for efficient range filtering and sorting. | <, <=, =, !=, >, >= |
date | Two representation are possible, either a String following the ISO 8601 datetime format, or a long value in the Unix time. Enables efficient range filtering and sorting. | <, <=, =, !=, >, >= |
Indexed content properties can be addressed in a CQL query using the content.property
field handler. Any content that contains content properties matching the query are returned in the results.
The query syntax is as follows: content.property[<KEY>].<PATH> <OPERATOR> value
Examples of CQL queries on content properties
1 2content.property[attachments].editDate >= 2001-01-01 content.property[attachments].description ~ "questions" content.property[metadata].content.tags IN ("cql", "help") content.property[metadata].content.likes <= 5
Legend:
Symbol | Meaning |
---|---|
KEY | The key of the content properties you're searching. |
PATH | The path to the value you'd like to search in the JSON document (use dot notation for embedded fields). |
OPERATOR | One of the supported CQL operators for the field type. |
App properties are entity properties stored against the app itself. In this case the app is considered to be the storage container. However, app properties are still unique to each host application: the same app installed on two different host applications will not share the same app properties.
App properties have the following limitations:
App properties can be read or modified by any authenticated user through the REST APIs, regardless of conditions or scopes. For this reason:
The following operations may be performed to manipulate app properties:
App properties can be set using Create or update app property:
1 2curl --request PUT \ --user 'email@example.com:<api_token>' \ --header "Accept: application/json" \ --header "Content-Type: application/json" \ --data '{"string":"string-value","number":5}' \ 'https://your-domain.atlassian.net/wiki/rest/atlassian-connect/1/addons/{addonKey}/properties/{propertyKey}'
Use Get app property to get the value of the property we just set:
1 2curl --request GET \ --user 'email@example.com:<api_token>' \ --header "Accept: application/json" \ --url 'https://your-domain.atlassian.net/wiki/rest/atlassian-connect/1/addons/{addonKey}/properties/{propertyKey}'
Here is an example snippet that will show a pop-up with a JSON property named my-property-key for an app with the key my-app-key.
1 2AP.require(['request'], function(request) { request({ url: '/rest/atlassian-connect/1/addons/my-app-key/properties/my-property-key?jsonValue=true', success: function(response) { // Convert the string response to JSON response = JSON.parse(response); alert(response); }, error: function(response) { console.log("Error loading API (" + uri + ")"); console.log(arguments); }, contentType: "application/json" }); });
Apart from using AP.request, the same endpoints are accessible via a request signed with JWT.
App properties can be referenced in following conditions to decide whether or not to show a web fragment:
addon_property_exists
addon_property_equal_to
addon_property_equal_to_context
addon_property_contains_any
addon_property_contains_all
addon_property_contains_context
addon_property_contains_any_user_group
For example, the following is a valid condition on the app property activated
:
1 2{ "condition": "addon_property_equal_to", "params": { "propertyKey": "activated", "objectName": "for-users" "value": "true" } }
The structure of the JSON value of the activated
app property might look like this:
1 2{ "for-anonymous": false, "for-users": true, "for-admins": true, }
Here is an example of a condition requiring that the browser user is in at least one specified group:
1 2{ "condition": "addon_property_contains_any_user_group", "params": { "propertyKey": "myListOfGroups" } }
Only if the for-users
sub-property is set to true against the app will the condition allow the
web fragment to show. Thus you can use this to decide whether or not to show web fragments based on
data that you have stored in app properties. This is very useful when you have host application
wide configuration that you wish to rely upon.
Using conditions with app properties only controls what users see in the product UI. Any authenticated user can access these properties using the REST APIs. For this reason, never use app properties to store private or personal information.
User properties are properties for a user stored against the app. In this case, the app is considered to be the storage container. These properties are partitioned by user within the app. However, user properties are unique to each host application: the same app installed on two different host applications does not share the same user properties. Only the app itself can access user properties, no other app or user can access properties created by another app or user. Note that this API is experimental, and certain contracts and restrictions are liable to change.
User properties have these limitations:
These operations can be performed to manipulate user properties:
Rate this page: