Skip to content

Commit f291f41

Browse files
authored
Merge pull request #219 from fleetbase/dev-v1.6.50
v1.6.50
2 parents 6995c83 + 9c05d89 commit f291f41

10 files changed

Lines changed: 133 additions & 17 deletions

File tree

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "fleetbase/core-api",
3-
"version": "1.6.49",
3+
"version": "1.6.50",
44
"description": "Core Framework and Resources for Fleetbase API",
55
"keywords": [
66
"fleetbase",

src/Http/Controllers/Api/v1/CommentController.php

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ public function create(CreateCommentRequest $request)
2323
{
2424
$content = $request->input('content');
2525
$subject = $request->input('subject', [
26-
'id' => $request->input('subject_id'),
26+
'id' => $request->input('subject_id') ?: $request->input('subject_uuid'),
2727
'type' => $request->input('subject_type'),
2828
]);
29-
$parent = $request->input('parent');
29+
$parent = $request->input('parent') ?: $request->input('parent_comment_uuid');
3030

3131
// Prepare comment creation data
3232
$data = [
@@ -38,7 +38,14 @@ public function create(CreateCommentRequest $request)
3838
// Resolve the parent
3939
$parentComment = null;
4040
if ($parent) {
41-
$parentComment = Comment::where(['public_id' => $parent, 'company_uuid' => session('company')])->first();
41+
$parentComment = Comment::where('company_uuid', session('company'))
42+
->where(function ($query) use ($parent) {
43+
$query->where('uuid', $parent)
44+
->orWhere('public_id', $parent)
45+
->orWhere('id', $parent);
46+
})
47+
->first();
48+
4249
if ($parentComment) {
4350
$data['parent_comment_uuid'] = $parentComment->uuid;
4451
$data['subject_uuid'] = $parentComment->subject_uuid;
@@ -47,14 +54,19 @@ public function create(CreateCommentRequest $request)
4754
}
4855

4956
// Resolve the subject
50-
if ($subject && !$parentComment) {
57+
if ($subject && data_get($subject, 'id') && data_get($subject, 'type') && !$parentComment) {
5158
$subjectClass = Utils::getMutationType(data_get($subject, 'type'));
5259
$subjectUuid = null;
5360
if ($subjectClass) {
54-
$subjectUuid = Utils::getUuid(app($subjectClass)->getTable(), [
55-
'public_id' => data_get($subject, 'id'),
56-
'company_uuid' => session('company'),
57-
]);
61+
$subjectId = data_get($subject, 'id');
62+
$subjectUuid = app($subjectClass)
63+
->newQuery()
64+
->where('company_uuid', session('company'))
65+
->where(function ($query) use ($subjectId) {
66+
$query->where('uuid', $subjectId)
67+
->orWhere('public_id', $subjectId);
68+
})
69+
->value('uuid');
5870
}
5971

6072
// If on subject found
@@ -66,6 +78,10 @@ public function create(CreateCommentRequest $request)
6678
$data['subject_type'] = $subjectClass;
6779
}
6880

81+
if (empty($data['subject_uuid']) || empty($data['subject_type'])) {
82+
return response()->apiError('Invalid subject provided for comment.');
83+
}
84+
6985
// create the comment
7086
try {
7187
$comment = Comment::publish($data);

src/Http/Controllers/Internal/v1/AuthController.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ public function login(LoginRequest $request)
6161
$tokenOwner instanceof User
6262
&& ($tokenOwner->email === $identity || $tokenOwner->phone === $identity)
6363
) {
64+
if ($tokenOwner->type === 'customer') {
65+
return response()->error('Customer accounts must sign in through the customer portal.', 403, ['code' => 'customer_login_not_allowed']);
66+
}
67+
6468
return response()->json([
6569
'token' => $authToken,
6670
'type' => $tokenOwner->getType(),
@@ -78,6 +82,10 @@ public function login(LoginRequest $request)
7882
$query->where('email', $identity)->orWhere('phone', $identity);
7983
})->first();
8084

85+
if ($user && $user->type === 'customer') {
86+
return response()->error('Customer accounts must sign in through the customer portal.', 403, ['code' => 'customer_login_not_allowed']);
87+
}
88+
8189
// If the user exists but has no password set (e.g. SSO-invited or provisioned
8290
// accounts), silently fall through to the generic credentials error below.
8391
// This guard MUST come before isInvalidPassword() which has a strict string

src/Http/Controllers/Internal/v1/ChatChannelController.php

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
namespace Fleetbase\Http\Controllers\Internal\v1;
44

55
use Fleetbase\Http\Controllers\FleetbaseController;
6+
use Fleetbase\Http\Resources\User as UserResource;
67
use Fleetbase\Models\ChatChannel;
8+
use Fleetbase\Models\ChatParticipant;
9+
use Fleetbase\Models\User;
710
use Illuminate\Http\Request;
811

912
class ChatChannelController extends FleetbaseController
@@ -15,6 +18,75 @@ class ChatChannelController extends FleetbaseController
1518
*/
1619
public $resource = 'chat_channel';
1720

21+
/**
22+
* Creates a chat channel and optional initial participants.
23+
*
24+
* @return \Fleetbase\Http\Resources\ChatChannel|\Illuminate\Http\Response
25+
*/
26+
public function createRecord(Request $request)
27+
{
28+
try {
29+
$name = $request->input('chatChannel.name');
30+
$meta = $request->input('chatChannel.meta', []);
31+
$participants = $request->array('chatChannel.participants');
32+
33+
$chatChannel = ChatChannel::create([
34+
'company_uuid' => session('company'),
35+
'created_by_uuid' => session('user'),
36+
'name' => $name,
37+
'meta' => $meta,
38+
]);
39+
40+
foreach ($participants as $userId) {
41+
$user = User::where('uuid', $userId)->orWhere('public_id', $userId)->first();
42+
43+
if (!$user || $user->uuid === session('user')) {
44+
continue;
45+
}
46+
47+
ChatParticipant::firstOrCreate([
48+
'company_uuid' => session('company'),
49+
'user_uuid' => $user->uuid,
50+
'chat_channel_uuid' => $chatChannel->uuid,
51+
]);
52+
}
53+
54+
$chatChannel->load(['participants.user', 'lastMessage']);
55+
$this->resource::wrap($this->resourceSingularlName);
56+
57+
return new $this->resource($chatChannel);
58+
} catch (\Exception $e) {
59+
return response()->error(app()->hasDebugModeEnabled() ? $e->getMessage() : 'Unable to create chat channel.');
60+
}
61+
}
62+
63+
/**
64+
* Query users available for a new or existing chat channel.
65+
*
66+
* @return \Fleetbase\Http\Resources\UserCollection
67+
*/
68+
public function getAvailableParticipants(Request $request)
69+
{
70+
$query = $request->input('query');
71+
$chatChannelId = $request->input('channel');
72+
$chatChannel = $chatChannelId ? ChatChannel::where('uuid', $chatChannelId)->orWhere('public_id', $chatChannelId)->first() : null;
73+
74+
$users = User::whereHas('companyUsers', function ($query) {
75+
$query->where('company_uuid', session('company'));
76+
})
77+
->where('uuid', '!=', session('user'))
78+
->when($query, function ($builder) use ($query) {
79+
$builder->search($query);
80+
});
81+
82+
if ($chatChannel) {
83+
$participantUserUuids = $chatChannel->participants()->pluck('user_uuid');
84+
$users->whereNotIn('uuid', $participantUserUuids);
85+
}
86+
87+
return UserResource::collection($users->limit(25)->get());
88+
}
89+
1890
/**
1991
* Retrieves the unread message count for a specific chat channel.
2092
*

src/Http/Controllers/Internal/v1/LookupController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ public function fleetbaseBlog(Request $request)
189189
{
190190
$limit = max(1, min($request->integer('limit', 6), 20));
191191
$cacheKey = $this->getFleetbaseBlogCacheKey($limit);
192-
$cacheTTL = now()->addDays(4); // 4 days as requested
192+
$cacheTTL = now()->addDays(1);
193193

194194
// Try to get from cache
195195
$posts = Cache::remember($cacheKey, $cacheTTL, function () use ($limit) {

src/Http/Filter/CommentFilter.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ public function subjectUuid(string $id)
3030
$this->builder->where('subject_uuid', $id);
3131
}
3232

33+
public function subjectType(string $type)
34+
{
35+
$resolved = Utils::getMutationType($type);
36+
37+
$this->builder->where('subject_type', $resolved ?: $type);
38+
}
39+
3340
public function parent(string $id)
3441
{
3542
if (Str::isUuid($id)) {

src/Http/Requests/CreateCommentRequest.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,22 @@ public function rules()
2525
{
2626
return [
2727
'subject' => [Rule::requiredIf(function () {
28-
return !$this->filled('subject_id') && !$this->filled('subject_type') && !$this->filled('parent') && $this->isMethod('POST');
28+
return !$this->filled('subject_id') && !$this->filled('subject_uuid') && !$this->filled('subject_type') && !$this->filled('parent') && !$this->filled('parent_comment_uuid') && $this->isMethod('POST');
2929
})],
3030
'subject_id' => [Rule::requiredIf(function () {
31-
return !$this->filled('parent') && !$this->filled('subject') && $this->isMethod('POST');
31+
return !$this->filled('subject_uuid') && !$this->filled('parent') && !$this->filled('parent_comment_uuid') && !$this->filled('subject') && $this->isMethod('POST');
32+
})],
33+
'subject_uuid' => [Rule::requiredIf(function () {
34+
return !$this->filled('subject_id') && !$this->filled('parent') && !$this->filled('parent_comment_uuid') && !$this->filled('subject') && $this->isMethod('POST');
3235
})],
3336
'subject_type' => [Rule::requiredIf(function () {
34-
return !$this->filled('parent') && !$this->filled('subject') && $this->isMethod('POST');
37+
return !$this->filled('parent') && !$this->filled('parent_comment_uuid') && !$this->filled('subject') && $this->isMethod('POST');
3538
})],
3639
'parent' => [Rule::requiredIf(function () {
37-
return !$this->filled('subject') && !$this->filled('subject_type') && !$this->filled('subject_id') && $this->isMethod('POST');
40+
return !$this->filled('parent_comment_uuid') && !$this->filled('subject') && !$this->filled('subject_type') && !$this->filled('subject_id') && !$this->filled('subject_uuid') && $this->isMethod('POST');
41+
})],
42+
'parent_comment_uuid' => [Rule::requiredIf(function () {
43+
return !$this->filled('parent') && !$this->filled('subject') && !$this->filled('subject_type') && !$this->filled('subject_id') && !$this->filled('subject_uuid') && $this->isMethod('POST');
3844
})],
3945
'content' => ['required'],
4046
];

src/Http/Resources/ChatChannel.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public function toArray($request)
2828
'created_by' => $this->when(Http::isPublicRequest(), fn () => $this->createdBy ? $this->createdBy->public_id : null),
2929
'name' => $this->name,
3030
'title' => $this->title,
31-
'last_message' => new ChatMessage($this->last_message),
31+
'last_message' => $this->last_message ? new ChatMessage($this->last_message) : null,
3232
'unread_count' => $this->when($user, fn () => $this->getUnreadMessageCountForUser($user)),
3333
'slug' => $this->slug,
3434
'feed' => $this->resource_feed,

src/Listeners/SendResourceLifecycleWebhook.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,18 @@ public function handle($event)
3737
$apiEnvironment = session()->get('api_environment', $event->apiEnvironment ?? 'live');
3838
$isSandbox = session()->get('is_sandbox', $event->isSandbox);
3939

40+
// Compute the event payload exactly once so the persisted ApiEvent record and the
41+
// outbound webhook body are guaranteed to be identical. $event->getEventData() resolves
42+
// the model live at handle time, whereas $event->data is a snapshot frozen at dispatch
43+
// time; using each in a different place lets the DB record and the webhook diverge.
44+
$payload = $event->getEventData();
45+
4046
// Prepare event
4147
$eventData = [
4248
'company_uuid' => $companyId,
4349
'event' => $event->broadcastAs(),
4450
'source' => $apiCredentialId ? 'api' : 'console',
45-
'data' => $event->getEventData(),
51+
'data' => $payload,
4652
'method' => $event->requestMethod,
4753
'description' => $this->getHumanReadableEventDescription($event),
4854
];
@@ -100,7 +106,7 @@ public function handle($event)
100106
'sent_at' => Carbon::now(),
101107
])
102108
->url($webhook->url)
103-
->payload($event->data)
109+
->payload($payload)
104110
->useSecret($apiSecret)
105111
->dispatch();
106112
} catch (\Exception|\Aws\Sqs\Exception\SqsException $exception) {

src/routes.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ function ($router, $controller) {
257257
$router->fleetbaseRoutes('custom-fields');
258258
$router->fleetbaseRoutes('custom-field-values');
259259
$router->fleetbaseRoutes('chat-channels', function ($router, $controller) {
260+
$router->get('available-participants', $controller('getAvailableParticipants'));
260261
$router->get('unread-count/{channelId}', $controller('getUnreadCountForChannel'));
261262
$router->get('unread-count', $controller('getUnreadCount'));
262263
});

0 commit comments

Comments
 (0)