liqlAdmin in khoros aurora graphql API
Hi Folks, I want to add roles to the users using graphQL API given below. const ADD_USER_ROLE_MUTATION = gql` mutation addUsersToRole($roleKey: RoleKeyInput!, $users: [UserIdInput!]!) { addUsersToRole(roleKey: $roleKey, users: $users) { result { id name } } } `; const [addUserRole] = useMutation(ADD_USER_ROLE_MUTATION); addUserRole({ variables: { roleKey: { roleName: "role" }, users: [{ id: userId }] } }); The issue I am facing is that when this mutation is executed by an Admin user, the role is successfully added to the target user. However, when the same mutation is executed by a normal user, it fails to add the role due to permission denied errors. Is there a parameter or keyword that can be used in this mutation to allow a normal user to update their own roles or self-related data? For example, in Khoros Classic, we can use the liqlAdmin keyword in REST API requests to bypass such permissions. Is there an equivalent for GraphQL in Khoros Aurora? Thanks in Advance.Solved2.4KViews
Sign in to react to this post13Comments
Any cons of NOT using LITHIUM.jQuery when calling an endpoint from a component?
Hi folks, I was wondering if using LITHIUM.jQuery when calling endpoints is the only preferred way of doing it: <@liaAddScript> ;(function ($) { $(document).ready(function () { function callLithiumEndpoint() { $.ajax({ url: '${endpointUrl}', }) } callLithiumEndpoint(); }); })(LITHIUM.jQuery); </@liaAddScript> Can it be done with vanilla JavaScript inside a <script> tag as well, for example using fetch? I noticed that endpoints can be triggered from a browser or a postman via their path https://<community-name>/pjakv59666/plugins/custom/<some-path-to-endpoint>/<component-name> Can it be treated as a simple url, passing there parameters and parsing it?Solved2.1KViews
Sign in to react to this post2Comments
- MattV5 years agoKhoros Staff
There are no specific issues with using vanilla javascript to call endpoints.
Using LITHIUM.jQuery is recommended if you intended to use jQuery.
Also, using liaAddScript is recommended if you need the code to be executed near the bottom of the page after OOB javascript has executed (It may also do some minification/obfuscation).
If none of those situations apply or are of concern, feel free to use plain JS in <script> tags. I would just encourage you to be mindful of code organization so the JS makes sense where it is placed, isn't repeated by multiple component includes, etc....
Sign in to react to this post
Logging a user out not working
Hello, I'm currently developing a solution to log out a user from the community sessions automatically. I followed the API Reference here: https://developer.khoros.com/khoroscommunitydevdocs/reference/authsignout I am currently getting the correct response of the user being signed out of all sessions but when I go to the community forums with my test user I can still see the user logged in. This is the json response that I am receiving: { "status":"success", "message":"", "data": { "signed_off_all_sessions":true, "id":"#######" } } Context: we do use a cookie for our users to log into the community site if they are logged into our site. But I have made sure to just be logged into the community site without said cookie when trying this call out. Any help would be welcomed.1.9KViews
Sign in to react to this post12Comments
How to create API accessible user account with Community
I am new to Khoros platform and want to crawl data from community. For that I did signup process with one lithium community and got my username and password. I am trying to authenticate myself with via retrieve-the-session-key but api response says curl --location --request \ POST 'https://community.alteryx.com/restapi/vc/authentication/sessions/login' \ --form 'user.login=dshrm' \ --form 'user.password=****' <response status="error"> <error code="302"> <message> User authentication failed. </message> </error> </response> I am trying to get user details via LiQl basic query `select * from users limit 1` What exactly process do I need to follow to authenticate myself ?1.6KViews
Sign in to react to this post11Comments
Select labels along with messages in one query
I query messages with SELECT id, subject, search_snippet, body, cover_image.view_href, teaser, view_href, author, conversation.last_post_time, replies.count(*), metrics.views FROM messages WHERE category.id = 'DE' AND conversation.style = 'tkb' AND body MATCHES 'mykeyword' AND depth = 0 ORDER BY post_time DESC LIMIT 10 To get the labels of each message i currently do an additional labels query for each message. Is there a way to get the labels along with the messages in one query?Solved1.4KViews
Sign in to react to this post8Comments
- Akenefick4 years agoGenius
I found this:
IN() Operator Syntax
"fieldname": { "in": [ "value1", "value2", "value3" ] }Example:
"board.id":{ "in":[ "stereos", "televisions" ] }So I think yours would look like this:
"labels.text":{ "in":[ "Text1", "Text2" ] }Sign in to react to this post
json query syntax matches AND OR
Hello, I cannot find the full json query syntax documentation here. Thats wha I'm asking in this post: How does a json based query look like for AND matches in body text. I want to query all posts containing term1 AND term2 in their body. My query currently is this. How do I add the term2? [ { "messages":{ "fields":[ "id", "subject", "search_snippet", "body", "cover_image.view_href", "teaser", "view_href", "author", "conversation.last_post_time", "replies.count(*)", "kudos.sum(weight)", "metrics.views", "labels" ], "constraints":[ { "category.id":"DE", "conversation.style":"tkb", "body":{ "matches":"term1" }, "depth":0 } ], "sorts": [ "post_time desc" ], "limit":10, "subQueries":{ "labels":{ "fields":[ "text", "id" ] } } } } ]1.4KViews
Sign in to react to this post6Comments
API v2 Search doesn't work
Reading this page, I quote: "In v2, perform a one-or-more term search with a comma-separated list of terms wrapped in parentheses. Use this when you want to return messages that have at least one of these terms in the defined fields. WHERE subject MATCHES ('apples', 'bananas', 'cherries')" This query returns 2 results: select subject,body from messages where subject matches 'attachment' This query returns 0 results. select subject,body from messages where subject matches ('attachment','android') According to the documentation I should be getting results. Fair to say that it's not WAI?1.4KViews
Sign in to react to this post9Comments
How to get only Messages where some specific custom field have value?
Hi Team, I have a custom field added by Khoros in the messages object, I want to get only Messages where that specific custom field has value. Sample query: select c_abcd from messages where c_abcd!="" I don't want to get all messages and then in the loop filter the messages which don't have any value. Is there any direct API or solution to get the messages where the c_abcd custom field has some value? Any related replies would be appreciated. Regards Aman1.3KViews
Sign in to react to this post11Comments
Join node/group 301 API error
Hi, I was able to implement Leave node successfully using membership API(Javascript). But Join node API is returning 301 error and I don't see error details, can we see actual error details to find the issue? Code: I am calling below function on button click. function joinNode() { const options = { method: 'POST', headers: {Accept: 'application/json', 'Content-Type': 'application/json'} }; console.log(options); fetch('https://lithium.com/api/2.0/nodes/grouphub:'+ groupID + '/membership_requests', options) .then(response => response.json()) .then(response => console.log(response)) .catch(err => console.error(err)); } Error details from console: POST https://lithium.com/api/2.0/nodes/grouphub:MexicoPowerApps/membership_requests 500 {status: 'error', message: 'An unexpected error occurred.', data: {…}, metadata: {…}} data:code: 301 developer_message: "" more_info: "" type: "error_data" [[Prototype]]: Object message: "An unexpected error occurred." metadata: {} status: "error" [[Prototype]]: ObjectSolved1.2KViews
Sign in to react to this post4Comments
- AbhishekGu3 years agoKhoros Alumni (Retired)
Hello radhika_kundana,
Seems like you didn't pass body parameter:
Add the following to the body section and run:{
"data" : {
"type" : "membership_request"
}
}For your reference sharing the developer doc link: https://developer.khoros.com/khoroscommunitydevdocs/reference/join-open-node
Hope it helps you.
Regards,
Abhishek GuptaSign in to react to this post
As far as anyone knows is there a way to transfer posts, etc., from PROD to STAGE
Has anyone come up with a script to do this? Querying Production and Posting to stage with either curl or the API? It would just be nice to be able to populate more and more realistic content on the Stage instance. Or even just to post articles programmatically? There's the REST API https://developer.khoros.com/khoroscommunitydevdocs/reference/rest But I don't see where the body of the messagePostBody goes. Example: POST (Create): <#assign subject = http.request.parameters.name.get("subject", "") /> <#if subject?length gt 0> <#-- Build the requestBody parameter and assign it to a variable--> <#assign messagePostBody = { "type": "message", "subject": subject, "board": { "type": "board", "id": "Otis" } } /> <#-- Make your REST call --> <#assign resp = rest("2.0", "/messages", "POST", messagePostBody) /> ${apiv2.toJson(resp)} <#else> { "status": "error", "message": "no subject parameter passed." } </#if> Do I just add a "body" member property to that messagePostBody with whatever the body of the message is? Or is there some esoteric way of doing it? For the example given, PUT: <#assign messagePostBody = { "type": "message", "id": "34", "subject": "How do I post a REST API message?" } /> There's a subject, a type, an id, but no body. How do I add body content? Or do I have to use cURL as noted here in "recipes"? Does one need to authenticate using cURL? Can it be done within components? A lot of this seems vague. There's not a lot of context I can find. Most recipes have instructions for what to do with the ingredients ... https://developer.khoros.com/khoroscommunitydevdocs/recipes/create-a-new-message-with-products Do we run this in Freemarker? How? Do we create a component? Do we use authentication? How? In a terminal? With a fox? In a box? With green eggs and ham? 😉 This would be very helpful information. These "recipes" assume a lot of knowledge about how to use cURL within the Khoros Community that isn't provided. I would love to run this in a component. But there's no information nearby that explains that. Please clarify? A lot? Complete examples in the context of the Community product would make all the difference. curl --request POST \ --url https://community-domain/api/2.0/messages \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' { "data": { "type": "message", "board": { "id": "runningShoes" }, "subject": "Alternative to Nike Revolution Running Shoes", "body": "I have the Nike Revolution Shoes and got the Reebok Protonium shoes, but it feels very stiff while running - not much comfort/cushion while running and uncomfortable. I originally switched to Saucony because it was very comfortable and lightweight. suggestions for Saucony …Solved1.2KViews
Sign in to react to this post13Comments
- Akenefick2 years agoGenius
I think maybe we're misunderstanding each other a little. When you say embed the cURL call, cURL is how you would make an API call from the command line. You wouldn't use cURL inside a Khoros component. You would use restBuilder or rest or restadmin to make the same API call with freemarker. Or if you were using JavaScript, you would use fetch maybe or XMLHttpRequest. So, I think when you say "cURL call" you are referring to the same thing I mean when I say "API call".
The examples I shared are making those calls embedded in a component.
I will take the cURL example from here Create message (khoros.com) and rewrite it using restBuilder so you can see what I mean.
So here is an example with cURL from the link above.
curl -L -X POST 'https://[COMMUNITY-DOMAIN]/api/2.0/messages/' \ -H 'Content-Type: application/json' \ -H 'Li-Api-Session-Key: [SESSION-KEY]' \ --data-raw '{ "data": { "type": "message", "board": { "id": "runningShoes" }, "subject": "Alternative to Saucony Ride 10 GTX", "body": "I have the Saucony Ride 9 and got the Saucony Ride 10 GTX, but it feels very stiff while running - not much comfort/cushion while running and uncomfortable. I originally switched to Saucony because it was very comfortable and lightweight. suggestions for Saucony running shoes for women? I run only about 10mi/wk. <li-image id=\"336i254DB2339\"/>", "tags": { "items": [ { "text": "trail running" }, { "text": "running shoes" } ] }, "labels": { "items": [ { "id": "womensRunningShoes", "text": "Womens Running Shoes" }, { "id": "recommendations", "text": "Recommendations" } ] }, "products": { "items": [ { "id": "sauconyRide10gtx" }, { "id": "sauconyFreedomIso" } ], "list_item_type": "product" } } }'Here is my (untested) attempt to rewrite with restBuilder which you could include in a component.
<#assign messagePostCall = restBuilder() .method("POST") .path("/messages") .version("v2") .header("Content-Type","application/json") .header("Li-Api-Session-Key","[SESSION-KEY]") .body({ "type": "message", "board": { "id": "runningShoes" }, "subject": "Alternative to Saucony Ride 10 GTX", "body": "I have the Saucony Ride 9 and got the Saucony Ride 10 GTX, but it feels very stiff while running - not much comfort/cushion while running and uncomfortable. I originally switched to Saucony because it was very comfortable and lightweight. suggestions for Saucony running shoes for women? I run only about 10mi/wk. <li-image id=\"336i254DB2339\"/>", "tags": { "items": [ { "text": "trail running" }, { "text": "running shoes" } ] }, "labels": { "items": [ { "id": "womensRunningShoes", "text": "Womens Running Shoes" }, { "id": "recommendations", "text": "Recommendations" } ] }, "products": { "items": [ { "id": "sauconyRide10gtx" }, { "id": "sauconyFreedomIso" } ], "list_item_type": "product" } }) /> <#assign resp = messagePostCall.call() />So, to compare the two:
- First line from cURL lists "POST" as the method which goes in "method" on restbuilder.
- Also from the first line of the cURL example is the URL 'https://[COMMUNITY-DOMAIN]/api/2.0/messages/'. Because you are inside a Khoros component you don't need to include the community domain. You also don't need to include api/2.0 as that is covered by the ".version" in restBuilder. So, all you need from the URL is the /messages which goes in the "path" on restBuilder.
- Next the content type and session key would go under .header in restBuilder.
- Lastly the "data" from cURL would be the .body in restBuilder.
Some additional notes. You don't actually need the .version("v2") here because v2 is the default. You really only need it if you are using API v1.
Also, because you are in a component, you don't really need a session key. If you are logged in Khoros knows who you are. I included it just so you could see everything from the cURL example.
Finally, if you want to make this call with admin permissions, you would add ".admin(true)" to the restBuilder.
Complete Example:
As mentioned in a previous post I was working on a component to create an abuse report. This is very similar to posting a regular message and I can share it here. This has two parts. First, a custom endpoint created in studio which is where I use restBuilder to make the API call to create the abuse report. Second, a custom compnent which I added to the "Content Archived Page". This component calls the custom endpoint I made when a button is clicked and passes along the message id.
Endpoint Code
<#assign messageId = http.request.parameters.name.get("id", "") /> <#assign path = "messages/" + messageId + "/abuse_reports" /> <#if config.getString("phase", "prod") == "stage"> <#assign body = "***UNARCHIVE REQUEST*** https://community.stage.ptc.com/t5/contentarchivals/viewpage/message-uid/" + messageId /> <#else> <#assign body = "***UNARCHIVE REQUEST*** https://community.ptc.com/t5/contentarchivals/viewpage/message-uid/" + messageId /> </#if> <#assign unarchiveCall = restBuilder() .method("POST") .path("${path}") .body({ "data":{ "type":"abuse_report", "body":"${body}" } }) .admin(true) /> <#assign resp = unarchiveCall.call() /> { "http_code":"${resp.http_code}", "status" : "${resp.status}" }Component Code
<div id="unarchive-button-container-ak"> <span class="lia-button lia-button-primary" id="unarchive-button-ak">Request Unarchive</span> </div> <div id="result-message-ak"></div> <style> div#result-message-ak { margin-top: 20px; } #result-message-ak p { padding: 10px; font-size: 16px; text-align: center; } div#unarchive-button-container-ak { width: 194px; margin-left: auto; margin-right: auto; } </style> <@liaAddScript> ;(function($) { const unarchiveButton = document.getElementById('unarchive-button-ak'); unarchiveButton.addEventListener("click", () => { const loc = window.location.pathname; const locArray = loc.split("/"); const messageID = locArray[locArray.length - 1]; console.log(messageID); const resultMessage = document.getElementById('result-message-ak'); const url = '/sejnu66972/plugins/custom/ptc/ptc1/unarchive?id=' + messageID async function unarchiveRequest(url) { const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" } }) const result = await response.json(); console.log(result); if (result.status == "success") { resultMessage.innerHTML = "<p>Your request was successfully sent. You should hear from a moderator within 24 business hours.</p>" } else { resultMessage.innerHTML = "<p>There was a problem sending your request. Please try again later or contact the community team directly at [email protected]</p>" } } unarchiveRequest(url); }) })(LITHIUM.jQuery); </@liaAddScript>Sorry for the wall of text. Again, hopefully that's not too much info. Also, sorry there are no comments in my code let me know if you have any questions.
Sign in to react to this post