Что такое XML-код EWS SOAP для получения ICalUid?

Мы используем Office JS для разработки надстройки для календаря Outlook. Для той же встречи идентификаторы EWS организатора и участников не совпадает. По-видимому, мне нужен ICalUid от Exchange, который является общим для организатора и участников, а также для разных событий для одного и того же предмета, именно то, что нам нужно. Но Office JS не предоставляет ни такого свойства, ни метода для его получения (только для .NET).

Но Office JS предоставляет Office.context.mailbox.makeEwsRequestAsync, с помощью которого я могу делать запросы SOAP к серверу Exchange, используя XML.

Что такое XML-код EWS SOAP для получения ICalUid из идентификатора EWS?

Это работает? Просто заменить 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.
}
social.technet.microsoft.com/Forums/projectserver/en-US/…
João Pimentel Ferreira 19.03.2022 15:50
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
45
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Для IcalUid вам понадобится

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

Имейте в виду, что ICalUid не является свойством для поиска, поэтому вы не сможете найти встречи на основе этого свойства, если вам это нужно, а затем посмотрите на использование свойства Extended Goid, такого как João, связанного в комментарии.

Просто для подтверждения: является ли ICalUid общим (точно одинаковым) как для Организатора, так и для всех Участников, когда я использую соответствующие идентификаторы EWS в качестве входных данных?

João Pimentel Ferreira 21.03.2022 13:29

в чем разница между ICalUid и расширенным свойством Goid?

João Pimentel Ferreira 21.03.2022 13:31

Goid — это свойство Exchange, которое используется Outlook для уникальной идентификации встреч в календаре, поэтому оно будет одинаковым для всех экземпляров, см. docs.microsoft.com/en-us/openspecs/exchange_server_protocols‌​/…. Он также устанавливается на приглашения, принятия и т. д. ICalUid — это свойство rfc, установленное на встрече, см. icalendar.org/iCalendar-RFC-5545/3-8-4-7-unique-identifier.h‌​tml

Glen Scales 21.03.2022 22:30

извините, я ничего не понимаю в запросах мыла к EWS, я пытаюсь разработать офисную надстройку js. Не могли бы вы опубликовать в своем ответе полный XML-код для получения ICalUid из ItemId? Я сделал, как вы сказали (просто заменив эту строку), и в ответ я снова получаю ItemId. Что поставить в BaseShape? Идентификаторы?

João Pimentel Ferreira 22.03.2022 09:40

Для тех, кто придет после меня, и за то, что не потерял 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'))
  }
}

Эта функция получает дополнительные идентификаторы, анализируя XML из запроса SOAP. Вам нужен 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.info(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 для получения всех возможных идентификаторов.

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

Просто добавьте все эти функции в область/модуль, а затем получите дополнительные идентификаторы с помощью

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

У вас будет объект с { ewsId, changeKey, GlobalObjectId, ConversationId, UID }

Другие вопросы по теме