3232use OCA \DAV \CardDAV \CardDavBackend ;
3333use OCA \DAV \DAV \GroupPrincipalBackend ;
3434use OCP \IConfig ;
35+ use OCP \IDBConnection ;
3536use Sabre \VObject \Component \VCalendar ;
3637use Sabre \VObject \Component \VCard ;
3738use Sabre \VObject \DateTimeParser ;
@@ -56,6 +57,9 @@ class BirthdayService {
5657 /** @var IConfig */
5758 private $ config ;
5859
60+ /** @var IDBConnection */
61+ private $ dbConnection ;
62+
5963 /**
6064 * BirthdayService constructor.
6165 *
@@ -64,11 +68,12 @@ class BirthdayService {
6468 * @param GroupPrincipalBackend $principalBackend
6569 * @param IConfig $config;
6670 */
67- public function __construct (CalDavBackend $ calDavBackEnd , CardDavBackend $ cardDavBackEnd , GroupPrincipalBackend $ principalBackend , IConfig $ config ) {
71+ public function __construct (CalDavBackend $ calDavBackEnd , CardDavBackend $ cardDavBackEnd , GroupPrincipalBackend $ principalBackend , IConfig $ config, IDBConnection $ dbConnection ) {
6872 $ this ->calDavBackEnd = $ calDavBackEnd ;
6973 $ this ->cardDavBackEnd = $ cardDavBackEnd ;
7074 $ this ->principalBackend = $ principalBackend ;
7175 $ this ->config = $ config ;
76+ $ this ->dbConnection = $ dbConnection ;
7277 }
7378
7479 /**
@@ -85,9 +90,9 @@ public function onCardChanged($addressBookId, $cardUri, $cardData) {
8590 $ book = $ this ->cardDavBackEnd ->getAddressBookById ($ addressBookId );
8691 $ targetPrincipals [] = $ book ['principaluri ' ];
8792 $ datesToSync = [
88- ['postfix ' => '' , 'field ' => 'BDAY ' , 'symbol ' => '* ' ],
89- ['postfix ' => '-death ' , 'field ' => 'DEATHDATE ' , 'symbol ' => "† " ],
90- ['postfix ' => '-anniversary ' , 'field ' => 'ANNIVERSARY ' , 'symbol ' => "⚭ " ],
93+ ['postfix ' => '' , 'field ' => 'BDAY ' , 'symbol ' => '* ' , ' utfSymbol ' => ' 🎂 ' ],
94+ ['postfix ' => '-death ' , 'field ' => 'DEATHDATE ' , 'symbol ' => "† " , ' utfSymbol ' => ' ⚰️ ' ],
95+ ['postfix ' => '-anniversary ' , 'field ' => 'ANNIVERSARY ' , 'symbol ' => "⚭ " , ' utfSymbol ' => ' 💍 ' ],
9196 ];
9297 foreach ($ targetPrincipals as $ principalUri ) {
9398 if (!$ this ->isUserEnabled ($ principalUri )) {
@@ -132,9 +137,9 @@ public function onCardDeleted($addressBookId, $cardUri) {
132137 * @throws \Sabre\DAV\Exception\BadRequest
133138 */
134139 public function ensureCalendarExists ($ principal ) {
135- $ book = $ this ->calDavBackEnd ->getCalendarByUri ($ principal , self ::BIRTHDAY_CALENDAR_URI );
136- if (!is_null ($ book )) {
137- return $ book ;
140+ $ calendar = $ this ->calDavBackEnd ->getCalendarByUri ($ principal , self ::BIRTHDAY_CALENDAR_URI );
141+ if (!is_null ($ calendar )) {
142+ return $ calendar ;
138143 }
139144 $ this ->calDavBackEnd ->createCalendar ($ principal , self ::BIRTHDAY_CALENDAR_URI , [
140145 '{DAV:}displayname ' => 'Contact birthdays ' ,
@@ -150,9 +155,10 @@ public function ensureCalendarExists($principal) {
150155 * @param string $dateField
151156 * @param string $postfix
152157 * @param string $summarySymbol
158+ * @param string $utfSummarySymbol
153159 * @return null|VCalendar
154160 */
155- public function buildDateFromContact ($ cardData , $ dateField , $ postfix , $ summarySymbol ) {
161+ public function buildDateFromContact ($ cardData , $ dateField , $ postfix , $ summarySymbol, $ utfSummarySymbol ) {
156162 if (empty ($ cardData )) {
157163 return null ;
158164 }
@@ -191,23 +197,47 @@ public function buildDateFromContact($cardData, $dateField, $postfix, $summarySy
191197 }
192198
193199 $ unknownYear = false ;
200+ $ originalYear = null ;
194201 if (!$ dateParts ['year ' ]) {
195- $ birthday = '1900 - ' . $ dateParts ['month ' ] . '- ' . $ dateParts ['date ' ];
202+ $ birthday = '1970 - ' . $ dateParts ['month ' ] . '- ' . $ dateParts ['date ' ];
196203
197204 $ unknownYear = true ;
205+ } else {
206+ $ parameters = $ birthday ->parameters ();
207+ if (isset ($ parameters ['X-APPLE-OMIT-YEAR ' ])) {
208+ $ omitYear = $ parameters ['X-APPLE-OMIT-YEAR ' ];
209+ if ($ dateParts ['year ' ] === $ omitYear ) {
210+ $ birthday = '1970- ' . $ dateParts ['month ' ] . '- ' . $ dateParts ['date ' ];
211+ $ unknownYear = true ;
212+ }
213+ } else {
214+ $ originalYear = (int )$ dateParts ['year ' ];
215+
216+ if ($ originalYear < 1970 ) {
217+ $ birthday = '1970- ' . $ dateParts ['month ' ] . '- ' . $ dateParts ['date ' ];
218+ }
219+ }
198220 }
199221
200222 try {
201223 $ date = new \DateTime ($ birthday );
202224 } catch (Exception $ e ) {
203225 return null ;
204226 }
205- if ($ unknownYear ) {
206- $ summary = $ doc ->FN ->getValue () . ' ' . $ summarySymbol ;
227+ if ($ this ->dbConnection ->supports4ByteText ()) {
228+ if ($ unknownYear ) {
229+ $ summary = $ utfSummarySymbol . ' ' . $ doc ->FN ->getValue ();
230+ } else {
231+ $ summary = $ utfSummarySymbol . ' ' . $ doc ->FN ->getValue () . " ( $ originalYear) " ;
232+ }
207233 } else {
208- $ year = (int )$ date ->format ('Y ' );
209- $ summary = $ doc ->FN ->getValue () . " ( $ summarySymbol$ year) " ;
234+ if ($ unknownYear ) {
235+ $ summary = $ doc ->FN ->getValue () . ' ' . $ summarySymbol ;
236+ } else {
237+ $ summary = $ doc ->FN ->getValue () . " ( $ summarySymbol$ originalYear) " ;
238+ }
210239 }
240+
211241 $ vCal = new VCalendar ();
212242 $ vCal ->VERSION = '2.0 ' ;
213243 $ vEvent = $ vCal ->createComponent ('VEVENT ' );
@@ -226,6 +256,11 @@ public function buildDateFromContact($cardData, $dateField, $postfix, $summarySy
226256 $ vEvent ->{'RRULE ' } = 'FREQ=YEARLY ' ;
227257 $ vEvent ->{'SUMMARY ' } = $ summary ;
228258 $ vEvent ->{'TRANSP ' } = 'TRANSPARENT ' ;
259+ $ vEvent ->{'X-NEXTCLOUD-BC-FIELD-TYPE ' } = $ dateField ;
260+ $ vEvent ->{'X-NEXTCLOUD-BC-UNKNOWN-YEAR ' } = $ unknownYear ? '1 ' : '0 ' ;
261+ if ($ originalYear !== null ) {
262+ $ vEvent ->{'X-NEXTCLOUD-BC-YEAR ' } = (string ) $ originalYear ;
263+ }
229264 $ alarm = $ vCal ->createComponent ('VALARM ' );
230265 $ alarm ->add ($ vCal ->createProperty ('TRIGGER ' , '-PT0M ' , ['VALUE ' => 'DURATION ' ]));
231266 $ alarm ->add ($ vCal ->createProperty ('ACTION ' , 'DISPLAY ' ));
@@ -235,6 +270,19 @@ public function buildDateFromContact($cardData, $dateField, $postfix, $summarySy
235270 return $ vCal ;
236271 }
237272
273+ /**
274+ * @param string $user
275+ */
276+ public function resetForUser ($ user ) {
277+ $ principal = 'principals/users/ ' .$ user ;
278+ $ calendar = $ this ->calDavBackEnd ->getCalendarByUri ($ principal , self ::BIRTHDAY_CALENDAR_URI );
279+ $ calendarObjects = $ this ->calDavBackEnd ->getCalendarObjects ($ calendar ['id ' ], CalDavBackend::CALENDAR_TYPE_CALENDAR );
280+
281+ foreach ($ calendarObjects as $ calendarObject ) {
282+ $ this ->calDavBackEnd ->deleteCalendarObject ($ calendar ['id ' ], $ calendarObject ['uri ' ], CalDavBackend::CALENDAR_TYPE_CALENDAR );
283+ }
284+ }
285+
238286 /**
239287 * @param string $user
240288 */
@@ -298,7 +346,7 @@ protected function getAllAffectedPrincipals($addressBookId) {
298346 */
299347 private function updateCalendar ($ cardUri , $ cardData , $ book , $ calendarId , $ type ) {
300348 $ objectUri = $ book ['uri ' ] . '- ' . $ cardUri . $ type ['postfix ' ] . '.ics ' ;
301- $ calendarData = $ this ->buildDateFromContact ($ cardData , $ type ['field ' ], $ type ['postfix ' ], $ type ['symbol ' ]);
349+ $ calendarData = $ this ->buildDateFromContact ($ cardData , $ type ['field ' ], $ type ['postfix ' ], $ type ['symbol ' ], $ type [ ' utfSymbol ' ] );
302350 $ existing = $ this ->calDavBackEnd ->getCalendarObject ($ calendarId , $ objectUri );
303351 if (is_null ($ calendarData )) {
304352 if (!is_null ($ existing )) {
0 commit comments