Skip to content

Commit e3da0ed

Browse files
Merge pull request #154 from limosa-io/copilot/fix-default-migration-inclusion
Make SCIM user table migrations opt-in instead of auto-loading
2 parents 6283a08 + e61e7e8 commit e3da0ed

File tree

6 files changed

+105
-50
lines changed

6 files changed

+105
-50
lines changed

Dockerfile

Lines changed: 24 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,32 @@ class UserFactory extends Factory
169169
$suffix = $this->faker->unique()->numberBetween(100, 999999);
170170
$username = $base . $suffix;
171171

172+
$roleTemplates = [
173+
['value' => 'admin', 'display' => 'Admin', 'type' => 'system'],
174+
['value' => 'developer', 'display' => 'Developer', 'type' => 'system'],
175+
['value' => 'manager', 'display' => 'Manager', 'type' => 'business'],
176+
['value' => 'support', 'display' => 'Support', 'type' => 'business'],
177+
['value' => 'auditor', 'display' => 'Auditor', 'type' => 'governance'],
178+
];
179+
180+
$selectedRoles = $this->faker->randomElements(
181+
$roleTemplates,
182+
$this->faker->numberBetween(1, count($roleTemplates))
183+
);
184+
$selectedRoles = array_values($selectedRoles);
185+
$primaryIndex = array_rand($selectedRoles);
186+
foreach ($selectedRoles as $index => &$role) {
187+
$role['primary'] = $index === $primaryIndex;
188+
}
189+
unset($role);
190+
172191
return [
173192
'name' => $username, // login username
174193
'formatted' => $formatted, // full name
175194
'email' => "{$username}@example.test",
176195
'password' => bcrypt('test'),
177196
'active' => $this->faker->boolean(),
197+
'roles' => $selectedRoles,
178198
];
179199
}
180200
}
@@ -229,6 +249,7 @@ class User extends Authenticatable
229249
'email',
230250
'password',
231251
'active',
252+
'roles',
232253

233254
];
234255

@@ -240,6 +261,7 @@ class User extends Authenticatable
240261
protected $casts = [
241262
'email_verified_at' => 'datetime',
242263
'active' => 'boolean',
264+
'roles' => 'array',
243265

244266
];
245267

@@ -277,55 +299,10 @@ class DemoSeeder extends Seeder
277299
}
278300
EOM
279301

280-
# Add migration to add SCIM fields to users table
281-
RUN cat > /example/database/migrations/2021_01_01_000003_add_scim_fields_to_users_table.php <<'EOM'
282-
<?php
283-
284-
use Illuminate\Database\Migrations\Migration;
285-
use Illuminate\Database\Schema\Blueprint;
286-
use Illuminate\Support\Facades\Schema;
287-
288-
return new class extends Migration {
289-
public function up(): void
290-
{
291-
Schema::table('users', function (Blueprint $table) {
292-
if (!Schema::hasColumn('users', 'formatted')) {
293-
$table->string('formatted')->nullable();
294-
}
295-
if (!Schema::hasColumn('users', 'displayName')) {
296-
$table->string('displayName')->nullable();
297-
}
298-
if (!Schema::hasColumn('users', 'active')) {
299-
$table->boolean('active')->default(false);
300-
}
301-
if (!Schema::hasColumn('users', 'roles')) {
302-
$table->json('roles')->nullable();
303-
}
304-
});
305-
}
306-
307-
public function down(): void
308-
{
309-
Schema::table('users', function (Blueprint $table) {
310-
if (Schema::hasColumn('users', 'formatted')) {
311-
$table->dropColumn('formatted');
312-
}
313-
if (Schema::hasColumn('users', 'displayName')) {
314-
$table->dropColumn('displayName');
315-
}
316-
if (Schema::hasColumn('users', 'active')) {
317-
$table->dropColumn('active');
318-
}
319-
if (Schema::hasColumn('users', 'roles')) {
320-
$table->dropColumn('roles');
321-
}
322-
});
323-
}
324-
};
325-
EOM
302+
# Publish SCIM migrations from the package
303+
RUN php artisan vendor:publish --tag=laravel-scim-migrations
326304

327305
# Run migrations and seed demo data
328306
RUN php artisan migrate && php artisan db:seed --class=Database\\Seeders\\DemoSeeder
329307

330308
CMD ["php","artisan","serve","--host=0.0.0.0","--port=8000"]
331-

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ Optionally publish the config for fine-grained control:
4545
php artisan vendor:publish --tag=laravel-scim
4646
```
4747

48+
If you need to add SCIM-specific columns (`formatted`, `active`, `roles`) to your users table, publish the migrations:
49+
50+
```bash
51+
php artisan vendor:publish --tag=laravel-scim-migrations
52+
php artisan migrate
53+
```
54+
55+
**Note:** These migrations are optional. Only publish them if your SCIM implementation requires these specific fields in your users table.
56+
4857
## SCIM routes
4958

5059
| Method | Path | Description |

database/migrations/2021_01_01_000003_add_scim_fields_to_users_table.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,15 @@ public function up(): void
1212
if (!Schema::hasColumn('users', 'formatted')) {
1313
$table->string('formatted')->nullable();
1414
}
15+
if (!Schema::hasColumn('users', 'displayName')) {
16+
$table->string('displayName')->nullable();
17+
}
1518
if (!Schema::hasColumn('users', 'active')) {
1619
$table->boolean('active')->default(false);
1720
}
21+
if (!Schema::hasColumn('users', 'roles')) {
22+
$table->json('roles')->nullable();
23+
}
1824
});
1925
}
2026
}
@@ -26,9 +32,15 @@ public function down(): void
2632
if (Schema::hasColumn('users', 'formatted')) {
2733
$table->dropColumn('formatted');
2834
}
35+
if (Schema::hasColumn('users', 'displayName')) {
36+
$table->dropColumn('displayName');
37+
}
2938
if (Schema::hasColumn('users', 'active')) {
3039
$table->dropColumn('active');
3140
}
41+
if (Schema::hasColumn('users', 'roles')) {
42+
$table->dropColumn('roles');
43+
}
3244
});
3345
}
3446
}

src/Attribute/JSONCollection.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ public function replace($value, Model &$object, ?Path $path = null)
2929

3030
public function doRead(&$object, $attributes = [])
3131
{
32-
return $object->{$this->attribute}?->values()->all();
32+
$value = $object->{$this->attribute};
33+
34+
if ($value === null) {
35+
return null;
36+
}
37+
38+
return collect($value)->values()->all();
3339
}
3440

3541
public function remove($value, Model &$object, Path $path = null)

src/ServiceProvider.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ class ServiceProvider extends \Illuminate\Support\ServiceProvider
1212
{
1313
public function boot(\Illuminate\Routing\Router $router)
1414
{
15-
$this->loadMigrationsFrom(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'migrations');
16-
1715
$this->publishes([
1816
__DIR__ . '/../config/scim.php' => config_path('scim.php'),
1917
], 'laravel-scim');
2018

19+
$this->publishes([
20+
__DIR__ . '/../database/migrations/' => database_path('migrations'),
21+
], 'laravel-scim-migrations');
22+
2123
// Match everything, except the Me routes
2224
$router->pattern('resourceType', '^((?!Me).)*$');
2325

tests/ServiceProviderTest.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace ArieTimmerman\Laravel\SCIMServer\Tests;
4+
5+
use ArieTimmerman\Laravel\SCIMServer\ServiceProvider;
6+
use Illuminate\Support\Facades\Artisan;
7+
use Orchestra\Testbench\TestCase as BaseTestCase;
8+
9+
class ServiceProviderTest extends BaseTestCase
10+
{
11+
protected function getPackageProviders($app)
12+
{
13+
return [ServiceProvider::class];
14+
}
15+
16+
public function testMigrationsCanBePublished()
17+
{
18+
// Test that the vendor:publish command can find the migration tag
19+
$result = Artisan::call('vendor:publish', [
20+
'--tag' => 'laravel-scim-migrations',
21+
'--provider' => ServiceProvider::class,
22+
'--force' => true,
23+
]);
24+
25+
// The command should succeed (return 0)
26+
$this->assertEquals(0, $result, 'Migrations should be publishable via vendor:publish command');
27+
}
28+
29+
public function testConfigCanBePublished()
30+
{
31+
// Test that the vendor:publish command can find the config tag
32+
$result = Artisan::call('vendor:publish', [
33+
'--tag' => 'laravel-scim',
34+
'--provider' => ServiceProvider::class,
35+
'--force' => true,
36+
]);
37+
38+
// The command should succeed (return 0)
39+
$this->assertEquals(0, $result, 'Config should be publishable via vendor:publish command');
40+
}
41+
42+
public function testMigrationFileExistsInPackage()
43+
{
44+
// Verify the migration file exists in the package
45+
$migrationPath = realpath(__DIR__ . '/../database/migrations/2021_01_01_000003_add_scim_fields_to_users_table.php');
46+
47+
$this->assertFileExists($migrationPath, 'Migration file should exist in the package');
48+
}
49+
}

0 commit comments

Comments
 (0)