Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add notifications system #36

Merged
merged 9 commits into from
Oct 30, 2023
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
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fleetbase/core-api",
"version": "1.3.1",
"version": "1.3.2",
"description": "Core Framework and Resources for Fleetbase API",
"keywords": [
"fleetbase",
Expand Down
35 changes: 35 additions & 0 deletions migrations/2023_10_18_080950_create_notifications_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateNotificationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('notifications', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('type');
$table->uuidMorphs('notifiable');
$table->text('data');
$table->timestamp('read_at')->nullable();
$table->timestamps();
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('notifications');
}
}
8 changes: 5 additions & 3 deletions src/Http/Controllers/Internal/v1/AuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -275,10 +275,12 @@ public function createPasswordReset(UserForgotPasswordRequest $request)
*/
public function resetPassword(ResetPasswordRequest $request)
{
// get verification code
$verificationCode = VerificationCode::where('code', $request->input('code'))->with(['subject'])->first();
$link = $request->input('link');
$password = $request->input('password');

if ($verificationCode->uuid !== $request->input('link')) {
// If link isn't valid
if ($verificationCode->uuid !== $link) {
return response()->error('Invalid password reset request!');
}

Expand All @@ -288,7 +290,7 @@ public function resetPassword(ResetPasswordRequest $request)
}

// reset users password
$verificationCode->subject->changePassword($request->input('password'));
$verificationCode->subject->changePassword($password);

// verify code by deleting so its unusable
$verificationCode->delete();
Expand Down
167 changes: 167 additions & 0 deletions src/Http/Controllers/Internal/v1/NotificationController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
<?php

namespace Fleetbase\Http\Controllers\Internal\v1;

use Fleetbase\Http\Controllers\FleetbaseController;
use Fleetbase\Models\Notification;
use Fleetbase\Models\Setting;
use Fleetbase\Support\NotificationRegistry;
use Illuminate\Http\Request;

/**
* Controller for managing notifications.
*/
class NotificationController extends FleetbaseController
{
/**
* The resource to query.
*
* @var string
*/
public $resource = 'notification';

/**
* Receives an array of ID's for notifications which should be marked as read.
*
* @param \Illuminate\Http\Request $request the HTTP request object
*
* @return \Illuminate\Http\Response the HTTP response
*/
public function markAsRead(Request $request)
{
$notifications = $request->input('notifications');
$total = count($notifications);
$read = [];

foreach ($notifications as $id) {
$notification = Notification::where('id', $id)->first();

if ($notification) {
$read[] = $notification->markAsRead();
}
}

return response()->json([
'status' => 'ok',
'message' => 'Notifications marked as read',
'marked_as_read' => count($read),
'total' => $total,
]);
}

/**
* Receives an array of ID's for notifications which should be marked as read.
*
* @return \Illuminate\Http\Response the HTTP response
*/
public function markAllAsRead()
{
$notifications = Notification::where('notifiable_id', session('user'))->get();

foreach ($notifications as $notification) {
$notification->markAsRead();
}

return response()->json([
'status' => 'ok',
'message' => 'All notifications marked as read',
]);
}

/**
* Deletes a single notification.
*
* @param int $notificationId the ID of the notification to delete
*
* @return \Illuminate\Http\Response the HTTP response
*/
public function deleteNotification($notificationId)
{
$notification = Notification::find($notificationId);

if ($notification) {
$notification->deleteNotification();

return response()->json(['message' => 'Notification deleted successfully'], 200);
} else {
return response()->json(['error' => 'Notification not found'], 404);
}
}

/**
* Deletes all notifications for the authenticated user.
*
* @param \Illuminate\Http\Request $request the HTTP request object
*
* @return \Illuminate\Http\Response the HTTP response
*/
public function bulkDelete(Request $request)
{
$notifications = $request->input('notifications');

if (empty($notifications)) {
Notification::where('notifiable_id', session('user'))->delete();
} else {
Notification::whereIn('id', $notifications)->delete();
}

return response()->json([
'status' => 'ok',
'message' => 'Selected notifications deleted successfully',
]);
}

/**
* Get the list of registered notifications from the NotificationRegistry.
*
* @return \Illuminate\Http\JsonResponse The JSON response
*/
public function registry()
{
return response()->json(NotificationRegistry::$notifications);
}

public function notifiables()
{
return response()->json(NotificationRegistry::getNotifiables());
}

/**
* Save user notification settings.
*
* @param Request $request the HTTP request object containing the notification settings data
*
* @return \Illuminate\Http\JsonResponse a JSON response
*
* @throws \Exception if the provided notification settings data is not an array
*/
public function saveSettings(Request $request)
{
$notificationSettings = $request->input('notificationSettings');
if (!is_array($notificationSettings)) {
throw new \Exception('Invalid notification settings data.');
}
Setting::configure('notification_settings', $notificationSettings);

return response()->json([
'status' => 'ok',
'message' => 'Notification settings succesfully saved.',
]);
}

/**
* Retrieve and return the notification settings for the user.
*
* @return \Illuminate\Http\JsonResponse
*/
public function getSettings()
{
$notificationSettings = Setting::lookup('notification_settings');

return response()->json([
'status' => 'ok',
'message' => 'Notification settings successfully fetched.',
'notificationSettings' => $notificationSettings,
]);
}
}
5 changes: 5 additions & 0 deletions src/Http/Controllers/Internal/v1/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
use Fleetbase\Models\CompanyUser;
use Fleetbase\Models\Invite;
use Fleetbase\Models\User;
use Fleetbase\Notifications\UserAcceptedCompanyInvite;
use Fleetbase\Notifications\UserInvited;
use Fleetbase\Support\NotificationRegistry;
use Fleetbase\Support\Utils;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
Expand Down Expand Up @@ -182,6 +184,9 @@ public function acceptCompanyInvite(AcceptCompanyInvite $request)
// create authentication token for user
$token = $user->createToken($invite->code);

// Notify company that user has accepted their invite
NotificationRegistry::notify(UserAcceptedCompanyInvite::class, $company, $user);

return response()->json([
'status' => 'ok',
'token' => $token->plainTextToken,
Expand Down
26 changes: 26 additions & 0 deletions src/Http/Filter/NotificationFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Fleetbase\Http\Filter;

class NotificationFilter extends Filter
{
public function queryForInternal()
{
$this->builder->where(function ($q) {
$q->where('notifiable_id', $this->session->get('company'));
$q->orWhere('notifiable_id', $this->session->get('user'));
});
}

public function query(?string $query)
{
$this->builder->search($query);
}

public function unread(?bool $unread)
{
if ($unread) {
$this->builder->whereNull('read_at');
}
}
}
2 changes: 2 additions & 0 deletions src/Models/Company.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Fleetbase\Traits\Searchable;
use Fleetbase\Traits\SendsWebhooks;
use Fleetbase\Traits\TracksApiCredential;
use Illuminate\Notifications\Notifiable;
use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;

Expand All @@ -23,6 +24,7 @@ class Company extends Model
use HasSlug;
use Searchable;
use SendsWebhooks;
use Notifiable;

/**
* The database connection to use.
Expand Down
18 changes: 18 additions & 0 deletions src/Models/Group.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@
use Fleetbase\Traits\HasApiModelBehavior;
use Fleetbase\Traits\HasPolicies;
use Fleetbase\Traits\HasUuid;
use Illuminate\Notifications\Notifiable;
use Spatie\Permission\Traits\HasPermissions;
use Spatie\Permission\Traits\HasRoles;
use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;

/**
* @property \Illuminate\Database\Eloquent\Collection $users
*/
class Group extends Model
{
use HasUuid;
Expand All @@ -20,6 +24,7 @@ class Group extends Model
use HasRoles;
use HasSlug;
use Filterable;
use Notifiable;

/**
* The database connection to use.
Expand Down Expand Up @@ -56,6 +61,11 @@ class Group extends Model
*/
protected $with = ['users', 'permissions', 'policies'];

/**
* The relationship of the multiple notifiables.
*/
public string $containsMultipleNotifiables = 'users';

/**
* Get the options for generating the slug.
*/
Expand All @@ -75,4 +85,12 @@ public function users()
{
return $this->hasManyThrough(User::class, GroupUser::class, 'group_uuid', 'uuid', 'uuid', 'user_uuid');
}

/**
* An array of each group members email to send notification emails to.
*/
public function routeNotificationForMail(): \Illuminate\Support\Collection
{
return $this->users->pluck('email');
}
}
Loading
Loading