Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
asbiin committed Aug 3, 2023
1 parent bf977a5 commit 3fcf454
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 224 deletions.
7 changes: 3 additions & 4 deletions app/Domains/Contact/Dav/ImportVCardResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace App\Domains\Contact\Dav;

use App\Domains\Contact\Dav\Services\ImportVCard;
use App\Models\Contact;
use Sabre\VObject\Component\VCard;

interface ImportVCardResource
Expand All @@ -14,12 +13,12 @@ interface ImportVCardResource
public function setContext(ImportVCard $context): self;

/**
* Can import Contact.
* Can import Card.
*/
public function can(VCard $vcard): bool;

/**
* Import Contact.
* Import Card.
*/
public function import(?Contact $contact, VCard $vcard): ?Contact;
public function import(VCard $vcard, mixed $result): mixed;
}
31 changes: 4 additions & 27 deletions app/Domains/Contact/Dav/Jobs/UpdateVCard.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@

use App\Domains\Contact\Dav\Services\GetEtag;
use App\Domains\Contact\Dav\Services\ImportVCard;
use App\Domains\Contact\Dav\Web\Backend\CardDAV\CardDAVBackend;
use App\Interfaces\ServiceInterface;
use App\Models\Contact;
use App\Services\QueuableService;
use Closure;
use Illuminate\Bus\Batchable;
Expand Down Expand Up @@ -66,8 +64,8 @@ public function execute(array $data): void
$this->withLocale($this->author->preferredLocale(), function () {
$newtag = $this->updateCard($this->data['uri'], $this->data['card']);

if (($etag = Arr::get($this->data, 'etag')) !== null && $newtag !== $etag) {
Log::warning(__CLASS__.' '.__FUNCTION__.' wrong etag when updating contact. Expected '.$etag.', get '.$newtag, [
if ($newtag !== null && ($etag = Arr::get($this->data, 'etag')) !== null && $newtag !== $etag) {
Log::warning(__CLASS__.' '.__FUNCTION__." wrong etag when updating contact. Expected [$etag], got [$newtag]", [
'contacturl' => $this->data['uri'],
'carddata' => $this->data['card'],
]);
Expand All @@ -80,31 +78,11 @@ public function execute(array $data): void
*/
private function updateCard(string $uri, mixed $card): ?string
{
$backend = app(CardDAVBackend::class)->withUser($this->author);

$contactId = null;
if ($uri) {
$contactObject = $backend->getObject($this->vault->id, $uri);
if ($contactObject) {
$contactId = $contactObject->id;
} else {
$contactObject = Contact::firstWhere([
'vault_id' => $this->vault->id,
'distant_uri' => $uri,
]);

if ($contactObject) {
$contactId = $contactObject->id;
}
}
}

try {
$result = app(ImportVCard::class)->execute([
'account_id' => $this->author->account_id,
'author_id' => $this->author->id,
'vault_id' => $this->vault->id,
'contact_id' => $contactId,
'entry' => $card,
'etag' => Arr::get($this->data, 'etag'),
'uri' => $uri,
Expand All @@ -117,13 +95,12 @@ private function updateCard(string $uri, mixed $card): ?string
'account_id' => $this->author->account_id,
'author_id' => $this->author->id,
'vault_id' => $this->vault->id,
'contact_id' => $result['contact_id'],
'entry' => $result['entry'],
]);
}
} catch (\Exception $e) {
Log::error(__CLASS__.' '.__FUNCTION__.': '.$e->getMessage(), [
'contacturl' => $uri,
'contact_id' => $contactId,
'uri' => $uri,
'carddata' => $card,
$e,
]);
Expand Down
7 changes: 4 additions & 3 deletions app/Domains/Contact/Dav/Services/ExportVCard.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@ public function execute(array $data): VCard

$vcard = $this->export($this->contact);

$this->contact->timestamps = false;
$this->contact->vcard = $vcard->serialize();
$this->contact->save();
Contact::withoutTimestamps(function () use ($vcard): void {
$this->contact->vcard = $vcard->serialize();
$this->contact->save();
});

return $vcard;
}
Expand Down
12 changes: 9 additions & 3 deletions app/Domains/Contact/Dav/Services/GetEtag.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use App\Interfaces\ServiceInterface;
use App\Services\BaseService;
use Illuminate\Database\Eloquent\ModelNotFoundException;

class GetEtag extends BaseService implements ServiceInterface
{
Expand All @@ -16,7 +17,7 @@ public function rules(): array
'account_id' => 'required|uuid|exists:accounts,id',
'author_id' => 'required|uuid|exists:users,id',
'vault_id' => 'required|uuid|exists:vaults,id',
'contact_id' => 'required|uuid|exists:contacts,id',
'entry' => 'required',
];
}

Expand All @@ -29,7 +30,6 @@ public function permissions(): array
'author_must_belong_to_account',
'vault_must_belong_to_account',
'author_must_be_in_vault',
'contact_must_belong_to_vault',
];
}

Expand All @@ -40,6 +40,12 @@ public function execute(array $data): string
{
$this->validateRules($data);

return $this->contact->distant_etag ?? '"'.hash('sha256', $this->contact->vcard).'"';
$entry = $data['entry'];

if ($entry->vault_id !== $this->vault->id) {
throw new ModelNotFoundException();
}

return $entry->distant_etag ?? '"'.hash('sha256', $entry->vcard).'"';
}
}
131 changes: 24 additions & 107 deletions app/Domains/Contact/Dav/Services/ImportVCard.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use App\Domains\Contact\Dav\ImportVCardResource;
use App\Domains\Contact\Dav\Order;
use App\Interfaces\ServiceInterface;
use App\Models\Contact;
use App\Services\BaseService;
use App\Traits\DAVFormat;
use Closure;
Expand Down Expand Up @@ -62,6 +61,8 @@ class ImportVCard extends BaseService implements ServiceInterface

public bool $external = false;

public ?array $data = null;

private ?Collection $importers = null;

/**
Expand Down Expand Up @@ -115,25 +116,21 @@ public function __construct(
*/
public function execute(array $data): array
{
$this->data = $data;

$this->validateRules($data);

$this->external = Arr::get($data, 'external', false);

if (Arr::get($data, 'contact_id') !== null) {
$this->validateContactBelongsToVault($data);

return $this->process($data, $this->contact);
} else {
return $this->process($data, null);
}
return $this->process($data);
}

/**
* Process data importation.
*
* @return array<string,mixed>
*/
private function process(array $data, ?Contact $contact): array
private function process(array $data): array
{
/**
* @var VCard|null $entry
Expand All @@ -145,11 +142,10 @@ private function process(array $data, ?Contact $contact): array
return [
'error' => self::ERROR_PARSER,
'reason' => static::$errorResults[self::ERROR_PARSER],
'name' => '(unknow)',
];
}

return $this->processEntry($data, $contact, $entry, $vcard);
return $this->processEntry($entry, $vcard);
}

/**
Expand Down Expand Up @@ -179,98 +175,50 @@ private function getEntry(array $data): array
*
* @return array<string,mixed>
*/
private function processEntry(array $data, ?Contact $contact, VCard $entry, string $vcard): array
private function processEntry(VCard $entry, string $vcard): array
{
if (! $this->canImportCurrentEntry($entry)) {
return [
'error' => self::ERROR_CARD_NOT_IMPORTABLE,
'reason' => static::$errorResults[self::ERROR_CARD_NOT_IMPORTABLE],
'name' => $this->name($entry),
];
}

if ($contact === null) {
$contact = $this->getExistingContact($data, $entry);
}

return $this->processEntryContact($data, $contact, $entry, $vcard);
return $this->processEntryContact($entry, $vcard);
}

/**
* Process entry importation.
*
* @return array<string,mixed>
*/
private function processEntryContact(array $data, ?Contact $contact, VCard $entry, string $vcard): array
private function processEntryContact(VCard $entry, string $vcard): array
{
$behaviour = $data['behaviour'] ?? self::BEHAVIOUR_ADD;
if ($contact && $behaviour === self::BEHAVIOUR_ADD) {
return [
'contact_id' => $contact->id,
'error' => self::ERROR_CONTACT_EXIST,
'reason' => static::$errorResults[self::ERROR_CONTACT_EXIST],
'name' => $this->name($entry),
];
}
$result = $this->importEntry($entry);

$contact = $this->importEntry($contact, $entry);

if ($contact === null) {
if ($result === null) {
return [
'error' => self::ERROR_CARD_NOT_IMPORTABLE,
'reason' => static::$errorResults[self::ERROR_CARD_NOT_IMPORTABLE],
'name' => $this->name($entry),
];
}

// Save vcard content
$contact->vcard = $vcard;

$contact = Contact::withoutTimestamps(function () use ($contact, $data): Contact {
$uri = Arr::get($data, 'uri');
if (Arr::get($data, 'external', false)) {
$contact->distant_etag = Arr::get($data, 'etag');
$contact->distant_uri = $uri;
}
$result = $result->withoutTimestamps(function () use ($result, $vcard): mixed {
$result->vcard = $vcard;
$result->save();

$contact->save();

return $contact;
return $result;
});

return [
'contact_id' => $contact->id,
'name' => $this->name($entry),
'id' => $result->id,
'entry' => $result,
];
}

/**
* Return the name of current entry.
* Only used for report display.
*
* @param VCard $entry
*/
private function name($entry): string
{
if ($entry->N !== null) {
return trim(implode(' ', $entry->N->getParts()));
}
if ($entry->FN !== null) {
return (string) $entry->FN;
}
if ($entry->EMAIL !== null) {
return (string) $entry->EMAIL;
}
if ($entry->NICKNAME !== null) {
return (string) $entry->NICKNAME;
}

return (string) trans('Unknown contact name');
}

/**
* Check whether a contact has a first name or a nickname. If not, contact
* can not be imported.
* Check whether an importer can import this card.
*/
private function canImportCurrentEntry(VCard $entry): bool
{
Expand All @@ -284,50 +232,19 @@ private function canImportCurrentEntry(VCard $entry): bool
}

/**
* Check whether the contact already exists in the database.
* Create the object matching the current entry.
*/
private function getExistingContact(array $data, VCard $entry): ?Contact
private function importEntry(VCard $entry): mixed
{
if ($this->external && $uri = Arr::get($data, 'uri')) {
return Contact::firstWhere([
'vault_id' => $this->vault->id,
'distant_uri' => $uri,
]);
}

return $this->existingUuid($entry);
}
$result = null;

/**
* Search with uuid.
*/
private function existingUuid(VCard $entry): ?Contact
{
return ! empty($uuid = (string) $entry->UID)
?
Contact::firstWhere([
'vault_id' => $this->vault->id,
'distant_uuid' => $uuid,
]) ??
Contact::firstWhere([
'vault_id' => $this->vault->id,
'id' => $uuid,
])
: null;
}

/**
* Create the Contact object matching the current entry.
*/
private function importEntry(?Contact $contact, VCard $entry): ?Contact
{
foreach ($this->importers() as $importer) {
if ($importer->can($entry)) {
$contact = $importer->import($contact, $entry);
$result = $importer->import($entry, $result);
}
}

return $contact;
return $result;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ public function prepareCard(Contact $contact): array
'account_id' => $this->user->account_id,
'author_id' => $this->user->id,
'vault_id' => $contact->vault_id,
'contact_id' => $contact->id,
'entry' => $contact->refresh(),
]);

return [
Expand Down
Loading

0 comments on commit 3fcf454

Please sign in to comment.