<!-- Miles33/Tera DP -->
<!-- Back4 Workflow to import lineage and job ads from Gemstone and publish them to VirtualCMS.
It uses input XML files generated by the "Generic Exporter" containing
either <ad> records or <jobAd> records. It will then call, for each ad
for which a section exists in VirtualCMS, the VC API to create the content
and another one to publish it immediately.
Parameters:
VCWebsiteUrl: VirtualCMS website (root. Like http://setup.virtualcms.it/henley-standard)
JobsSectionId: Id of the "Jobs" section on VirtualCMS
VCAuthCodeKey: authCode for this customer. To be obtained from VirtualCom
The Workflow contains a XML which maps the codes of the Gemstone classifications
to the section ids on VirtualCMS. This is the variable ClassificationMap. To create
this XML, please follow the instructions in the documentation.
-->
<codeWorkflow xmlns="http://www.teradp.com/schemas/GN4/1/WFRes.xsd">
<References>
<Reference>Newtonsoft.Json.dll</Reference>
<Reference>System.Web.dll</Reference>
</References>
<Imports>
<Import>System.Web</Import>
<Import>System.Net</Import>
<Import>System.Text</Import>
<Import>System.Security.Cryptography</Import>
<Import>Newtonsoft.Json</Import>
<Import>Newtonsoft.Json.Linq</Import>
</Imports>
<Members><![CDATA[
Dim ClassificationMap As XElement =
<root>
<!--classification short_name="PLet" long_name="Property to Let" vcId="572"/>
<classification short_name="GRAD" long_name="Graduate"/>
<classification short_name="Marr" long_name="Marriage"/>
<classification short_name="CV" long_name="Charity & Voluntary Work"/>
<classification short_name="TT" long_name="Trusted Trades"/>
<classification short_name="HS" long_name="Health & Safety"/>
<classification short_name="Gal" long_name="Galleries"/>
<classification short_name="HHR" long_name="Hospitality, Hotel & Restaurant"/>
<classification short_name="MDay" long_name="Mothers Day"/>
<classification short_name="Thank" long_name="Thanks"/>
<classification short_name="DLS" long_name="Defence, Law, Security"/>
<classification short_name="MServ" long_name="Miscellaneous Services" vcId="564"/>
<classification short_name="HL" long_name="Henley Life"/>
<classification short_name="ROP" long_name="Run of Paper"/>
<classification short_name="Carp" long_name="Carpets & Curtains" vcId="544"/>
<classification short_name="TD" long_name="The Directory"/>
<classification short_name="ACS" long_name="Art. Culture, Sports"/>
<classification short_name="OG" long_name="Oil & Gas"/>
<classification short_name="NYNY" long_name="New Year New You"/>
<classification short_name="Wdine" long_name="Wine & Dine"/>
<classification short_name="MIL" long_name="Military"/>
<classification short_name="SA" long_name="Secretarial & Administration"/>
<classification short_name="Art" long_name="Art Galleries"/>
<classification short_name="Lost" long_name="Lost & Found" vcId="562"/>
<classification short_name="Cloth" long_name="Clothing & Footware" vcId="547"/>
<classification short_name="PUR" long_name="Purchasing"/>
<classification short_name="TC" long_name="Telecommunications"/>
<classification short_name="TY" long_name="Treat Yourself"/>
<classification short_name="CSCC" long_name="Customer Service, Call Centre"/>
<classification short_name="CON" long_name="Consultancy"/>
<classification short_name="MARK" long_name="Marketing"/>
<classification short_name="Accr" long_name="Accommodation/Rooms" vcId="539"/>
<classification short_name="LEG" long_name="Legal"/>
<classification short_name="Auto" long_name="Automotive"/>
<classification short_name="Want" long_name="Wanted" vcId="581"/>
<classification short_name="TV" long_name="TV & Audio" vcId="578"/>
<classification short_name="Birth" long_name="Births"/>
<classification short_name="Music" long_name="Musical Eqiupment" vcId="568"/>
<classification short_name="SITS" long_name="Situations Vacant" vcId="575"/>
<classification short_name="Sport" long_name="Sport"/>
<classification short_name="SGM" long_name="Service Guide"/>
<classification short_name="QCare" long_name="Quality Caring"/>
<classification short_name="Car" long_name="Cars and Vans for Sale" vcId="545"/>
<classification short_name="MAN" long_name="Manufacturing"/>
<classification short_name="Goods" long_name="General Household Goods" vcId="556"/>
<classification short_name="HHG" long_name="Henley House & Garden"/>
<classification short_name="PS" long_name="Public Sector"/>
<classification short_name="Rev" long_name="Review of the Year"/>
<classification short_name="Mot" long_name="Motors"/>
<classification short_name="RFash" long_name="Regatta Fashion"/>
<classification short_name="Hbeau" long_name="Health & Beauty" vcId="557"/>
<classification short_name="MED" long_name="Media"/>
<classification short_name="HS" long_name="Health Services"/>
<classification short_name="SS" long_name="Social Services"/>
<classification short_name="TM" long_name="Town Map"/>
<classification short_name="SALES" long_name="Sales"/>
<classification short_name="Jewel" long_name="Jewellery & Gifts" vcId="560"/>
<classification short_name="Trade" long_name="Local Trades & Services"/>
<classification short_name="Greet" long_name="Greetings"/>
<classification short_name="MBike" long_name="Motobikes" vcId="567"/>
<classification short_name="FA" long_name="Finance & Accounting"/>
<classification short_name="AFG" long_name="Agriculture, Forestry, Gardening"/>
<classification short_name="RET" long_name="Retail"/>
<classification short_name="Off" long_name="Official Notices"/>
<classification short_name="Local" long_name="Keep it Local"/>
<classification short_name="ATT" long_name="Attractions"/>
<classification short_name="VG" long_name="Visitor Guide ROP"/>
<classification short_name="Weds" long_name="Weddings"/>
<classification short_name="SOA" long_name="Summer Out & About"/>
<classification short_name="NHome" long_name="New Homes"/>
<classification short_name="Death" long_name="Deaths"/>
<classification short_name="FDay" long_name="Fathers Day"/>
<classification short_name="PUB" long_name="Publishing"/>
<classification short_name="Home" long_name="Home Improvement" vcId="559"/>
<classification short_name="SE" long_name="Self Employed"/>
<classification short_name="ROS" long_name="Run of Site"/>
<classification short_name="WON" long_name="Whats On"/>
<classification short_name="TEL" long_name="Telecom"/>
<classification short_name="XTV" long_name="Christmas TV"/>
<classification short_name="Leaf" long_name="Leaflets"/>
<classification short_name="DIS" long_name="Distribution"/>
<classification short_name="Cycle" long_name="Cycles & Sports" vcId="548"/>
<classification short_name="Jobs" long_name="Jobs"/>
<classification short_name="CS" long_name="Customer Service"/>
<classification short_name="" long_name="Online Announcements"/>
<classification short_name="ES" long_name="Engineering and Science"/>
<classification short_name="HEAL" long_name="Health"/>
<classification short_name="Inmem" long_name="In Memoriam"/>
<classification short_name="BF" long_name="Banking & Finance"/>
<classification short_name="Bus" long_name="Business" vcId="542"/>
<classification short_name="CLEAN" long_name="Cleaning"/>
<classification short_name="East" long_name="Easter Out & About"/>
<classification short_name="River" long_name="Messing About on the River"/>
<classification short_name="Stabl" long_name="Stable Talk"/>
<classification short_name="IN" long_name="Insurance"/>
<classification short_name="TD" long_name="Transport & Distribution"/>
<classification short_name="SWant" long_name="Situations Wanted" vcId="576"/>
<classification short_name="TRAV" long_name="Travel"/>
<classification short_name="ELEC" long_name="Electronics"/>
<classification short_name="RD" long_name="Research and Development"/>
<classification short_name="Train" long_name="Training & Tuition" vcId="577"/>
<classification short_name="ME" long_name="Management & Executive"/>
<classification short_name="Gard" long_name="Garden Furniture & Equipment" vcId="555"/>
<classification short_name="EA" long_name="Estate Agents"/>
<classification short_name="ACC" long_name="Accounting"/>
<classification short_name="TRAIN" long_name="Training"/>
<classification short_name="Hols" long_name="Holidays" vcId="558"/>
<classification short_name="MMess" long_name="Mothers Day Messages"/>
<classification short_name="Regat" long_name="Regatta Supplement"/>
<classification short_name="Mob" long_name="Mobility" vcId="565"/>
<classification short_name="CON" long_name="Construction"/>
<classification short_name="DEF" long_name="Defence"/>
<classification short_name="EC" long_name="Education & Childcare"/>
<classification short_name="PCBH" long_name="Personal Care, Beauty, Hairdressing"/>
<classification short_name="PS" long_name="Personal" vcId="569"/>
<classification short_name="Moth" long_name="Mother & Baby" vcId="566"/>
<classification short_name="BP" long_name="Business Promotion"/>
<classification short_name="XFest" long_name="Christmas Festival"/>
<classification short_name="HS" long_name="Henley Show"/>
<classification short_name="FServ" long_name="Funeral Services"/>
<classification short_name="EDU" long_name="Education"/>
<classification short_name="FClas" long_name="First Class"/>
<classification short_name="Dom" long_name="Domestic Appliances" vcId="549"/>
<classification short_name="CIT" long_name="Computing/IT"/>
<classification short_name="BBAT" long_name="Bumps, Babies & Toddlers"/>
<classification short_name="SVD" long_name="Situations Vac Display"/>
<classification short_name="VMess" long_name="Valentines Message"/>
<classification short_name="FGO" long_name="Feeling Good"/>
<classification short_name="HAGS" long_name="Homes & Gardens"/>
<classification short_name="BI" long_name="Banking & Investments"/>
<classification short_name="VServ" long_name="Vehicle Services" vcId="579"/>
<classification short_name="HOUS" long_name="Housing"/>
<classification short_name="PO" long_name="Production & Operations"/>
<classification short_name="Barg" long_name="Bargains Under 50" vcId="541"/>
<classification short_name="BC" long_name="Building & Construction"/>
<classification short_name="River" long_name="River" vcId="574"/>
<classification short_name="Cvan" long_name="Caravans" vcId="543"/>
<classification short_name="ENG" long_name="Engineering"/>
<classification short_name="ADV" long_name="Advertorial"/>
<classification short_name="RW" long_name="Retail and Wholesale"/>
<classification short_name="PSale" long_name="Property for Sale" vcId="571"/>
<classification short_name="PGG" long_name="Christmas Greetings - Pubs & Restaurants"/>
<classification short_name="SC" long_name="Scientific"/>
<classification short_name="CVWan" long_name="Cars and Vans Wanted" vcId="580"/>
<classification short_name="ES" long_name="Energy Sector (Oil/Gas/Electricity)"/>
<classification short_name="Event" long_name="Events" vcId="550"/>
<classification short_name="Rewin" long_name="Rewind Supplement"/>
<classification short_name="Acc" long_name="Accommodation"/>
<classification short_name="LLS" long_name="Law and Legal Services"/>
<classification short_name="CHU" long_name="Churches"/>
<classification short_name="Creat" long_name="Creature Comforts"/>
<classification short_name="MSale" long_name="Miscellaneous Sales" vcId="563"/>
<classification short_name="EU" long_name="Energy & Utilities"/>
<classification short_name="Farm" long_name="Farm & Garden" vcId="552"/>
<classification short_name="Val" long_name="Valentines Day"/>
<classification short_name="REC" long_name="Recruitment"/>
<classification short_name="AN" long_name="Anniversaries"/>
<classification short_name="Regat" long_name="Regatta/Festival" vcId="573"/>
<classification short_name="TGG" long_name="Christmas Greetings - Trade"/>
<classification short_name="Engag" long_name="Engagement"/>
<classification short_name="Gdoor" long_name="Garage Doors" vcId="554"/>
<classification short_name="SE" long_name="Senior Executive"/>
<classification short_name="Tserv" long_name="Thanksgiving Service"/>
<classification short_name="CNP" long_name="Charity, Non Profit"/>
<classification short_name="Ant" long_name="Antiques & Collectables" vcId="540"/>
<classification short_name="TCH" long_name="Travel, Catering & Hospitality"/>
<classification short_name="HR" long_name="Human Resources"/>
<classification short_name="AV" long_name="Aviation"/>
<classification short_name="AFS" long_name="Articles For Sale"/>
<classification short_name="IT" long_name="Information Technology"/>
<classification short_name="Pets" long_name="Pets & Livestock" vcId="570"/>
<classification short_name="SS" long_name="Shops & Services"/>
<classification short_name="HFest" long_name="Henley Festival"/>
<classification short_name="OA" long_name="Office/Administration"/>
<classification short_name="TS" long_name="Trade/Services"/>
<classification short_name="Furn" long_name="Furniture" vcId="553"/>
<classification short_name="PTE" long_name="Places to Eat"/>
<classification short_name="Xmas" long_name="Christmas"/>
<classification short_name="Fun" long_name="Fun things to do this Summer"/>
<classification short_name="Logs" long_name="Logs & Solid Fuel" vcId="561"/>
<classification short_name="LT" long_name="Logistics & Transport"/>
<classification short_name="Child" long_name="Childcare" vcId="546"/-->
</root>
Function LoadPar(ByVal sParName As String, Optional ByVal sDefaultVar As String = Nothing) As String
Dim sRet As String = Context.ParValue(sParName)
If String.IsNullOrEmpty(sRet) Then
If IsNothing(sDefaultVar) Then
Utils.LogError("Parameter '" & sParName & "' missing! Cannot proceed!")
Else
sRet = sDefaultVar
Utils.LogMessage("Parameter '" & sParName & "' missing or empty. Using default value '" & sDefaultVar & "'.", TeraDP.GN4.Workflow.LogEntry.LogCode.Warning)
End If
End If
Return sRet
End Function
Shared Function GetMd5Hash(ByVal md5Hash As MD5, ByVal input As String) As String
' Convert the input string to a byte array and compute the hash.
Dim data As Byte() = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input))
' Create a new Stringbuilder to collect the bytes
' and create a string.
Dim sBuilder As New StringBuilder()
' Loop through each byte of the hashed data
' and format each one as a hexadecimal string.
Dim i As Integer
For i = 0 To data.Length - 1
sBuilder.Append(data(i).ToString("x2"))
Next i
' Return the hexadecimal string.
Return sBuilder.ToString()
End Function 'GetMd5Hash
Function CallVCSite(ByVal sUrl As String) As JObject
Try
Dim req As WebRequest = WebRequest.Create(sUrl)
Dim resp As WebResponse = req.GetResponse()
Dim sr As IO.StreamReader = New IO.StreamReader(resp.GetResponseStream())
Return JObject.Parse(sr.ReadToEnd())
Catch ex As Exception
Utils.LogError(String.Format("Error calling {0}: {1}", sUrl, ex.Message))
End Try
Return Nothing
End Function
]]></Members>
<Sequential Description="Back4 Workflow to import lineage and job ads from Gemstone and publish them to VirtualCMS" DisplayProgress="true"><![CDATA[
' Load parameters
Dim sVCURL As String = LoadPar("VCWebsiteUrl")
Dim sVCAuthCode As String = LoadPar("VCAuthCodeKey") ' Higgs: 897f42b8486a60685c7b248c6916dc73
Dim sJobsSectionId As String = LoadPar("JobsSectionId")
Dim sClassId as String = LoadPar("DefaultClassId") ' default classification Id
If String.IsNullOrEmpty(sVCURL) Or _
String.IsNullOrEmpty(sVCAuthCode) Then Return
If String.IsNullOrEmpty(sJobsSectionId) Then Utils.LogWarning("Missing or invalid key 'JobsSectionId': jobs will not be imported!")
Dim lUrls As List(Of String) = New List(Of String)
For Each aData As TeraDP.GN4.Workflow.IActivityData In Context.Data
Try
Dim loadXmlAct As LoadXml = New LoadXml(Context) With {
.Name = "loadXml",
.Description = "Load the xml file in memory",
.Data = aData
}
Dim loadXmlRes As LoadXmlResult = loadXmlAct.Do()
Dim xDoc As Xml.XmlDocument = New XmlDocument()
Using read As XmlReader = loadXmlRes.XmlOut.CreateReader()
xDoc.Load(read)
End Using
Dim root As XmlNode = xDoc.DocumentElement
' Process all new Jobs in the XML
For Each job As XmlNode In root.SelectNodes("//JobAd|//ad")
'Job Fields (2): http://setup.virtualcms.it/henley-standard/webservices/preset/getFields.jsp?presetId=2
Dim sFrom, sTo As String
Dim iPresetId As Integer = 3 ' Lineage Ad by default
If job.Name = "JobAd" Then iPresetId = 2 ' Job
Dim sTmp As String = "?presetId=" & iPresetId
If iPresetId = 2 And Not String.IsNullOrEmpty(sJobsSectionId) Then
' Jobs
Dim sTitle As String = job.Attributes("JobAdHeader").Value.ToString
If String.IsNullOrEmpty(sTitle) Then sTitle = "missing title"
sTmp &= "&title=" & HttpUtility.UrlEncode(sTitle)
sTmp &= "&keywords=jobs%20" & HttpUtility.UrlEncode(job.Attributes("JobAdHeader").Value)
sTmp &= "&field[20]=" & HttpUtility.UrlEncode(job.Attributes("JobAdHeader").Value) ' 20 = "Job Title",
sTmp &= "&field[21]=" & job.Attributes("SearchCriteriaJobType").Value ' 21 = "Job Type",
sTmp &= "&field[22]=" & HttpUtility.UrlEncode(job.Attributes("ContactAddress2").Value) ' 22 = "Location",
sTmp &= "&field[23]=" & HttpUtility.UrlEncode(job.Attributes("JobAdPlainText").Value) ' 23 = "Description",
sTmp &= "&text=" & HttpUtility.UrlEncode(job.Attributes("JobAdPlainText").Value) ' text is the alternative to the description
' 24 = "Salary",
' 25 = "Hours",
sFrom = job.Attributes("ValidFrom").Value
If Not String.IsNullOrEmpty(sFrom) Then sTmp &= "&field[26]=" & sFrom.Substring(0, 4) & "-" & sFrom.Substring(4, 2) & "-" & sFrom.Substring(6, 2) & "%2000:00:00" ' 26 = "Date Posted",
sTo = job.Attributes("ValidTo").Value
If Not String.IsNullOrEmpty(sTo) Then sTmp &= "&field[27]=" & sTo.Substring(0, 4) & "-" & sTo.Substring(4, 2) & "-" & sTo.Substring(6, 2) & "%2000:00:00" ' 27 = "Date Expiry",
sTmp &= "&field[28]=" & job.Attributes("JobAdID").Value ' 28 = "URN",
Using MD5Hash As MD5 = MD5.Create()
Dim hash As String = GetMd5Hash(MD5Hash, sTitle & sVCAuthCode)
sTmp &= "&authCode=" & hash
End Using
sTmp &= "&m33sect=" & sJobsSectionId
lUrls.Add(sTmp) ' Add the job to the list of URLS to call
Else
' Classified ads
Dim sTitle As String = job.SelectSingleNode("id").InnerText
sTmp &= "&title=" & HttpUtility.UrlEncode(sTitle)
sTmp &= "&keywords=" & HttpUtility.UrlEncode(sTitle)
sTmp &= "&text=" & HttpUtility.UrlEncode(job.SelectSingleNode("text").InnerText)
Using MD5Hash As MD5 = MD5.Create()
Dim hash As String = GetMd5Hash(MD5Hash, sTitle & sVCAuthCode)
sTmp &= "&authCode=" & hash
End Using
Dim sClassName As String = job.SelectSingleNode("section").InnerText ' Now we have to find this in the external (mapping XML)
If Not String.IsNullOrEmpty(sClassName) Then
Dim oClass As XElement = ClassificationMap.XPathSelectElement("./classification[@short_name='" & sClassName & "']")
If Not IsNothing(oClass) Then
If Not IsNothing(oClass.@vcId) Then
sClassId = oClass.@vcId.ToString
Else
Utils.LogWarning(String.Format("Classified {0} does not have a vcId.", sClassName))
End If
Else
Utils.LogWarning(String.Format("Cannot find Classification {0} in the map.", sClassName))
End If ' Do we have a class
sTmp &= "&m33sect=" & sClassId ' this is the classified section
lUrls.Add(sTmp) ' We don't want to add ads without a classification
End If ' Is the classification in the input node?
End If ' is this a job or a classified?
Next ' end for each job/ad
Catch ex As Exception
Utils.LogError(ex.Message)
End Try
' Call VC's API for each URL we have generated
For Each sPars As String In lUrls
' http://setup.virtualcms.it/henley-standard/
Dim sUrl As String = sVCURL & "/webservices/preset/create.jsp" & sPars
Dim VCResult As JObject = CallVCSite(sUrl)
' This is a JSON string with "OK" to signify all is fine, or "KO" if error. We don't store the id of the ad
If Not IsNothing(VCResult) And VCResult.GetValue("status").ToString = "KO" Then
Utils.LogWarning(String.Format("Error '{0}' creating Ad: {1}", VCResult.GetValue("error").ToString, sPars))
Else
Dim sSectionId As String = sPars.Substring(sPars.IndexOf("m33sect=") + 8)
If Not String.IsNullOrEmpty(sSectionId) Then
sUrl = sVCURL & "/webservices/article/publish.jsp?articleId=" & VCResult.GetValue("internalId").ToString & _
"§ionId=" & sSectionId & _
"&type=shift"
Using MD5Hash As MD5 = MD5.Create()
Dim hash As String = GetMd5Hash(MD5Hash, VCResult.GetValue("internalId").ToString & sVCAuthCode)
sUrl &= "&authCode=" & hash
End Using
Dim jResp As JObject = CallVCSite(sUrl)
If Not IsNothing(jResp) And jResp.GetValue("status").ToString = "OK" Then
Utils.LogInfo(String.Format("Ad: {0} published successfully!", VCResult.GetValue("internalId").ToString))
Else
Utils.LogWarning(String.Format("Ad: {0} failed to publish: {1}",
VCResult.GetValue("internalId").ToString,
jResp.GetValue("error").ToString))
End If
Else
Utils.LogInfo(String.Format("Created Ad: {0}. Please, publish it manually.", VCResult.GetValue("internalId").ToString))
End If
End If
Next
Next
]]></Sequential>
</codeWorkflow>