feat: register login with google

This commit is contained in:
2025-08-24 14:50:15 +03:30
parent d14ad7f0f5
commit 0e49229621
13 changed files with 443 additions and 53 deletions
+3 -3
View File
@@ -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=/
+57 -3
View File
@@ -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'],
]);
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([
@@ -286,4 +296,48 @@ 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,
]);
}
}
+1 -1
View File
@@ -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()
@@ -0,0 +1,64 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Laravel\Telescope\IncomingEntry;
use Laravel\Telescope\Telescope;
use Laravel\Telescope\TelescopeApplicationServiceProvider;
class TelescopeServiceProvider extends TelescopeApplicationServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
// Telescope::night();
$this->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');
});
}
}
+1
View File
@@ -2,4 +2,5 @@
return [
App\Providers\AppServiceProvider::class,
App\Providers\TelescopeServiceProvider::class,
];
+1 -1
View File
@@ -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",
Generated
+7 -7
View File
@@ -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",
+2 -2
View File
@@ -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', ''),
+207
View File
@@ -0,0 +1,207 @@
<?php
use Laravel\Telescope\Http\Middleware\Authorize;
use Laravel\Telescope\Watchers;
return [
/*
|--------------------------------------------------------------------------
| Telescope Master Switch
|--------------------------------------------------------------------------
|
| This option may be used to disable all Telescope watchers regardless
| of their individual configuration, which simply provides a single
| and convenient way to enable or disable Telescope data storage.
|
*/
'enabled' => 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),
],
];
@@ -1,33 +0,0 @@
<?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::create('personal_access_tokens', function (Blueprint $table) {
$table->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');
}
};
@@ -0,0 +1,70 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Get the migration connection name.
*/
public function getConnection(): ?string
{
return config('telescope.storage.database.connection');
}
/**
* Run the migrations.
*/
public function up(): void
{
$schema = Schema::connection($this->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');
}
};
@@ -0,0 +1,26 @@
<?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()
{
Schema::table('user_package_name', function (Blueprint $table) {
$table->string('fcm_token')->nullable();
});
}
public function down()
{
Schema::table('user_package_name', function (Blueprint $table) {
$table->dropColumn('fcm_token');
});
}
};
+2 -1
View File
@@ -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');