Forum Discussion
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!
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