Получение пользовательского списка календарей из CalDAV

Я пытаюсь получить список календарей текущего пользователя с сервера CalDAV.

Мне удалось получить эту информацию, используя нашу первоначальную тестовую учетную запись со следующим запросом:

PROPFIND /calendars/users/test/
<propfind xmlns='DAV:'>
    <allprop/>
</propfind>

Результатом является элемент <multistatus> с несколькими элементами <response>. Если я извлеку элементы, где resourcetype — это календарь, я получу свой список календарей.

Однако, когда мы добавили дополнительных пользователей, это привело к ошибке «Не найдено», поэтому вместо этого я использовал запрос «основного совпадения», чтобы получить путь «календарь-домашняя установка» текущего пользователя.

Этот путь выглядит как /d817aaec-7d24-5b38-bc2f-6369da72cdd9/. Итак, я попробовал вышеуказанный запрос с этим путем. Теперь результатом является элемент <multistatus> только с одним элементом <response>. Он не содержит календарей. Первый ответ точно такой же, как и первый ответ в моем первоначальном запросе.

Я не могу на всю жизнь придумать волшебный соус, который позволил бы мне получить список календарей пользователей во всех случаях.

ИЗМЕНИТЬ:

Вот часть моего кода. URL-адрес «/calendars/users/test/», который я пробовал изначально, возвращается из GetRequestAddress(). Мой второй случай, когда я использовал principal-match, чтобы получить путь календаря, используемый CalendarHomeSet (оба показаны ниже).

Headers["Depth"] = "1";
//XElement xmlResult = UploadXml(GetRequestAddress(), // Alternatively, CalendarHomeSet
    method: CalDavMethod.PropertyFind,
    xml: XDocument.Parse("<propfind xmlns='DAV:'>" +
        "<allprop/>" +
        "</propfind>").Root);

private string GetRequestAddress(string calendarHRef = null, string resource = null)
{
    string path = calendarHRef;
    if (String.IsNullOrWhiteSpace(path))
        path = String.Format("/calendars/users/{0}/", UserName);
    if (!String.IsNullOrWhiteSpace(resource))
        path = Path.Combine(path, resource);
    return path;
}

/// <summary>
/// Gets/sets the path to the parent folder of any calendar subfolders
/// owned by the current user.
/// </summary>
public string CalendarHomeSet
{
    get
    {
        if (calendarHomeSet == null)
        {
            Headers["Depth"] = "0";

            XElement xmlResult = UploadXml(String.Format("/principals/users/{0}/", UserName),
                method: "REPORT",
                xml: XDocument.Parse(XmlHeader +
                    "<D:principal-match xmlns:D=\"DAV:\">" +
                        "<D:self/>" +
                        "<D:prop>" +
                            "<C:calendar-home-set xmlns:C=\"urn:ietf:params:xml:ns:caldav\"/>" +
                        "</D:prop>" +
                    "</D:principal-match>").Root);
            //
            XElement el = xmlResult.Descendants(CalDavXmlns + "calendar-home-set").FirstOrDefault();
            if (el != null)
            {
                calendarHomeSet = (string)el;
                if (!calendarHomeSet.EndsWith("/"))
                    calendarHomeSet += '/';
            }
        }
        return calendarHomeSet;
    }

    set
    {
        calendarHomeSet = value;
    }
}

private string calendarHomeSet = null;

ВТОРОЕ ИЗМЕНЕНИЕ:

Вот еще некоторые подробности о точном содержании моих запросов и ответов. Обратите внимание, что в первом случае результаты включают коллекцию, за которой следуют две коллекции календарей.

PROPFIND /calendars/users/test/

<propfind xmlns="DAV:">
  <allprop />
</propfind>

Ответ:

<multistatus xmlns="DAV:">
  <response>
    <href>/calendars/users/test/</href>
    <propstat>
      <prop>
        <getetag>"4293-1000-4FFC9A16"</getetag>
        <current-user-principal>
          <href>/principals/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/</href>
        </current-user-principal>
        <displayname>Test User</displayname>
        <getcontenttype>httpd/unix-directory</getcontenttype>
        <supportedlock>
          <lockentry>
            <lockscope>
              <exclusive />
            </lockscope>
            <locktype>
              <write />
            </locktype>
          </lockentry>
          <lockentry>
            <lockscope>
              <shared />
            </lockscope>
            <locktype>
              <write />
            </locktype>
          </lockentry>
        </supportedlock>
        <resourcetype>
          <collection />
        </resourcetype>
        <getcontentlength />
        <getlastmodified>Tue, 10 Jul 2012 21:09:42 GMT</getlastmodified>
        <creationdate>2012-07-10T21:09:42Z</creationdate>
        <resource-class xmlns="http://twistedmatrix.com/xml_namespace/dav/">CalendarHomeFile</resource-class>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
  <response>
    <href>/calendars/users/test/calendar/</href>
    <propstat>
      <prop>
        <getetag>"42DB-1000-50108ABC"</getetag>
        <current-user-principal>
          <href>/principals/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/</href>
        </current-user-principal>
        <calendar-order xmlns="http://apple.com/ns/ical/">1</calendar-order>
        <displayname>calendar</displayname>
        <calendar-color xmlns="http://apple.com/ns/ical/">#F64F00FF</calendar-color>
        <getctag xmlns="http://calendarserver.org/ns/">2012-07-26 00:09:32.361284</getctag>
        <getcontenttype>httpd/unix-directory</getcontenttype>
        <supportedlock>
          <lockentry>
            <lockscope>
              <exclusive />
            </lockscope>
            <locktype>
              <write />
            </locktype>
          </lockentry>
          <lockentry>
            <lockscope>
              <shared />
            </lockscope>
            <locktype>
              <write />
            </locktype>
          </lockentry>
        </supportedlock>
        <resourcetype>
          <collection />
          <calendar xmlns="urn:ietf:params:xml:ns:caldav" />
        </resourcetype>
        <getcontentlength />
        <schedule-calendar-transp xmlns="urn:ietf:params:xml:ns:caldav">
          <opaque />
        </schedule-calendar-transp>
        <getlastmodified>Thu, 26 Jul 2012 00:09:32 GMT</getlastmodified>
        <creationdate>2012-07-26T00:09:32Z</creationdate>
        <resource-class xmlns="http://twistedmatrix.com/xml_namespace/dav/">CalDAVFile</resource-class>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
  <response>
    <href>/calendars/users/test/8C1F393E-04E8-428A-819A-933C3A9338AD/</href>
    <propstat>
      <prop>
        <getetag>"43AA-1000-50079D1C"</getetag>
        <current-user-principal>
          <href>/principals/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/</href>
        </current-user-principal>
        <calendar-order xmlns="http://apple.com/ns/ical/">0</calendar-order>
        <displayname>Jon Wood Calendar</displayname>
        <calendar-color xmlns="http://apple.com/ns/ical/">#711a76</calendar-color>
        <getctag xmlns="http://calendarserver.org/ns/">2012-07-19 05:37:32.673835</getctag>
        <getcontenttype>httpd/unix-directory</getcontenttype>
        <supportedlock>
          <lockentry>
            <lockscope>
              <exclusive />
            </lockscope>
            <locktype>
              <write />
            </locktype>
          </lockentry>
          <lockentry>
            <lockscope>
              <shared />
            </lockscope>
            <locktype>
              <write />
            </locktype>
          </lockentry>
        </supportedlock>
        <resourcetype>
          <collection />
          <calendar xmlns="urn:ietf:params:xml:ns:caldav" />
        </resourcetype>
        <getcontentlength />
        <schedule-calendar-transp xmlns="urn:ietf:params:xml:ns:caldav">
          <transparent />
        </schedule-calendar-transp>
        <getlastmodified>Thu, 19 Jul 2012 05:37:32 GMT</getlastmodified>
        <creationdate>2012-07-19T05:37:32Z</creationdate>
        <resource-class xmlns="http://twistedmatrix.com/xml_namespace/dav/">CalDAVFile</resource-class>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
  <response>
    <href>/calendars/users/test/outbox/</href>
    <propstat>
      <prop>
        <getetag>"D4E-1000-4FFB15AF"</getetag>
        <current-user-principal>
          <href>/principals/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/</href>
        </current-user-principal>
        <displayname>outbox</displayname>
        <getctag xmlns="http://calendarserver.org/ns/">2012-07-09 17:32:31.950308</getctag>
        <getcontenttype>httpd/unix-directory</getcontenttype>
        <supportedlock>
          <lockentry>
            <lockscope>
              <exclusive />
            </lockscope>
            <locktype>
              <write />
            </locktype>
          </lockentry>
          <lockentry>
            <lockscope>
              <shared />
            </lockscope>
            <locktype>
              <write />
            </locktype>
          </lockentry>
        </supportedlock>
        <resourcetype>
          <collection />
          <schedule-outbox xmlns="urn:ietf:params:xml:ns:caldav" />
        </resourcetype>
        <getcontentlength />
        <getlastmodified>Mon, 09 Jul 2012 17:32:31 GMT</getlastmodified>
        <creationdate>2012-07-09T17:32:31Z</creationdate>
        <resource-class xmlns="http://twistedmatrix.com/xml_namespace/dav/">ScheduleOutboxFile</resource-class>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
  <response>
    <href>/calendars/users/test/freebusy</href>
    <propstat>
      <prop>
        <getetag>"D7D-0-4FFC3F7C"</getetag>
        <current-user-principal>
          <href>/principals/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/</href>
        </current-user-principal>
        <displayname>freebusy</displayname>
        <getcontenttype>text/plain</getcontenttype>
        <supportedlock>
          <lockentry>
            <lockscope>
              <exclusive />
            </lockscope>
            <locktype>
              <write />
            </locktype>
          </lockentry>
          <lockentry>
            <lockscope>
              <shared />
            </lockscope>
            <locktype>
              <write />
            </locktype>
          </lockentry>
        </supportedlock>
        <resourcetype>
          <free-busy-url xmlns="http://calendarserver.org/ns/" />
        </resourcetype>
        <getcontentlength>0</getcontentlength>
        <getlastmodified>Tue, 10 Jul 2012 14:43:08 GMT</getlastmodified>
        <creationdate>2012-07-10T14:43:08Z</creationdate>
        <resource-class xmlns="http://twistedmatrix.com/xml_namespace/dav/">FreeBusyURLFile</resource-class>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
  <response>
    <href>/calendars/users/test/inbox/</href>
    <propstat>
      <prop>
        <getetag>"42FB-1000-4FF21C60"</getetag>
        <current-user-principal>
          <href>/principals/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/</href>
        </current-user-principal>
        <displayname>inbox</displayname>
        <getctag xmlns="http://calendarserver.org/ns/">2012-07-02 22:10:40.527683</getctag>
        <getcontenttype>httpd/unix-directory</getcontenttype>
        <supportedlock>
          <lockentry>
            <lockscope>
              <exclusive />
            </lockscope>
            <locktype>
              <write />
            </locktype>
          </lockentry>
          <lockentry>
            <lockscope>
              <shared />
            </lockscope>
            <locktype>
              <write />
            </locktype>
          </lockentry>
        </supportedlock>
        <resourcetype>
          <collection />
          <schedule-inbox xmlns="urn:ietf:params:xml:ns:caldav" />
        </resourcetype>
        <getcontentlength />
        <schedule-default-calendar-URL xmlns="urn:ietf:params:xml:ns:caldav">
          <href xmlns="DAV:">/calendars/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/calendar</href>
        </schedule-default-calendar-URL>
        <getlastmodified>Mon, 02 Jul 2012 22:10:40 GMT</getlastmodified>
        <creationdate>2012-07-02T22:10:40Z</creationdate>
        <resource-class xmlns="http://twistedmatrix.com/xml_namespace/dav/">ScheduleInboxFile</resource-class>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
</multistatus>

Затем я попробовал тот же запрос, но по другому URL-адресу. На этот раз я использовал URL-адрес, полученный путем запроса принципала. Теперь результаты по-прежнему содержат исходную коллекцию, но не содержат календарей.

PROPFIND /calendars/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/ (CalendarHomeSet)

<propfind xmlns="DAV:">
  <allprop />
</propfind>

Ответ:

<multistatus xmlns="DAV:">
  <response>
    <href>/calendars/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/</href>
    <propstat>
      <prop>
        <getetag>"4293-1000-4FFC9A16"</getetag>
        <current-user-principal>
          <href>/principals/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/</href>
        </current-user-principal>
        <displayname>Test User</displayname>
        <getcontenttype>httpd/unix-directory</getcontenttype>
        <supportedlock>
          <lockentry>
            <lockscope>
              <exclusive />
            </lockscope>
            <locktype>
              <write />
            </locktype>
          </lockentry>
          <lockentry>
            <lockscope>
              <shared />
            </lockscope>
            <locktype>
              <write />
            </locktype>
          </lockentry>
        </supportedlock>
        <resourcetype>
          <collection />
        </resourcetype>
        <getcontentlength />
        <getlastmodified>Tue, 10 Jul 2012 21:09:42 GMT</getlastmodified>
        <creationdate>2012-07-10T21:09:42Z</creationdate>
        <resource-class xmlns="http://twistedmatrix.com/xml_namespace/dav/">CalendarHomeFile</resource-class>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
</multistatus>

ТРЕТЬЕ ИЗМЕНЕНИЕ:

А вот запрос и ответ, которые я использовал, чтобы получить домашний набор календаря:

REPORT /principals/users/test/

<D:principal-match xmlns:D="DAV:">
  <D:self />
  <D:prop>
    <C:calendar-home-set xmlns:C="urn:ietf:params:xml:ns:caldav" />
  </D:prop>
</D:principal-match>

Ответ:

<multistatus xmlns="DAV:">
  <response>
    <href>/principals/users/test/</href>
    <propstat>
      <prop>
        <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">
          <href xmlns="DAV:">/calendars/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9</href>
        </calendar-home-set>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
</multistatus>

person Jonathan Wood    schedule 24.07.2012    source источник


Ответы (1)


Две вещи, о которых я могу думать прямо сейчас:

  1. Вы указываете заголовок Depth: 1?
  2. Есть ли у новых пользователей календари? Список может быть просто пуст для новых пользователей.

Если эти указатели не помогают, вы должны показать полные запросы и ответы.

ИЗМЕНИТЬ

Вот как вы обычно должны выполнять обнаружение в CalDAV.

  1. Выполните PROPFIND для URL-адреса, предоставленного пользователем, запросив {DAV:}current-user-principal.
  2. Используя этот URL, вы делаете PROPFIND, чтобы узнать больше информации о пользователе. Здесь обычно следует запрашивать свойство calendar-home-set в пространстве имен caldav.
  3. Затем, используя набор календарей, выполните PROPFIND (глубина: 1), чтобы найти календари.

У меня такое ощущение, что, поскольку вы выполняете основное соответствие и не используете принципала текущего пользователя; это происходит немного неправильно. Но я не совсем уверен. Моя догадка заключается в том, что ваш обнаруженный домашний набор календаря неверен.

person Evert    schedule 26.07.2012
comment
Спасибо за ответ. Я использую Depth = 1 и смог подтвердить, что у всех пользователей есть календарь по умолчанию. Я отредактировал свой вопрос, чтобы показать больше моего кода. Спасибо за любую помощь. - person Jonathan Wood; 26.07.2012
comment
Я хотел бы видеть, точно что вы отправляете на сервер и получаете обратно... в терминах xml. Я автор сервера CalDAV (SabreDAV), поэтому тела запроса/ответа будут для меня гораздо полезнее :) - person Evert; 26.07.2012
comment
Спасибо за ответ. Я добавил точное содержание в конце моего вопроса. Я ожидал, что второй ответ будет таким же, как и первый. (Кроме того, если мы хотим перейти с DCS на SabreDAV, на что это похоже? Необходимы какие-либо инструменты? - person Jonathan Wood; 26.07.2012
comment
Я могу сказать, что это DCS. Больше всего выделяется базовый URL. Первый начинается с /calendars/users, второй /calendars/__uids__. Это заставило бы меня задуматься, правильно ли вы получили домашний набор календаря. Calendar-home-set может быть списком ссылок, так что, может быть, вы взяли только первый? Кроме того... если вы правильно реализуете протокол CalDAV, переключение на SabreDAV должно быть легким. Однако миграция данных сложнее - person Evert; 26.07.2012
comment
И пока вы на правильном пути, но да... последнее, о чем я хотел бы спросить, это... можете ли вы показать запрос и ответ, который вы используете для получения календаря-домашний набор. - person Evert; 26.07.2012
comment
Еще раз спасибо. Перенос данных не является проблемой, поскольку этот проект еще не развернут. Я добавил запрос и ответ, которые я использовал для установки домашнего календаря. Это было разработано в основном путем догадок, проб и ошибок. Так что у меня запросто может быть что-то не так. - person Jonathan Wood; 26.07.2012
comment
Я думаю, что я бы предложил не использовать отчет о совпадении принципала, а вместо этого использовать свойство принципала текущего пользователя. Вы можете просто сделать propfind в любом месте и получить текущий основной URL-адрес. Используя это, сделайте еще один поиск для календаря-домашний набор. Примерно так любой клиент CalDAV выполняет обнаружение. - person Evert; 26.07.2012
comment
Я пытаюсь выяснить правильный синтаксис для этого. Похоже, что в спецификациях CalDav ничего не говорится о current-user-principal. - person Jonathan Wood; 27.07.2012
comment
Он был добавлен в более позднем rfc из-за проблем с основным соответствием. Проверьте URL-адрес, на который я ссылался в своем ответе. - person Evert; 27.07.2012
comment
Спасибо за дополнительную помощь. Я думаю, вам просто нужно понять этот материал внутри и снаружи, чтобы знать, что нужно. Для меня угадывание правильного синтаксиса (я не вижу примеров запросов по ссылке, которую вы разместили) кажется очень болезненной. Во всяком случае, у меня наконец-то это заработало. Однако результатом стал /calendars/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9, который, по-видимому, является тем же путем, который я использовал изначально. - person Jonathan Wood; 27.07.2012
comment
Верна ли моя догадка? Как вы в конечном итоге обнаружили этот URL? Лучший способ (имхо) лучше понять протокол - посмотреть, как это делают другие (правильные) клиенты. - person Evert; 27.07.2012
comment
Какой URL? Я вычислил URL-адрес /calendars/users/test/ методом проб и ошибок в браузере. Я нашел URL-адрес /calendars/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9, используя запрос principal-match, чтобы получить путь к календарю текущего пользователя. Предложенный вами подход дает мне тот же URL. Но я не могу получить список календарей, доступных для этого URL. Да, я бы отдал левую ногу, чтобы увидеть пример клиентского кода C или C#, который действительно работает с DCS! Все поиски найти это не увенчались успехом. (Я нашел несколько примеров C#, которые просто неверны.) - person Jonathan Wood; 27.07.2012
comment
давайте продолжим это обсуждение в чате - person Evert; 27.07.2012