Khoros Communities 19.3 Release
New Features
Add custom CSV fields to Case Portal export CSV files
We have expanded the Case Portal’s existing CSV download ability to enable admins to include custom fields from the CRM’s case object as part of the download. By default, the CSV export for the Case Portal includes the fields added in the Case Portal Dashboard grid. For example:
- ID
- Status
- Title
- Author
- Origin
- Created Date
- Last Modified Date
- Closed Date
To add custom fields stored in your CRM to your CSV exports, you must:
- Add the field name in the Admin > Features > Case Portal page
- Create a new text key in Studio for the column header/name in the export
To add custom fields from your CRM to your Case Portal exports:
- Go to Admin > Features > Case Portal.
- In the Custom CSV Fields, enter one or more field names from your CRM. (Entries must be separated by commas.)
Note: Custom CSV Field values:
* Must map to a Salesforce Text, Number, or Picklist field
* Cannot include spaces
* Cannot use field names that are not present in the Case object of Salesforce
* Cannot include duplicate entries
* Must be unique across both the “Custom columns for case list” and “Custom CSV Fields” lists - Click Save.
To create text keys for each custom CSV export column header:
Note: This step is optional, but if you don’t create a text key, the value(s) your entered in the Custom CSV Fields above are used as the column headers.
- Go to Studio > Text Editor > Custom Text.
- Select the language from the Language drop-down list you want to use and click View.
- Click Add New Text Key.
- Enter the Text Key Name for each Custom CSV field you added in Step 2 of the procedure above, using the following format:
caseportal.custom_csv_column.CUSTOMCSVFIELD
Note: Text Key Names cannot include spaces. - Enter the Text Key Value. (This value is the text that appears as the column header for this field in the CSV export.)
- Click Add.
Your new custom text key appears in the list: - Click Save.
To view, edit, or delete a Custom Text Key in the future, click View to review the list and take the appropriate action.
Now, when you click Export CSV from the Case Portal, the export will have a new column for the custom field.
API changes
Community API v2
Edit and delete attachments on an existing message
You can now edit and delete attachments on a message.
Add a single attachment to an existing message
Upload a single attachment to a message by issuing an HTTP POST to the /messages/:messageId/attachments sub-collection.
Session Key Example
curl -X POST \
http://COMMUNITY DOMAIN]/api/2.0/messages/770/attachments \
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
-H 'Li-Api-Session-Key: [SESSION KEY]' \
-F 'api.request={ "data": { "type": "attachment", "field": "attachment1" } }' \
-F attachment1=@[ATTACHMENT FILE PATH]
OAuth Example
curl -X POST \
https://[LITHIUM API DOMAIN]/community/2.0/[TENANT ID]/messages/770/attachments \
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
-H 'Authorization: Bearer [TOKEN]' \
-H 'client-id: [CLIENT ID]' \
-F 'api.request={ "data": { "type": "attachment", "field": "attachment1" } }' \
-F attachment1=@[ATTACHMENT FILE PATH]
Remove a single attachment from an existing message
Remove an attachment from a message by issuing an HTTP DELETE to /messages/:messageId/attachments/:attachmentId (where :attachmentId is m[:messageId]_[ATTACHMENT FILE NAME]).
Session Key Example
curl -X DELETE \
https://[COMMUNITY DOMAIN]/api/2.0/messages/770/attachments/m770_myAttachment.png \
-H 'li-api-session-key: [SESSION KEY]'
OAuth Example
curl -X DELETE \
https://[LITHIUM API DOMAIN]/api/2.0/[TENANT ID]/messages/770/attachments/m770_myAttachment.png \
-H 'Authorization: Bearer [TOKEN]' \
-H 'client-id: [CLIENT ID]'
Add multiple attachments to an existing message
When uploading multiple attachments, pass them as an array of attachments in an attachments_to_add field. Each attachment should specify a field parameter that is set to the multipart form/data file field name that contains the attachment you are uploading.
The body will look something like this:
{
"data":{
"type":"message",
"id":"134",
"attachments_to_add":{
"list_item_type":"attachment",
"items":[
{
"type":"attachment",
"field":"attachment1"
},
{
"type":"attachment",
"field":"attachment2"
}
]
}
}
}
Session Key Example
curl -X PUT \
https://[COMMUNITY DOMAIN]/api/2.0/messages/770 \
-H 'Content-Type: multipart/form-data' \
-H 'Li-Api-Session-Key: UEPHCNuCYElGLDY4lyC6n1Mfjtu1JSMNrWI0DtAuGGg.' \
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
-F 'api.request={ "data": { "type": "message", "id": "134", "attachments_to_add": { "list_item_type": "attachment", "items": [ { "type": "attachment", "field": "attachment1" }, { "type": "attachment", "field": "attachment2" } ] } } }' \
-F attachment1=@/Users/mac.username/Pictures/rick.png \
-F attachment2=@/Users/mac.username/Pictures/morty.png
OAuth Example
curl -X PUT \
https://[LITHIUM API DOMAIN]/community/2.0/[TENANT ID]/messages/770 \
-H 'Content-Type: multipart/form-data' \
-H 'Authorization: Bearer [TOKEN]' \
-H 'client-id: [CLIENT ID]' \
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
-F 'api.request={ "data": { "type": "message", "id": "134", "attachments_to_add": { "list_item_type": "attachment", "items": [ { "type": "attachment", "field": "attachment1" }, { "type": "attachment", "field": "attachment2" } ] } } }' \
-F attachment1=@/Users/mac.username/Pictures/rick.png \
-F attachment2=@/Users/mac.username/Pictures/morty.png
Remove multiple attachments from an existing message
When removing multiple attachments use the attachments_to_remove field to specify an array of attachments to remove from the message. Each attachment should specify the attachment id of the attachment to remove, which should be in the format: m<message.id>_<filename>. Example: m283_picture.jpg.
The body will look something like this:
{
"data":{
"type":"message",
"attachments_to_remove":{
"list_item_type":"attachment",
"items":[
{
"type":"attachment",
"id":"m283_picture.jpg"
},
{
"type":"attachment",
"id":"2"
}
]
}
}
}
Session Key Example
curl -X PUT \
https://[COMMUNITY DOMAIN]/api/2.0/messages/770 \
-H 'Content-Type: application/json' \
-H 'Li-Api-Session-Key: 1CEPXdZFka9q6aRHThoIoCfFMKXWLrl-X8MTo1i16X0.' \
-d '{
"data": {
"type": "message",
"attachments_to_remove": {
"list_item_type": "attachment",
"items": [
{ "type": "attachment", "id": "1" },
{ "type": "attachment", "id": "2" }
]
}
}
}
}'
OAuth Example
curl -X PUT \
https://[LITHIUM API DOMAIN]/community/2.0/[TENANT ID]/messages/770 \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer [TOKEN]' \
-H 'client-id: [CLIENT ID]' \
-d '{
"data": {
"type": "message",
"attachments_to_remove": {
"list_item_type": "attachment",
"items": [
{ "type": "attachment", "id": "1" },
{ "type": "attachment", "id": "2" }
]
}
}
}
}'
FreeMarker
restBuilder is a convenience method that enables you to build Community REST API calls. It includes useful options, such as passing headers and parameters to a REST call via FreeMarker. You can use restBuilder as an alternative to the rest, restadmin, liql, and liqladmin FreeMarker methods.
You may use restBuilder in components and endpoints.
restBuilder supports the methods listed in the table below. Assign restBuilder() to a variable and then use variable.call() to make the REST call.
Note: You do not use .call() with the .liql method to invoke your LiQL query.
restBuilder() methods
Method |
Description |
Supported with |
.path(“endpoint path”) |
Specify the endpoint path |
V1 V2 |
.method(“HTTP method”) |
Specify the HTTP method to use |
V1 V2 |
.header(“header name”, “header value”) |
Pass header parameters. Add as many as required. |
V2 |
.body(FreeMarker hash) |
The body of the message |
V2 |
.admin(boolean) |
Pass true to make the call as an administrator |
V1 V2 |
.version(“version number”) |
Specify the API version. Pass v1 or v2. Default: v2 |
V1 |
.queryParam("param name", "param value") |
Set query parameters |
V1 V2 |
.call() |
Make the REST call to the Community API. Not used when making a LiQL query with the .liql method. |
V1 |
.liql("LiQL query") |
Make a LiQL query. Do not combine this with any other restBuilder methods. |
V2 |
Post a message via Community API V2 with administrator permissions
This example posts a message to a board with a POST call to API v2 as an administrator on behalf of the user in context.
<#assign messagePostCall = restBuilder()
.method("POST")
.path("/messages")
.body({
"type": "message",
"board": {
"type": "board",
"id": myBoard,
},
"subject": "Test Message",
"body": "This is a test"
})
.admin(true) />
<#assign resp = messagePostCall.call() />
Post a message via API V1
This example posts a message to a board via API v1.
<#assign messagePostCall = restBuilder()
.version("v1")
.method("POST")
.path("/boards/id/" + boardId + "/messages/post")
.queryParam("message.subject", "test rest v1 post")
.queryParam("message.body", "<div>test rest v1 post body</div>") />
<#assign resp = messagePostCall.call() />
Make a LiQL call
This example makes a LiQL query. Note that with the .liql method, we do not use .call() to invoke the LiQL query.
<#assign resp = restBuilder()
.liql("SELECT id,subject,body,board FROM messages WHERE board.id = 'myBoard' AND depth = 0") />
Documentation Errata
We fixed a typo in the Board/threads API v1 documentation that incorrectly stated that the maximum results per page is 100. The maximum results per page is 1000.
You Found It. We Fixed It.
- We have fixed the issue with Message Editor v2 where a colon and forward slash ( 😕) got converted into an emoji in URLs. Now, “😕” gets converted to an emoji only when there is a space before and after the “😕” or if it appears at the end of a line.
- Previously, on communities with a large number (1000s) of nodes, the Admin > Community Structure tab would take several minutes to load, instead of seconds. This page-loading issue has been fixed.
- We have fixed the issue where adding roles to a group member from the member list UI was being applied at the global role instead of the current node.
- Previously, there was an edge-case scenario where the wrong member would receive a reason notification for a deleted topic. We have fixed this issue and now only the author of the thread is notified of the deletion.
- We have fixed the issue where search results for Places were appearing at the Category level but not at the Community level.
- Previously (on non-responsive communities running on 19.1 or 19.2), when an author added HTML to a TKB that contained an attribute surrounded by quotes, it would throw an unexpected error. Additionally, if that author was creating a new post, left the page, and tried to create a new port, the author couldn’t access the message editor and received more errors. This issue has been fixed.
- Previously, when uploading videos to a post from the “From My Videos” tab, you were only able to see previews of the last 3 videos you added. We have fixed this issue, and you can now preview all of your saved videos.
- We have added an option to navigate back to the Case Portal Dashboard if your applied filter doesn't produce a result.
- We have fixed the issue where attachments being added via the Case Portal were not being attached to the Salesforce case.