用于获取 ICalUid 的 EWS SOAP XML 代码是什么?

发布于 2025-01-15 09:35:58 字数 2512 浏览 4 评论 0原文

我们正在使用 Office JS 开发 Outlook 日历插件。对于同一约会,组织者和与会者的 EWS ID 不匹配。显然,我需要来自 Exchange 的 ICalUid,这在组织者和与会者之间很常见,并且在同一项目的不同活动中很常见,这正是我们所需要的。但 Office JS 不提供此类属性或方法来获取它(仅适用于 .NET)。

但是 Office JS 提供了 Office.context .mailbox.makeEwsRequestAsync 我可以使用 XML 向 Exchange 服务器发出 SOAP 请求。

从 EWS Id 获取 ICalUid 的 EWS SOAP XML 代码是什么?

这有效吗?只需将 FieldURI 替换为 ICalUid 即可?

function getSubjectRequest(id) {
   // Return a GetItem operation request for the subject of the specified item. 
   var result = 
'<?xml version="1.0" encoding="utf-8"?>' +
'<soap:Envelope xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"' +
'               xmlns:xsd="https://www.w3.org/2001/XMLSchema"' +
'               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"' +
'               xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">' +
'  <soap:Header>' +
'    <RequestServerVersion Version="Exchange2013" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" soap:mustUnderstand="0" />' +
'  </soap:Header>' +
'  <soap:Body>' +
'    <GetItem xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">' +
'      <ItemShape>' +
'        <t:BaseShape>IdOnly</t:BaseShape>' +
'        <t:AdditionalProperties>' +
'            <t:FieldURI FieldURI="item:ICalUid"/>' +
'        </t:AdditionalProperties>' +
'      </ItemShape>' +
'      <ItemIds><t:ItemId Id="' + id + '"/></ItemIds>' +
'    </GetItem>' +
'  </soap:Body>' +
'</soap:Envelope>';

   return result;
}

function sendRequest() {
   // Create a local variable that contains the mailbox.
   var mailbox = Office.context.mailbox;

   mailbox.makeEwsRequestAsync(getSubjectRequest(mailbox.item.itemId), callback);
}

function callback(asyncResult)  {
   var result = asyncResult.value;
   var context = asyncResult.context;

   // Process the returned response here.
}

We're using Office JS to develop an Addin for Outlook Calendar. For the same appointment, the EWS Ids of the Organizer and Attendees do not match. Apparently I need ICalUid from Exchange which is common across organizer and attendees and common across different events for the same Item, exactly what we need. But Office JS does not provide such property nor method to fetch it (only for .NET).

But Office JS provides Office.context.mailbox.makeEwsRequestAsync with which I can make SOAP requests to the Exchange server, using XML.

What is the EWS SOAP XML code to get ICalUid from EWS Id?

Does this work? Just replacing FieldURI with ICalUid?

function getSubjectRequest(id) {
   // Return a GetItem operation request for the subject of the specified item. 
   var result = 
'<?xml version="1.0" encoding="utf-8"?>' +
'<soap:Envelope xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"' +
'               xmlns:xsd="https://www.w3.org/2001/XMLSchema"' +
'               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"' +
'               xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">' +
'  <soap:Header>' +
'    <RequestServerVersion Version="Exchange2013" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" soap:mustUnderstand="0" />' +
'  </soap:Header>' +
'  <soap:Body>' +
'    <GetItem xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">' +
'      <ItemShape>' +
'        <t:BaseShape>IdOnly</t:BaseShape>' +
'        <t:AdditionalProperties>' +
'            <t:FieldURI FieldURI="item:ICalUid"/>' +
'        </t:AdditionalProperties>' +
'      </ItemShape>' +
'      <ItemIds><t:ItemId Id="' + id + '"/></ItemIds>' +
'    </GetItem>' +
'  </soap:Body>' +
'</soap:Envelope>';

   return result;
}

function sendRequest() {
   // Create a local variable that contains the mailbox.
   var mailbox = Office.context.mailbox;

   mailbox.makeEwsRequestAsync(getSubjectRequest(mailbox.item.itemId), callback);
}

function callback(asyncResult)  {
   var result = asyncResult.value;
   var context = asyncResult.context;

   // Process the returned response here.
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

吹梦到西洲 2025-01-22 09:35:58

对于 IcalUid,您需要

<t:FieldURI FieldURI="calendar:UID"/>

记住,ICalUid 不是可搜索的属性,因此如果您需要此属性,您将无法找到基于此属性的约会,然后查看使用扩展 Goid 属性,如评论中链接的 João 。

For the IcalUid you would need

<t:FieldURI FieldURI="calendar:UID"/>

Keep in mind through the ICalUid isn't a searchable property so you won't be able to find Appointments based on this property if you need this then look at using the Extended Goid property like João linked in the comment.

不交电费瞎发啥光 2025-01-22 09:35:58

对于那些在我之后并且没有像我一样在这方面损失 3 天 的人,以下是我实现的方法

此函数获取组织者和参加者的 ewsId,因为他们有不同的方式来获取

// 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'))
  }
}

它函数通过解析 SOAP 请求中的 XML 来获取额外的 ID。您需要 jQuery,因为用它解析 XML 非常容易。

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'))
      }
    }
  })
}

该函数生成 XML SOAP 请求以获取所有可能的 id

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
}

这些是用于美化和验证 XML 的辅助函数

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'
}

只需将所有这些函数添加到作用域/模块,然后通过以下方式获取额外的 Id

getExtendedIds((err, res) => {
  if (!err) {
    console.log(res)
  }
})

您将拥有一个带有 { 的对象ewsId、changeKey、GlobalObjectId、ConversationId、UID }

For the ones coming after me and for not losing 3 days on this like I did, here is how I achieved

This function gets the ewsId for both Organizer and Attendee, since they have different means to get it

// 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'))
  }
}

This function gets the extra IDs by parsing the XML from the SOAP request. You need jQuery since it is very easy to parse XML with it.

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'))
      }
    }
  })
}

This 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 and validate XML

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'
}

Just add all these functions to the scope/module, and then get the extra Ids by

getExtendedIds((err, res) => {
  if (!err) {
    console.log(res)
  }
})

You'll have an object with { ewsId, changeKey, GlobalObjectId, ConversationId, UID }

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文