Remove sensitive roles from inactive users
Saw this idea and couldn't remember if I shared this already. Basically an endpoint that gets called every day and Loops through a list of roles Finds users with those roles Checks that they're not special accounts, e.g. API user accounts Removes the sensitive roles Per affected user it lists the roles that were removed and the roles that remain Optionally sends a PM to the user to notify them Comments inline. I use Google Apps Script to schedule a daily run, but of course there are other options. Disclaimer: I'm not a trained programmer <#-- Automatically remove roles with permissions from users who haven't logged in for a while --> <#assign user_limit = http.request.parameters.name.get("user_limit", "100")?string /> <#-- How many days must the user have been inactive --> <#assign days_staff = http.request.parameters.name.get("", "50")?number /> <#assign days_mod = http.request.parameters.name.get("", "30")?number /> <#assign send_pm = http.request.parameters.name.get("pm", "false")?boolean /> <#-- Roles to remove from the users we find --> <#assign user_roles_remove = [ "Administrator", "LSI", "Level Two Moderator", "Lithium", "Moderator" ]/> <#-- Some users, like API accounts should be skipped, these are their IDs --> <#assign staff_exceptions = [ 123, 456, 789 ]/> </#if> <#assign users_pm_ids = []/> <#-- Spinning up a sequnce to store the IDs of users we may want to PM about their removed access --> <#assign today_long = .now?date?long/> <#assign prev_long_staff = today_long - days_staff * 1000 * 60 * 60 * 24/> <#assign prev_long_mod = today_long - days_mod * 1000 * 60 * 60 * 24/> <#-- convert the user's last visit date string to the long format for calculation --> <#function fnLVD(lvd)> <#assign lvd_show = lvd?datetime?string["yyyy-MM-dd"]/> <#assign lvd_long = lvd?datetime?long/> <#return lvd_long/> </#function> <xml> <users> <#-- Mods --> <#assign query_mod = restadmin("2.0","/search?q=" + "SELECT id,login,last_visit_time FROM users WHERE roles.name IN('Moderator','Level Two Moderator') LIMIT ${user_limit}"?url)/> <#list query_mod.data.items?sort_by("last_visit_time") as u> <#assign lvd_long = fnLVD(u.last_visit_time)/> <#if (lvd_long < prev_long_mod)> <#assign user_id = u.id/> <#assign user_login = u.login/> <#assign query_user_roles = restadmin("2.0","/search?q=" + "SELECT name FROM roles WHERE users.id = '${user_id}' LIMIT 500"?url)/> <#assign user_roles_before = []/> <#list query_user_roles.data.items as r> <#assign role_name = r.name/> <#assign user_roles_before = user_roles_before + [role_name]/> </#list> <#list user_roles_remove as r> <#if (user_roles_before?seq_index_of(r) …870Views
Sign in to react to this post0Comments
Community Metrics Keys (List)
Originally posted in https://community.khoros.com/t5/Admin-Metrics/About-Community-Admin-Metrics-and-Definitions/tac-p/745216#M76 but most likely people in need of such a list are not gonna find this directly, so I make it a separate post that hopefully can be found more easily. As it has been difficult (like forever) to find a comprehensive list of all available metric keys for a variety of use cases like building ranking formulas, badge rules, API queries etc. I have parsed various resources and compiled the following JSON list of metric keys. As I mentioned in the original post, this is a programmatically extracted and compiled list, there might be errors (please let me know if you find any, and also if you know of other sources I've missed with keys that are not present in the list or information about keys that should be added, as description for example) and these keys have not been tested if they work for various features (like not all metrics can be used for badge rules for example). { "abandoned_registrations": { "source": [ "admin/metrics/advanced", "pdf/2017" ], "title": "Abandoned Registrations", "desc": "The number of new users registered, who abandoned during the process. Viewing Account Report Metrics The Lithium reports on a variety of metrics that are of interest in to those who are monitoring account activity for a community. The Account Reports metrics section lets you run reports on these metrics for users, roles, or for any node in the community (the community as a whole, categories, forums, or chats). You can also set the granularity of these reports (hourly, daily, weekly, or monthly) and select a start and end date. You can report on a single metric, or select up to five metrics to be included in a report." }, "abandons": { "title": "Abandoned Turns", "desc": "The number of times a user left a waiting queue voluntarily before reaching the chatting list. A user can leave the waiting queue multiple times during a single session. Incremental Abandonment", "source": [ "pdf/2017" ] }, "accepted_solutions": { "source": [ "admin/metrics/advanced", "api/v1/users/metrics", "pdf/2017" ], "title": "Accepted Solutions*", "desc": "The number of times messages were accepted as solutions. This metric counts solutions written and accepted as a solution by anyone in the community." }, "accepted_solutions_to_threads_ratio": { "source": [ "admin/metrics/advanced", "api/v1/users/metrics", "pdf/2017" ], "title": "Topics Ratio", "desc": "The number of Net Accepted Solutionsdivided by the number of Net Forum Topics. This metric gives an indication of the percent of topics that are being solved in the community, category, or forum. Topics Posted to Solution Accepted" }, "action_requests": { "source": [ "admin/metrics/advanced", "pdf/2017" ], "title": "Action Requests", "desc": "The total number of server requests that occur when a user post…631Views
Sign in to react to this post0Comments
Events (occasion) RSS feed for syndication
We're using the Events module more, but one thing we were missing was a way to syndicate the events to other sites in a useful way: chronological by date of upcoming event, including title, desc, feature image...etc. I created an endpoint component to produce the RSS feed that I think we need for this. I've decided to share it here in case others find it useful. A few values are coded for our community but most are easily replaced for your case. In the comments I included some sample URLs that control which labels are included in the feed, how many items ahead, etc. If you'd like to see an example of this output, here's a sample feed from our community. <?xml version="1.0" encoding="UTF-8"?> <#-- sample URLs: Default event board: https://communities.sas.com/plugins/custom/sasinstitute/sasinstitute/events-rss Specific event board: https://communities.sas.com/plugins/custom/sasinstitute/sasinstitute/events-rss?board=community-events Specific event board, no event message body in feed: https://communities.sas.com/plugins/custom/sasinstitute/sasinstitute/events-rss?board=community-events&description=false Next 10 events: https://communities.sas.com/plugins/custom/sasinstitute/sasinstitute/events-rss?board=community-events&size=10 Next 5 events for "Users Groups": https://communities.sas.com/plugins/custom/sasinstitute/sasinstitute/events-rss?board=community-events&label=Users%20Groups --> <#-- our community domain, checking for stage vs prod --> <#assign root="https://communities.sas.com"/> <#if config.getString("phase", "prod") == "stage"> <#assign root = "https://communities-lithiumstage.sas.com" /> </#if> <#assign board = http.request.parameters.name.get("board","events")/> <#assign label = http.request.parameters.name.get("label", "")/> <#assign filter = http.request.parameters.name.get("filter","upcoming")/> <#assign include_desc = http.request.parameters.name.get("description", "true")/> <#assign size= http.request.parameters.name.get("size","5")/> <#assign time_filter = ""/> <#if filter != ""> <#assign time_filter = "AND occasion_data.status = '${filter}'"/> </#if> <#assign label_filter = ""/> <#if (label)?has_content> <#assign label_filter = "AND labels.text MATCHES('${label}')"/> </#if> <#assign board_href = "#"/> <#assign board_title = "Events"/> <#assign board_description = ""/> <#assign boardq = rest("2.0", "/search?q=" + "select title, description, view_href from boards where id='${board}' and conversation_style='occasion'"?url)/> <#if boardq.data?? && boardq.data.items?? && boardq.data.items?size gt 0> <#assign board_href = "${boardq.data.items[0].view_href}"/> <#assign board_title = "${boardq.data.items[0].title}"/> <#assign board_description = "${boardq.data.items[…852Views
Sign in to react to this post3Comments
Handling the upcoming LIMIT and OFFSET changes
You might be aware of the upcoming changes to LIMIT and OFFSET having a maximum value of 1000 in 23.12. Obviously this is likely to cause a problem to any custom components that loop through data such as messages. Cursor will work fine in some scenarios, but any kind of custom pagination will need UI/UX work to access records greater than 2000! Using cursor we'd only be able to move forward and not skip to page 1000 for example. Any other thoughts on how this could be achieved with CURSOR?!1.5KViews
Sign in to react to this post11Comments
Email bounce handling on Khoros communities
Hello and a Happy New Year! 1. Does Khoros by default "from: [email protected]" apply bounce logic to notifications sent by the community? Inspecting the email sources I can see Variable envelope return path (VERP) being setup, so my assumption for this is yes, but how can we tell from an API if the user has a valid email address? 2. Upon changing the default "from" to "[email protected]" the return path no longer is what it was, instead it is the same as the from address, meaning I should be somehow responsible for dealing with bounces, is this assumption correct? 3. Is there a recommended approach on how to tell what emails coming to that address are bounced mails? How to tell which target email has bounced and what type it was? Searching the internet didn't provide much in terms of SDKs (we cannot use 3rd party providers like zerobounce / mailchimp etc) 4. How would I notify Khoros through the api to have feature parity, for detected bounces? Trying to investigate this myself, I found the following. Searching for user by email: v2 does not have this feature v1 returns 1 account for an email even though multiple exist (contradicting uniqueness described at rest v1 docs ) Updating user email verified status: neither allows setting the status v2 is read-only Updating user email notification preferences: v1 doesn't have an option to change email only preferences, all the other options are there v2 can only change "email_excluded" property Would this suffice from a product level? 5. Can Khoros be configured to use a custom SMTP relay for sending messages? no such configuration is available from the admin, and to my knowledge we are required to do through a company policy. Thank you in advance! Similar question https://community.khoros.com/t5/Developer-Discussion/Using-Hard-Bounce-Info-to-unsubscribe-people-in-their-IDP-and/m-p/6693221.1KViews
Sign in to react to this post6Comments
Online User Count is Completely Wrong
I'm trying to get an accurate count of online users and it's quite obvious the count is completely wrong just by looking at the results I'm encountering on my staging environment. The LIQL query used is fairly simple: SELECT count(*) FROM users WHERE online_status='online' Given the number of people who access our staging server, I would expect the result of this to be a low single digit number. Instead, I got a result of over 30 users. So I dug into the API results: SELECT login,last_visit_time FROM users WHERE online_status='online' The results list users with last visit times from 2020 and 2021 as well as users from earlier in 2022 that I know for a fact aren't online. How is Khoros defining an "online user" here? Is the behavior I'm seeing a bug or expected behavior?1.1KViews
Sign in to react to this post9Comments
Inconsistent Documentation Search API LiQL Combination v One Or More
Hi, I may be missing something here, but the documentation seems to say two different things about how combination and one_or_more search constraints work in LiQL. In the Search API Overview the table that maps v1 API parameters to their LiQL equivalents says that: Combine terms using a string of keywords. Note that this syntax returns results when two or more o the terms appear. WHERE subject MATCHES 'apples bananas cherries' However, the documentation at Combinatorial searches with LiQL at Query for a combination of terms says that: SELECT id, subject FROM messages WHERE subject MATCHES('apples','bananas' 'cherries') A query using this format will not return matches containing only one of the search terms when three or more terms are included in the search string. And below in Query for one or more terms that states : SELECT id, subject FROM messages WHERE subject MATCHES 'apples bananas cherries' The query in the example above returns the ID and subject of messages that include the following combinations of text in the subject field: apples bananas cherries apples bananas apples cherries bananas cherries apples bananas cherries Unless am I misunderstanding or missing something, the first query I posted and the third query I posted should have the same result, but according to the documentation have two different results. Could someone help clarify which is the actual result?Solved704Views
Sign in to react to this post7Comments
- JavidH4 years agoKhoros Alumni (Retired)
Hello brendanmkelly, We have updated the Combinatorial Searches with LiQL as per the information provided by the engineering team.
Sign in to react to this post
Access Denied Issues on developer.khoros.com
Hi all, We're experiencing some access issues for customers trying to get to bookmarked and shared links to developer.khoros.com. UPDATE (4/6/21 3:50PST): We're making progress with our hosting platform. Please continue to use the workaround if you're experiencing issues. We are working with our hosting platform to resolve the issues. Workaround: Access developer.khoros.com via Atlas. From the main Atlas menu, select Dev Network and then select the area of the Dev Docs you'd like to work with (Community, Care, Marketing). Please accept my apologies for the inconvenience.570Views
Sign in to react to this post0Comments