diff --git a/app/Domains/Contact/Dav/ImportVCardResource.php b/app/Domains/Contact/Dav/ImportVCardResource.php index 1edb0fe4631..0a414d474d7 100644 --- a/app/Domains/Contact/Dav/ImportVCardResource.php +++ b/app/Domains/Contact/Dav/ImportVCardResource.php @@ -20,5 +20,5 @@ public function can(VCard $vcard): bool; /** * Import Card. */ - public function import(VCard $vcard, mixed $result): mixed; + public function import(VCard $vcard, ?VCardResource $result): ?VCardResource; } diff --git a/app/Domains/Contact/Dav/Importer.php b/app/Domains/Contact/Dav/Importer.php index e9090c4e8d2..baed3e8ccde 100644 --- a/app/Domains/Contact/Dav/Importer.php +++ b/app/Domains/Contact/Dav/Importer.php @@ -4,6 +4,10 @@ use App\Domains\Contact\Dav\Services\ImportVCard; use App\Models\Account; +use App\Models\User; +use App\Models\Vault; +use Ramsey\Uuid\Uuid; +use Sabre\VObject\Component\VCard; abstract class Importer implements ImportVCardResource { @@ -24,7 +28,23 @@ public function setContext(ImportVCard $context): ImportVCardResource */ protected function account(): Account { - return $this->context->vault->account; + return $this->vault()->account; + } + + /** + * Get the vault. + */ + protected function vault(): Vault + { + return $this->context->vault; + } + + /** + * Get the author. + */ + protected function author(): User + { + return $this->context->author; } /** @@ -34,4 +54,28 @@ protected function formatValue(?string $value): ?string { return ! empty($value) ? str_replace('\;', ';', trim($value)) : null; } + + /** + * Get uid of the card. + */ + protected function getUid(VCard $entry): ?string + { + if (! empty($uuid = (string) $entry->UID)) { + return $uuid; + } + + return null; + } + + /** + * Import UID. + */ + protected function importUid(array $data, VCard $entry): array + { + if (($uuid = $this->getUid($entry)) !== null && Uuid::isValid($uuid) && ! $this->context->external) { + $data['id'] = $uuid; + } + + return $data; + } } diff --git a/app/Domains/Contact/Dav/Services/GetEtag.php b/app/Domains/Contact/Dav/Services/GetEtag.php index 2fc3aef4a15..6336d132833 100644 --- a/app/Domains/Contact/Dav/Services/GetEtag.php +++ b/app/Domains/Contact/Dav/Services/GetEtag.php @@ -2,6 +2,7 @@ namespace App\Domains\Contact\Dav\Services; +use App\Domains\Contact\Dav\VCardResource; use App\Interfaces\ServiceInterface; use App\Services\BaseService; use Illuminate\Database\Eloquent\ModelNotFoundException; @@ -40,6 +41,7 @@ public function execute(array $data): string { $this->validateRules($data); + /** @var VCardResource */ $entry = $data['entry']; if ($entry->vault_id !== $this->vault->id) { diff --git a/app/Domains/Contact/Dav/Services/ImportVCard.php b/app/Domains/Contact/Dav/Services/ImportVCard.php index 8ea3dcd49c6..ff60c3b7c06 100644 --- a/app/Domains/Contact/Dav/Services/ImportVCard.php +++ b/app/Domains/Contact/Dav/Services/ImportVCard.php @@ -4,11 +4,13 @@ use App\Domains\Contact\Dav\ImportVCardResource; use App\Domains\Contact\Dav\Order; +use App\Domains\Contact\Dav\VCardResource; use App\Interfaces\ServiceInterface; use App\Services\BaseService; use App\Traits\DAVFormat; use Closure; use Illuminate\Contracts\Foundation\Application; +use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Str; @@ -194,6 +196,7 @@ private function processEntry(VCard $entry, string $vcard): array */ private function processEntryContact(VCard $entry, string $vcard): array { + /** @var Model|VCardResource */ $result = $this->importEntry($entry); if ($result === null) { @@ -234,7 +237,7 @@ private function canImportCurrentEntry(VCard $entry): bool /** * Create the object matching the current entry. */ - private function importEntry(VCard $entry): mixed + private function importEntry(VCard $entry): ?VCardResource { $result = null; diff --git a/app/Domains/Contact/Dav/VCardResource.php b/app/Domains/Contact/Dav/VCardResource.php new file mode 100644 index 00000000000..0ff3c76a9f5 --- /dev/null +++ b/app/Domains/Contact/Dav/VCardResource.php @@ -0,0 +1,13 @@ +getExistingContact($vcard); @@ -57,11 +57,11 @@ public function import(VCard $vcard, mixed $result): mixed $contactData = $this->importNames($contactData, $vcard); $contactData = $this->importGender($contactData, $vcard); - if ($contact !== null && $contactData !== $original) { - $contact = app(UpdateContact::class)->execute($contactData); - } else { + if ($contact === null) { $contactData['listed'] = true; $contact = app(CreateContact::class)->execute($contactData); + } elseif ($contactData !== $original) { + $contact = app(UpdateContact::class)->execute($contactData); } if ($this->context->external && $contact->distant_uuid === null) { @@ -88,11 +88,11 @@ private function getExistingContact(VCard $vcard): ?Contact $contact = null; if (($uri = Arr::get($this->context->data, 'uri')) !== null) { - $contact = $backend->getObject($this->context->vault->id, $uri); + $contact = $backend->getObject($this->vault()->id, $uri); if ($contact === null) { $contact = Contact::firstWhere([ - 'vault_id' => $this->context->vault->id, + 'vault_id' => $this->vault()->id, 'distant_uri' => $uri, ]); } @@ -102,13 +102,13 @@ private function getExistingContact(VCard $vcard): ?Contact $contactId = $this->getUid($vcard); if ($contactId !== null) { $contact = Contact::firstWhere([ - 'vault_id' => $this->context->vault->id, + 'vault_id' => $this->vault()->id, 'id' => $contactId, ]); } } - if ($contact !== null && $contact->vault_id !== $this->context->vault->id) { + if ($contact !== null && $contact->vault_id !== $this->vault()->id) { throw new ModelNotFoundException(); } @@ -122,8 +122,8 @@ private function getContactData(?Contact $contact): array { $result = [ 'account_id' => $this->account()->id, - 'vault_id' => $this->context->vault->id, - 'author_id' => $this->context->author->id, + 'vault_id' => $this->vault()->id, + 'author_id' => $this->author()->id, 'first_name' => $contact ? $contact->first_name : null, 'last_name' => $contact ? $contact->last_name : null, 'middle_name' => $contact ? $contact->middle_name : null, @@ -199,12 +199,12 @@ private function importNameFromFN(array $contactData, VCard $entry): array { $fullnameParts = preg_split('/\s+/', $entry->FN, 2); - if (Str::of($this->context->author->name_order)->startsWith('%first_name% %last_name%')) { + if (Str::of($this->author()->name_order)->startsWith('%first_name% %last_name%')) { $contactData['first_name'] = $this->formatValue($fullnameParts[0]); if (count($fullnameParts) > 1) { $contactData['last_name'] = $this->formatValue($fullnameParts[1]); } - } elseif (Str::of($this->context->author->name_order)->startsWith('%last_name% %first_name%')) { + } elseif (Str::of($this->author()->name_order)->startsWith('%last_name% %first_name%')) { $contactData['last_name'] = $this->formatValue($fullnameParts[0]); if (count($fullnameParts) > 1) { $contactData['first_name'] = $this->formatValue($fullnameParts[1]); @@ -220,30 +220,6 @@ private function importNameFromFN(array $contactData, VCard $entry): array return $contactData; } - /** - * Import uid of the contact. - */ - private function importUid(array $contactData, VCard $entry): array - { - if (($uuid = $this->getUid($entry)) !== null && Uuid::isValid($uuid) && ! $this->context->external) { - $contactData['id'] = $uuid; - } - - return $contactData; - } - - /** - * Import uid of the contact. - */ - private function getUid(VCard $entry): ?string - { - if (! empty($uuid = (string) $entry->UID)) { - return $uuid; - } - - return null; - } - /** * Import gender of the contact. */ diff --git a/app/Models/Contact.php b/app/Models/Contact.php index 8a3725aee7a..2900e19b129 100644 --- a/app/Models/Contact.php +++ b/app/Models/Contact.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Domains\Contact\Dav\VCardResource; use App\Helpers\AvatarHelper; use App\Helpers\ContactImportantDateHelper; use App\Helpers\ImportantDateHelper; @@ -23,7 +24,7 @@ use Laravel\Scout\Attributes\SearchUsingPrefix; use Laravel\Scout\Searchable; -class Contact extends Model +class Contact extends Model implements VCardResource { use HasFactory, SoftDeletes, HasUuids; use Searchable;