Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 29 additions & 172 deletions app/Console/Commands/ImportVCards.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,15 @@
namespace App\Console\Commands;

use App\User;
use App\Gender;
use App\Address;
use App\Contact;
use App\Country;
use App\ContactField;
use App\ContactFieldType;
use Sabre\VObject\Reader;
use App\Traits\VCardImporter;
use Illuminate\Console\Command;
use Sabre\VObject\Component\VCard;
use Illuminate\Filesystem\Filesystem;

class ImportVCards extends Command
{
use VCardImporter;

/**
* The name and signature of the console command.
*
Expand All @@ -29,17 +25,8 @@ class ImportVCards extends Command
* @var string
*/
protected $description = 'Imports contacts from vCard files for a specific user';
protected $gender;

/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
private $path;

/**
* Execute the console command.
Expand All @@ -49,7 +36,7 @@ public function __construct()
*/
public function handle(Filesystem $filesystem)
{
$path = './'.$this->argument('path');
$this->path = './'.$this->argument('path');

$user = User::where('email', $this->argument('user'))->first();

Expand All @@ -59,178 +46,48 @@ public function handle(Filesystem $filesystem)
return;
}

if (! $filesystem->exists($path) || $filesystem->extension($path) !== 'vcf') {
if (! $filesystem->exists($this->path) || $filesystem->extension($this->path) !== 'vcf') {
$this->error('The provided vcard file was not found or is not valid!');

return;
}

$matchCount = preg_match_all('/(BEGIN:VCARD.*?END:VCARD)/s', $filesystem->get($path), $matches);

$this->info("We found {$matchCount} contacts in {$path}.");

if ($this->confirm('Would you like to import them?', true)) {
$this->info("Importing contacts from {$path}");

$this->output->progressStart($matchCount);

$skippedContacts = 0;

// create special gender for this import
// we don't know which gender all the contacts are, so we need to create a special status for them, as we
// can't guess whether they are men, women or else.
$this->gender = new Gender;
$this->gender->account_id = $user->account_id;
$this->gender->name = 'vCard';
$this->gender->save();

collect($matches[0])->map(function ($vcard) {
return Reader::read($vcard);
})->each(function (VCard $vcard) use ($user, $skippedContacts) {
if ($this->contactExists($vcard, $user)) {
$this->output->progressAdvance();
$skippedContacts++;

return;
}

// Skip contact if there isn't a first name or a nickname
if (! $this->contactHasName($vcard)) {
$this->output->progressAdvance();
$skippedContacts++;

return;
}

$contact = new Contact();
$contact->account_id = $user->account_id;

if ($vcard->N && ! empty($vcard->N->getParts()[1])) {
$contact->first_name = $this->formatValue($vcard->N->getParts()[1]);
$contact->middle_name = $this->formatValue($vcard->N->getParts()[2]);
$contact->last_name = $this->formatValue($vcard->N->getParts()[0]);
} else {
$contact->first_name = $this->formatValue($vcard->NICKNAME);
}

$contact->gender_id = $this->gender->id;
$contact->job = $this->formatValue($vcard->ORG);

$contact->setAvatarColor();

$contact->save();

if ($vcard->BDAY && ! empty((string) $vcard->BDAY)) {
$birthdate = new \DateTime((string) $vcard->BDAY);

$specialDate = $contact->setSpecialDate('birthdate', $birthdate->format('Y'), $birthdate->format('m'), $birthdate->format('d'));
$specialDate->setReminder('year', 1, trans('people.people_add_birthday_reminder', ['name' => $contact->first_name]));
}

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();
$this->work($user->account_id, $filesystem->get($this->path));
}

if ($country) {
$address->country_id = $country->id;
}
protected function workInit($matchCount)
{
$this->info("We found {$matchCount} contacts in {$this->path}.");

$address->contact_id = $contact->id;
$address->account_id = $contact->account_id;
$address->save();
}
if (! $this->confirm('Would you like to import them?', true)) {
return false;
}

if (! is_null($this->formatValue($vcard->EMAIL))) {
// Saves the email
$contactFieldType = ContactFieldType::where('type', 'email')->first();
$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();
}
$this->info("Importing contacts from {$this->path}");
$this->output->progressStart($matchCount);

if (! is_null($this->formatValue($vcard->TEL))) {
// Saves the phone number
$contactFieldType = ContactFieldType::where('type', 'phone')->first();
$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();
}

$contact->updateGravatar();

$contact->logEvent('contact', $contact->id, 'create');

$this->output->progressAdvance();
});

$this->output->progressFinish();

$this->info("Successfully imported {$matchCount} contacts and skipped {$skippedContacts}.");
}
return true;
}

/**
* Formats and returns a string for the contact.
*
* @param null|string $value
* @return null|string
*/
private function formatValue($value)
protected function workContactExists($vcard)
{
return ! empty((string) $value) ? (string) $value : null;
$this->output->progressAdvance();
}

/**
* Checks whether a contact already exists for a given account.
*
* @param VCard $vcard
* @param User $user
* @return bool
*/
private function contactExists(VCard $vcard, User $user)
protected function workContactNoFirstname($vcard)
{
$email = (string) $vcard->EMAIL;

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

$contactField = null;

if ($contactFieldType) {
$contactField = ContactField::where([
['account_id', $user->account_id],
['data', $email],
['contact_field_type_id', $contactFieldType->id],
])->first();
}
$this->output->progressAdvance();
}

return $email && $contactField;
protected function workNext($vcard)
{
$this->output->progressAdvance();
}

/**
* Checks whether a contact has a first name or a nickname.
* Nickname is used as a fallback if no first name is provided.
*
* @param VCard $vcard
* @return bool
*/
public function contactHasName(VCard $vcard): bool
protected function workEnd($numberOfContactsInTheFile, $skippedContacts, $importedContacts)
{
return ! empty($vcard->N->getParts()[1]) || ! empty((string) $vcard->NICKNAME);
$this->output->progressFinish();

$this->info("Successfully imported {$importedContacts} contacts and skipped {$skippedContacts}.");
}
}
32 changes: 18 additions & 14 deletions app/Console/Commands/SendReminders.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,29 @@ public function handle()
$reminder->delete();
continue;
}
$this->handleReminder($reminder);
}
}

$account = $reminder->contact->account;
$numberOfUsersInAccount = $account->users->count();
$counter = 1;
private function handleReminder($reminder)
{
$account = $reminder->contact->account;
$numberOfUsersInAccount = $account->users->count();
$counter = 1;

foreach ($account->users as $user) {
if ($user->shouldBeReminded($reminder->next_expected_date)) {
if (! $account->hasLimitations()) {
dispatch(new SendReminderEmail($reminder, $user));
}
foreach ($account->users as $user) {
if ($user->shouldBeReminded($reminder->next_expected_date)) {
if (! $account->hasLimitations()) {
dispatch(new SendReminderEmail($reminder, $user));
}

if ($counter == $numberOfUsersInAccount) {
// We should only do this when we are sure that this is
// the last user who should be warned in this account.
dispatch(new SetNextReminderDate($reminder, $user->timezone));
}
if ($counter == $numberOfUsersInAccount) {
// We should only do this when we are sure that this is
// the last user who should be warned in this account.
dispatch(new SetNextReminderDate($reminder, $user->timezone));
}
$counter++;
}
$counter++;
}
}
}
64 changes: 29 additions & 35 deletions app/Contact.php
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ public function logEvent($objectType, $objectId, $natureOfOperation)
* @param string $lastName
* @return bool
*/
public function setName(String $firstName, String $middleName = null, String $lastName)
public function setName(String $firstName, String $lastName, String $middleName = null)
{
if ($firstName == '') {
return false;
Expand Down Expand Up @@ -1422,40 +1422,34 @@ public function removeSpecialDate($occasion)
return;
}

if ($occasion == 'birthdate') {
if (! $this->birthday_special_date_id) {
return;
}

$this->birthdate->deleteReminder();
$this->birthdate->delete();

$this->birthday_special_date_id = null;
$this->save();
}

if ($occasion == 'deceased_date') {
if (! $this->deceased_special_date_id) {
return;
}

$this->deceasedDate->deleteReminder();
$this->deceasedDate->delete();

$this->deceased_special_date_id = null;
$this->save();
}

if ($occasion == 'first_met') {
if (! $this->first_met_special_date_id) {
return;
}

$this->firstMetDate->deleteReminder();
$this->firstMetDate->delete();

$this->first_met_special_date_id = null;
$this->save();
switch ($occasion) {
case 'birthdate':
if ($this->birthday_special_date_id) {
$this->birthdate->deleteReminder();
$this->birthdate->delete();

$this->birthday_special_date_id = null;
$this->save();
}
break;
case 'deceased_date':
if ($this->deceased_special_date_id) {
$this->deceasedDate->deleteReminder();
$this->deceasedDate->delete();

$this->deceased_special_date_id = null;
$this->save();
}
break;
case 'first_met':
if ($this->first_met_special_date_id) {
$this->firstMetDate->deleteReminder();
$this->firstMetDate->delete();

$this->first_met_special_date_id = null;
$this->save();
}
break;
}
}

Expand Down
Loading