Skip to content

Commit

Permalink
feat: add more vcard exports (#6878)
Browse files Browse the repository at this point in the history
  • Loading branch information
asbiin authored Sep 16, 2023
1 parent ec100c4 commit 457081c
Show file tree
Hide file tree
Showing 28 changed files with 532 additions and 70 deletions.
45 changes: 45 additions & 0 deletions app/Domains/Contact/ManageContact/Dav/ExportAdr.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace App\Domains\Contact\ManageContact\Dav;

use App\Domains\Contact\Dav\ExportVCardResource;
use App\Domains\Contact\Dav\Order;
use App\Models\Contact;
use Sabre\VObject\Component\VCard;

/**
* @implements ExportVCardResource<Contact>
*/
#[Order(20)]
class ExportAdr implements ExportVCardResource
{
public function getType(): string
{
return Contact::class;
}

/**
* @param Contact $resource
*/
public function export(mixed $resource, VCard $vcard): void
{
$vcard->remove('ADR');

if (($addresses = $resource->addresses) !== null) {
foreach ($addresses as $address) {
// https://datatracker.ietf.org/doc/html/rfc6350#section-6.3.1
$vcard->add('ADR', [
'',
$address->line_1,
$address->line_2,
$address->city,
$address->province,
$address->postal_code,
$address->country,
], $address->addressType ? [
'TYPE' => $address->addressType->name,
] : []);
}
}
}
}
85 changes: 85 additions & 0 deletions app/Domains/Contact/ManageContact/Dav/ExportContactInformation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

namespace App\Domains\Contact\ManageContact\Dav;

use App\Domains\Contact\Dav\Exporter;
use App\Domains\Contact\Dav\ExportVCardResource;
use App\Domains\Contact\Dav\Order;
use App\Models\Contact;
use App\Models\ContactInformation;
use Sabre\VObject\Component\VCard;

/**
* @implements ExportVCardResource<Contact>
*/
#[Order(30)]
class ExportContactInformation extends Exporter implements ExportVCardResource
{
public function getType(): string
{
return Contact::class;
}

/**
* @param Contact $resource
*/
public function export(mixed $resource, VCard $vcard): void
{
$vcard->remove('TEL');
$vcard->remove('EMAIL');
$vcard->remove('socialProfile');
$vcard->remove('URL');

$resource->contactInformations
->each(fn ($contactInformation) => $this->addContactInformationToVCard($vcard, $contactInformation));
}

private function addContactInformationToVCard(VCard $vcard, ContactInformation $contactInformation)
{
switch ($contactInformation->contactInformationType->name) {
case trans('Email address'):
// https://datatracker.ietf.org/doc/html/rfc6350#section-6.4.2
$vcard->add('EMAIL', $contactInformation->data, [
// 'TYPE' => $contactInformation->contactInformationType->type,
]);
break;
case trans('Phone'):
// https://datatracker.ietf.org/doc/html/rfc6350#section-6.4.1
$vcard->add('TEL', $contactInformation->data, [
//'TYPE' => $contactInformation->contactInformationType->type,
]);
break;
case trans('Facebook'):
$vcard->add('socialProfile', $this->escape('https://www.facebook.com/'.$contactInformation->data), [
'TYPE' => 'facebook',
]);
break;
case trans('Mastodon'):
$vcard->add('socialProfile', $this->escape($contactInformation->data), [
'TYPE' => 'Mastodon',
]);
break;
case trans('Whatsapp'):
$vcard->add('socialProfile', $this->escape('https://wa.me/'.$contactInformation->data), [
'TYPE' => 'whatsapp',
]);
break;
case trans('Telegram'):
$vcard->add('socialProfile', $this->escape('https://t.me/'.$contactInformation->data), [
'TYPE' => 'telegram',
]);
break;
case trans('LinkedIn'):
$vcard->add('socialProfile', $this->escape('https://www.linkedin.com/in/'.$contactInformation->data), [
'TYPE' => 'linkedin',
]);
break;
default:
// If field isn't a supported social profile, but still has a protocol, then export it as a url.
if (! empty($type = $contactInformation->contactInformationType->type)) {
$vcard->add('URL', $this->escape($type.$contactInformation->data));
}
break;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace App\Domains\Settings\ManageGenders\Dav;
namespace App\Domains\Contact\ManageContact\Dav;

use App\Domains\Contact\Dav\ExportVCardResource;
use App\Domains\Contact\Dav\Order;
Expand Down Expand Up @@ -44,6 +44,8 @@ public function export(mixed $resource, VCard $vcard): void
break;
}
}

// https://datatracker.ietf.org/doc/html/rfc6350#section-6.2.7
$vcard->add('GENDER', $gender);
}
}
46 changes: 46 additions & 0 deletions app/Domains/Contact/ManageContact/Dav/ExportImportantDates.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace App\Domains\Contact\ManageContact\Dav;

use App\Domains\Contact\Dav\Exporter;
use App\Domains\Contact\Dav\ExportVCardResource;
use App\Domains\Contact\Dav\Order;
use App\Models\Contact;
use App\Models\ContactImportantDate;
use Illuminate\Support\Str;
use Sabre\VObject\Component\VCard;

/**
* @implements ExportVCardResource<Contact>
*/
#[Order(40)]
class ExportImportantDates extends Exporter implements ExportVCardResource
{
public function getType(): string
{
return Contact::class;
}

/**
* @param Contact $resource
*/
public function export(mixed $resource, VCard $vcard): void
{
$vcard->remove('BDAY');

$resource->importantDates
->each(fn ($importantDate) => $this->addImportantDateToVCard($vcard, $importantDate));
}

public function addImportantDateToVCard(VCard $vcard, ContactImportantDate $importantDate)
{
if (($type = $importantDate->contactImportantDateType) !== null && mb_strtolower($type->label) === ContactImportantDate::TYPE_BIRTHDATE) {
$date = $importantDate->year ? Str::padLeft((string) $importantDate->year, 2, '0') : '--';
$date .= $importantDate->month ? Str::padLeft((string) $importantDate->month, 2, '0') : '--';
$date .= $importantDate->day ? Str::padLeft((string) $importantDate->day, 2, '0') : '--';

// https://datatracker.ietf.org/doc/html/rfc6350#section-6.2.5
$vcard->add('BDAY', $date);
}
}
}
3 changes: 3 additions & 0 deletions app/Domains/Contact/ManageContact/Dav/ExportNames.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,18 @@ public function export(mixed $resource, VCard $vcard): void
$vcard->remove('N');
$vcard->remove('NICKNAME');

// https://datatracker.ietf.org/doc/html/rfc6350#section-6.2.1
$vcard->add('FN', $this->escape($resource->name));

// https://datatracker.ietf.org/doc/html/rfc6350#section-6.2.2
$vcard->add('N', [
$this->escape($resource->last_name),
$this->escape($resource->first_name),
$this->escape($resource->middle_name),
]);

if (! empty($resource->nickname)) {
// https://datatracker.ietf.org/doc/html/rfc6350#section-6.2.3
$vcard->add('NICKNAME', $this->escape($resource->nickname));
}
}
Expand Down
1 change: 1 addition & 0 deletions app/Domains/Contact/ManageContact/Dav/ExportTimestamp.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public function export(mixed $resource, VCard $vcard): void
{
$vcard->remove('REV');

// https://datatracker.ietf.org/doc/html/rfc6350#section-6.7.4
$vcard->REV = $resource->updated_at->format('Ymd\\THis\\Z');
}
}
40 changes: 40 additions & 0 deletions app/Domains/Contact/ManageContact/Dav/ExportWorkInformation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace App\Domains\Contact\ManageContact\Dav;

use App\Domains\Contact\Dav\Exporter;
use App\Domains\Contact\Dav\ExportVCardResource;
use App\Domains\Contact\Dav\Order;
use App\Models\Contact;
use Sabre\VObject\Component\VCard;

/**
* @implements ExportVCardResource<Contact>
*/
#[Order(40)]
class ExportWorkInformation extends Exporter implements ExportVCardResource
{
public function getType(): string
{
return Contact::class;
}

/**
* @param Contact $resource
*/
public function export(mixed $resource, VCard $vcard): void
{
$vcard->remove('ORG');
$vcard->remove('TITLE');

if (($company = $resource->company) !== null) {
// https://datatracker.ietf.org/doc/html/rfc6350#section-6.6.4
$vcard->add('ORG', $this->escape($company->name));
}

if (! empty($resource->job_position)) {
// https://datatracker.ietf.org/doc/html/rfc6350#section-6.6.1
$vcard->add('TITLE', $this->escape($resource->job_position));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ public static function dataForTemplatePage(Contact $contact, User $user, Templat
'vault' => $contact->vault_id,
'contact' => $contact->id,
]),
'download_vcard' => route('contact.vcard.download', [
'vault' => $contact->vault,
'contact' => $contact,
]),
],
];
}
Expand Down
1 change: 1 addition & 0 deletions app/Domains/Contact/ManageGroups/Dav/ExportMembers.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public function export($resource, VCard $vcard): void
{
$kind = collect($vcard->select('X-ADDRESSBOOKSERVER-KIND'))->first();

// https://datatracker.ietf.org/doc/html/rfc6350#section-6.6.5
$this->exportType($resource, $vcard, $kind ? 'X-ADDRESSBOOKSERVER-MEMBER' : 'MEMBER');
}

Expand Down
8 changes: 5 additions & 3 deletions app/Domains/Vault/ManageAddresses/Services/CreateAddress.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,10 @@ public function execute(array $data): Address

private function geocodeAddress(): void
{
GetGPSCoordinate::dispatch([
'address_id' => $this->address->id,
])->onQueue('low');
if (config('monica.location_iq_api_key')) {
GetGPSCoordinate::dispatch([
'address_id' => $this->address->id,
])->onQueue('low');
}
}
}
8 changes: 5 additions & 3 deletions app/Domains/Vault/ManageAddresses/Services/UpdateAddress.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,10 @@ private function update(): void

private function geocodeAddress(): void
{
GetGPSCoordinate::dispatch([
'address_id' => $this->address->id,
])->onQueue('low');
if (config('monica.location_iq_api_key')) {
GetGPSCoordinate::dispatch([
'address_id' => $this->address->id,
])->onQueue('low');
}
}
}
13 changes: 12 additions & 1 deletion database/factories/ContactFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ public function definition()
'can_be_deleted' => true,
'prefix' => 'Dr.',
'suffix' => 'III',
'company_id' => Company::factory(),
'gender_id' => fn (array $properties) => Gender::factory()->create([
'account_id' => Vault::find($properties['vault_id'])->account_id,
])->getKey(),
Expand Down Expand Up @@ -84,4 +83,16 @@ public function nickname()
'nickname' => $this->faker->unique()->firstName,
]);
}

/**
* Indicate that the contact has a job.
*
* @return \Illuminate\Database\Eloquent\Factories\Factory
*/
public function company()
{
return $this->state(fn () => [
'company_id' => Company::factory(),
]);
}
}
2 changes: 1 addition & 1 deletion database/factories/ContactImportantDateTypeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public function definition()
{
return [
'vault_id' => Vault::factory(),
'label' => 'birthdate',
'label' => 'Birthdate',
'internal_type' => ContactImportantDate::TYPE_BIRTHDATE,
'can_be_deleted' => true,
];
Expand Down
2 changes: 1 addition & 1 deletion database/factories/ContactInformationTypeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public function definition()
return [
'account_id' => Account::factory(),
'name' => $this->faker->name(),
'protocol' => '+tel',
'protocol' => 'mailto:',
'can_be_deleted' => false,
'type' => 'email',
];
Expand Down
2 changes: 0 additions & 2 deletions server.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

use function Safe\parse_url;

/**
* Laravel - A PHP Framework For Web Artisans
*
Expand Down
Loading

0 comments on commit 457081c

Please sign in to comment.