Reputation: 469
I'm trying to fetch iCalUId for a specific appointment object using office js (for an outlook add-in)
The only ids for an appointment object seems to be itemId which can also be converted to what Microsoft calls the Rest Identifier
is there any way to fetch the iCalUid as well?
Upvotes: 3
Views: 1061
Reputation: 16263
I use Office.context.mailbox.makeEwsRequestAsync
since the RESP API for Office JS will be fully decommissioned in November 2022. To make EWS requests using this JS function you have to provide XML files as input with the required request (so called SOAP requests) and the response will be also a XML file which I parse with jQuery.parseXML
.
/* The following function gets the ewsId for both Organizer and Attendee,
since they have different means to get it.
Beware that these ewsIds are different between organizer and attendees. */
// Event Outlook ID is available when
// a) Outlook event already existed in user's calendar or
// b) it was already saved by the user in the current session
function getEventOutlookUid (callback) {
if (typeof Office.context.mailbox.item.getItemIdAsync === 'function') { // is Organizer
Office.context.mailbox.item.getItemIdAsync(function (result) {
if (result.status === Office.AsyncResultStatus.Succeeded) {
callback(null, result.value)
} else {
console.warn(`EventOutlookUid unavailable: ${result.error.message}. Probably just a new event`)
callback(null, null)
}
})
} else if (Office.context.mailbox.item.itemId) { // is Attendee
callback(null, Office.context.mailbox.item.itemId)
} else {
callback(Error('Neither Office.context.mailbox.item.getItemIdAsync nor Office.context.mailbox.item.itemId could get Outlook Item UID'))
}
}
/* The following function gets the extra IDs by parsing the XML from the SOAP request.
I use jQuery since it is very easy to parse XML with it. The function returns in callback an object
`{ ewsId: eventOutlookUid, changeKey, UID, GlobalObjectId, ConversationId }` */
function getExtendedIds (callback) {
getEventOutlookUid((err, eventOutlookUid) => {
if (err) {
console.error('Error fetching Outlook UID ' + err.message)
callback(Error(err))
} else {
const soapRequest = generateCalendarUidSoapRequest(eventOutlookUid)
if (validateXML(soapRequest)) {
Office.context.mailbox.makeEwsRequestAsync(soapRequest, function (result) {
if (result.status === Office.AsyncResultStatus.Succeeded) {
// console.log(prettifyXml(result.value))
const res = $.parseXML(result.value)
const changeKey = res.getElementsByTagName('t:ItemId')[0].getAttribute('ChangeKey')
const UID = res.getElementsByTagName('t:UID')[0].textContent
const GlobalObjectId = res.getElementsByTagName('t:GlobalObjectId')[0].textContent
const ConversationId = res.getElementsByTagName('t:ConversationId')[0].getAttribute('Id')
callback(null, { ewsId: eventOutlookUid, changeKey, UID, GlobalObjectId, ConversationId })
}
})
} else {
callback(Error('Invalid XML request'))
}
}
})
}
/* The following function generates the XML SOAP request to get all possible ids */
function generateCalendarUidSoapRequest (itemId) {
const request = '<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' +
' <soap:Header><t:RequestServerVersion Version="Exchange2013" /></soap:Header>' +
' <soap:Body>' +
' <m:GetItem>' +
' <m:ItemShape>' +
' <t:BaseShape>AllProperties</t:BaseShape>' +
' </m:ItemShape >' +
' <t:AdditionalProperties>' +
' <t:FieldURI FieldURI="calendar:UID"/>' +
' <t:ExtendedFieldURI DistinguishedPropertySetId="Meeting" PropertyId="3" PropertyType="Binary" />' +
' </t:AdditionalProperties>' +
' <m:ItemIds>' +
' <t:ItemId Id="' + itemId + '" />' +
' </m:ItemIds>' +
' </m:GetItem>' +
' </soap:Body>' +
'</soap:Envelope>'
return request
}
/* These are auxiliary functions to pretiffy
(for console.log and debug) and validate the XML as input */
function prettifyXml (sourceXml) {
const xmlDoc = new DOMParser().parseFromString(sourceXml, 'application/xml')
const xsltDoc = new DOMParser().parseFromString([
// describes how we want to modify the XML - indent everything
'<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">',
' <xsl:strip-space elements="*"/>',
' <xsl:template match="para[content-style][not(text())]">', // change to just text() to strip space in text nodes
' <xsl:value-of select="normalize-space(.)"/>',
' </xsl:template>',
' <xsl:template match="node()|@*">',
' <xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>',
' </xsl:template>',
' <xsl:output indent="yes"/>',
'</xsl:stylesheet>'
].join('\n'), 'application/xml')
const xsltProcessor = new XSLTProcessor()
xsltProcessor.importStylesheet(xsltDoc)
const resultDoc = xsltProcessor.transformToDocument(xmlDoc)
const resultXml = new XMLSerializer().serializeToString(resultDoc)
return resultXml
}
function validateXML (xmlString) {
const domParser = new DOMParser()
const dom = domParser.parseFromString(xmlString, 'text/xml')
// print the name of the root element or error message
return dom.documentElement.nodeName !== 'parsererror'
}
getExtendedIds((err, res) => {
if (!err) {
console.log(res) // res: { ewsId, changeKey, GlobalObjectId, ConversationId, UID }
}
})
By calling getExtendedIds
you'll have an object with { ewsId, changeKey, GlobalObjectId, ConversationId, UID }
I use GlobalObjectId
as a unique Id for the same appointment amongst Organizer and Attendees.
Upvotes: 0
Reputation:
Unfortunately we don't have an Office JS API to retrieve the iCalUId. You can, however, make a REST call to retrieve the item from the server and obtain the iCalUId from the JSON response. See this documentation for more details.
We also have a UserVoice page where we track feature requests. Please add a request there. Feature requests are considered when we go through our planning process.
Upvotes: 2