使用 Office js 获取约会对象的 iCalUId
Fetching iCalUId for an appointment object using office js
我正在尝试使用 office js(对于 outlook 加载项)
获取特定约会对象的 iCalUId
约会对象的唯一 ID 似乎是 itemId which can also be converted to what Microsoft calls the Rest Identifier
还有什么方法可以获取 iCalUid 吗?
很遗憾,我们没有 Office JS API 来检索 iCalUId。但是,您可以制作一个 REST call to retrieve the item from the server and obtain the iCalUId from the JSON response. See this documentation 以获取更多详细信息。
我们还有一个 UserVoice 页面,用于跟踪功能请求。请在那里添加请求。我们在规划过程中会考虑功能请求。
我使用 Office.context.mailbox.makeEwsRequestAsync
,因为 Office JS 的 RESP API 将于 2022 年 11 月完全停用。要使用此 JS 功能发出 EWS 请求,您必须提供 XML 文件作为输入所需的请求(所谓的 SOAP 请求),响应也将是一个 XML 文件,我用 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 }
}
})
通过调用 getExtendedIds
你将得到一个 { ewsId, changeKey, GlobalObjectId, ConversationId, UID }
的对象
我使用 GlobalObjectId
作为组织者和参加者之间同一约会的唯一 ID。
我正在尝试使用 office js(对于 outlook 加载项)
获取特定约会对象的 iCalUId约会对象的唯一 ID 似乎是 itemId which can also be converted to what Microsoft calls the Rest Identifier
还有什么方法可以获取 iCalUid 吗?
很遗憾,我们没有 Office JS API 来检索 iCalUId。但是,您可以制作一个 REST call to retrieve the item from the server and obtain the iCalUId from the JSON response. See this documentation 以获取更多详细信息。
我们还有一个 UserVoice 页面,用于跟踪功能请求。请在那里添加请求。我们在规划过程中会考虑功能请求。
我使用 Office.context.mailbox.makeEwsRequestAsync
,因为 Office JS 的 RESP API 将于 2022 年 11 月完全停用。要使用此 JS 功能发出 EWS 请求,您必须提供 XML 文件作为输入所需的请求(所谓的 SOAP 请求),响应也将是一个 XML 文件,我用 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 }
}
})
通过调用 getExtendedIds
你将得到一个 { ewsId, changeKey, GlobalObjectId, ConversationId, UID }
我使用 GlobalObjectId
作为组织者和参加者之间同一约会的唯一 ID。