From 0e492296214efbfe17deb7d30a79d0d48f53a11f Mon Sep 17 00:00:00 2001 From: AmirmahdiNourkazemi Date: Sun, 24 Aug 2025 14:50:15 +0330 Subject: [PATCH] feat: register login with google --- .env.example | 6 +- app/Http/Controllers/UserController.php | 64 +++++- app/Models/User.php | 2 +- app/Providers/TelescopeServiceProvider.php | 64 ++++++ bootstrap/providers.php | 1 + composer.json | 2 +- composer.lock | 14 +- config/database.php | 4 +- config/telescope.php | 207 ++++++++++++++++++ ...24_create_personal_access_tokens_table.php | 33 --- ..._084639_create_telescope_entries_table.php | 70 ++++++ ...d_fcm_token_to_user_package_name_table.php | 26 +++ routes/api.php | 3 +- 13 files changed, 443 insertions(+), 53 deletions(-) create mode 100644 app/Providers/TelescopeServiceProvider.php create mode 100644 config/telescope.php delete mode 100644 database/migrations/2025_04_24_142124_create_personal_access_tokens_table.php create mode 100644 database/migrations/2025_08_24_084639_create_telescope_entries_table.php create mode 100644 database/migrations/2025_08_24_095104_add_fcm_token_to_user_package_name_table.php diff --git a/.env.example b/.env.example index dbec459..d5dee6b 100644 --- a/.env.example +++ b/.env.example @@ -8,7 +8,7 @@ APP_LOCALE=en APP_FALLBACK_LOCALE=en APP_FAKER_LOCALE=en_US -APP_MAINTENANCE_DRIVER=file +# APP_MAINTENANCE_DRIVER=file # APP_MAINTENANCE_STORE=database PHP_CLI_SERVER_WORKERS=4 @@ -23,11 +23,11 @@ LOG_LEVEL=debug DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 -DB_DATABASE=book_db +DB_DATABASE=meditation DB_USERNAME=root DB_PASSWORD= -SESSION_DRIVER=database +SESSION_DRIVER=file SESSION_LIFETIME=120 SESSION_ENCRYPT=false SESSION_PATH=/ diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 1e80d9c..0fc6464 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -16,6 +16,7 @@ use Illuminate\Support\Facades\Storage; use Illuminate\Validation\Rule; use Laravel\Socialite\Facades\Socialite; +use Illuminate\Support\Facades\Http; class UserController extends Controller { public function login(Request $request) @@ -71,7 +72,10 @@ public function register(Request $request) 'mobile' => ['string', new MobileNumber, 'nullable', 'unique:users', 'required_without:email'], ]); - $data['mobile'] = MobileNumberHelper::formatMobile($data['mobile']); + if(isset($data['mobile'])){ + $data['mobile'] = MobileNumberHelper::formatMobile($data['mobile']); + } + if (!isset($data['password'])) { $data['password'] = Hash::make(config('app.default_password')); // Hash default password } else { @@ -94,7 +98,8 @@ public function loginOTP(Request $request) { $data = $request->validate([ 'mobile' => ['string', new MobileNumber, 'required'], - 'package_name' => 'string|required' + 'package_name' => 'string|required', + 'fcm_token' => 'string', ]); if (!$packageName = PackageName::where('name', $data['package_name'])->first()) { @@ -130,7 +135,12 @@ public function loginOTP(Request $request) if (!$user->packageNames()->where('package_names.id', $packageName->id)->exists()) { - $user->packageNames()->attach($packageName->id, ['tries' => $packageName->tries]); + $user->packageNames()->attach($packageName->id, ['tries' => $packageName->tries, + + 'fcm_token' => $data['fcm_token'] ?? null,]); + } else { + $user->packageNames()->updateExistingPivot($packageName->id,[ + 'fcm_token' => $data['fcm_token'] ?? null,]); } return response()->json([ @@ -164,7 +174,7 @@ public function checkOTP(Request $request) if ($user->is_admin) { $token = $user->createToken('token', ['admin'])->plainTextToken; } else { - $token = $user->createToken('token', ['admin'])->plainTextToken; + $token = $user->createToken('token', ['user'])->plainTextToken; } return response()->json([ @@ -285,5 +295,49 @@ public function try(Request $request, $name) { public function oauthCallback(Request $request) { return dd(Socialite::driver('google')->stateless()->user()); - } + } + + public function googleLogin(Request $request) + { + $data = $request->validate([ + 'access_token' => 'string|required', + 'package_name' => 'string|required', + ]); + + if (!$packageName = PackageName::where('name', $data['package_name'])->first()) { + return response()->json([ + 'message' => 'package name not found' + ], 404); + } + + $response = Http::get("https://www.googleapis.com/oauth2/v3/userinfo", [ + 'access_token' => $data['access_token'] + ])->json(); + + if (!isset($response['email'])) { + return response()->json([ + 'message' => 'invalid token' + ], 400); + } + if (!$user = User::where('email', $response['email'])->first()) { + $user = User::create([ + 'email' => $response['email'], + 'password' => config('app.default_password'), + ]); + + if (!$user->packageNames()->where('package_names.id', $packageName->id)->exists()) { + $user->packageNames()->attach($packageName->id, [ + 'tries' => $packageName->tries, + 'source' => $data['source'] ?? 0, + ]); + } + } + + $token = $user->createToken('token', ['user'])->plainTextToken; + + return response()->json([ + 'user' => $user, + 'token' => $token, + ]); + } } diff --git a/app/Models/User.php b/app/Models/User.php index a78e2c3..cbb8897 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -77,7 +77,7 @@ public function transactions() public function packageNames() { - return $this->belongsToMany(PackageName::class, 'user_package_name')->withPivot(['id', 'tries'])->withTimestamps(); + return $this->belongsToMany(PackageName::class, 'user_package_name')->withPivot(['id', 'tries','fcm_token'])->withTimestamps(); } public function products() diff --git a/app/Providers/TelescopeServiceProvider.php b/app/Providers/TelescopeServiceProvider.php new file mode 100644 index 0000000..2349df4 --- /dev/null +++ b/app/Providers/TelescopeServiceProvider.php @@ -0,0 +1,64 @@ +hideSensitiveRequestDetails(); + + $isLocal = $this->app->environment('local'); + + Telescope::filter(function (IncomingEntry $entry) use ($isLocal) { + return $isLocal || + $entry->isReportableException() || + $entry->isFailedRequest() || + $entry->isFailedJob() || + $entry->isScheduledTask() || + $entry->hasMonitoredTag(); + }); + } + + /** + * Prevent sensitive request details from being logged by Telescope. + */ + protected function hideSensitiveRequestDetails(): void + { + if ($this->app->environment('local')) { + return; + } + + Telescope::hideRequestParameters(['_token']); + + Telescope::hideRequestHeaders([ + 'cookie', + 'x-csrf-token', + 'x-xsrf-token', + ]); + } + + /** + * Register the Telescope gate. + * + * This gate determines who can access Telescope in non-local environments. + */ +protected function gate() +{ + Gate::define('viewTelescope', function ($user) { + return app()->environment('local'); + }); +} + +} diff --git a/bootstrap/providers.php b/bootstrap/providers.php index 38b258d..d544739 100644 --- a/bootstrap/providers.php +++ b/bootstrap/providers.php @@ -2,4 +2,5 @@ return [ App\Providers\AppServiceProvider::class, + App\Providers\TelescopeServiceProvider::class, ]; diff --git a/composer.json b/composer.json index 43fef95..2bf2cb8 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ "laravel/framework": "^12.0", "laravel/sanctum": "^4.1", "laravel/socialite": "^5.14", - "laravel/telescope": "^5.0", + "laravel/telescope": "^5.11", "laravel/tinker": "^2.10.1", "masbug/flysystem-google-drive-ext": "^2.4", "predis/predis": "^2.3", diff --git a/composer.lock b/composer.lock index 89169fc..0d89937 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a5afd4740f5c2b59ec13722935f7674f", + "content-hash": "42dd77e9fe0ce2302eb093764611bad0", "packages": [ { "name": "brick/math", @@ -1764,16 +1764,16 @@ }, { "name": "laravel/telescope", - "version": "v5.7.0", + "version": "v5.11.3", "source": { "type": "git", "url": "https://github.com/laravel/telescope.git", - "reference": "440908cb856cfbef9323244f7978ad4bf8cd2daa" + "reference": "7684604e104e7755b70dcacfeee06888e2470689" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/telescope/zipball/440908cb856cfbef9323244f7978ad4bf8cd2daa", - "reference": "440908cb856cfbef9323244f7978ad4bf8cd2daa", + "url": "https://api.github.com/repos/laravel/telescope/zipball/7684604e104e7755b70dcacfeee06888e2470689", + "reference": "7684604e104e7755b70dcacfeee06888e2470689", "shasum": "" }, "require": { @@ -1827,9 +1827,9 @@ ], "support": { "issues": "https://github.com/laravel/telescope/issues", - "source": "https://github.com/laravel/telescope/tree/v5.7.0" + "source": "https://github.com/laravel/telescope/tree/v5.11.3" }, - "time": "2025-03-27T17:25:52+00:00" + "time": "2025-08-21T14:25:40+00:00" }, { "name": "laravel/tinker", diff --git a/config/database.php b/config/database.php index 8910562..23be267 100644 --- a/config/database.php +++ b/config/database.php @@ -16,7 +16,7 @@ | */ - 'default' => env('DB_CONNECTION', 'sqlite'), + 'default' => env('DB_CONNECTION', 'mysql'), /* |-------------------------------------------------------------------------- @@ -47,7 +47,7 @@ 'url' => env('DB_URL'), 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), - 'database' => env('DB_DATABASE', 'laravel'), + 'database' => env('DB_DATABASE', 'meditation'), 'username' => env('DB_USERNAME', 'root'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), diff --git a/config/telescope.php b/config/telescope.php new file mode 100644 index 0000000..af8ca1b --- /dev/null +++ b/config/telescope.php @@ -0,0 +1,207 @@ + env('TELESCOPE_ENABLED', true), + + /* + |-------------------------------------------------------------------------- + | Telescope Domain + |-------------------------------------------------------------------------- + | + | This is the subdomain where Telescope will be accessible from. If the + | setting is null, Telescope will reside under the same domain as the + | application. Otherwise, this value will be used as the subdomain. + | + */ + + 'domain' => env('TELESCOPE_DOMAIN'), + + /* + |-------------------------------------------------------------------------- + | Telescope Path + |-------------------------------------------------------------------------- + | + | This is the URI path where Telescope will be accessible from. Feel free + | to change this path to anything you like. Note that the URI will not + | affect the paths of its internal API that aren't exposed to users. + | + */ + + 'path' => env('TELESCOPE_PATH', 'telescope'), + + /* + |-------------------------------------------------------------------------- + | Telescope Storage Driver + |-------------------------------------------------------------------------- + | + | This configuration options determines the storage driver that will + | be used to store Telescope's data. In addition, you may set any + | custom options as needed by the particular driver you choose. + | + */ + + 'driver' => env('TELESCOPE_DRIVER', 'database'), + + 'storage' => [ + 'database' => [ + 'connection' => env('DB_CONNECTION', 'mysql'), + 'chunk' => 1000, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Telescope Queue + |-------------------------------------------------------------------------- + | + | This configuration options determines the queue connection and queue + | which will be used to process ProcessPendingUpdate jobs. This can + | be changed if you would prefer to use a non-default connection. + | + */ + + 'queue' => [ + 'connection' => env('TELESCOPE_QUEUE_CONNECTION'), + 'queue' => env('TELESCOPE_QUEUE'), + 'delay' => env('TELESCOPE_QUEUE_DELAY', 10), + ], + + /* + |-------------------------------------------------------------------------- + | Telescope Route Middleware + |-------------------------------------------------------------------------- + | + | These middleware will be assigned to every Telescope route, giving you + | the chance to add your own middleware to this list or change any of + | the existing middleware. Or, you can simply stick with this list. + | + */ + + 'middleware' => [ + 'web', + Authorize::class, + ], + + /* + |-------------------------------------------------------------------------- + | Allowed / Ignored Paths & Commands + |-------------------------------------------------------------------------- + | + | The following array lists the URI paths and Artisan commands that will + | not be watched by Telescope. In addition to this list, some Laravel + | commands, like migrations and queue commands, are always ignored. + | + */ + + 'only_paths' => [ + // 'api/*' + ], + + 'ignore_paths' => [ + 'livewire*', + 'nova-api*', + 'pulse*', + ], + + 'ignore_commands' => [ + // + ], + + /* + |-------------------------------------------------------------------------- + | Telescope Watchers + |-------------------------------------------------------------------------- + | + | The following array lists the "watchers" that will be registered with + | Telescope. The watchers gather the application's profile data when + | a request or task is executed. Feel free to customize this list. + | + */ + + 'watchers' => [ + Watchers\BatchWatcher::class => env('TELESCOPE_BATCH_WATCHER', true), + + Watchers\CacheWatcher::class => [ + 'enabled' => env('TELESCOPE_CACHE_WATCHER', true), + 'hidden' => [], + 'ignore' => [], + ], + + Watchers\ClientRequestWatcher::class => env('TELESCOPE_CLIENT_REQUEST_WATCHER', true), + + Watchers\CommandWatcher::class => [ + 'enabled' => env('TELESCOPE_COMMAND_WATCHER', true), + 'ignore' => [], + ], + + Watchers\DumpWatcher::class => [ + 'enabled' => env('TELESCOPE_DUMP_WATCHER', true), + 'always' => env('TELESCOPE_DUMP_WATCHER_ALWAYS', false), + ], + + Watchers\EventWatcher::class => [ + 'enabled' => env('TELESCOPE_EVENT_WATCHER', true), + 'ignore' => [], + ], + + Watchers\ExceptionWatcher::class => env('TELESCOPE_EXCEPTION_WATCHER', true), + + Watchers\GateWatcher::class => [ + 'enabled' => env('TELESCOPE_GATE_WATCHER', true), + 'ignore_abilities' => [], + 'ignore_packages' => true, + 'ignore_paths' => [], + ], + + Watchers\JobWatcher::class => env('TELESCOPE_JOB_WATCHER', true), + + Watchers\LogWatcher::class => [ + 'enabled' => env('TELESCOPE_LOG_WATCHER', true), + 'level' => 'error', + ], + + Watchers\MailWatcher::class => env('TELESCOPE_MAIL_WATCHER', true), + + Watchers\ModelWatcher::class => [ + 'enabled' => env('TELESCOPE_MODEL_WATCHER', true), + 'events' => ['eloquent.*'], + 'hydrations' => true, + ], + + Watchers\NotificationWatcher::class => env('TELESCOPE_NOTIFICATION_WATCHER', true), + + Watchers\QueryWatcher::class => [ + 'enabled' => env('TELESCOPE_QUERY_WATCHER', true), + 'ignore_packages' => true, + 'ignore_paths' => [], + 'slow' => 100, + ], + + Watchers\RedisWatcher::class => env('TELESCOPE_REDIS_WATCHER', true), + + Watchers\RequestWatcher::class => [ + 'enabled' => env('TELESCOPE_REQUEST_WATCHER', true), + 'size_limit' => env('TELESCOPE_RESPONSE_SIZE_LIMIT', 64), + 'ignore_http_methods' => [], + 'ignore_status_codes' => [], + ], + + Watchers\ScheduleWatcher::class => env('TELESCOPE_SCHEDULE_WATCHER', true), + Watchers\ViewWatcher::class => env('TELESCOPE_VIEW_WATCHER', true), + ], +]; diff --git a/database/migrations/2025_04_24_142124_create_personal_access_tokens_table.php b/database/migrations/2025_04_24_142124_create_personal_access_tokens_table.php deleted file mode 100644 index e828ad8..0000000 --- a/database/migrations/2025_04_24_142124_create_personal_access_tokens_table.php +++ /dev/null @@ -1,33 +0,0 @@ -id(); - $table->morphs('tokenable'); - $table->string('name'); - $table->string('token', 64)->unique(); - $table->text('abilities')->nullable(); - $table->timestamp('last_used_at')->nullable(); - $table->timestamp('expires_at')->nullable(); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('personal_access_tokens'); - } -}; diff --git a/database/migrations/2025_08_24_084639_create_telescope_entries_table.php b/database/migrations/2025_08_24_084639_create_telescope_entries_table.php new file mode 100644 index 0000000..700a83f --- /dev/null +++ b/database/migrations/2025_08_24_084639_create_telescope_entries_table.php @@ -0,0 +1,70 @@ +getConnection()); + + $schema->create('telescope_entries', function (Blueprint $table) { + $table->bigIncrements('sequence'); + $table->uuid('uuid'); + $table->uuid('batch_id'); + $table->string('family_hash')->nullable(); + $table->boolean('should_display_on_index')->default(true); + $table->string('type', 20); + $table->longText('content'); + $table->dateTime('created_at')->nullable(); + + $table->unique('uuid'); + $table->index('batch_id'); + $table->index('family_hash'); + $table->index('created_at'); + $table->index(['type', 'should_display_on_index']); + }); + + $schema->create('telescope_entries_tags', function (Blueprint $table) { + $table->uuid('entry_uuid'); + $table->string('tag'); + + $table->primary(['entry_uuid', 'tag']); + $table->index('tag'); + + $table->foreign('entry_uuid') + ->references('uuid') + ->on('telescope_entries') + ->onDelete('cascade'); + }); + + $schema->create('telescope_monitoring', function (Blueprint $table) { + $table->string('tag')->primary(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + $schema = Schema::connection($this->getConnection()); + + $schema->dropIfExists('telescope_entries_tags'); + $schema->dropIfExists('telescope_entries'); + $schema->dropIfExists('telescope_monitoring'); + } +}; diff --git a/database/migrations/2025_08_24_095104_add_fcm_token_to_user_package_name_table.php b/database/migrations/2025_08_24_095104_add_fcm_token_to_user_package_name_table.php new file mode 100644 index 0000000..edff31d --- /dev/null +++ b/database/migrations/2025_08_24_095104_add_fcm_token_to_user_package_name_table.php @@ -0,0 +1,26 @@ +string('fcm_token')->nullable(); + }); +} + +public function down() +{ + Schema::table('user_package_name', function (Blueprint $table) { + $table->dropColumn('fcm_token'); + }); +} + +}; diff --git a/routes/api.php b/routes/api.php index e6618d1..5652f33 100644 --- a/routes/api.php +++ b/routes/api.php @@ -10,12 +10,13 @@ Route::get('package-names/{name}/products', [ProductController::class, 'index']); Route::prefix('auth')->controller(UserController::class)->group(function () { - Route::middleware(['throttle:3,1', 'auto-ban'])->post('login-otp', 'loginOTP'); + Route::middleware(['throttle:3,1'])->post('login-otp', 'loginOTP'); Route::post('check-otp', 'checkOTP'); Route::post('login', 'login'); Route::post('register', 'register'); + Route::post('/login-google', 'googleLogin'); Route::get('/oauth/callback', 'oauthCallback'); Route::middleware('auth:sanctum')->group(function () { Route::put('logout', 'logout');