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

What is the EWS SOAP XML code to get ICalUid?

我们正在使用 Office JS 开发 Outlook 日历插件。对于同一个约会,组织者和参加者的 EWS ID 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).

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

从 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.
}

对于 IcalUid,您需要

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

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

对于那些追随我的人并且没有像我一样浪费 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'
}

只需将所有这些功能添加到 scope/module,然后通过

获取额外的 ID
getExtendedIds((err, res) => {
  if (!err) {
    console.log(res)
  }
})

您将拥有一个 { ewsId, changeKey, GlobalObjectId, ConversationId, UID }

的对象