Forum Discussion
Hi all,
Sorry to be late to this thread, as has already been said trying to get thread level subscriber counts is not very well supported at the moment. It should be better using the APIs provided by Aurora.
For Board subscriber counts
I have written an excel file which allows you to iterate through every board in a community and find out how many people are subscribed to that board.
Instructions:
Open this XLSM file: https://1drv.ms/x/s!AkiSjdO4yjrasPABOjsq12IkyikdVA?e=mYjICe
You may need to enable content (depending on the security settings of your excel installation)
Go to the settings tab and enter:
UserName: the user name of a user in your community who at least as read permissions to the API
Password: The password for the above user (note: if your community uses SSO then you will need to create a non-sso user using the create user button in the Users Tab).
Community URL: The base url for your community (i.e. https://community.khoros.com
ClientID: Go to this page: OAuth 2.0 authorization grant flow (khoros.com) and follow the steps to register an App and you get this client id.
Once done go back to the Report Data tab and click Get Subscription Data and it will pull every single category / board from your community and put the subscriptions to that board in this file.
As noted previously this count DOES NOT include subscriptions to the actual topic just the board.
If you get an error when you try to run the code you may need to add some references. To do this open the file, right click on the sheet name and click "View Code". When the VBA editor opens click Tools at the top and click References.
This file requires:
- Visual Basic for Applications
- Microsoft Excel 16.0 Object Library (likely anything newer will also work)
- OLE Automation
- Microsoft Office 16.0 Object Library (likely anything newer will also work)
- Microsoft ActiveX Data Objects 6.1 Library
- Microsoft Forms 2.0 Object Library
- Microsoft XML v6.0
Disclaimer: this file is provided as is, it was clean of viruses and only does what I say it does at the time I uploaded it but you should treat any file you don't know with suspicion until your happy it works safely.
This file REQUIRES Microsoft Excel Desktop and will not function in the Web browser.
Feel free to reuse any of my VBA code, although would love to know if you use guys use it for anything else cool!
- keithkelly2 years agoLeader
Whoa! This worked. I checked the VBA for anything scummy and found nothing.
I did, however, make one change in Main_Prog to allow it to work for me:
strLiql = "Select id,title from categories
where ancestor_categories.id = 'communities'ORDER BY position DESC limit 1000"making it:
strLiql = "Select id,title from categories ORDER BY position DESC limit 1000"
Thank you for sharing this! Currently I have a PowerQuery M script getting other sorts of data, and have been hoping to get some API tools a bit more integrated into Excel for stuff like this. This file gives a sweet jump-start!
I will share my (re)usages!
- allensmith812 years agoBoss
Good catch! I thought I had removed everything that was specific to our community.
Also please you didn't find anything scummy 🙂
Allen Smith
Technical & Compliance Lead
Microsoft Tech Community
- keithkelly2 years agoLeader
Alright here's my addition for the time being. I cleaned it up a bit to make sense to me, which may not make sense to everyone - however, here's my variant.
New Addition:
Changes
- Small reorg of Functions code
- Changed Subscriber sheet name to BoardSubCounts
- Added sheet BoardSubscribers. Columns:
- Column: Category ID
- Column: Board ID
- Column: Board Name
- Column: Subscriber User
- Range: A2 = SubReportStart
- Button Text: Get Subscribers
- Button Macro: BoardSubscribersReport.xlsm!Main_Prog.GetSubscribers
Gotcha: I've only tested this on Staging, and expect it to take quite a while to print on even our small production environment. This inspires a future deviation (stay tuned), but I'm sharing this code because it demonstrates the simplicity of extending what allensmith81 has given us. (I added a new sheet & created 1 new method "Sub GetSubscribers()")
VBA for Modules / Functions: (contains cleaned-up methods)
Dim msXML As XMLHTTP60 Sub CheckAndUpdateSessionKey() Dim keyAge As Long keyAge = DateDiff("n", ThisWorkbook.Sheets("Settings").Range("SessionKey").Offset(0, 1).Value, Now()) If keyAge > 30 Or ThisWorkbook.Sheets("Settings").Range("SessionKey").Value = "" Or _ ThisWorkbook.Sheets("Settings").Range("SessionKey").Value = "Invalid session key." Then UpdateSessionKey End If End Sub Sub UpdateSessionKey() Dim strUname As String, strUpass As String, strURL As String, strCall As String, strResponse As String Dim XDoc As Object, root As Object Set XDoc = CreateObject("MSXML2.DOMDocument") XDoc.async = False: XDoc.validateOnParse = False strUname = ThisWorkbook.Sheets("Settings").Range("Username").Value strUpass = URLEncode(ThisWorkbook.Sheets("Settings").Range("Password").Value) strURL = ThisWorkbook.Sheets("Settings").Range("CommunityUrl").Value strCall = strURL & "/restapi/vc/authentication/sessions/login?user.login=" & strUname & "&user.password=" & strUpass strResponse = vbaCURL(strCall, "POST") XDoc.LoadXML (strResponse) Set root = XDoc.DocumentElement ThisWorkbook.Sheets("Settings").Range("SessionKey").Value = root.FirstChild.Text ThisWorkbook.Sheets("Settings").Range("SessionKey").Offset(0, 1).Value = Now() End Sub Public Function URLEncode(ByVal StringVal As String, Optional SpaceAsPlus As Boolean = False) As String Dim bytes() As Byte, b As Byte, i As Integer, space As String If SpaceAsPlus Then space = "+" Else space = "%20" If Len(StringVal) > 0 Then With New ADODB.Stream .Mode = adModeReadWrite .Type = adTypeText .Charset = "UTF-8" .Open .WriteText StringVal .Position = 0 .Type = adTypeBinary .Position = 3 ' skip BOM bytes = .Read End With ReDim result(UBound(bytes)) As String For i = UBound(bytes) To 0 Step -1 b = bytes(i) Select Case b Case 97 To 122, 65 To 90, 48 To 57, 45, 46, 95, 126 result(i) = Chr(b) Case 32 result(i) = space Case 0 To 15 result(i) = "%0" & Hex(b) Case Else result(i) = "%" & Hex(b) End Select Next i URLEncode = Join(result, "") End If End Function Public Function vbaCURL(ByVal strURL As String, ByVal strCallType As String, Optional strSessionKey As String) As String Dim strclientid As String strclientid = ThisWorkbook.Sheets("Settings").Range("clientid").Value If msXML Is Nothing Then Set msXML = New XMLHTTP60 With msXML .Open strCallType, strURL, False: .setRequestHeader "Cache-Control", "no-cache" .setRequestHeader "client-id", strclientid If strSessionKey <> "" Then .setRequestHeader "Li-Api-Session-Key", strSessionKey .send vbaCURL = StrConv(.responseBody, vbUnicode) End With End Function Function liqlQuery(strLiql As String, strCallType As String) As String Dim strURL As String, strPath As String strURL = ThisWorkbook.Sheets("Settings").Range("CommunityURL").Value strPath = "/api/2.0/search?q=" & URLEncode(strLiql) & "&format=xml" liqlQuery = vbaCURL(strURL & strPath, strCallType, ThisWorkbook.Sheets("Settings").Range("SessionKey").Value) End Function Function GetSubscriptionsCount(strBoardid As String) As String Dim strQuery As String, strResponse As String, XDoc As Object, root As Object strQuery = ThisWorkbook.Sheets("Settings").Range("CommunityURL").Value & "/restapi/vc/boards/id/" & strBoardid & "/subscribers/email/board/count" strResponse = vbaCURL(strQuery, "GET", ThisWorkbook.Sheets("Settings").Range("SessionKey").Value) Set XDoc = CreateObject("MSXML2.DOMDocument") XDoc.async = False: XDoc.validateOnParse = False XDoc.LoadXML (strResponse) Set root = XDoc.DocumentElement GetSubscriptionsCount = root.FirstChild.Text End Function Function GetCatName(strBoardid As String) As String Dim strResponse As String, strLiql As String, XDoc As Object, root As Object strLiql = "Select parent_category.title from boards where id='" & strBoardid & "'" strResponse = liqlQuery(strLiql, "GET") Set XDoc = CreateObject("MSXML2.DOMDocument") XDoc.async = False: XDoc.validateOnParse = False XDoc.LoadXML (strResponse) Set root = XDoc.DocumentElement GetCatName = XDoc.SelectSingleNode("//items/item/parent_category/title").Text End Function
VBA for Modules / Main_Prog (contains new method)
Option Explicit Sub GetSubscriptions() Dim xmlDoc As Object, root As Object Dim xmlCatID As Object, xmlCatTitle As Object Dim xmlBoardID As Object, xmlBoardTitle As Object Dim intCat As Long, intBoard As Long Dim strLiql As String, strLiql2 As String Dim strResponse As String, strResponse2 As String Dim dbloffset As Long Call CheckAndUpdateSessionKey strLiql = "Select id,title from categories ORDER BY position DESC limit 1000" Set xmlDoc = CreateObject("MSXML2.DOMDocument") xmlDoc.async = False: xmlDoc.validateOnParse = False Debug.Print strLiql strResponse = liqlQuery(strLiql, "GET") xmlDoc.LoadXML (strResponse) Set root = xmlDoc.DocumentElement Set xmlCatID = xmlDoc.getElementsByTagName("id") Set xmlCatTitle = xmlDoc.getElementsByTagName("title") With ThisWorkbook.Sheets("BoardSubCounts") For intCat = 0 To xmlCatID.Length - 1 strLiql2 = "select id, title from boards where ancestor_categories.id = '" & xmlCatID(intCat).Text & "' ORDER BY position DESC limit 1000" Set xmlDoc = CreateObject("MSXML2.DOMDocument") xmlDoc.async = False: xmlDoc.validateOnParse = False strResponse2 = liqlQuery(strLiql2, "GET") xmlDoc.LoadXML (strResponse2) Set root = xmlDoc.DocumentElement Set xmlBoardID = xmlDoc.getElementsByTagName("id") Set xmlBoardTitle = xmlDoc.getElementsByTagName("title") For intBoard = 0 To xmlBoardID.Length - 1 .Range("ReportStart").Offset(intBoard + dbloffset, 0).Value = xmlCatTitle(intCat).Text .Range("ReportStart").Offset(intBoard + dbloffset, 1).Value = xmlBoardTitle(intBoard).Text .Range("ReportStart").Offset(intBoard + dbloffset, 2).Value = GetSubscriptionsCount(xmlBoardID(intBoard).Text) DoEvents Next dbloffset = dbloffset + xmlBoardID.Length Next End With End Sub Sub GetSubscribers() Dim xmlDoc As Object, root As Object Dim xmlCatID As Object, xmlCatTitle As Object Dim xmlBoardID As Object, xmlBoardTitle As Object Dim xmlSubUsers As Object, xmlSubEmails As Object Dim intCat As Long, intBoard As Long, intSub As Long Dim strLiql As String, strLiql2 As String Dim sheetName As String Dim strResponse As String, strResponse2 As String Dim dbloffset As Long Call CheckAndUpdateSessionKey strLiql = "Select id,title from categories ORDER BY position DESC limit 1000" sheetName = "BoardSubscribers" Set xmlDoc = CreateObject("MSXML2.DOMDocument") xmlDoc.async = False: xmlDoc.validateOnParse = False Debug.Print strLiql strResponse = liqlQuery(strLiql, "GET") xmlDoc.LoadXML (strResponse) Set root = xmlDoc.DocumentElement Set xmlCatID = xmlDoc.getElementsByTagName("id") Set xmlCatTitle = xmlDoc.getElementsByTagName("title") With ThisWorkbook.Sheets(sheetName) For intCat = 0 To xmlCatID.Length - 1 strLiql2 = "select id, title from boards where ancestor_categories.id = '" & xmlCatID(intCat).Text & "' ORDER BY position DESC limit 1000" Set xmlDoc = CreateObject("MSXML2.DOMDocument") xmlDoc.async = False: xmlDoc.validateOnParse = False strResponse2 = liqlQuery(strLiql2, "GET") xmlDoc.LoadXML (strResponse2) Set root = xmlDoc.DocumentElement Set xmlBoardID = xmlDoc.getElementsByTagName("id") Set xmlBoardTitle = xmlDoc.getElementsByTagName("title") For intBoard = 0 To xmlBoardID.Length - 1 Dim strQuery As String, strResponse3 As String, XDocSub As Object, rootSub As Object strQuery = ThisWorkbook.Sheets("Settings").Range("CommunityURL").Value & "/restapi/vc/boards/id/" & xmlBoardID(intBoard).Text & "/subscribers/email/board" strResponse3 = vbaCURL(strQuery, "GET", ThisWorkbook.Sheets("Settings").Range("SessionKey").Value) Set XDocSub = CreateObject("MSXML2.DOMDocument") XDocSub.async = False: XDocSub.validateOnParse = False XDocSub.LoadXML (strResponse3) Set rootSub = XDocSub.DocumentElement Set xmlSubUsers = XDocSub.getElementsByTagName("login") For intSub = 0 To xmlSubUsers.Length - 1 .Range("SubReportStart").Offset(intSub + dbloffset, 0).Value = xmlCatTitle(intCat).Text .Range("SubReportStart").Offset(intSub + dbloffset, 1).Value = xmlBoardID(intBoard).Text .Range("SubReportStart").Offset(intSub + dbloffset, 2).Value = xmlBoardTitle(intBoard).Text .Range("SubReportStart").Offset(intSub + dbloffset, 3).Value = xmlSubUsers(intSub).Text DoEvents Next dbloffset = dbloffset + xmlSubUsers.Length Next Next End With End Sub
We need a GitHub repo. This absolutelly triggers me to continue building some Tabular Components based on this same concept, to do this work server-side for larger lists such as Subscriber reports, message lists, etc. Stay tuned & keep innovating.
Related Content
- 3 months ago
- 3 months ago
- 8 months ago