Skip to content
This repository was archived by the owner on Jun 8, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
wip
  • Loading branch information
djaiss committed Mar 11, 2022
commit bd7e7f6c34ec103c3c9d6dd7609ca8fda8268b62
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
class ScheduleContactReminder extends BaseService implements ServiceInterface
{
private ContactReminder $contactReminder;
private ScheduledContactReminder $scheduledContactReminder;
private array $data;
private Carbon $upcomingDate;

Expand Down Expand Up @@ -77,8 +76,7 @@ private function schedule(): void
$users = $this->contactReminder->contact->vault->users;

foreach ($users as $user) {

// we'll loop through all the user notification channel of this user
// we'll loop through all the user notification channels of this user
// and schedule the reminder for each of them
$notificationChannels = $user->notificationChannels;
foreach ($notificationChannels as $channel) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php

namespace App\Services\User\NotificationChannels;

use App\Models\User;
use App\Jobs\CreateAuditLog;
use App\Services\BaseService;
use App\Interfaces\ServiceInterface;
use App\Models\ScheduledContactReminder;
use App\Models\UserNotificationChannel;
use App\Models\Vault;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;

class ScheduleAllContactRemindersForNotificationChannel extends BaseService implements ServiceInterface
{
private array $data;
private UserNotificationChannel $userNotificationChannel;

/**
* Get the validation rules that apply to the service.
*
* @return array
*/
public function rules(): array
{
return [
'account_id' => 'required|integer|exists:accounts,id',
'author_id' => 'required|integer|exists:users,id',
'user_notification_channel_id' => 'required|integer|exists:user_notification_channels,id',
];
}

/**
* Get the permissions that apply to the user calling the service.
*
* @return array
*/
public function permissions(): array
{
return [
'author_must_belong_to_account',
];
}

/**
* Schedule all the contact reminders of the given user for a given user
* notification channel.
* This is useful when we create a new user notification channel, or when
* we activate a formerly inactive user notification channel.
*
* @param array $data
* @return UserNotificationChannel
*/
public function execute(array $data): UserNotificationChannel
{
$this->data = $data;
$this->validate();
$this->schedule();

return $this->userNotificationChannel;
}

private function validate(): void
{
$this->validateRules($this->data);

$this->userNotificationChannel = UserNotificationChannel::where('user_id', $this->data['author_id'])
->findOrFail($this->data['user_notification_channel_id']);
}

private function schedule(): void
{
$vaults = Vault::where('account_id', $this->data['account_id'])
->pluck('id')->toArray();

$contactReminders = DB::table('contact_reminders')
->join('contacts', 'contacts.id', '=', 'contact_reminders.contact_id')
->join('vaults', 'vaults.id', '=', 'contacts.vault_id')
->whereIn('vaults.id', $vaults)
->get();

foreach ($contactReminders as $contactReminder) {
if (!$contactReminder->year) {
$upcomingDate = Carbon::parse('1900-' . $contactReminder->month . '-' . $contactReminder->day);
} else {
$upcomingDate = Carbon::parse($contactReminder->year . '-' . $contactReminder->month . '-' . $contactReminder->day);
}

if ($upcomingDate->isPast()) {
$upcomingDate->year = Carbon::now()->year;

if ($upcomingDate->isPast()) {
$upcomingDate->year = Carbon::now()->addYear()->year;
}
}

$upcomingDate->shiftTimezone($this->userNotificationChannel->user->timezone);
$upcomingDate->hour = $this->userNotificationChannel->preferred_time->hour;
$upcomingDate->minute = $this->userNotificationChannel->preferred_time->minute;

$this->scheduledContactReminder = ScheduledContactReminder::create([
'contact_reminder_id' => $contactReminder->id,
'user_notification_channel_id' => $this->userNotificationChannel->id,
'user_id' => $this->userNotificationChannel->user->id,
'scheduled_at' => $upcomingDate->tz('UTC'),
]);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use App\Services\BaseService;
use App\Interfaces\ServiceInterface;
use App\Models\UserNotificationChannel;
use Illuminate\Support\Facades\DB;

class ToggleUserNotificationChannel extends BaseService implements ServiceInterface
{
Expand Down Expand Up @@ -50,6 +51,7 @@ public function execute(array $data): UserNotificationChannel
$this->data = $data;
$this->validate();
$this->toggle();
$this->updateScheduledReminders();
$this->log();

return $this->userNotificationChannel;
Expand All @@ -68,6 +70,39 @@ private function toggle(): void
$this->userNotificationChannel->save();
}

/**
* If the notification channel is deactivated, we need to delete all the
* upcoming scheduled reminders for that channel.
* If the notification channel is reactivated, we need to reschedule all
* the contact reminders for this channel specifically.
*
* @return void
*/
private function updateScheduledReminders(): void
{
if ($this->userNotificationChannel->active) {
$this->rescheduledReminders();
} else {
$this->deleteScheduledReminders();
}
}

private function deleteScheduledReminders(): void
{
DB::table('scheduled_contact_reminders')
->where('user_notification_channel_id', $this->userNotificationChannel->id)
->delete();
}

private function rescheduledReminders(): void
{
(new ScheduleAllContactRemindersForNotificationChannel)->execute([
'account_id' => $this->data['account_id'],
'author_id' => $this->data['author_id'],
'user_notification_channel_id' => $this->userNotificationChannel->id,
]);
}

private function log(): void
{
CreateAuditLog::dispatch([
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace Tests\Unit\Services\Contact\ManageReminder;

use Carbon\Carbon;
use Tests\TestCase;
use App\Models\Vault;
use App\Models\Contact;
use App\Models\ContactReminder;
use App\Models\UserNotificationChannel;
use Illuminate\Validation\ValidationException;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use App\Services\Contact\ManageReminder\ScheduleContactReminder;
use App\Services\User\NotificationChannels\ScheduleAllContactRemindersForNotificationChannel;

class ScheduleAllContactRemindersForNotificationChannelTest extends TestCase
{
use DatabaseTransactions;

/** @test */
public function it_schedules_reminders(): void
{
Carbon::setTestNow(Carbon::create(2018, 1, 1));

$regis = $this->createUser();
$regis->timezone = 'UTC';
$regis->save();

$vaultA = $this->createVault($regis->account);
$vaultA = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vaultA);
$contact = Contact::factory()->create(['vault_id' => $vaultA->id]);

$reminderA = ContactReminder::factory()->create([
'contact_id' => $contact->id,
'type' => ContactReminder::TYPE_ONE_TIME,
'day' => 2,
'month' => 10,
'year' => 2000,
]);

$vaultB = $this->createVault($regis->account);
$vaultB = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vaultB);
$contact = Contact::factory()->create(['vault_id' => $vaultB->id]);

$reminderB = ContactReminder::factory()->create([
'contact_id' => $contact->id,
'type' => ContactReminder::TYPE_ONE_TIME,
'day' => 2,
'month' => 10,
'year' => 1090,
]);
$channel = UserNotificationChannel::factory()->create([
'user_id' => $regis->id,
'preferred_time' => '18:00',
]);

$request = [
'account_id' => $regis->account_id,
'author_id' => $regis->id,
'user_notification_channel_id' => $channel->id,
];

(new ScheduleAllContactRemindersForNotificationChannel)->execute($request);

$this->assertDatabaseHas('scheduled_contact_reminders', [
'contact_reminder_id' => $reminderA->id,
'user_notification_channel_id' => $channel->id,
'scheduled_at' => '2018-10-02 18:00:00',
]);
$this->assertDatabaseHas('scheduled_contact_reminders', [
'contact_reminder_id' => $reminderB->id,
'user_notification_channel_id' => $channel->id,
'scheduled_at' => '2018-10-02 18:00:00',
]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,39 @@
use Tests\TestCase;
use App\Models\User;
use App\Jobs\CreateAuditLog;
use App\Models\Contact;
use App\Models\ContactReminder;
use Illuminate\Support\Facades\Queue;
use App\Models\UserNotificationChannel;
use App\Models\Vault;
use Illuminate\Validation\ValidationException;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use App\Services\User\NotificationChannels\ToggleUserNotificationChannel;
use Carbon\Carbon;

class ToggleUserNotificationChannelTest extends TestCase
{
use DatabaseTransactions;

/** @test */
public function it_toggles_the_channel(): void
public function it_toggles_the_channel_if_the_channel_was_inactive(): void
{
$ross = $this->createUser();
$channel = UserNotificationChannel::factory()->create([
'user_id' => $ross->id,
'active' => false,
]);
$vault = $this->createVault($ross->account);
$vault = $this->setPermissionInVault($ross, Vault::PERMISSION_EDIT, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
ContactReminder::factory()->create([
'contact_id' => $contact->id,
'type' => ContactReminder::TYPE_ONE_TIME,
'day' => 2,
'month' => 10,
'year' => 2000,
]);
$this->executeService($ross, $channel);
}

Expand Down Expand Up @@ -53,6 +67,7 @@ public function it_fails_if_notification_channel_doesnt_belong_to_user(): void
private function executeService(User $author, UserNotificationChannel $channel): void
{
Queue::fake();
Carbon::setTestNow(Carbon::create(2018, 1, 1));

$request = [
'account_id' => $author->account_id,
Expand All @@ -73,6 +88,11 @@ private function executeService(User $author, UserNotificationChannel $channel):
$channel
);

$this->assertDatabaseHas('scheduled_contact_reminders', [
'user_notification_channel_id' => $channel->id,
'scheduled_at' => '2018-10-02 09:00:00',
]);

Queue::assertPushed(CreateAuditLog::class, function ($job) {
return $job->auditLog['action_name'] === 'user_notification_channel_toggled';
});
Expand Down
Loading