Skip to content

Commit

Permalink
Allow multiple imported fields, replace existing
Browse files Browse the repository at this point in the history
  • Loading branch information
barryvdh committed Mar 6, 2018
1 parent f4b4d29 commit 75f5b60
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 53 deletions.
2 changes: 1 addition & 1 deletion app/Http/Controllers/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ public function storeImport(ImportsRequest $request)
'filename' => $filename,
]);

dispatch(new AddContactFromVCard($importJob));
dispatch(new AddContactFromVCard($importJob, $request->get('behaviour')));

return redirect()->route('settings.import');
}
Expand Down
113 changes: 64 additions & 49 deletions app/Jobs/AddContactFromVCard.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ class AddContactFromVCard implements ShouldQueue
const ERROR_CONTACT_EXIST = 'import_vcard_contact_exist';
const ERROR_CONTACT_DOESNT_HAVE_FIRSTNAME = 'import_vcard_contact_no_firstname';

const BEHAVIOUR_ADD = 'behaviour_add';
const BEHAVIOUR_REPLACE = 'behaviour_replace';

protected $importJob;
protected $behaviour;
protected $importedContacts = 0;
protected $skippedContacts = 0;
protected $gender;
Expand All @@ -40,9 +44,10 @@ class AddContactFromVCard implements ShouldQueue
*
* @return void
*/
public function __construct(ImportJob $importJob)
public function __construct(ImportJob $importJob, $behaviour = self::BEHAVIOUR_ADD)
{
$this->importJob = $importJob;
$this->behaviour = $behaviour;
}

/**
Expand All @@ -68,23 +73,27 @@ public function handle()
collect($matches[0])->map(function ($vcard) {
return Reader::read($vcard);
})->each(function (VCard $vcard) {
if ($this->contactExists($vcard, $this->importJob->account_id)) {

// Skip contact if there isn't a first name or a nickname
if (! $this->contactHasName($vcard)) {
$this->skippedContacts++;
$this->fileImportJobReport($vcard, self::VCARD_SKIPPED, self::ERROR_CONTACT_EXIST);
$this->fileImportJobReport($vcard, self::VCARD_SKIPPED, self::ERROR_CONTACT_DOESNT_HAVE_FIRSTNAME);

return;
}

// Skip contact if there isn't a first name or a nickname
if (! $this->contactHasName($vcard)) {
$contact = $this->existingContact($vcard, $this->importJob->account_id);
if ($contact && $this->behaviour === self::BEHAVIOUR_ADD) {
$this->skippedContacts++;
$this->fileImportJobReport($vcard, self::VCARD_SKIPPED, self::ERROR_CONTACT_DOESNT_HAVE_FIRSTNAME);
$this->fileImportJobReport($vcard, self::VCARD_SKIPPED, self::ERROR_CONTACT_EXIST);

return;
}

$contact = new Contact();
$contact->account_id = $this->importJob->account_id;
if (! $contact) {
$contact = new Contact();
$contact->account_id = $this->importJob->account_id;
}

if ($vcard->N && ! empty($vcard->N->getParts()[1])) {
$contact->first_name = $this->formatValue($vcard->N->getParts()[1]);
Expand All @@ -110,54 +119,60 @@ public function handle()
}

if ($vcard->ADR) {
$address = new Address();
$address->street = $this->formatValue($vcard->ADR->getParts()[2]);
$address->city = $this->formatValue($vcard->ADR->getParts()[3]);
$address->province = $this->formatValue($vcard->ADR->getParts()[4]);
$address->postal_code = $this->formatValue($vcard->ADR->getParts()[5]);

$country = Country::where('country', $vcard->ADR->getParts()[6])
->orWhere('iso', strtolower($vcard->ADR->getParts()[6]))
->first();

if ($country) {
$address->country_id = $country->id;
foreach ($vcard->ADR as $adr) {

$country = Country::where('country', $adr->getParts()[6])
->orWhere('iso', strtolower($adr->getParts()[6]))
->first();

Address::firstOrCreate([
'account_id' => $contact->account_id,
'contact_id' => $contact->id,
'street' => $this->formatValue($adr->getParts()[2]),
'city' => $this->formatValue($adr->getParts()[3]),
'province' => $this->formatValue($adr->getParts()[4]),
'postal_code' => $this->formatValue($adr->getParts()[5]),
'country_id' => $country ? $country->id : null,
]);
}

$address->contact_id = $contact->id;
$address->account_id = $contact->account_id;
$address->save();
}

if (! is_null($this->formatValue($vcard->EMAIL))) {
if ($vcard->EMAIL) {
// Saves the email
$contactFieldType = ContactFieldType::where('type', 'email')
->where('account_id', $contact->account_id)
->first();

if (! empty($contactFieldType)) {
$contactField = new ContactField;
$contactField->account_id = $contact->account_id;
$contactField->contact_id = $contact->id;
$contactField->data = $this->formatValue($vcard->EMAIL);
$contactField->contact_field_type_id = $contactFieldType->id;
$contactField->save();
if ($contactFieldType) {
foreach ($vcard->EMAIL as $data) {
ContactField::firstOrCreate([
'account_id' => $contact->account_id,
'contact_id' => $contact->id,
'data' => $this->formatValue($data),
'contact_field_type_id' => $contactFieldType->id,
]);
}
}

}

if (! is_null($this->formatValue($vcard->TEL))) {
if ($vcard->TEL) {
// Saves the phone number
$contactFieldType = ContactFieldType::where('type', 'phone')
->where('account_id', $contact->account_id)
->first();

if (! empty($contactFieldType)) {
$contactField = new ContactField;
$contactField->account_id = $contact->account_id;
$contactField->contact_id = $contact->id;
$contactField->data = $this->formatValue($vcard->TEL);
$contactField->contact_field_type_id = $contactFieldType->id;
$contactField->save();
foreach ($vcard->TEL as $data) {
ContactField::firstOrCreate([
'account_id' => $contact->account_id,
'contact_id' => $contact->id,
'data' => $this->formatValue($data),
'contact_field_type_id' => $contactFieldType->id,
]);
}

}
}

Expand All @@ -175,10 +190,15 @@ public function handle()
$this->importJob->save();
} catch (\Exception $e) {
$this->importJob->contacts_found = $numberOfContactsInTheFile;
$this->importJob->contacts_skipped = $this->skippedContacts;
$this->importJob->contacts_imported = $this->importedContacts;
$this->importJob->failed = 1;
$this->importJob->failed_reason = $e->getMessage();
$this->importJob->ended_at = \Carbon\Carbon::now();
$this->importJob->save();

logger($e);

Storage::disk('public')->delete($this->importJob->filename);
}

Expand Down Expand Up @@ -214,28 +234,23 @@ private function formatValue($value)
*
* @param VCard $vcard
* @param User $user
* @return bool
* @return Contact|null
*/
private function contactExists(VCard $vcard, $account_id)
private function existingContact(VCard $vcard, $account_id)
{
$email = (string) $vcard->EMAIL;

$contactFieldType = ContactFieldType::where([
['account_id', $account_id],
['type', 'email'],
])->first();

$contactField = null;

if ($contactFieldType) {
if ($vcard->EMAIL && $contactFieldType) {
$contactField = ContactField::where([
['account_id', $account_id],
['data', $email],
['contact_field_type_id', $contactFieldType->id],
])->first();
}
])->whereIn('data', iterator_to_array($vcard->EMAIL))->first();

return $email && $contactField;
return $contactField->contact;
}
}

private function fileImportJobReport(VCard $vcard, $status, $reason = null)
Expand Down
4 changes: 4 additions & 0 deletions resources/lang/en/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@
'import_upload_rule_time' => 'It might take up to 1 minute to upload the contacts and process them. Be patient.',
'import_upload_rule_cant_revert' => 'Make sure data is accurate before uploading, as you can\'t undo the upload.',
'import_upload_form_file' => 'Your <code>.vcf</code> or <code>.vCard</code> file:',
'import_upload_behaviour' => 'Import behaviour:',
'import_upload_behaviour_add' => 'Add new contacts, skip existing',
'import_upload_behaviour_replace' => 'Replace existing contacts',
'import_upload_behaviour_help' => 'Note: Replacing will replace all data found in the vCard, but will keep existing contact fields',
'import_report_title' => 'Importing report',
'import_report_date' => 'Date of the import',
'import_report_type' => 'Type of import',
Expand Down
8 changes: 6 additions & 2 deletions resources/views/settings/imports/index.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@
<li class="table-row">
<div class="table-cell">
@if (! is_null($importJob->ended_at))
@if ($importJob->contacts_found != $importJob->contacts_imported)
@if ($importJob->failed)
<i class="fa fa-exclamation-triangle danger"></i>
@elseif ($importJob->contacts_found != $importJob->contacts_imported)
<i class="fa fa-check-circle warning"></i>
@else
<i class="fa fa-check-circle success"></i>
Expand All @@ -55,7 +57,9 @@
<span class="date">{{ \App\Helpers\DateHelper::getShortDateWithTime($importJob->created_at) }}</span>
</div>
<div class="table-cell">
@if (! is_null($importJob->ended_at))
@if($importJob->failed_reason)
{{ $importJob->failed_reason }}
@elseif (! is_null($importJob->ended_at))
{{ trans('settings.import_result_stat', ['total_contacts' => $importJob->contacts_found, 'total_imported' => $importJob->contacts_imported, 'total_skipped' => $importJob->contacts_skipped]) }}
@endif
</div>
Expand Down
10 changes: 9 additions & 1 deletion resources/views/settings/imports/upload.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
<li>{!! trans('settings.import_upload_rule_format') !!}</li>
<li>{{ trans('settings.import_upload_rule_vcard') }}</li>
<li>{!! trans('settings.import_upload_rule_instructions') !!}</li>
<li>{{ trans('settings.import_upload_rule_multiple') }}</li>
<li>{{ trans('settings.import_upload_rule_limit') }}</li>
<li>{{ trans('settings.import_upload_rule_time') }}</li>
<li>{{ trans('settings.import_upload_rule_cant_revert') }}</li>
Expand All @@ -60,6 +59,15 @@
<small id="fileHelp" class="form-text text-muted">{{ trans('people.information_edit_max_size', ['size' => 10]) }}</small>
</div>

<div class="form-group">
<label for="behaviour">{!! trans('settings.import_upload_behaviour') !!}</label>
<select class="form-control" name="behaviour" id="behaviour">
<option value="{{ \App\Jobs\AddContactFromVCard::BEHAVIOUR_ADD }}" selected>{!! trans('settings.import_upload_behaviour_add') !!}</option>
<option value="{{ \App\Jobs\AddContactFromVCard::BEHAVIOUR_REPLACE }}">{!! trans('settings.import_upload_behaviour_replace') !!}</option>
</select>
<small id="behaviourHelp" class="form-text text-muted">{{ trans('settings.import_upload_behaviour_help') }}</small>
</div>

<div class="form-group actions">
<button type="submit" class="btn btn-primary">{{ trans('app.upload') }}</button>
<a href="/settings/import" class="btn btn-secondary">{{ trans('app.cancel') }}</a>
Expand Down

0 comments on commit 75f5b60

Please sign in to comment.