Skip to content

Commit

Permalink
Allow multiple imported fields, replace existing (#980)
Browse files Browse the repository at this point in the history
  • Loading branch information
barryvdh authored and asbiin committed May 13, 2018
1 parent 4abb99c commit acaa6a3
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 62 deletions.
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
UNRELEASED CHANGES:

* Add ability to sort contact list by untagged contacts
* Allow multiple imported fields and replace existing contacts

RELEASED VERSIONS:

Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,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: 61 additions & 52 deletions app/ImportJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ class ImportJob extends Model
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 $table = 'import_jobs';

/**
Expand Down Expand Up @@ -113,7 +116,7 @@ public function importJobReports()
*
* @return [type] [description]
*/
public function process()
public function process($behaviour = self::BEHAVIOUR_ADD)
{
$this->initJob();

Expand All @@ -123,7 +126,7 @@ public function process()

$this->getSpecialGender();

$this->processEntries();
$this->processEntries($behaviour);

$this->deletePhysicalFile();

Expand All @@ -138,6 +141,8 @@ public function process()
public function initJob(): void
{
$this->started_at = now();
$this->contacts_imported = 0;
$this->contacts_skipped = 0;
$this->save();
}

Expand Down Expand Up @@ -234,13 +239,13 @@ public function getEntries()
*
* @return
*/
public function processEntries()
public function processEntries($behaviour = self::BEHAVIOUR_ADD)
{
collect($this->entries[0])->map(function ($vcard) {
return Reader::read($vcard);
})->each(function (VCard $vCard) {
})->each(function (VCard $vCard) use ($behaviour) {
$this->currentEntry = $vCard;
$this->processSingleEntry();
$this->processSingleEntry($behaviour);
});
}

Expand All @@ -250,21 +255,22 @@ public function processEntries()
* @param VCard $vCard
* @return [type] [description]
*/
public function processSingleEntry()
public function processSingleEntry($behaviour = self::BEHAVIOUR_ADD)
{
if (! $this->checkImportFeasibility()) {
$this->skipEntry(self::ERROR_CONTACT_DOESNT_HAVE_FIRSTNAME);

return;
}

if ($this->contactExists()) {
$contact = $this->existingContact();
if ($contact && $behaviour === self::BEHAVIOUR_ADD) {
$this->skipEntry(self::ERROR_CONTACT_EXIST);

return;
}

$this->createContactFromCurrentEntry();
$this->createContactFromCurrentEntry($contact);
}

/**
Expand Down Expand Up @@ -309,36 +315,35 @@ public function isValidEmail(string $email): bool
/**
* Check whether the contact already exists in the database.
*
* @return bool
* @return Contact|null
*/
public function contactExists(): bool
public function existingContact()
{
if (is_null($this->currentEntry->EMAIL)) {
return false;
return;
}

$email = (string) $this->currentEntry->EMAIL;

if ($this->isValidEmail($email) == false) {
return false;
if (! $this->isValidEmail($email)) {
return;
}

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

$contactField = null;

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

return $email && $contactField;
if ($contactField) {
return $contactField->contact;
}
}
}

/**
Expand Down Expand Up @@ -398,12 +403,14 @@ private function formatValue($value)
*
* @return Contact
*/
public function createContactFromCurrentEntry()
public function createContactFromCurrentEntry($contact = null)
{
$contact = new \App\Contact;
$contact->account_id = $this->account_id;
$contact->gender_id = $this->gender->id;
$contact->save();
if (! $contact) {
$contact = new \App\Contact;
$contact->account_id = $this->account_id;
$contact->gender_id = $this->gender->id;
$contact->save();
}

$this->importNames($contact);
$this->importWorkInformation($contact);
Expand Down Expand Up @@ -481,21 +488,17 @@ public function importAddress(\App\Contact $contact): void
return;
}

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

$iso = CountriesHelper::find($this->currentEntry->ADR->getParts()[6]);

if ($iso) {
$address->country = $iso;
foreach ($this->currentEntry->ADR as $adr) {
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' => CountriesHelper::find($adr->getParts()[6]),
]);
}

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

/**
Expand All @@ -508,13 +511,15 @@ public function importEmail(\App\Contact $contact): void
return;
}

if ($this->isValidEmail($this->currentEntry->EMAIL)) {
$contactField = new \App\ContactField;
$contactField->contact_id = $contact->id;
$contactField->account_id = $contact->account_id;
$contactField->data = $this->formatValue($this->currentEntry->EMAIL);
$contactField->contact_field_type_id = $this->contactFieldEmailId();
$contactField->save();
foreach ($this->currentEntry->EMAIL as $email) {
if ($this->isValidEmail($email)) {
ContactField::firstOrCreate([
'account_id' => $contact->account_id,
'contact_id' => $contact->id,
'data' => $this->formatValue($email),
'contact_field_type_id' => $this->contactFieldEmailId(),
]);
}
}
}

Expand All @@ -524,13 +529,17 @@ public function importEmail(\App\Contact $contact): void
*/
public function importTel(\App\Contact $contact): void
{
if (! is_null($this->formatValue($this->currentEntry->TEL))) {
$contactField = new \App\ContactField;
$contactField->contact_id = $contact->id;
$contactField->account_id = $contact->account_id;
$contactField->data = $this->formatValue($this->currentEntry->TEL);
$contactField->contact_field_type_id = $this->contactFieldPhoneId();
$contactField->save();
if (is_null($this->currentEntry->TEL)) {
return;
}

foreach ($this->currentEntry->TEL as $tel) {
ContactField::firstOrCreate([
'account_id' => $contact->account_id,
'contact_id' => $contact->id,
'data' => $this->formatValue($tel),
'contact_field_type_id' => $this->contactFieldPhoneId(),
]);
}
}

Expand Down
6 changes: 4 additions & 2 deletions app/Jobs/AddContactFromVCard.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,17 @@ class AddContactFromVCard implements ShouldQueue
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

protected $importJob;
protected $behaviour;

/**
* Create a new job instance.
*
* @return void
*/
public function __construct(ImportJob $importJob)
public function __construct(ImportJob $importJob, $behaviour = ImportJob::BEHAVIOUR_ADD)
{
$this->importJob = $importJob;
$this->behaviour = $behaviour;
}

/**
Expand All @@ -32,6 +34,6 @@ public function __construct(ImportJob $importJob)
*/
public function handle()
{
$this->importJob->process();
$this->importJob->process($this->behaviour);
}
}
4 changes: 4 additions & 0 deletions resources/lang/en/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,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_choice('settings.import_result_stat', $importJob->contacts_found, ['total_contacts' => $importJob->contacts_found, 'total_imported' => $importJob->contacts_imported, 'total_skipped' => $importJob->contacts_skipped]) }}
@endif
</div>
Expand Down
17 changes: 13 additions & 4 deletions resources/views/settings/imports/upload.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,19 @@
<small id="fileHelp" class="form-text text-muted">{{ trans('people.information_edit_max_size', ['size' => 10]) }}</small>
</div>

<div class="form-group actions">
<button id="upload" type="submit" class="btn btn-primary">{{ trans('app.upload') }}</button>
<a href="/settings/import" class="btn btn-secondary">{{ trans('app.cancel') }}</a>
</div> <!-- .form-group -->
<div class="form-group">
<label for="behaviour">{{ trans('settings.import_upload_behaviour') }}</label>
<select class="form-control" name="behaviour" id="behaviour">
<option value="{{ \App\ImportJob::BEHAVIOUR_ADD }}" selected>{{ trans('settings.import_upload_behaviour_add') }}</option>
<option value="{{ \App\ImportJob::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 id="upload" type="submit" class="btn btn-primary">{{ trans('app.upload') }}</button>
<a href="/settings/import" class="btn btn-secondary">{{ trans('app.cancel') }}</a>
</div> <!-- .form-group -->
</form>
</div>
</div>
Expand Down
3 changes: 2 additions & 1 deletion tests/Unit/ImportJobTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,8 @@ public function test_it_checks_if_a_contact_exists()
]);

$importJob->currentEntry = $vcard;
$this->assertFalse($importJob->contactExists());
$contact = $importJob->existingContact();
$this->assertNull($contact);
}

public function test_it_returns_an_unknown_name_if_no_name_is_in_entry()
Expand Down

0 comments on commit acaa6a3

Please sign in to comment.