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
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.6.33",
"version": "1.6.34",
"description": "Core Framework and Resources for Fleetbase API",
"keywords": [
"fleetbase",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

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

return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
// Add options column to users table
Schema::table('users', function (Blueprint $table) {
if (!Schema::hasColumn('users', 'options')) {
$table->json('options')->nullable()->after('meta');
}
});

// Add meta column to companies table
Schema::table('companies', function (Blueprint $table) {
if (!Schema::hasColumn('companies', 'meta')) {
$table->json('meta')->nullable()->after('options');
}
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
// Remove options column from users table
Schema::table('users', function (Blueprint $table) {
if (Schema::hasColumn('users', 'options')) {
$table->dropColumn('options');
}
});

// Remove meta column from companies table
Schema::table('companies', function (Blueprint $table) {
if (Schema::hasColumn('companies', 'meta')) {
$table->dropColumn('meta');
}
});
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

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

return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('companies', function (Blueprint $table) {
$table->timestamp('onboarding_completed_at')->nullable()->after('updated_at');
$table->string('onboarding_completed_by_uuid')->nullable()->after('onboarding_completed_at');
$table->index('onboarding_completed_at');
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('companies', function (Blueprint $table) {
$table->dropIndex(['onboarding_completed_at']);
$table->dropColumn(['onboarding_completed_at', 'onboarding_completed_by_uuid']);
});
}
};
18 changes: 16 additions & 2 deletions src/Http/Controllers/Internal/v1/OnboardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ public function createAccount(OnboardRequest $request)
'last_login' => $isAdmin ? now() : null,
]);

// create company FIRST (required for billing resource tracking)
$company = Company::create(['name' => $request->input('organization_name')]);

// set company_uuid before creating user (required for billing resource tracking)
$attributes['company_uuid'] = $company->uuid;

// create user account
$user = User::create($attributes);

Expand All @@ -66,8 +72,7 @@ public function createAccount(OnboardRequest $request)
// set the user type
$user->setUserType($isAdmin ? 'admin' : 'user');

// create company
$company = new Company(['name' => $request->input('organization_name')]);
// set company owner
$company->setOwner($user)->save();

// assign user to organization
Expand Down Expand Up @@ -224,6 +229,15 @@ public function verifyEmail(Request $request)
$user->updateLastLogin();
$token = $user->createToken($user->uuid);

// Mark company onboarding as complete (email verification is final step)
$company = $user->company;
if ($company && $company->onboarding_completed_at === null) {
$company->update([
'onboarding_completed_at' => $verifiedAt,
'onboarding_completed_by_uuid' => $user->uuid,
]);
}

return response()->json([
'status' => 'ok',
'verified_at' => $verifiedAt,
Expand Down
41 changes: 21 additions & 20 deletions src/Http/Resources/Organization.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,27 @@ class Organization extends FleetbaseResource
public function toArray($request)
{
return [
'id' => $this->when(Http::isInternalRequest(), $this->id, $this->public_id),
'uuid' => $this->when(Http::isInternalRequest(), $this->uuid),
'owner_uuid' => $this->when(Http::isInternalRequest(), $this->owner_uuid),
'public_id' => $this->when(Http::isInternalRequest(), $this->public_id),
'name' => $this->name,
'description' => $this->description,
'phone' => $this->phone,
'type' => $this->when(Http::isInternalRequest(), $this->type),
'users_count' => $this->when(Http::isInternalRequest(), $this->companyUsers()->count()),
'timezone' => $this->timezone,
'country' => $this->country,
'currency' => $this->currency,
'logo_url' => $this->logo_url,
'backdrop_url' => $this->backdrop_url,
'branding' => Setting::getBranding(),
'options' => $this->options ?? Utils::createObject([]),
'owner' => $this->owner ? new User($this->owner) : null,
'slug' => $this->slug,
'status' => $this->status,
'joined_at' => $this->when(Http::isInternalRequest() && $request->hasSession() && $request->session()->has('user'), function () {
'id' => $this->when(Http::isInternalRequest(), $this->id, $this->public_id),
'uuid' => $this->when(Http::isInternalRequest(), $this->uuid),
'owner_uuid' => $this->when(Http::isInternalRequest(), $this->owner_uuid),
'public_id' => $this->when(Http::isInternalRequest(), $this->public_id),
'name' => $this->name,
'description' => $this->description,
'phone' => $this->phone,
'type' => $this->when(Http::isInternalRequest(), $this->type),
'users_count' => $this->when(Http::isInternalRequest(), $this->companyUsers()->count()),
'timezone' => $this->timezone,
'country' => $this->country,
'currency' => $this->currency,
'logo_url' => $this->logo_url,
'backdrop_url' => $this->backdrop_url,
'branding' => Setting::getBranding(),
'options' => $this->options ?? Utils::createObject([]),
'owner' => $this->owner ? new User($this->owner) : null,
'slug' => $this->slug,
'status' => $this->status,
'onboarding_completed' => $this->when(Http::isInternalRequest(), $this->onboarding_completed_at !== null),
'joined_at' => $this->when(Http::isInternalRequest() && $request->hasSession() && $request->session()->has('user'), function () {
if ($this->resource->joined_at) {
return $this->resource->joined_at;
}
Expand Down
69 changes: 35 additions & 34 deletions src/Http/Resources/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,40 +18,41 @@ class User extends FleetbaseResource
public function toArray($request)
{
$data = [
'id' => $this->when(Http::isInternalRequest(), $this->id, $this->public_id),
'uuid' => $this->when(Http::isInternalRequest(), $this->uuid),
'company_uuid' => $this->when(Http::isInternalRequest(), $this->company_uuid),
'public_id' => $this->when(Http::isInternalRequest(), $this->public_id),
'company' => $this->when(Http::isPublicRequest(), $this->company ? $this->company->public_id : null),
'name' => $this->name,
'username' => $this->username,
'email' => $this->email,
'phone' => $this->phone,
'country' => $this->country,
'timezone' => $this->timezone,
'avatar_url' => $this->avatar_url,
'meta' => data_get($this, 'meta', Utils::createObject()),
'role' => $this->when(Http::isInternalRequest(), new Role($this->role), null),
'policies' => $this->when(Http::isInternalRequest(), Policy::collection($this->policies), []),
'permissions' => $this->when(Http::isInternalRequest(), $this->serializePermissions($this->permissions), []),
'role_name' => $this->when(Http::isInternalRequest(), $this->role ? $this->role->name : null),
'type' => $this->type,
'locale' => $this->getLocale(),
'types' => $this->when(Http::isInternalRequest(), $this->types ?? []),
'company_name' => $this->when(Http::isInternalRequest(), $this->company_name),
'session_status' => $this->when(Http::isInternalRequest(), $this->session_status),
'is_admin' => $this->when(Http::isInternalRequest(), $this->is_admin),
'is_online' => $this->is_online,
'ip_address' => $this->ip_address,
'date_of_birth' => $this->date_of_birth,
'email_verified_at' => $this->email_verified_at,
'phone_verified_at' => $this->phone_verified_at,
'last_seen_at' => $this->last_seen_at,
'last_login' => $this->last_login,
'status' => $this->status,
'slug' => $this->slug,
'updated_at' => $this->updated_at,
'created_at' => $this->created_at,
'id' => $this->when(Http::isInternalRequest(), $this->id, $this->public_id),
'uuid' => $this->when(Http::isInternalRequest(), $this->uuid),
'company_uuid' => $this->when(Http::isInternalRequest(), $this->company_uuid),
'public_id' => $this->when(Http::isInternalRequest(), $this->public_id),
'company' => $this->when(Http::isPublicRequest(), $this->company ? $this->company->public_id : null),
'name' => $this->name,
'username' => $this->username,
'email' => $this->email,
'phone' => $this->phone,
'country' => $this->country,
'timezone' => $this->timezone,
'avatar_url' => $this->avatar_url,
'meta' => data_get($this, 'meta', Utils::createObject()),
'role' => $this->when(Http::isInternalRequest(), new Role($this->role), null),
'policies' => $this->when(Http::isInternalRequest(), Policy::collection($this->policies), []),
'permissions' => $this->when(Http::isInternalRequest(), $this->serializePermissions($this->permissions), []),
'role_name' => $this->when(Http::isInternalRequest(), $this->role ? $this->role->name : null),
'type' => $this->type,
'locale' => $this->getLocale(),
'types' => $this->when(Http::isInternalRequest(), $this->types ?? []),
'company_name' => $this->when(Http::isInternalRequest(), $this->company_name),
'company_onboarding_completed' => $this->when(Http::isInternalRequest(), $this->company_onboarding_completed),
'session_status' => $this->when(Http::isInternalRequest(), $this->session_status),
'is_admin' => $this->when(Http::isInternalRequest(), $this->is_admin),
'is_online' => $this->is_online,
'ip_address' => $this->ip_address,
'date_of_birth' => $this->date_of_birth,
'email_verified_at' => $this->email_verified_at,
'phone_verified_at' => $this->phone_verified_at,
'last_seen_at' => $this->last_seen_at,
'last_login' => $this->last_login,
'status' => $this->status,
'slug' => $this->slug,
'updated_at' => $this->updated_at,
'created_at' => $this->created_at,
];

return ResourceTransformerRegistry::transform($this->resource, $data);
Expand Down
11 changes: 9 additions & 2 deletions src/Models/Company.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Fleetbase\Casts\Json;
use Fleetbase\FleetOps\Models\Driver;
use Fleetbase\Traits\HasApiModelBehavior;
use Fleetbase\Traits\HasMetaAttributes;
use Fleetbase\Traits\HasOptionsAttributes;
use Fleetbase\Traits\HasPublicId;
use Fleetbase\Traits\HasUuid;
Expand All @@ -28,6 +29,7 @@ class Company extends Model
use TracksApiCredential;
use HasApiModelBehavior;
use HasOptionsAttributes;
use HasMetaAttributes;
use HasSlug;
use Searchable;
use SendsWebhooks;
Expand Down Expand Up @@ -86,6 +88,7 @@ class Company extends Model
'website_url',
'description',
'options',
'meta',
'type',
'currency',
'country',
Expand All @@ -95,6 +98,8 @@ class Company extends Model
'status',
'slug',
'trial_ends_at',
'onboarding_completed_at',
'onboarding_completed_by_uuid',
];

/**
Expand All @@ -117,8 +122,10 @@ class Company extends Model
* @var array
*/
protected $casts = [
'options' => Json::class,
'trial_ends_at' => 'datetime',
'options' => Json::class,
'meta' => Json::class,
'trial_ends_at' => 'datetime',
'onboarding_completed_at' => 'datetime',
];

/**
Expand Down
21 changes: 17 additions & 4 deletions src/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Fleetbase\Traits\HasApiModelBehavior;
use Fleetbase\Traits\HasCacheableAttributes;
use Fleetbase\Traits\HasMetaAttributes;
use Fleetbase\Traits\HasOptionsAttributes;
use Fleetbase\Traits\HasPresence;
use Fleetbase\Traits\HasPublicId;
use Fleetbase\Traits\HasSessionAttributes;
Expand Down Expand Up @@ -53,6 +54,7 @@ class User extends Authenticatable
use HasApiModelBehavior;
use HasCacheableAttributes;
use HasMetaAttributes;
use HasOptionsAttributes;
use HasTimestamps;
use LogsActivity;
use CausesActivity;
Expand Down Expand Up @@ -149,6 +151,7 @@ class User extends Authenticatable
'date_of_birth',
'timezone',
'meta',
'options',
'country',
'ip_address',
'last_login',
Expand Down Expand Up @@ -181,6 +184,7 @@ class User extends Authenticatable
'avatar_url',
'session_status',
'company_name',
'company_onboarding_completed',
'is_admin',
'is_online',
'last_seen_at',
Expand All @@ -192,10 +196,11 @@ class User extends Authenticatable
* @var array
*/
protected $casts = [
'meta' => Json::class,
'email_verified_at' => 'datetime',
'phone_verified_at' => 'datetime',
'last_login' => 'datetime',
'meta' => Json::class,
'options' => Json::class,
'email_verified_at' => 'datetime',
'phone_verified_at' => 'datetime',
'last_login' => 'datetime',
];

/**
Expand Down Expand Up @@ -749,6 +754,14 @@ public function getCompanyNameAttribute(): ?string
return data_get($this, 'company.name');
}

/**
* Get the users's company onboard completed.
*/
public function getCompanyOnboardingCompletedAttribute(): bool
{
return data_get($this, 'company.onboarding_completed_at') !== null;
}

/**
* Get the users's company name.
*/
Expand Down
5 changes: 4 additions & 1 deletion src/Services/UserCacheService.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,10 @@ public static function invalidateCompany(string $companyId): void
*/
public static function generateETag(User $user): string
{
return '"user-' . $user->uuid . '-' . $user->updated_at->timestamp . '"';
$userMeta = json_encode($user->meta);
$userOptions = json_encode($user->options);

return '"user-' . $user->uuid . '-' . $user->updated_at->timestamp . '-' . strlen($userMeta) . '-' . strlen($userOptions) . '"';
}

/**
Expand Down
Loading