Skip to content

Commit ec77011

Browse files
authored
fix user profile controller (#665)
* fix: fix user profile controller * Fix styling * fix: wip --------- Co-authored-by: binaryk <binaryk@users.noreply.github.com>
1 parent 59db1f0 commit ec77011

File tree

10 files changed

+74
-64
lines changed

10 files changed

+74
-64
lines changed

.github/workflows/release.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ jobs:
3131
- name: Install dependencies
3232
run: composer install --no-dev --prefer-dist --no-interaction --optimize-autoloader
3333

34+
- name: Run Tests
35+
run: composer test
36+
3437
- name: Get next version
3538
id: get_version
3639
run: |

src/Commands/SetupCommand.php

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ public function handle()
4646
}
4747

4848
$this->setAppNamespace();
49-
49+
5050
$this->configureUserModel();
51-
51+
5252
$this->createAiRoutesFile();
5353

5454
$this->info('Restify setup successfully.');
@@ -148,30 +148,32 @@ protected function setAppNamespaceOn($file, $namespace)
148148
protected function configureUserModel()
149149
{
150150
$this->comment('Searching for User models in your application...');
151-
151+
152152
$userModels = $this->findUserModels();
153-
153+
154154
if (empty($userModels)) {
155155
$this->warn('No User models found in App namespace. Using default \\App\\Models\\User.');
156+
156157
return;
157158
}
158-
159+
159160
if (count($userModels) === 1) {
160161
$selectedModel = $userModels[0];
161162
if ($this->confirm("Found User model: {$selectedModel}. Use this as your authentication model?", true)) {
162163
$this->updateUserModelConfig($selectedModel);
163164
$this->info("Updated restify config to use: {$selectedModel}");
164165
}
166+
165167
return;
166168
}
167-
169+
168170
$this->info('Multiple User models found:');
169171
foreach ($userModels as $index => $model) {
170172
$this->line(" [{$index}] {$model}");
171173
}
172-
174+
173175
$choice = $this->ask('Please select the User model to use (enter the number)', '0');
174-
176+
175177
if (isset($userModels[$choice])) {
176178
$selectedModel = $userModels[$choice];
177179
$this->updateUserModelConfig($selectedModel);
@@ -191,24 +193,24 @@ protected function findUserModels()
191193
$appPath = app_path();
192194
$namespace = $this->laravel->getNamespace();
193195
$userModels = [];
194-
196+
195197
$iterator = new \RecursiveIteratorIterator(
196198
new \RecursiveDirectoryIterator($appPath, \RecursiveDirectoryIterator::SKIP_DOTS),
197199
\RecursiveIteratorIterator::SELF_FIRST
198200
);
199-
201+
200202
foreach ($iterator as $file) {
201203
if ($file->isFile() && $file->getExtension() === 'php') {
202-
$relativePath = str_replace($appPath . DIRECTORY_SEPARATOR, '', $file->getPathname());
204+
$relativePath = str_replace($appPath.DIRECTORY_SEPARATOR, '', $file->getPathname());
203205
$className = str_replace(['/', '.php'], ['\\', ''], $relativePath);
204-
$fqcn = $namespace . $className;
205-
206+
$fqcn = $namespace.$className;
207+
206208
if ($this->isUserModel($file->getPathname(), $className)) {
207209
$userModels[] = $fqcn;
208210
}
209211
}
210212
}
211-
213+
212214
return $userModels;
213215
}
214216

@@ -224,9 +226,9 @@ protected function isUserModel($filePath, $className)
224226
if (! str_contains(strtolower($className), 'user')) {
225227
return false;
226228
}
227-
229+
228230
$content = file_get_contents($filePath);
229-
231+
230232
return str_contains($content, 'extends Authenticatable') ||
231233
str_contains($content, 'use Authenticatable') ||
232234
str_contains($content, 'implements AuthenticatableContract') ||
@@ -242,20 +244,21 @@ protected function isUserModel($filePath, $className)
242244
protected function updateUserModelConfig($userModel)
243245
{
244246
$configPath = config_path('restify.php');
245-
247+
246248
if (! file_exists($configPath)) {
247249
$this->warn('restify.php config file not found.');
250+
248251
return;
249252
}
250-
253+
251254
$content = file_get_contents($configPath);
252255
$escapedUserModel = addslashes($userModel);
253-
256+
254257
$pattern = "/'user_model'\s*=>\s*['\"].*?['\"]/";
255258
$replacement = "'user_model' => \"{$escapedUserModel}\"";
256-
259+
257260
$newContent = preg_replace($pattern, $replacement, $content);
258-
261+
259262
if ($newContent !== $content) {
260263
file_put_contents($configPath, $newContent);
261264
} else {
@@ -271,19 +274,20 @@ protected function updateUserModelConfig($userModel)
271274
protected function createAiRoutesFile()
272275
{
273276
$routesPath = base_path('routes');
274-
$aiRoutesFile = $routesPath . '/ai.php';
275-
277+
$aiRoutesFile = $routesPath.'/ai.php';
278+
276279
if (file_exists($aiRoutesFile)) {
277280
$this->line('AI routes file already exists.');
281+
278282
return;
279283
}
280-
284+
281285
app(Filesystem::class)->ensureDirectoryExists($routesPath);
282-
286+
283287
$content = "<?php\n\nuse Binaryk\\LaravelRestify\\MCP\\RestifyServer;\nuse Laravel\\Mcp\\Server\\Facades\\Mcp;\n\n// Restify MCP Server - provides AI agents access to your Restify repositories\n// Mcp::web('restify', RestifyServer::class)\n// ->middleware(['auth:sanctum']); // Available at /mcp/restify\n\n// Mcp::local('restify', RestifyServer::class); // Start with ./artisan mcp:start restify\n\n// Example custom servers:\n// Mcp::web('demo', \\App\\Mcp\\Servers\\PublicServer::class); // Available at /mcp/demo\n// Mcp::local('demo', \\App\\Mcp\\Servers\\LocalServer::class); // Start with ./artisan mcp:start demo\n";
284-
288+
285289
file_put_contents($aiRoutesFile, $content);
286-
290+
287291
$this->info('Created routes/ai.php file for MCP server configuration.');
288292
}
289293
}

src/Http/Controllers/Auth/LoginController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function __invoke(Request $request)
3232

3333
$tokenTtl = config('restify.auth.token_ttl');
3434
$expiresAt = $tokenTtl ? now()->addMinutes($tokenTtl) : null;
35-
35+
3636
$token = $user->createToken('login', ['*'], $expiresAt);
3737

3838
return rest($user)->indexMeta([

src/Http/Controllers/Auth/LogoutController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ public function __invoke(Request $request)
2222
'message' => 'Successfully logged out.',
2323
]);
2424
}
25-
}
25+
}

src/Http/Controllers/Auth/RegisterController.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ public function __invoke(Request $request)
2828

2929
$tokenTtl = config('restify.auth.token_ttl');
3030
$expiresAt = $tokenTtl ? now()->addMinutes($tokenTtl) : null;
31-
31+
3232
$token = $user->createToken('login', ['*'], $expiresAt);
33-
33+
3434
$meta = [
3535
'token' => $token->plainTextToken,
3636
'expires_in' => $tokenTtl ? $tokenTtl * 60 : null,
3737
];
38-
38+
3939
if ($user instanceof MustVerifyEmail && ! $user->hasVerifiedEmail()) {
4040
$user->notify(new VerifyEmail);
4141
$meta['email_verification_sent'] = true;

src/Http/Controllers/Auth/VerifyController.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,18 @@ class VerifyController extends Controller
1414
public function __invoke(Request $request, int $id, string $hash)
1515
{
1616
$frontendUrl = config('restify.auth.user_verify_url');
17-
17+
1818
if (! $request->hasValidSignature()) {
1919
if ($frontendUrl) {
2020
$redirectUrl = str_replace(
2121
['{id}', '{emailHash}'],
2222
[$id, $hash],
2323
$frontendUrl
2424
);
25-
26-
return redirect($redirectUrl . '?success=false&message=' . urlencode('Invalid or expired verification link.'));
25+
26+
return redirect($redirectUrl.'?success=false&message='.urlencode('Invalid or expired verification link.'));
2727
}
28-
28+
2929
throw new AuthorizationException('Invalid or expired verification link.');
3030
}
3131

@@ -41,10 +41,10 @@ public function __invoke(Request $request, int $id, string $hash)
4141
[$user->getKey(), $hash],
4242
$frontendUrl
4343
);
44-
45-
return redirect($redirectUrl . '?success=false&message=' . urlencode('Invalid hash'));
44+
45+
return redirect($redirectUrl.'?success=false&message='.urlencode('Invalid hash'));
4646
}
47-
47+
4848
throw new AuthorizationException('Invalid hash');
4949
}
5050

@@ -59,7 +59,7 @@ public function __invoke(Request $request, int $id, string $hash)
5959
$frontendUrl
6060
);
6161

62-
return redirect($redirectUrl . '?success=true&message=' . urlencode('Email verified successfully.'));
62+
return redirect($redirectUrl.'?success=true&message='.urlencode('Email verified successfully.'));
6363
}
6464

6565
return rest($user)->indexMeta([

src/Http/Controllers/ProfileController.php

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
use Binaryk\LaravelRestify\Http\Requests\ProfileRequestRequest;
66
use Binaryk\LaravelRestify\Http\Requests\RestifyRequest;
77
use Binaryk\LaravelRestify\Repositories\Repository;
8-
use Binaryk\LaravelRestify\Services\Search\RepositorySearchService;
98
use Illuminate\Http\JsonResponse;
109
use Illuminate\Support\Facades\Auth;
1110

@@ -14,6 +13,15 @@ class ProfileController extends RepositoryController
1413
public function __invoke(ProfileRequestRequest $request): JsonResponse
1514
{
1615
if ($repository = $this->guessRepository($request)) {
16+
return $request->repositoryWith(tap($request->modelQuery(Auth::id(), 'users'),
17+
fn ($query) => $repository::showQuery(
18+
$request,
19+
$repository::mainQuery($request,
20+
$query->with($repository::collectWiths($request, $repository)->all()))
21+
))->with($repository::collectWiths($request, $repository)->all())->firstOrFail(), 'users')
22+
->allowToShow($request)
23+
->show($request, Auth::id());
24+
1725
return data($repository->serializeForShow($request));
1826
}
1927

@@ -28,19 +36,11 @@ public function guessRepository(RestifyRequest $request): ?Repository
2836
return null;
2937
}
3038

31-
if (method_exists($repository, 'canUseForProfile')) {
32-
if (! call_user_func([$repository, 'canUseForProfile'], $request)) {
33-
return null;
34-
}
39+
if (method_exists($repository, 'canUseForProfile') && ! call_user_func([$repository, 'canUseForProfile'],
40+
$request)) {
41+
return null;
3542
}
3643

37-
$user = tap(RepositorySearchService::make()->search(
38-
$request,
39-
$repository
40-
), function ($query) use ($request, $repository) {
41-
$repository::indexQuery($request, $query);
42-
})->whereKey(Auth::id())->firstOrFail();
43-
44-
return $repository->withResource($user);
44+
return $repository;
4545
}
4646
}

src/Http/Requests/Concerns/InteractWithRepositories.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public function viaQuery(): Relation
9191
public function modelQuery(?string $repositoryId = null, ?string $uriKey = null): Builder|Relation
9292
{
9393
return $this->newQuery($uriKey)->where(
94-
$this->model()->getRouteKeyName(),
94+
$this->model($uriKey)->getRouteKeyName(),
9595
$repositoryId ?? $this->route('repositoryId')
9696
);
9797
}

tests/Controllers/ProfileControllerTest.php

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ protected function setUp(): void
3030

3131
public function test_profile_returns_authenticated_user(): void
3232
{
33+
$this->withoutExceptionHandling();
34+
3335
$response = $this->getJson(Restify::path('profile'))
3436
->assertOk()
3537
->assertJsonStructure([
@@ -46,16 +48,11 @@ public function test_profile_returns_authenticated_user_with_related_posts(): vo
4648
$this->getJson(Restify::path('profile', [
4749
'related' => 'posts',
4850
]))
49-
->assertOk()
50-
->assertJsonStructure([
51-
'data' => [
52-
'posts' => [
53-
[
54-
'title',
55-
],
56-
],
57-
],
58-
]);
51+
->assertJson(fn ($json) => $json
52+
->where('data.attributes.email', $this->authenticatedAs->email)
53+
->has('data.relationships.posts')
54+
->etc()
55+
);
5956
}
6057

6158
public function test_profile_update()

tests/Fixtures/User/UserRepository.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,17 @@
66
use Binaryk\LaravelRestify\Http\Requests\RestifyRequest;
77
use Binaryk\LaravelRestify\Repositories\Repository;
88
use Binaryk\LaravelRestify\Repositories\UserProfile;
9+
use Illuminate\Http\Request;
910

1011
class UserRepository extends Repository
1112
{
1213
use UserProfile;
1314

15+
public static function canUseForProfile(Request $request): bool
16+
{
17+
return true;
18+
}
19+
1420
public static string $model = User::class;
1521

1622
public static bool $wasBooted = false;

0 commit comments

Comments
 (0)