Merge pull request #2830 from nextcloud/downstream-fix-birthday-generation-incase-no-year-is-set

Fix generation of birthday, deathdate and anniversary in case where n…
This commit is contained in:
Roeland Jago Douma 2017-01-05 10:47:22 +01:00 committed by GitHub
commit 0453c47023
2 changed files with 56 additions and 18 deletions

View File

@ -30,6 +30,11 @@ use Exception;
use OCA\DAV\CardDAV\CardDavBackend;
use OCA\DAV\DAV\GroupPrincipalBackend;
use Sabre\VObject\Component\VCalendar;
use Sabre\VObject\Component\VCard;
use Sabre\VObject\DateTimeParser;
use Sabre\VObject\Document;
use Sabre\VObject\InvalidDataException;
use Sabre\VObject\Property\VCard\DateAndOrTime;
use Sabre\VObject\Reader;
class BirthdayService {
@ -129,6 +134,12 @@ class BirthdayService {
}
try {
$doc = Reader::read($cardData);
// We're always converting to vCard 4.0 so we can rely on the
// VCardConverter handling the X-APPLE-OMIT-YEAR property for us.
if (!$doc instanceof VCard) {
return null;
}
$doc = $doc->convert(Document::VCARD40);
} catch (Exception $e) {
return null;
}
@ -136,21 +147,43 @@ class BirthdayService {
if (!isset($doc->{$dateField})) {
return null;
}
if (!isset($doc->FN)) {
return null;
}
$birthday = $doc->{$dateField};
if (!(string)$birthday) {
return null;
}
$title = str_replace('{name}',
strtr((string)$doc->FN, array('\,' => ',', '\;' => ';')),
'{name}'
);
// Skip if the BDAY property is not of the right type.
if (!$birthday instanceof DateAndOrTime) {
return null;
}
// Skip if we can't parse the BDAY value.
try {
$dateParts = DateTimeParser::parseVCardDateTime($birthday->getValue());
} catch (InvalidDataException $e) {
return null;
}
$unknownYear = false;
if (!$dateParts['year']) {
$birthday = '1900-' . $dateParts['month'] . '-' . $dateParts['date'];
$unknownYear = true;
}
try {
$date = new \DateTime($birthday);
} catch (Exception $e) {
return null;
}
$summary = $title . ' (' . $summarySymbol . $date->format('Y') . ')';
if ($unknownYear) {
$summary = $doc->FN->getValue() . ' ' . $summarySymbol;
} else {
$year = (int)$date->format('Y');
$summary = $doc->FN->getValue() . " ($summarySymbol$year)";
}
$vCal = new VCalendar();
$vCal->VERSION = '2.0';
$vEvent = $vCal->createComponent('VEVENT');

View File

@ -55,18 +55,18 @@ class BirthdayServiceTest extends TestCase {
/**
* @dataProvider providesVCards
* @param boolean $nullExpected
* @param boolean $expectedSummary
* @param string | null $data
*/
public function testBuildBirthdayFromContact($nullExpected, $data) {
public function testBuildBirthdayFromContact($expectedSummary, $data) {
$cal = $this->service->buildDateFromContact($data, 'BDAY', '*');
if ($nullExpected) {
if ($expectedSummary === null) {
$this->assertNull($cal);
} else {
$this->assertInstanceOf('Sabre\VObject\Component\VCalendar', $cal);
$this->assertTrue(isset($cal->VEVENT));
$this->assertEquals('FREQ=YEARLY', $cal->VEVENT->RRULE->getValue());
$this->assertEquals('12345 (*1900)', $cal->VEVENT->SUMMARY->getValue());
$this->assertEquals($expectedSummary, $cal->VEVENT->SUMMARY->getValue());
$this->assertEquals('TRANSPARENT', $cal->VEVENT->TRANSP->getValue());
}
}
@ -233,14 +233,19 @@ class BirthdayServiceTest extends TestCase {
public function providesVCards() {
return [
[true, null],
[true, ''],
[true, 'yasfewf'],
[true, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
[true, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
[true, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:someday\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
[false, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:1900-01-01\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
[false, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:1900-12-31\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
[null, null],
[null, ''],
[null, 'yasfewf'],
[null, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
[null, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
[null, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:someday\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
['12345 (*1900)', "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:19000101\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
['12345 (*1900)', "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:19001231\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
['12345 *', "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:--1231\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
['12345 *', "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY;X-APPLE-OMIT-YEAR=1604:16041231\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
[null, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:;VALUE=text:circa 1800\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
[null, "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nUID:12345\r\nN:12345;;;;\r\nBDAY:20031231\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
['12345 (*900)', "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nUID:12345\r\nFN:12345\r\nN:12345;;;;\r\nBDAY:09001231\r\nEND:VCARD\r\n", "Dr. Foo Bar"],
];
}
}