mstilkerich / carddavclient

CardDAV client library for PHP ("PHP-CardDavClient")
MIT License
20 stars 4 forks source link

Filtering categories #19

Closed L1800Turbo closed 2 years ago

L1800Turbo commented 2 years ago

Hello,

I'm trying to implement the library in a small script, where I want to get all entries matching a specific category. The Server is radicale.

If I run $abook->query(['CATEGORIES' => '//']) as $uri => $arrEtagVCard I get all VCards having a category.

When I run $abook->query(['CATEGORIES' => '/Test/']) as $uri => $arrEtagVCard I get a server error:

` PHP Fatal error: Uncaught Exception: Expected Multistatus HTTP request was not successful (500 Internal Server Error): A server error occurred. Please contact the administrator. in /opt/pr2cardDav/vendor/mstilkerich/carddavclient/src/CardDavClient.php:480 Stack trace:

0 /opt/pr2cardDav/vendor/mstilkerich/carddavclient/src/CardDavClient.php(496): MStilkerich\CardDavClient\CardDavClient::assertHttpStatus(Object(GuzzleHttp\Psr7\Response), 207, 207, 'Expected Multis...')

1 /opt/pr2cardDav/vendor/mstilkerich/carddavclient/src/CardDavClient.php(350): MStilkerich\CardDavClient\CardDavClient::checkAndParseXMLMultistatus(Object(GuzzleHttp\Psr7\Response))

2 /opt/pr2cardDav/vendor/mstilkerich/carddavclient/src/AddressbookCollection.php(299): MStilkerich\CardDavClient\CardDavClient->query('http://10.18.1....', Object(MStilkerich\CardDavClient\XmlElements\Filter), Array, 0)

3 /opt/pr2cardDav/mysql2cardCav.php(157): MStilkerich\CardDavClient\AddressbookCollection->query(Object(MStilkerich\CardDavClient\XmlElements\Filte in /opt/pr2cardDav/vendor/mstilkerich/carddavclient/src/CardDavClient.php on line 480

`

Do I need to implement the filter in another way? Is radicale maybe not compatible with this kind of request and it needs to be changed?

Thank you!

mstilkerich commented 2 years ago

Hi, it's a bug in radicale. The vobject library they use appears to use different python classes for the attributes, e.g. list for CATEGORIES, Name for N. The text match code expects the objects to have a lower() method, which is not the case for these classes. So while for some attributes (e.g. FN) the filter works fine, for others (like N and CATEGORIES, whose class has no lower method), a server error is raised.

[2022-02-17 16:06:28 +0000] [1/Thread-15] [ERROR] An exception occurred during REPORT request on '/mikey/newbook/': Failed to filter item 'sabre-vobject-52eb1cc7-9eda-49ca-beb1-8ddbbd770e38.vcf' from 'mikey/newbook': 'list' object has no attribute 'lower'
[2022-02-17 16:06:43 +0000] [1/Thread-17] [ERROR] An exception occurred during REPORT request on '/mikey/newbook/': Failed to filter item 'sabre-vobject-52eb1cc7-9eda-49ca-beb1-8ddbbd770e38.vcf' from 'mikey/newbook': 'Name' object has no attribute 'lower'

It's probably easy to fix, but I don't know the first thing about python :-) So I'd suggest to report an issue at Kozea/Radicale. But don't get your hopes too high, I already reported two addressbook-query related issues, which never received any reaction. So you'll probably have to work around it doing the filtering yourself.

Example:

foreach ($abook->query(['CATEGORIES' => '//']) as $uri => $arrEtagVCard) {
    $card = $arrEtagVCard['vcard'];

    if (!empty(array_filter(
        $card->CATEGORIES->getParts(),
        function($cat) { return str_contains($cat, 'Test'); }
    ))) {
        echo ": MATCH\n";
    }
}
L1800Turbo commented 2 years ago

Thank you for the quick reaction!

My workaround would have been similar (less elegant probably), but I was quite sure to make a mistake in the syntax..