├── public ├── favicon.ico ├── robots.txt ├── vendor │ └── telescope │ │ ├── favicon.ico │ │ └── mix-manifest.json ├── .htaccess └── index.php ├── resources ├── css │ └── app.css ├── views │ └── vendor │ │ └── l5-swagger │ │ ├── .gitkeep │ │ └── index.blade.php └── js │ ├── app.js │ └── bootstrap.js ├── database ├── .gitignore ├── seeders │ └── DatabaseSeeder.php ├── migrations │ ├── 2019_08_19_000000_create_failed_jobs_table.php │ ├── 2019_12_14_000001_create_personal_access_tokens_table.php │ └── 2023_06_30_032145_create_permission_tables.php └── factories │ └── UserFactory.php ├── bootstrap ├── cache │ └── .gitignore └── app.php ├── storage ├── logs │ └── .gitignore ├── app │ ├── public │ │ └── .gitignore │ └── .gitignore ├── framework │ ├── testing │ │ └── .gitignore │ ├── views │ │ └── .gitignore │ ├── cache │ │ ├── data │ │ │ └── .gitignore │ │ └── .gitignore │ ├── sessions │ │ └── .gitignore │ └── .gitignore └── api-docs │ └── api-docs.json ├── docs └── readme │ └── Logo.png ├── app ├── Helpers │ └── Constants.php ├── Modules │ ├── Auth │ │ ├── Routes │ │ │ └── api.php │ │ ├── Resources │ │ │ └── LoginResource.php │ │ ├── Requests │ │ │ └── LoginRequest.php │ │ └── Controllers │ │ │ └── AuthController.php │ ├── Room │ │ ├── Repositories │ │ │ ├── RoomRepositoryInterface.php │ │ │ ├── RoomTypeRepositoryInterface.php │ │ │ ├── RoomRepository.php │ │ │ └── RoomTypeRepository.php │ │ ├── Controllers │ │ │ ├── FloorController.php │ │ │ ├── AmenityController.php │ │ │ ├── RoomController.php │ │ │ └── RoomTypeController.php │ │ ├── Routes │ │ │ └── api.php │ │ ├── Models │ │ │ ├── Amenity.php │ │ │ ├── RoomType.php │ │ │ ├── Floor.php │ │ │ └── Room.php │ │ ├── Resources │ │ │ ├── RoomResource.php │ │ │ └── RoomTypeResource.php │ │ ├── Requests │ │ │ ├── CreateRoomRequest.php │ │ │ └── CreateRoomTypeRequest.php │ │ └── Migrations │ │ │ ├── 2023_07_30_110456_create_floors_table.php │ │ │ ├── 2023_07_30_103837_create_room_types_table.php │ │ │ ├── 2023_07_30_103153_create_amenities_table.php │ │ │ └── 2023_07_30_110457_create_rooms_table.php │ └── User │ │ ├── Repositories │ │ ├── UserProfileRepositoryInterface.php │ │ ├── UserProfileRepository.php │ │ ├── UserRepositoryInterface.php │ │ └── UserRepository.php │ │ ├── Resources │ │ ├── UserProfileResource.php │ │ ├── UserDeletedResource.php │ │ ├── UserResource.php │ │ └── UserCreatedResource.php │ │ ├── Models │ │ ├── UserProfile.php │ │ └── User.php │ │ ├── Migrations │ │ ├── 2014_10_12_100000_create_password_reset_tokens_table.php │ │ ├── 2014_10_12_000000_create_users_table.php │ │ └── 2023_07_25_100858_create_user_profiles_table.php │ │ ├── Routes │ │ └── api.php │ │ ├── Requests │ │ ├── DeleteUserRequest.php │ │ ├── ShowUserRequest.php │ │ ├── CreateUserProfileRequest.php │ │ └── CreateUserRequest.php │ │ └── Controllers │ │ └── UserController.php ├── Http │ ├── Middleware │ │ ├── EncryptCookies.php │ │ ├── VerifyCsrfToken.php │ │ ├── PreventRequestsDuringMaintenance.php │ │ ├── TrimStrings.php │ │ ├── TrustHosts.php │ │ ├── Authenticate.php │ │ ├── ValidateSignature.php │ │ ├── TrustProxies.php │ │ └── RedirectIfAuthenticated.php │ ├── Controllers │ │ └── Controller.php │ └── Kernel.php ├── Providers │ ├── BroadcastServiceProvider.php │ ├── AuthServiceProvider.php │ ├── AppServiceProvider.php │ ├── MigrationServiceProvider.php │ ├── EventServiceProvider.php │ ├── RouteServiceProvider.php │ ├── RepositoryServiceProvider.php │ └── TelescopeServiceProvider.php ├── Console │ └── Kernel.php └── Exceptions │ └── Handler.php ├── .shift ├── tests ├── Datasets │ └── Emails.php ├── TestCase.php ├── CreatesApplication.php ├── Pest.php └── Feature │ └── UsersTest.php ├── .gitattributes ├── package.json ├── vite.config.js ├── .gitignore ├── .editorconfig ├── routes ├── web.php ├── channels.php ├── console.php └── api.php ├── SECURITY.md ├── config ├── cors.php ├── services.php ├── view.php ├── hashing.php ├── broadcasting.php ├── sanctum.php ├── filesystems.php ├── cache.php ├── queue.php ├── mail.php ├── auth.php ├── logging.php ├── database.php ├── permission.php ├── telescope.php ├── app.php ├── session.php └── l5-swagger.php ├── LICENSE ├── phpunit.xml ├── .env.github ├── .env.testing ├── .env.example ├── artisan ├── composer.json ├── CODE_OF_CONDUCT.md ├── docker-compose.yml ├── CONTRIBUTING.md └── README.md /public/favicon.ico: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/css/app.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite* 2 | -------------------------------------------------------------------------------- /resources/views/vendor/l5-swagger/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bootstrap/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /resources/js/app.js: -------------------------------------------------------------------------------- 1 | import './bootstrap'; 2 | -------------------------------------------------------------------------------- /storage/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /storage/app/public/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/app/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !public/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /storage/framework/testing/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/views/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/cache/data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/sessions/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !data/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /docs/readme/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajithnow/hotel-manager-laravel/HEAD/docs/readme/Logo.png -------------------------------------------------------------------------------- /public/vendor/telescope/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajithnow/hotel-manager-laravel/HEAD/public/vendor/telescope/favicon.ico -------------------------------------------------------------------------------- /app/Helpers/Constants.php: -------------------------------------------------------------------------------- 1 | name('login'); -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | only('user_uuid'); 10 | } 11 | } -------------------------------------------------------------------------------- /app/Modules/Room/Repositories/RoomRepository.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | // 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /app/Http/Middleware/VerifyCsrfToken.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | // 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /app/Modules/Room/Routes/api.php: -------------------------------------------------------------------------------- 1 | name('create'); 8 | Route::name('type.')->prefix('type')->group( 9 | function () { 10 | Route::post('create', [RoomTypeController::class, 'store'])->name('create'); 11 | } 12 | ); 13 | -------------------------------------------------------------------------------- /app/Modules/Room/Models/Amenity.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | // 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrimStrings.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | 'current_password', 16 | 'password', 17 | 'password_confirmation', 18 | ]; 19 | } 20 | -------------------------------------------------------------------------------- /app/Modules/Room/Models/Floor.php: -------------------------------------------------------------------------------- 1 | make(Kernel::class)->bootstrap(); 18 | 19 | return $app; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrustHosts.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | public function hosts(): array 15 | { 16 | return [ 17 | $this->allSubdomainsOfApplicationUrl(), 18 | ]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Modules/Room/Resources/RoomResource.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | public function toArray(Request $request): array 16 | { 17 | return parent::toArray($request); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | public function toArray(Request $request): array 17 | { 18 | return parent::toArray($request); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Http/Middleware/Authenticate.php: -------------------------------------------------------------------------------- 1 | expectsJson() ? null : route('login'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/Modules/Room/Resources/RoomTypeResource.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | public function toArray(Request $request): array 17 | { 18 | return parent::toArray($request); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Modules/User/Resources/UserProfileResource.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | public function toArray(Request $request): array 16 | { 17 | return parent::toArray($request); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/Modules/User/Models/UserProfile.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | // 'fbclid', 16 | // 'utm_campaign', 17 | // 'utm_content', 18 | // 'utm_medium', 19 | // 'utm_source', 20 | // 'utm_term', 21 | ]; 22 | } 23 | -------------------------------------------------------------------------------- /database/seeders/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | create(); 16 | 17 | // \App\Models\User::factory()->create([ 18 | // 'name' => 'Test User', 19 | // 'email' => 'test@example.com', 20 | // ]); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/Modules/Room/Controllers/RoomController.php: -------------------------------------------------------------------------------- 1 | create($request); 15 | return (new RoomResource($data))->response()->setStatusCode(200); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/Modules/Room/Models/Room.php: -------------------------------------------------------------------------------- 1 | belongsTo(RoomType::class, 'room_type_uuid'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /routes/channels.php: -------------------------------------------------------------------------------- 1 | id === (int) $id; 18 | }); 19 | -------------------------------------------------------------------------------- /app/Providers/AuthServiceProvider.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | protected $policies = [ 16 | // 17 | ]; 18 | 19 | /** 20 | * Register any authentication / authorization services. 21 | */ 22 | public function boot(): void 23 | { 24 | // 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->register(\L5Swagger\L5SwaggerServiceProvider::class); 16 | $this->app->register(RepositoryServiceProvider::class); 17 | } 18 | 19 | /** 20 | * Bootstrap any application services. 21 | */ 22 | public function boot(): void 23 | { 24 | // 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /routes/console.php: -------------------------------------------------------------------------------- 1 | comment(Inspiring::quote()); 19 | })->purpose('Display an inspiring quote'); 20 | -------------------------------------------------------------------------------- /app/Modules/User/Resources/UserDeletedResource.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | public function toArray(Request $request): array 16 | { 17 | return [ 18 | 'message' => 'User Deleted Successfully', 19 | 'data' => [ 20 | 21 | ], 22 | 'status' => 'success', 23 | 'code' => 204, 24 | ]; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews -Indexes 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Handle Authorization Header 9 | RewriteCond %{HTTP:Authorization} . 10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 11 | 12 | # Redirect Trailing Slashes If Not A Folder... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_URI} (.+)/$ 15 | RewriteRule ^ %1 [L,R=301] 16 | 17 | # Send Requests To Front Controller... 18 | RewriteCond %{REQUEST_FILENAME} !-d 19 | RewriteCond %{REQUEST_FILENAME} !-f 20 | RewriteRule ^ index.php [L] 21 | 22 | -------------------------------------------------------------------------------- /app/Console/Kernel.php: -------------------------------------------------------------------------------- 1 | command('inspire')->hourly(); 16 | } 17 | 18 | /** 19 | * Register the commands for the application. 20 | */ 21 | protected function commands(): void 22 | { 23 | $this->load(__DIR__.'/Commands'); 24 | 25 | require base_path('routes/console.php'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /app/Modules/Room/Requests/CreateRoomRequest.php: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | public function rules(): array 23 | { 24 | return [ 25 | // 26 | ]; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/Modules/Auth/Requests/LoginRequest.php: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | public function rules(): array 23 | { 24 | return [ 25 | 'user_name' => 'required', 26 | 'password' => 'required' 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/Modules/User/Resources/UserResource.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | public function toArray($request): array 15 | { 16 | return [ 17 | 'message' => 'User fetched successfully.', 18 | 'data' => [ 19 | 'user_uuid' => $this->uuid, 20 | 'user_name' => $this->name, 21 | 'created_at' => $this->created_at 22 | ], 23 | 'status' => 'success', 24 | 'code' => 201, 25 | ]; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/Exceptions/Handler.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | protected $dontFlash = [ 16 | 'current_password', 17 | 'password', 18 | 'password_confirmation', 19 | ]; 20 | 21 | /** 22 | * Register the exception handling callbacks for the application. 23 | */ 24 | public function register(): void 25 | { 26 | $this->reportable(function (Throwable $e) { 27 | // 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrustProxies.php: -------------------------------------------------------------------------------- 1 | |string|null 14 | */ 15 | protected $proxies; 16 | 17 | /** 18 | * The headers that should be used to detect proxies. 19 | * 20 | * @var int 21 | */ 22 | protected $headers = 23 | Request::HEADER_X_FORWARDED_FOR | 24 | Request::HEADER_X_FORWARDED_HOST | 25 | Request::HEADER_X_FORWARDED_PORT | 26 | Request::HEADER_X_FORWARDED_PROTO | 27 | Request::HEADER_X_FORWARDED_AWS_ELB; 28 | } 29 | -------------------------------------------------------------------------------- /app/Modules/User/Migrations/2014_10_12_100000_create_password_reset_tokens_table.php: -------------------------------------------------------------------------------- 1 | string('email')->primary(); 16 | $table->string('token'); 17 | $table->timestamp('created_at')->nullable(); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | */ 24 | public function down(): void 25 | { 26 | Schema::dropIfExists('password_reset_tokens'); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | uuid('uuid')->primary(); 16 | $table->timestamps(); 17 | $table->string('name')->unique(); 18 | $table->text('description')->nullable(); 19 | $table->json('meta')->nullable(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | */ 26 | public function down(): void 27 | { 28 | Schema::dropIfExists('floors'); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /app/Modules/Room/Migrations/2023_07_30_103837_create_room_types_table.php: -------------------------------------------------------------------------------- 1 | uuid('uuid')->primary(); 16 | $table->timestamps(); 17 | $table->string('name')->unique(); 18 | $table->text('description')->nullable(); 19 | $table->json('meta')->nullable(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | */ 26 | public function down(): void 27 | { 28 | Schema::dropIfExists('room_types'); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /app/Modules/User/Resources/UserCreatedResource.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | public function toArray($request): array 18 | { 19 | return [ 20 | 'message' => 'User created successfully.', 21 | 'data' => [ 22 | 'user_uuid' => $this->uuid, 23 | 'user_name' => $this->name, 24 | 'created_at' => $this->created_at 25 | ], 26 | 'status' => 'success', 27 | 'code' => 201, 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/Providers/MigrationServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadMigrationsFrom($migrationsPath); 29 | } 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /routes/api.php: -------------------------------------------------------------------------------- 1 | prefix('user')->group(base_path('app/Modules/User/Routes/api.php')); 19 | 20 | //Auth Module Routes 21 | Route::name('auth.')->prefix('auth')->group(base_path('app/Modules/Auth/Routes/api.php')); 22 | 23 | //Room Module Routes 24 | Route::name('room.')->prefix('room')->group(base_path('app/Modules/Room/Routes/api.php')); -------------------------------------------------------------------------------- /app/Http/Middleware/RedirectIfAuthenticated.php: -------------------------------------------------------------------------------- 1 | check()) { 24 | return redirect(RouteServiceProvider::HOME); 25 | } 26 | } 27 | 28 | return $next($request); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /database/migrations/2019_08_19_000000_create_failed_jobs_table.php: -------------------------------------------------------------------------------- 1 | uuid('uuid')->primary(); 16 | $table->text('connection'); 17 | $table->text('queue'); 18 | $table->longText('payload'); 19 | $table->longText('exception'); 20 | $table->timestamp('failed_at')->useCurrent(); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | */ 27 | public function down(): void 28 | { 29 | Schema::dropIfExists('failed_jobs'); 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /app/Modules/User/Migrations/2014_10_12_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | uuid('uuid')->primary(); 16 | $table->string('name'); 17 | $table->string('email')->unique(); 18 | $table->timestamp('email_verified_at')->nullable(); 19 | $table->string('password'); 20 | $table->rememberToken(); 21 | $table->timestamps(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | */ 28 | public function down(): void 29 | { 30 | Schema::dropIfExists('users'); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /config/cors.php: -------------------------------------------------------------------------------- 1 | ['api/*', 'sanctum/csrf-cookie'], 19 | 20 | 'allowed_methods' => ['*'], 21 | 22 | 'allowed_origins' => ['*'], 23 | 24 | 'allowed_origins_patterns' => [], 25 | 26 | 'allowed_headers' => ['*'], 27 | 28 | 'exposed_headers' => [], 29 | 30 | 'max_age' => 0, 31 | 32 | 'supports_credentials' => false, 33 | 34 | ]; 35 | -------------------------------------------------------------------------------- /app/Modules/Room/Migrations/2023_07_30_103153_create_amenities_table.php: -------------------------------------------------------------------------------- 1 | uuid('uuid')->primary(); 16 | $table->timestamps(); 17 | $table->string('name')->unique(); 18 | $table->text('description')->nullable(); 19 | $table->boolean('addon')->default(false); 20 | $table->decimal('addon_cost')->default(0.00); 21 | $table->json('meta')->nullable(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | */ 28 | public function down(): void 29 | { 30 | Schema::dropIfExists('amenities'); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /app/Modules/User/Routes/api.php: -------------------------------------------------------------------------------- 1 | name('create'); 19 | Route::get('{id}', [UserController::class, 'show'])->name('show'); 20 | Route::delete('{id}', [UserController::class, 'destroy'])->name('destroy'); 21 | Route::patch('update', [UserController::class, 'update'])->name('update'); 22 | 23 | Route::post('profile', [UserController::class, 'createProfile'])->name('create-profile'); 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/Providers/EventServiceProvider.php: -------------------------------------------------------------------------------- 1 | > 16 | */ 17 | protected $listen = [ 18 | Registered::class => [ 19 | SendEmailVerificationNotification::class, 20 | ], 21 | ]; 22 | 23 | /** 24 | * Register any events for your application. 25 | */ 26 | public function boot(): void 27 | { 28 | // 29 | } 30 | 31 | /** 32 | * Determine if events and listeners should be automatically discovered. 33 | */ 34 | public function shouldDiscoverEvents(): bool 35 | { 36 | return false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /config/services.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'domain' => env('MAILGUN_DOMAIN'), 19 | 'secret' => env('MAILGUN_SECRET'), 20 | 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'), 21 | 'scheme' => 'https', 22 | ], 23 | 24 | 'postmark' => [ 25 | 'token' => env('POSTMARK_TOKEN'), 26 | ], 27 | 28 | 'ses' => [ 29 | 'key' => env('AWS_ACCESS_KEY_ID'), 30 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 31 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 32 | ], 33 | 34 | ]; 35 | -------------------------------------------------------------------------------- /database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php: -------------------------------------------------------------------------------- 1 | uuid('uuid')->primary(); 16 | $table->uuid('tokenable_uuid'); 17 | $table->string('tokenable_type'); 18 | $table->string('name'); 19 | $table->string('token', 64)->unique(); 20 | $table->text('abilities')->nullable(); 21 | $table->timestamp('last_used_at')->nullable(); 22 | $table->timestamp('expires_at')->nullable(); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | */ 30 | public function down(): void 31 | { 32 | Schema::dropIfExists('personal_access_tokens'); 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ajithkumar S 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class UserFactory extends Factory 12 | { 13 | /** 14 | * Define the model's default state. 15 | * 16 | * @return array 17 | */ 18 | public function definition(): array 19 | { 20 | return [ 21 | 'name' => fake()->name(), 22 | 'email' => fake()->unique()->safeEmail(), 23 | 'email_verified_at' => now(), 24 | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 25 | 'remember_token' => Str::random(10), 26 | ]; 27 | } 28 | 29 | /** 30 | * Indicate that the model's email address should be unverified. 31 | */ 32 | public function unverified(): static 33 | { 34 | return $this->state(fn (array $attributes) => [ 35 | 'email_verified_at' => null, 36 | ]); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | ./tests/Unit 10 | 11 | 12 | ./tests/Feature 13 | 14 | 15 | 16 | 17 | ./app 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /config/view.php: -------------------------------------------------------------------------------- 1 | [ 17 | resource_path('views'), 18 | ], 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Compiled View Path 23 | |-------------------------------------------------------------------------- 24 | | 25 | | This option determines where all the compiled Blade templates will be 26 | | stored for your application. Typically, this is within the storage 27 | | directory. However, as usual, you are free to change this value. 28 | | 29 | */ 30 | 31 | 'compiled' => env( 32 | 'VIEW_COMPILED_PATH', 33 | realpath(storage_path('framework/views')) 34 | ), 35 | 36 | ]; 37 | -------------------------------------------------------------------------------- /app/Modules/Room/Requests/CreateRoomTypeRequest.php: -------------------------------------------------------------------------------- 1 | 23 | */ 24 | public function rules(): array 25 | { 26 | return [ 27 | 'name' => 'required|unique:room_types,name', 28 | 'description' => 'nullable' 29 | ]; 30 | } 31 | 32 | protected function failedValidation(ValidationValidator $validator) 33 | { 34 | throw new HttpResponseException(response()->json([ 35 | 'message' => 'Validation error', 36 | 'errors' => $validator->errors(), 37 | ], 403)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/Modules/Room/Migrations/2023_07_30_110457_create_rooms_table.php: -------------------------------------------------------------------------------- 1 | uuid('uuid')->primary(); 16 | $table->timestamps(); 17 | $table->string('name')->unique(); 18 | $table->text('description')->nullable(); 19 | $table->uuid('room_type_id'); 20 | $table->foreign('room_type_id')->references('uuid')->on('room_types'); 21 | $table->decimal('price')->default(0.0); 22 | $table->integer('max_pax')->default(2); 23 | $table->uuid('floor_id'); 24 | $table->foreign('floor_id')->references('uuid')->on('floors'); 25 | $table->json('meta')->nullable(); 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | */ 32 | public function down(): void 33 | { 34 | Schema::dropIfExists('rooms'); 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /app/Providers/RouteServiceProvider.php: -------------------------------------------------------------------------------- 1 | by($request->user()?->id ?: $request->ip()); 29 | }); 30 | 31 | $this->routes(function () { 32 | Route::middleware('api') 33 | ->prefix('api') 34 | ->group(base_path('routes/api.php')); 35 | 36 | Route::middleware('web') 37 | ->group(base_path('routes/web.php')); 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/Modules/User/Migrations/2023_07_25_100858_create_user_profiles_table.php: -------------------------------------------------------------------------------- 1 | uuid('uuid')->primary(); 16 | $table->uuid('user_uuid'); 17 | $table->foreign('user_uuid')->references('uuid')->on('users')->cascadeOnDelete(); 18 | $table->string('address_line_1')->nullable(); 19 | $table->string('address_line_2')->nullable(); 20 | $table->string('city')->nullable(); 21 | $table->string('state')->nullable(); 22 | $table->string('country')->nullable(); 23 | $table->string('phone')->nullable(); 24 | $table->boolean('is_verified')->default(false); 25 | $table->timestamps(); 26 | 27 | $table->index('user_uuid'); 28 | }); 29 | } 30 | 31 | /** 32 | * Reverse the migrations. 33 | */ 34 | public function down(): void 35 | { 36 | Schema::dropIfExists('user_profiles'); 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /app/Providers/RepositoryServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->bind(UserRepositoryInterface::class, UserRepository::class); 23 | $this->app->bind(UserProfileRepositoryInterface::class, UserProfileRepository::class); 24 | $this->app->bind(RoomRepositoryInterface::class, RoomRepository::class); 25 | $this->app->bind(RoomTypeRepositoryInterface::class, RoomTypeRepository::class); 26 | } 27 | 28 | /** 29 | * Bootstrap any application services. 30 | */ 31 | public function boot(): void 32 | { 33 | // 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/Modules/User/Requests/DeleteUserRequest.php: -------------------------------------------------------------------------------- 1 | route('id'); 23 | return $request; 24 | } 25 | 26 | /** 27 | * Get the validation rules that apply to the request. 28 | * 29 | * @return array 30 | */ 31 | public function rules(): array 32 | { 33 | return [ 34 | 'uuid' => 'required|uuid|exists:users,uuid' 35 | ]; 36 | } 37 | 38 | protected function failedValidation(ValidationValidator $validator) 39 | { 40 | throw new HttpResponseException(response()->json([ 41 | 'message' => 'Validation error', 42 | 'errors' => $validator->errors(), 43 | ], 403)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /resources/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * We'll load the axios HTTP library which allows us to easily issue requests 3 | * to our Laravel back-end. This library automatically handles sending the 4 | * CSRF token as a header based on the value of the "XSRF" token cookie. 5 | */ 6 | 7 | import axios from 'axios'; 8 | window.axios = axios; 9 | 10 | window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 11 | 12 | /** 13 | * Echo exposes an expressive API for subscribing to channels and listening 14 | * for events that are broadcast by Laravel. Echo and event broadcasting 15 | * allows your team to easily build robust real-time web applications. 16 | */ 17 | 18 | // import Echo from 'laravel-echo'; 19 | 20 | // import Pusher from 'pusher-js'; 21 | // window.Pusher = Pusher; 22 | 23 | // window.Echo = new Echo({ 24 | // broadcaster: 'pusher', 25 | // key: import.meta.env.VITE_PUSHER_APP_KEY, 26 | // cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1', 27 | // wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`, 28 | // wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80, 29 | // wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443, 30 | // forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https', 31 | // enabledTransports: ['ws', 'wss'], 32 | // }); 33 | -------------------------------------------------------------------------------- /.env.github: -------------------------------------------------------------------------------- 1 | APP_NAME=Laravel 2 | APP_ENV=testing 3 | APP_KEY=base64:uJSAN4A7rIzCdrNfW4nw/75buchlEhQGnrOu51972ms= 4 | APP_DEBUG=true 5 | APP_URL=http://localhost 6 | 7 | LOG_CHANNEL=stack 8 | LOG_DEPRECATIONS_CHANNEL=null 9 | LOG_LEVEL=debug 10 | 11 | DB_CONNECTION=sqlite 12 | DB_DATABASE=database/database.sqlite 13 | 14 | BROADCAST_DRIVER=log 15 | CACHE_DRIVER=file 16 | FILESYSTEM_DISK=local 17 | QUEUE_CONNECTION=sync 18 | SESSION_DRIVER=file 19 | SESSION_LIFETIME=120 20 | 21 | MEMCACHED_HOST=127.0.0.1 22 | 23 | REDIS_HOST=redis 24 | REDIS_PASSWORD=null 25 | REDIS_PORT=6379 26 | 27 | MAIL_MAILER=smtp 28 | MAIL_HOST=mailpit 29 | MAIL_PORT=1025 30 | MAIL_USERNAME=null 31 | MAIL_PASSWORD=null 32 | MAIL_ENCRYPTION=null 33 | MAIL_FROM_ADDRESS="hello@example.com" 34 | MAIL_FROM_NAME="${APP_NAME}" 35 | 36 | AWS_ACCESS_KEY_ID= 37 | AWS_SECRET_ACCESS_KEY= 38 | AWS_DEFAULT_REGION=us-east-1 39 | AWS_BUCKET= 40 | AWS_USE_PATH_STYLE_ENDPOINT=false 41 | 42 | PUSHER_APP_ID= 43 | PUSHER_APP_KEY= 44 | PUSHER_APP_SECRET= 45 | PUSHER_HOST= 46 | PUSHER_PORT=443 47 | PUSHER_SCHEME=https 48 | PUSHER_APP_CLUSTER=mt1 49 | 50 | VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}" 51 | VITE_PUSHER_HOST="${PUSHER_HOST}" 52 | VITE_PUSHER_PORT="${PUSHER_PORT}" 53 | VITE_PUSHER_SCHEME="${PUSHER_SCHEME}" 54 | VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" 55 | 56 | SCOUT_DRIVER=meilisearch 57 | MEILISEARCH_HOST=http://meilisearch:7700 58 | -------------------------------------------------------------------------------- /app/Modules/User/Requests/ShowUserRequest.php: -------------------------------------------------------------------------------- 1 | route('uuid'); 24 | return $request; 25 | } 26 | 27 | /** 28 | * Get the validation rules that apply to the request. 29 | * 30 | * @return array 31 | */ 32 | public function rules(): array 33 | { 34 | return [ 35 | 'uuid' => 'required|uuid|exists:users,uuid' 36 | ]; 37 | } 38 | 39 | protected function failedValidation(ValidationValidator $validator) 40 | { 41 | throw new HttpResponseException(response()->json([ 42 | 'message' => 'Validation error', 43 | 'errors' => $validator->errors(), 44 | ], 403)); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /.env.testing: -------------------------------------------------------------------------------- 1 | APP_NAME=Laravel 2 | APP_ENV=testing 3 | APP_KEY=base64:uJSAN4A7rIzCdrNfW4nw/75buchlEhQGnrOu51972ms= 4 | APP_DEBUG=true 5 | APP_URL=http://localhost 6 | 7 | LOG_CHANNEL=stack 8 | LOG_DEPRECATIONS_CHANNEL=null 9 | LOG_LEVEL=debug 10 | 11 | DB_CONNECTION=mysql 12 | DB_HOST=mysql 13 | DB_PORT=3306 14 | DB_DATABASE=testing 15 | DB_USERNAME=sail 16 | DB_PASSWORD=password 17 | 18 | BROADCAST_DRIVER=log 19 | CACHE_DRIVER=file 20 | FILESYSTEM_DISK=local 21 | QUEUE_CONNECTION=sync 22 | SESSION_DRIVER=file 23 | SESSION_LIFETIME=120 24 | 25 | MEMCACHED_HOST=127.0.0.1 26 | 27 | REDIS_HOST=redis 28 | REDIS_PASSWORD=null 29 | REDIS_PORT=6379 30 | 31 | MAIL_MAILER=smtp 32 | MAIL_HOST=mailpit 33 | MAIL_PORT=1025 34 | MAIL_USERNAME=null 35 | MAIL_PASSWORD=null 36 | MAIL_ENCRYPTION=null 37 | MAIL_FROM_ADDRESS="hello@example.com" 38 | MAIL_FROM_NAME="${APP_NAME}" 39 | 40 | AWS_ACCESS_KEY_ID= 41 | AWS_SECRET_ACCESS_KEY= 42 | AWS_DEFAULT_REGION=us-east-1 43 | AWS_BUCKET= 44 | AWS_USE_PATH_STYLE_ENDPOINT=false 45 | 46 | PUSHER_APP_ID= 47 | PUSHER_APP_KEY= 48 | PUSHER_APP_SECRET= 49 | PUSHER_HOST= 50 | PUSHER_PORT=443 51 | PUSHER_SCHEME=https 52 | PUSHER_APP_CLUSTER=mt1 53 | 54 | VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}" 55 | VITE_PUSHER_HOST="${PUSHER_HOST}" 56 | VITE_PUSHER_PORT="${PUSHER_PORT}" 57 | VITE_PUSHER_SCHEME="${PUSHER_SCHEME}" 58 | VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" 59 | 60 | SCOUT_DRIVER=meilisearch 61 | MEILISEARCH_HOST=http://meilisearch:7700 62 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | APP_NAME=Laravel 2 | APP_ENV=local 3 | APP_KEY=base64:uJSAN4A7rIzCdrNfW4nw/75buchlEhQGnrOu51972ms= 4 | APP_DEBUG=true 5 | APP_URL=http://localhost 6 | 7 | LOG_CHANNEL=stack 8 | LOG_DEPRECATIONS_CHANNEL=null 9 | LOG_LEVEL=debug 10 | 11 | DB_CONNECTION=mysql 12 | DB_HOST=mysql 13 | DB_PORT=3306 14 | DB_DATABASE=example_app 15 | DB_USERNAME=sail 16 | DB_PASSWORD=password 17 | 18 | BROADCAST_DRIVER=log 19 | CACHE_DRIVER=file 20 | FILESYSTEM_DISK=local 21 | QUEUE_CONNECTION=sync 22 | SESSION_DRIVER=file 23 | SESSION_LIFETIME=120 24 | 25 | MEMCACHED_HOST=127.0.0.1 26 | 27 | REDIS_HOST=redis 28 | REDIS_PASSWORD=null 29 | REDIS_PORT=6379 30 | 31 | MAIL_MAILER=smtp 32 | MAIL_HOST=mailpit 33 | MAIL_PORT=1025 34 | MAIL_USERNAME=null 35 | MAIL_PASSWORD=null 36 | MAIL_ENCRYPTION=null 37 | MAIL_FROM_ADDRESS="hello@example.com" 38 | MAIL_FROM_NAME="${APP_NAME}" 39 | 40 | AWS_ACCESS_KEY_ID= 41 | AWS_SECRET_ACCESS_KEY= 42 | AWS_DEFAULT_REGION=us-east-1 43 | AWS_BUCKET= 44 | AWS_USE_PATH_STYLE_ENDPOINT=false 45 | 46 | PUSHER_APP_ID= 47 | PUSHER_APP_KEY= 48 | PUSHER_APP_SECRET= 49 | PUSHER_HOST= 50 | PUSHER_PORT=443 51 | PUSHER_SCHEME=https 52 | PUSHER_APP_CLUSTER=mt1 53 | 54 | VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}" 55 | VITE_PUSHER_HOST="${PUSHER_HOST}" 56 | VITE_PUSHER_PORT="${PUSHER_PORT}" 57 | VITE_PUSHER_SCHEME="${PUSHER_SCHEME}" 58 | VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" 59 | 60 | SCOUT_DRIVER=meilisearch 61 | MEILISEARCH_HOST=http://meilisearch:7700 62 | -------------------------------------------------------------------------------- /app/Modules/User/Requests/CreateUserProfileRequest.php: -------------------------------------------------------------------------------- 1 | 23 | */ 24 | public function rules(): array 25 | { 26 | return [ 27 | 'user_uuid' => 'required|exists:users,uuid|unique:user_profiles,user_uuid', 28 | 'address_line_1' => 'nullable|string|max:255', 29 | 'address_line_2' => 'nullable|string|max:255', 30 | 'city' => 'nullable|string|max:100', 31 | 'state' => 'nullable|string|max:100', 32 | 'country' => 'nullable|string|max:100', 33 | 'phone' => 'nullable|string|max:20', 34 | 'is_verified' => 'nullable|boolean', 35 | ]; 36 | } 37 | 38 | protected function failedValidation(ValidationValidator $validator) 39 | { 40 | throw new HttpResponseException(response()->json([ 41 | 'message' => 'Validation error', 42 | 'errors' => $validator->errors(), 43 | ], 403)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/Modules/User/Repositories/UserRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | in('Feature'); 18 | 19 | /* 20 | |-------------------------------------------------------------------------- 21 | | Expectations 22 | |-------------------------------------------------------------------------- 23 | | 24 | | When you're writing tests, you often need to check that values meet certain conditions. The 25 | | "expect()" function gives you access to a set of "expectations" methods that you can use 26 | | to assert different things. Of course, you may extend the Expectation API at any time. 27 | | 28 | */ 29 | 30 | expect()->extend('toBeOne', function () { 31 | return $this->toBe(1); 32 | }); 33 | 34 | /* 35 | |-------------------------------------------------------------------------- 36 | | Functions 37 | |-------------------------------------------------------------------------- 38 | | 39 | | While Pest is very powerful out-of-the-box, you may have some testing code specific to your 40 | | project that you don't want to repeat in every file. Here you can also expose helpers as 41 | | global functions to help you to reduce the number of lines of code in your test files. 42 | | 43 | */ 44 | 45 | function something() 46 | { 47 | // .. 48 | } 49 | -------------------------------------------------------------------------------- /app/Modules/Auth/Controllers/AuthController.php: -------------------------------------------------------------------------------- 1 | user_name)->first(); 42 | if (!$user || !Hash::check($request->password, $user->password)) { 43 | return (new LoginResource(['invalid login']))->response()->setStatusCode(503); 44 | } 45 | $token = $user->createToken('token')->plainTextToken; 46 | return (new LoginResource(['token' => $token]))->response()->setStatusCode(200); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/Modules/User/Models/User.php: -------------------------------------------------------------------------------- 1 | 23 | */ 24 | protected $fillable = [ 25 | 'name', 26 | 'email', 27 | 'password', 28 | ]; 29 | 30 | protected $keyType = 'string'; 31 | public $incrementing = false; 32 | 33 | /** 34 | * The attributes that should be hidden for serialization. 35 | * 36 | * @var array 37 | */ 38 | protected $hidden = [ 39 | 'password', 40 | 'remember_token', 41 | ]; 42 | 43 | /** 44 | * The attributes that should be cast. 45 | * 46 | * @var array 47 | */ 48 | protected $casts = [ 49 | 'email_verified_at' => 'datetime', 50 | 'password' => 'hashed', 51 | ]; 52 | 53 | /** 54 | * The "booting" method of the User model. 55 | * 56 | * @return void 57 | */ 58 | protected static function boot() 59 | { 60 | parent::boot(); 61 | 62 | static::creating(function ($model) { 63 | $model->uuid = (string) Str::uuid(); 64 | }); 65 | } 66 | 67 | 68 | public function profile(){ 69 | return $this->hasOne(UserProfile::class); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /config/hashing.php: -------------------------------------------------------------------------------- 1 | 'bcrypt', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Bcrypt Options 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may specify the configuration options that should be used when 26 | | passwords are hashed using the Bcrypt algorithm. This will allow you 27 | | to control the amount of time it takes to hash the given password. 28 | | 29 | */ 30 | 31 | 'bcrypt' => [ 32 | 'rounds' => env('BCRYPT_ROUNDS', 10), 33 | ], 34 | 35 | /* 36 | |-------------------------------------------------------------------------- 37 | | Argon Options 38 | |-------------------------------------------------------------------------- 39 | | 40 | | Here you may specify the configuration options that should be used when 41 | | passwords are hashed using the Argon algorithm. These will allow you 42 | | to control the amount of time it takes to hash the given password. 43 | | 44 | */ 45 | 46 | 'argon' => [ 47 | 'memory' => 65536, 48 | 'threads' => 1, 49 | 'time' => 4, 50 | ], 51 | 52 | ]; 53 | -------------------------------------------------------------------------------- /app/Modules/User/Requests/CreateUserRequest.php: -------------------------------------------------------------------------------- 1 | 25 | */ 26 | public function rules() 27 | { 28 | return [ 29 | 'name' => 'required|max:255', 30 | 'email' => 'required|email|unique:users', 31 | 'password' => 'required|min:8', 32 | ]; 33 | } 34 | 35 | /** 36 | * Get the validated data from the request. 37 | * 38 | * @param string|null $key 39 | * @param mixed $default 40 | * @return mixed|array 41 | */ 42 | public function validated($key = null, $default = null) 43 | { 44 | $validatedData = parent::validated(); 45 | $validatedData['password'] = bcrypt($this->input('password')); 46 | return $validatedData; 47 | } 48 | 49 | protected function failedValidation(ValidationValidator $validator) 50 | { 51 | throw new HttpResponseException(response()->json([ 52 | 'message' => 'Validation error', 53 | 'errors' => $validator->errors(), 54 | ], 403)); 55 | } 56 | 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | singleton( 30 | Illuminate\Contracts\Http\Kernel::class, 31 | App\Http\Kernel::class 32 | ); 33 | 34 | $app->singleton( 35 | Illuminate\Contracts\Console\Kernel::class, 36 | App\Console\Kernel::class 37 | ); 38 | 39 | $app->singleton( 40 | Illuminate\Contracts\Debug\ExceptionHandler::class, 41 | App\Exceptions\Handler::class 42 | ); 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Return The Application 47 | |-------------------------------------------------------------------------- 48 | | 49 | | This script returns the application instance. The instance is given to 50 | | the calling script so we can separate the building of the instances 51 | | from the actual running of the application and sending responses. 52 | | 53 | */ 54 | 55 | return $app; 56 | -------------------------------------------------------------------------------- /artisan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | make(Illuminate\Contracts\Console\Kernel::class); 34 | 35 | $status = $kernel->handle( 36 | $input = new Symfony\Component\Console\Input\ArgvInput, 37 | new Symfony\Component\Console\Output\ConsoleOutput 38 | ); 39 | 40 | /* 41 | |-------------------------------------------------------------------------- 42 | | Shutdown The Application 43 | |-------------------------------------------------------------------------- 44 | | 45 | | Once Artisan has finished running, we will fire off the shutdown events 46 | | so that any final work may be done by the application before we shut 47 | | down the process. This is the last thing to happen to the request. 48 | | 49 | */ 50 | 51 | $kernel->terminate($input, $status); 52 | 53 | exit($status); 54 | -------------------------------------------------------------------------------- /app/Providers/TelescopeServiceProvider.php: -------------------------------------------------------------------------------- 1 | hideSensitiveRequestDetails(); 20 | 21 | Telescope::filter(function (IncomingEntry $entry) { 22 | if ($this->app->environment('local')) { 23 | return true; 24 | } 25 | 26 | return $entry->isReportableException() || 27 | $entry->isFailedRequest() || 28 | $entry->isFailedJob() || 29 | $entry->isScheduledTask() || 30 | $entry->hasMonitoredTag(); 31 | }); 32 | } 33 | 34 | /** 35 | * Prevent sensitive request details from being logged by Telescope. 36 | */ 37 | protected function hideSensitiveRequestDetails(): void 38 | { 39 | if ($this->app->environment('local')) { 40 | return; 41 | } 42 | 43 | Telescope::hideRequestParameters(['_token']); 44 | 45 | Telescope::hideRequestHeaders([ 46 | 'cookie', 47 | 'x-csrf-token', 48 | 'x-xsrf-token', 49 | ]); 50 | } 51 | 52 | /** 53 | * Register the Telescope gate. 54 | * 55 | * This gate determines who can access Telescope in non-local environments. 56 | */ 57 | protected function gate(): void 58 | { 59 | Gate::define('viewTelescope', function ($user) { 60 | return in_array($user->email, [ 61 | // 62 | ]); 63 | }); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | make(Kernel::class); 51 | 52 | $response = $kernel->handle( 53 | $request = Request::capture() 54 | )->send(); 55 | 56 | $kernel->terminate($request, $response); 57 | -------------------------------------------------------------------------------- /app/Modules/Room/Controllers/RoomTypeController.php: -------------------------------------------------------------------------------- 1 | create($request->validated()); 45 | return (new ResourcesRoomTypeResource($data))->response()->setStatusCode(201); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/Modules/User/Repositories/UserRepository.php: -------------------------------------------------------------------------------- 1 | uuid)->update($user->toArray()); 30 | } 31 | 32 | /** 33 | * Delete a User. 34 | * 35 | * @param string $uuid The uuid of the user to delete. 36 | * @return bool True if the user is successfully deleted, false otherwise. 37 | */ 38 | public function delete(string $uuid): bool 39 | { 40 | return User::destroy($uuid); 41 | } 42 | 43 | public function get(string $uuid): User 44 | { 45 | return User::find($uuid); 46 | } 47 | 48 | /** 49 | * Find a user by ID. 50 | * 51 | * @param string $uuid The UUID of the user to find. 52 | * @return User|null The found User instance, or null if not found. 53 | */ 54 | public function findById(string $uuid): User 55 | { 56 | return User::find($uuid); 57 | } 58 | 59 | /** 60 | * Get all users. 61 | * 62 | * @return array An array of User instances. 63 | */ 64 | public function findAll(): array 65 | { 66 | return User::all()->toArray(); 67 | } 68 | 69 | /** 70 | * Find a user by email. 71 | * 72 | * @param string $email The email of the user to find. 73 | * @return User|null The found User instance, or null if not found. 74 | */ 75 | public function findByEmail(string $email): User 76 | { 77 | return User::where('email', $email)->first(); 78 | } 79 | 80 | public function findByUUID(string $uuid): User 81 | { 82 | return User::findOrFail($uuid); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /config/broadcasting.php: -------------------------------------------------------------------------------- 1 | env('BROADCAST_DRIVER', 'null'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Broadcast Connections 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may define all of the broadcast connections that will be used 26 | | to broadcast events to other systems or over websockets. Samples of 27 | | each available type of connection are provided inside this array. 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'pusher' => [ 34 | 'driver' => 'pusher', 35 | 'key' => env('PUSHER_APP_KEY'), 36 | 'secret' => env('PUSHER_APP_SECRET'), 37 | 'app_id' => env('PUSHER_APP_ID'), 38 | 'options' => [ 39 | 'cluster' => env('PUSHER_APP_CLUSTER'), 40 | 'host' => env('PUSHER_HOST') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com', 41 | 'port' => env('PUSHER_PORT', 443), 42 | 'scheme' => env('PUSHER_SCHEME', 'https'), 43 | 'encrypted' => true, 44 | 'useTLS' => env('PUSHER_SCHEME', 'https') === 'https', 45 | ], 46 | 'client_options' => [ 47 | // Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html 48 | ], 49 | ], 50 | 51 | 'ably' => [ 52 | 'driver' => 'ably', 53 | 'key' => env('ABLY_KEY'), 54 | ], 55 | 56 | 'redis' => [ 57 | 'driver' => 'redis', 58 | 'connection' => 'default', 59 | ], 60 | 61 | 'log' => [ 62 | 'driver' => 'log', 63 | ], 64 | 65 | 'null' => [ 66 | 'driver' => 'null', 67 | ], 68 | 69 | ], 70 | 71 | ]; 72 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel/laravel", 3 | "type": "project", 4 | "description": "The skeleton application for the Laravel framework.", 5 | "keywords": ["laravel", "framework"], 6 | "license": "MIT", 7 | "require": { 8 | "php": "^8.1", 9 | "darkaonline/l5-swagger": "^8.5", 10 | "guzzlehttp/guzzle": "^7.2", 11 | "laravel/framework": "^10.10", 12 | "laravel/sanctum": "^3.2", 13 | "laravel/telescope": "^4.15", 14 | "laravel/tinker": "^2.8", 15 | "spatie/laravel-permission": "^5.10" 16 | }, 17 | "require-dev": { 18 | "fakerphp/faker": "^1.9.1", 19 | "laravel/pint": "^1.0", 20 | "laravel/sail": "^1.18", 21 | "mockery/mockery": "^1.4.4", 22 | "nunomaduro/collision": "^7.0", 23 | "pestphp/pest": "^2.8", 24 | "pestphp/pest-plugin-laravel": "^2.0", 25 | "phpunit/phpunit": "^10.1", 26 | "spatie/laravel-ignition": "^2.0" 27 | }, 28 | "autoload": { 29 | "psr-4": { 30 | "App\\": "app/", 31 | "Database\\Factories\\": "database/factories/", 32 | "Database\\Seeders\\": "database/seeders/" 33 | }, 34 | "files": [ 35 | "app/Helpers/Constants.php" 36 | ] 37 | }, 38 | "autoload-dev": { 39 | "psr-4": { 40 | "Tests\\": "tests/" 41 | } 42 | }, 43 | "scripts": { 44 | "post-autoload-dump": [ 45 | "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", 46 | "@php artisan package:discover --ansi" 47 | ], 48 | "post-update-cmd": [ 49 | "@php artisan vendor:publish --tag=laravel-assets --ansi --force" 50 | ], 51 | "post-root-package-install": [ 52 | "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" 53 | ], 54 | "post-create-project-cmd": [ 55 | "@php artisan key:generate --ansi" 56 | ] 57 | }, 58 | "extra": { 59 | "laravel": { 60 | "dont-discover": [] 61 | } 62 | }, 63 | "config": { 64 | "optimize-autoloader": true, 65 | "preferred-install": "dist", 66 | "sort-packages": true, 67 | "allow-plugins": { 68 | "pestphp/pest-plugin": true, 69 | "php-http/discovery": true 70 | } 71 | }, 72 | "minimum-stability": "stable", 73 | "prefer-stable": true 74 | } 75 | -------------------------------------------------------------------------------- /config/sanctum.php: -------------------------------------------------------------------------------- 1 | explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( 19 | '%s%s', 20 | 'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1', 21 | Sanctum::currentApplicationUrlWithPort() 22 | ))), 23 | 24 | /* 25 | |-------------------------------------------------------------------------- 26 | | Sanctum Guards 27 | |-------------------------------------------------------------------------- 28 | | 29 | | This array contains the authentication guards that will be checked when 30 | | Sanctum is trying to authenticate a request. If none of these guards 31 | | are able to authenticate the request, Sanctum will use the bearer 32 | | token that's present on an incoming request for authentication. 33 | | 34 | */ 35 | 36 | 'guard' => ['web'], 37 | 38 | /* 39 | |-------------------------------------------------------------------------- 40 | | Expiration Minutes 41 | |-------------------------------------------------------------------------- 42 | | 43 | | This value controls the number of minutes until an issued token will be 44 | | considered expired. If this value is null, personal access tokens do 45 | | not expire. This won't tweak the lifetime of first-party sessions. 46 | | 47 | */ 48 | 49 | 'expiration' => null, 50 | 51 | /* 52 | |-------------------------------------------------------------------------- 53 | | Sanctum Middleware 54 | |-------------------------------------------------------------------------- 55 | | 56 | | When authenticating your first-party SPA with Sanctum you may need to 57 | | customize some of the middleware Sanctum uses while processing the 58 | | request. You may change the middleware listed below as required. 59 | | 60 | */ 61 | 62 | 'middleware' => [ 63 | 'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class, 64 | 'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class, 65 | ], 66 | 67 | ]; 68 | -------------------------------------------------------------------------------- /config/filesystems.php: -------------------------------------------------------------------------------- 1 | env('FILESYSTEM_DISK', 'local'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Filesystem Disks 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may configure as many filesystem "disks" as you wish, and you 24 | | may even configure multiple disks of the same driver. Defaults have 25 | | been set up for each driver as an example of the required values. 26 | | 27 | | Supported Drivers: "local", "ftp", "sftp", "s3" 28 | | 29 | */ 30 | 31 | 'disks' => [ 32 | 33 | 'local' => [ 34 | 'driver' => 'local', 35 | 'root' => storage_path('app'), 36 | 'throw' => false, 37 | ], 38 | 39 | 'public' => [ 40 | 'driver' => 'local', 41 | 'root' => storage_path('app/public'), 42 | 'url' => env('APP_URL').'/storage', 43 | 'visibility' => 'public', 44 | 'throw' => false, 45 | ], 46 | 47 | 's3' => [ 48 | 'driver' => 's3', 49 | 'key' => env('AWS_ACCESS_KEY_ID'), 50 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 51 | 'region' => env('AWS_DEFAULT_REGION'), 52 | 'bucket' => env('AWS_BUCKET'), 53 | 'url' => env('AWS_URL'), 54 | 'endpoint' => env('AWS_ENDPOINT'), 55 | 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false), 56 | 'throw' => false, 57 | ], 58 | 59 | ], 60 | 61 | /* 62 | |-------------------------------------------------------------------------- 63 | | Symbolic Links 64 | |-------------------------------------------------------------------------- 65 | | 66 | | Here you may configure the symbolic links that will be created when the 67 | | `storage:link` Artisan command is executed. The array keys should be 68 | | the locations of the links and the values should be their targets. 69 | | 70 | */ 71 | 72 | 'links' => [ 73 | public_path('storage') => storage_path('app/public'), 74 | ], 75 | 76 | ]; 77 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Introduction 4 | 5 | We, as contributors and maintainers, pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | This code of conduct outlines our expectations for all those who participate in our community, as well as the consequences for unacceptable behavior. 8 | 9 | We invite all those who participate in our project to help us create safe and positive experiences for everyone. 10 | 11 | ## Our Standards 12 | 13 | Examples of behavior that contributes to creating a positive environment include: 14 | 15 | - Being respectful and considerate of others' opinions and experiences. 16 | - Using inclusive language and avoiding derogatory or offensive comments. 17 | - Being open to constructive feedback and ideas from others. 18 | - Showing empathy and kindness towards others. 19 | - Respecting privacy and personal boundaries. 20 | 21 | Examples of unacceptable behavior include: 22 | 23 | - Harassment, discrimination, or any form of offensive or inappropriate behavior. 24 | - Trolling, insulting, or derogatory comments or personal attacks. 25 | - Intimidating or bullying others. 26 | - Publishing private information without explicit permission. 27 | - Any other conduct that violates the rights of others or creates a hostile or uncomfortable environment. 28 | 29 | ## Consequences of Unacceptable Behavior 30 | 31 | Unacceptable behavior will not be tolerated by our community. Anyone who engages in such behavior may be temporarily or permanently banned from participating in our project and community activities. 32 | 33 | ## Reporting and Enforcement 34 | 35 | If you experience or witness any instances of unacceptable behavior, please report it to the project maintainers. All reports will be reviewed and investigated promptly and confidentially. The project team is obligated to respect the privacy and security of the reporter of any incident. 36 | 37 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned with this Code of Conduct or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 38 | 39 | ## Scope 40 | 41 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. 42 | 43 | ## Attribution 44 | 45 | This Code of Conduct is adapted from the Contributor Covenant (https://www.contributor-covenant.org), version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 46 | 47 | -------------------------------------------------------------------------------- /app/Http/Kernel.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | protected $middleware = [ 17 | // \App\Http\Middleware\TrustHosts::class, 18 | \App\Http\Middleware\TrustProxies::class, 19 | \Illuminate\Http\Middleware\HandleCors::class, 20 | \App\Http\Middleware\PreventRequestsDuringMaintenance::class, 21 | \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, 22 | \App\Http\Middleware\TrimStrings::class, 23 | \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, 24 | ]; 25 | 26 | /** 27 | * The application's route middleware groups. 28 | * 29 | * @var array> 30 | */ 31 | protected $middlewareGroups = [ 32 | 'web' => [ 33 | \App\Http\Middleware\EncryptCookies::class, 34 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, 35 | \Illuminate\Session\Middleware\StartSession::class, 36 | \Illuminate\View\Middleware\ShareErrorsFromSession::class, 37 | \App\Http\Middleware\VerifyCsrfToken::class, 38 | \Illuminate\Routing\Middleware\SubstituteBindings::class, 39 | ], 40 | 41 | 'api' => [ 42 | // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, 43 | \Illuminate\Routing\Middleware\ThrottleRequests::class.':api', 44 | \Illuminate\Routing\Middleware\SubstituteBindings::class, 45 | ], 46 | ]; 47 | 48 | /** 49 | * The application's middleware aliases. 50 | * 51 | * Aliases may be used instead of class names to conveniently assign middleware to routes and groups. 52 | * 53 | * @var array 54 | */ 55 | protected $middlewareAliases = [ 56 | 'auth' => \App\Http\Middleware\Authenticate::class, 57 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 58 | 'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class, 59 | 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 60 | 'can' => \Illuminate\Auth\Middleware\Authorize::class, 61 | 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 62 | 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, 63 | 'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class, 64 | 'signed' => \App\Http\Middleware\ValidateSignature::class, 65 | 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 66 | 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, 67 | ]; 68 | } 69 | -------------------------------------------------------------------------------- /resources/views/vendor/l5-swagger/index.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{config('l5-swagger.documentations.'.$documentation.'.api.title')}} 6 | 7 | 8 | 9 | 28 | 29 | 30 | 31 |
32 | 33 | 34 | 35 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /tests/Feature/UsersTest.php: -------------------------------------------------------------------------------- 1 | 'test', 13 | 'email' => 'test@test.com', 14 | 'password' => 'test@1234', 15 | ])->assertStatus(201); 16 | })->group('users'); 17 | 18 | it('cannot create a user with the same email', function () { 19 | postUser([ 20 | 'name' => 'test', 21 | 'email' => 'test@test.com', 22 | 'password' => 'test@1234', 23 | ])->assertStatus(201); 24 | 25 | postUser([ 26 | 'name' => 'test', 27 | 'email' => 'test@test.com', 28 | 'password' => 'test@jsjsjjsj', 29 | ])->assertStatus(403)->assertJson([ 30 | 'message' => 'Validation error', 31 | 'errors' => [ 32 | 'email' => ['The email has already been taken.'] 33 | ] 34 | ]); 35 | })->group('users'); 36 | 37 | it('cannot create a user with a password less than 8 characters', function () { 38 | postUser([ 39 | 'name' => 'test', 40 | 'email' => 'test@test2.com', 41 | 'password' => 'test', 42 | ])->assertStatus(403)->assertJson([ 43 | 'message' => 'Validation error', 44 | 'errors' => [ 45 | 'password' => ['The password field must be at least 8 characters.'] 46 | ] 47 | ]); 48 | })->group('users'); 49 | 50 | it('can create a user profile with valid data', function (){ 51 | postUser([ 52 | 'name' => 'test', 53 | 'email' => 'test@test2.com', 54 | 'password' => 'test@yyyyei', 55 | ])->assertStatus(201); 56 | $user = User::first(); 57 | $uuid = $user->uuid; 58 | $data = [ 59 | 'user_uuid' => $uuid, 60 | 'address_line_1' => 'ad1', 61 | 'address_line_2' => 'ad2', 62 | 'city' => 'city', 63 | 'state' => 'state', 64 | 'country'=> 'country', 65 | 'is_verified' => false 66 | ]; postUserProfile($data)->assertStatus(201); 67 | })->group('users'); 68 | 69 | it('it cannot create a user profile with invalid id', function (){ 70 | $data = [ 71 | 'user_uuid' => '01c14b35-4411-4a75-9b47-c867f1f2e720', 72 | 'address_line_1' => 'ad1', 73 | 'address_line_2' => 'ad2', 74 | 'city' => 'city', 75 | 'state' => 'state', 76 | 'country'=> 'country', 77 | 'is_verified' => false 78 | ]; 79 | postUserProfile($data)->assertStatus(403); 80 | })->group('users'); 81 | 82 | it('it cannot create a duplicate user profile', function (){ 83 | postUser([ 84 | 'name' => 'test', 85 | 'email' => 'test@test2.com', 86 | 'password' => 'test@yuiyujjhj', 87 | ])->assertStatus(201); 88 | $user = User::first(); 89 | $uuid = $user->uuid; 90 | $data = [ 91 | 'user_uuid' => $uuid, 92 | 'address_line_1' => 'ad1', 93 | 'address_line_2' => 'ad2', 94 | 'city' => 'city', 95 | 'state' => 'state', 96 | 'country'=> 'country', 97 | 'is_verified' => false 98 | ]; postUserProfile($data)->assertStatus(201); 99 | postUserProfile($data)->assertStatus(403); 100 | })->group('users'); 101 | 102 | 103 | 104 | function postUser(array $data) 105 | { 106 | return post(route('user.create'), $data); 107 | } 108 | 109 | function postUserProfile(array $data) 110 | { 111 | return post(route('user.create-profile'), $data); 112 | } 113 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | laravel.test: 4 | build: 5 | context: ./vendor/laravel/sail/runtimes/8.2 6 | dockerfile: Dockerfile 7 | args: 8 | WWWGROUP: '${WWWGROUP}' 9 | image: sail-8.2/app 10 | extra_hosts: 11 | - 'host.docker.internal:host-gateway' 12 | ports: 13 | - '${APP_PORT:-80}:80' 14 | - '${VITE_PORT:-5173}:${VITE_PORT:-5173}' 15 | environment: 16 | WWWUSER: '${WWWUSER}' 17 | LARAVEL_SAIL: 1 18 | XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}' 19 | XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}' 20 | IGNITION_LOCAL_SITES_PATH: '${PWD}' 21 | volumes: 22 | - '.:/var/www/html' 23 | networks: 24 | - sail 25 | depends_on: 26 | - mysql 27 | - redis 28 | - meilisearch 29 | - mailpit 30 | - selenium 31 | mysql: 32 | image: 'mysql/mysql-server:8.0' 33 | ports: 34 | - '${FORWARD_DB_PORT:-3306}:3306' 35 | environment: 36 | MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}' 37 | MYSQL_ROOT_HOST: '%' 38 | MYSQL_DATABASE: '${DB_DATABASE}' 39 | MYSQL_USER: '${DB_USERNAME}' 40 | MYSQL_PASSWORD: '${DB_PASSWORD}' 41 | MYSQL_ALLOW_EMPTY_PASSWORD: 1 42 | volumes: 43 | - 'sail-mysql:/var/lib/mysql' 44 | - './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh' 45 | networks: 46 | - sail 47 | healthcheck: 48 | test: 49 | - CMD 50 | - mysqladmin 51 | - ping 52 | - '-p${DB_PASSWORD}' 53 | retries: 3 54 | timeout: 5s 55 | redis: 56 | image: 'redis:alpine' 57 | ports: 58 | - '${FORWARD_REDIS_PORT:-6379}:6379' 59 | volumes: 60 | - 'sail-redis:/data' 61 | networks: 62 | - sail 63 | healthcheck: 64 | test: 65 | - CMD 66 | - redis-cli 67 | - ping 68 | retries: 3 69 | timeout: 5s 70 | meilisearch: 71 | image: 'getmeili/meilisearch:latest' 72 | ports: 73 | - '${FORWARD_MEILISEARCH_PORT:-7700}:7700' 74 | volumes: 75 | - 'sail-meilisearch:/meili_data' 76 | networks: 77 | - sail 78 | healthcheck: 79 | test: 80 | - CMD 81 | - wget 82 | - '--no-verbose' 83 | - '--spider' 84 | - 'http://localhost:7700/health' 85 | retries: 3 86 | timeout: 5s 87 | mailpit: 88 | image: 'axllent/mailpit:latest' 89 | ports: 90 | - '${FORWARD_MAILPIT_PORT:-1025}:1025' 91 | - '${FORWARD_MAILPIT_DASHBOARD_PORT:-8025}:8025' 92 | networks: 93 | - sail 94 | selenium: 95 | image: seleniarm/standalone-chromium 96 | extra_hosts: 97 | - 'host.docker.internal:host-gateway' 98 | volumes: 99 | - '/dev/shm:/dev/shm' 100 | networks: 101 | - sail 102 | networks: 103 | sail: 104 | driver: bridge 105 | volumes: 106 | sail-mysql: 107 | driver: local 108 | sail-redis: 109 | driver: local 110 | sail-meilisearch: 111 | driver: local 112 | -------------------------------------------------------------------------------- /config/cache.php: -------------------------------------------------------------------------------- 1 | env('CACHE_DRIVER', 'file'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Cache Stores 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may define all of the cache "stores" for your application as 26 | | well as their drivers. You may even define multiple stores for the 27 | | same cache driver to group types of items stored in your caches. 28 | | 29 | | Supported drivers: "apc", "array", "database", "file", 30 | | "memcached", "redis", "dynamodb", "octane", "null" 31 | | 32 | */ 33 | 34 | 'stores' => [ 35 | 36 | 'apc' => [ 37 | 'driver' => 'apc', 38 | ], 39 | 40 | 'array' => [ 41 | 'driver' => 'array', 42 | 'serialize' => false, 43 | ], 44 | 45 | 'database' => [ 46 | 'driver' => 'database', 47 | 'table' => 'cache', 48 | 'connection' => null, 49 | 'lock_connection' => null, 50 | ], 51 | 52 | 'file' => [ 53 | 'driver' => 'file', 54 | 'path' => storage_path('framework/cache/data'), 55 | 'lock_path' => storage_path('framework/cache/data'), 56 | ], 57 | 58 | 'memcached' => [ 59 | 'driver' => 'memcached', 60 | 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), 61 | 'sasl' => [ 62 | env('MEMCACHED_USERNAME'), 63 | env('MEMCACHED_PASSWORD'), 64 | ], 65 | 'options' => [ 66 | // Memcached::OPT_CONNECT_TIMEOUT => 2000, 67 | ], 68 | 'servers' => [ 69 | [ 70 | 'host' => env('MEMCACHED_HOST', '127.0.0.1'), 71 | 'port' => env('MEMCACHED_PORT', 11211), 72 | 'weight' => 100, 73 | ], 74 | ], 75 | ], 76 | 77 | 'redis' => [ 78 | 'driver' => 'redis', 79 | 'connection' => 'cache', 80 | 'lock_connection' => 'default', 81 | ], 82 | 83 | 'dynamodb' => [ 84 | 'driver' => 'dynamodb', 85 | 'key' => env('AWS_ACCESS_KEY_ID'), 86 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 87 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 88 | 'table' => env('DYNAMODB_CACHE_TABLE', 'cache'), 89 | 'endpoint' => env('DYNAMODB_ENDPOINT'), 90 | ], 91 | 92 | 'octane' => [ 93 | 'driver' => 'octane', 94 | ], 95 | 96 | ], 97 | 98 | /* 99 | |-------------------------------------------------------------------------- 100 | | Cache Key Prefix 101 | |-------------------------------------------------------------------------- 102 | | 103 | | When utilizing the APC, database, memcached, Redis, or DynamoDB cache 104 | | stores there might be other applications using the same cache. For 105 | | that reason, you may prefix every cache key to avoid collisions. 106 | | 107 | */ 108 | 109 | 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'), 110 | 111 | ]; 112 | -------------------------------------------------------------------------------- /config/queue.php: -------------------------------------------------------------------------------- 1 | env('QUEUE_CONNECTION', 'sync'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Queue Connections 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may configure the connection information for each server that 24 | | is used by your application. A default configuration has been added 25 | | for each back-end shipped with Laravel. You are free to add more. 26 | | 27 | | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null" 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'sync' => [ 34 | 'driver' => 'sync', 35 | ], 36 | 37 | 'database' => [ 38 | 'driver' => 'database', 39 | 'table' => 'jobs', 40 | 'queue' => 'default', 41 | 'retry_after' => 90, 42 | 'after_commit' => false, 43 | ], 44 | 45 | 'beanstalkd' => [ 46 | 'driver' => 'beanstalkd', 47 | 'host' => 'localhost', 48 | 'queue' => 'default', 49 | 'retry_after' => 90, 50 | 'block_for' => 0, 51 | 'after_commit' => false, 52 | ], 53 | 54 | 'sqs' => [ 55 | 'driver' => 'sqs', 56 | 'key' => env('AWS_ACCESS_KEY_ID'), 57 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 58 | 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), 59 | 'queue' => env('SQS_QUEUE', 'default'), 60 | 'suffix' => env('SQS_SUFFIX'), 61 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 62 | 'after_commit' => false, 63 | ], 64 | 65 | 'redis' => [ 66 | 'driver' => 'redis', 67 | 'connection' => 'default', 68 | 'queue' => env('REDIS_QUEUE', 'default'), 69 | 'retry_after' => 90, 70 | 'block_for' => null, 71 | 'after_commit' => false, 72 | ], 73 | 74 | ], 75 | 76 | /* 77 | |-------------------------------------------------------------------------- 78 | | Job Batching 79 | |-------------------------------------------------------------------------- 80 | | 81 | | The following options configure the database and table that store job 82 | | batching information. These options can be updated to any database 83 | | connection and table which has been defined by your application. 84 | | 85 | */ 86 | 87 | 'batching' => [ 88 | 'database' => env('DB_CONNECTION', 'mysql'), 89 | 'table' => 'job_batches', 90 | ], 91 | 92 | /* 93 | |-------------------------------------------------------------------------- 94 | | Failed Queue Jobs 95 | |-------------------------------------------------------------------------- 96 | | 97 | | These options configure the behavior of failed queue job logging so you 98 | | can control which database and table are used to store the jobs that 99 | | have failed. You may change them to any database / table you wish. 100 | | 101 | */ 102 | 103 | 'failed' => [ 104 | 'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'), 105 | 'database' => env('DB_CONNECTION', 'mysql'), 106 | 'table' => 'failed_jobs', 107 | ], 108 | 109 | ]; 110 | -------------------------------------------------------------------------------- /config/mail.php: -------------------------------------------------------------------------------- 1 | env('MAIL_MAILER', 'smtp'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Mailer Configurations 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may configure all of the mailers used by your application plus 24 | | their respective settings. Several examples have been configured for 25 | | you and you are free to add your own as your application requires. 26 | | 27 | | Laravel supports a variety of mail "transport" drivers to be used while 28 | | sending an e-mail. You will specify which one you are using for your 29 | | mailers below. You are free to add additional mailers as required. 30 | | 31 | | Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2", 32 | | "postmark", "log", "array", "failover" 33 | | 34 | */ 35 | 36 | 'mailers' => [ 37 | 'smtp' => [ 38 | 'transport' => 'smtp', 39 | 'url' => env('MAIL_URL'), 40 | 'host' => env('MAIL_HOST', 'smtp.mailgun.org'), 41 | 'port' => env('MAIL_PORT', 587), 42 | 'encryption' => env('MAIL_ENCRYPTION', 'tls'), 43 | 'username' => env('MAIL_USERNAME'), 44 | 'password' => env('MAIL_PASSWORD'), 45 | 'timeout' => null, 46 | 'local_domain' => env('MAIL_EHLO_DOMAIN'), 47 | ], 48 | 49 | 'ses' => [ 50 | 'transport' => 'ses', 51 | ], 52 | 53 | 'mailgun' => [ 54 | 'transport' => 'mailgun', 55 | // 'client' => [ 56 | // 'timeout' => 5, 57 | // ], 58 | ], 59 | 60 | 'postmark' => [ 61 | 'transport' => 'postmark', 62 | // 'client' => [ 63 | // 'timeout' => 5, 64 | // ], 65 | ], 66 | 67 | 'sendmail' => [ 68 | 'transport' => 'sendmail', 69 | 'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'), 70 | ], 71 | 72 | 'log' => [ 73 | 'transport' => 'log', 74 | 'channel' => env('MAIL_LOG_CHANNEL'), 75 | ], 76 | 77 | 'array' => [ 78 | 'transport' => 'array', 79 | ], 80 | 81 | 'failover' => [ 82 | 'transport' => 'failover', 83 | 'mailers' => [ 84 | 'smtp', 85 | 'log', 86 | ], 87 | ], 88 | ], 89 | 90 | /* 91 | |-------------------------------------------------------------------------- 92 | | Global "From" Address 93 | |-------------------------------------------------------------------------- 94 | | 95 | | You may wish for all e-mails sent by your application to be sent from 96 | | the same address. Here, you may specify a name and address that is 97 | | used globally for all e-mails that are sent by your application. 98 | | 99 | */ 100 | 101 | 'from' => [ 102 | 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), 103 | 'name' => env('MAIL_FROM_NAME', 'Example'), 104 | ], 105 | 106 | /* 107 | |-------------------------------------------------------------------------- 108 | | Markdown Mail Settings 109 | |-------------------------------------------------------------------------- 110 | | 111 | | If you are using Markdown based email rendering, you may configure your 112 | | theme and component paths here, allowing you to customize the design 113 | | of the emails. Or, you may simply stick with the Laravel defaults! 114 | | 115 | */ 116 | 117 | 'markdown' => [ 118 | 'theme' => 'default', 119 | 120 | 'paths' => [ 121 | resource_path('views/vendor/mail'), 122 | ], 123 | ], 124 | 125 | ]; 126 | -------------------------------------------------------------------------------- /config/auth.php: -------------------------------------------------------------------------------- 1 | [ 17 | 'guard' => 'web', 18 | 'passwords' => 'users', 19 | ], 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Authentication Guards 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Next, you may define every authentication guard for your application. 27 | | Of course, a great default configuration has been defined for you 28 | | here which uses session storage and the Eloquent user provider. 29 | | 30 | | All authentication drivers have a user provider. This defines how the 31 | | users are actually retrieved out of your database or other storage 32 | | mechanisms used by this application to persist your user's data. 33 | | 34 | | Supported: "session" 35 | | 36 | */ 37 | 38 | 'guards' => [ 39 | 'web' => [ 40 | 'driver' => 'session', 41 | 'provider' => 'users', 42 | ], 43 | ], 44 | 45 | /* 46 | |-------------------------------------------------------------------------- 47 | | User Providers 48 | |-------------------------------------------------------------------------- 49 | | 50 | | All authentication drivers have a user provider. This defines how the 51 | | users are actually retrieved out of your database or other storage 52 | | mechanisms used by this application to persist your user's data. 53 | | 54 | | If you have multiple user tables or models you may configure multiple 55 | | sources which represent each model / table. These sources may then 56 | | be assigned to any extra authentication guards you have defined. 57 | | 58 | | Supported: "database", "eloquent" 59 | | 60 | */ 61 | 62 | 'providers' => [ 63 | 'users' => [ 64 | 'driver' => 'eloquent', 65 | 'model' => App\Models\User::class, 66 | ], 67 | 68 | // 'users' => [ 69 | // 'driver' => 'database', 70 | // 'table' => 'users', 71 | // ], 72 | ], 73 | 74 | /* 75 | |-------------------------------------------------------------------------- 76 | | Resetting Passwords 77 | |-------------------------------------------------------------------------- 78 | | 79 | | You may specify multiple password reset configurations if you have more 80 | | than one user table or model in the application and you want to have 81 | | separate password reset settings based on the specific user types. 82 | | 83 | | The expiry time is the number of minutes that each reset token will be 84 | | considered valid. This security feature keeps tokens short-lived so 85 | | they have less time to be guessed. You may change this as needed. 86 | | 87 | | The throttle setting is the number of seconds a user must wait before 88 | | generating more password reset tokens. This prevents the user from 89 | | quickly generating a very large amount of password reset tokens. 90 | | 91 | */ 92 | 93 | 'passwords' => [ 94 | 'users' => [ 95 | 'provider' => 'users', 96 | 'table' => 'password_reset_tokens', 97 | 'expire' => 60, 98 | 'throttle' => 60, 99 | ], 100 | ], 101 | 102 | /* 103 | |-------------------------------------------------------------------------- 104 | | Password Confirmation Timeout 105 | |-------------------------------------------------------------------------- 106 | | 107 | | Here you may define the amount of seconds before a password confirmation 108 | | times out and the user is prompted to re-enter their password via the 109 | | confirmation screen. By default, the timeout lasts for three hours. 110 | | 111 | */ 112 | 113 | 'password_timeout' => 10800, 114 | 115 | ]; 116 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for considering contributing to the Hotelier App! We appreciate your efforts in making our project better. 4 | 5 | To ensure a smooth and collaborative experience for everyone, please follow these guidelines when contributing to the project. 6 | 7 | ## Table of Contents 8 | 9 | - [Code of Conduct](#code-of-conduct) 10 | - [Ways to Contribute](#ways-to-contribute) 11 | - [Coding Guidelines](#coding-guidelines) 12 | - [Commit Message Guidelines](#commit-message-guidelines) 13 | - [Issue and Pull Request Guidelines](#issue-and-pull-request-guidelines) 14 | - [Recognition](#recognition) 15 | 16 | ## Code of Conduct 17 | 18 | Please review and abide by our [Code of Conduct](CODE_OF_CONDUCT.md) during your participation in the project. 19 | 20 | ## Ways to Contribute 21 | 22 | There are several ways you can contribute to the Hotelier App: 23 | 24 | - **Reporting Issues**: If you encounter any bugs or issues, please report them on the [issue tracker](https://github.com/ajithnow/hotel-manager-laravel/issues). 25 | 26 | - **Feature Requests**: If you have ideas for new features or enhancements, you can submit them as [feature requests](https://github.com/ajithnow/hotel-manager-laravel/issues). 27 | 28 | - **Bug Fixes and Improvements**: You can contribute to the project by fixing bugs, improving existing features, or optimizing performance. Please follow the guidelines mentioned below. 29 | 30 | - **Documentation**: Help improve the project's documentation by fixing typos, adding examples, or enhancing the existing documentation. 31 | 32 | - **Translations**: If the project supports multiple languages, you can contribute by translating the application or documentation into other languages. 33 | 34 | ## Coding Guidelines 35 | 36 | Please adhere to the following coding guidelines when contributing to the project: 37 | 38 | - Follow the coding style and conventions used in the project. 39 | - Write clear, concise, and well-documented code. 40 | - Ensure your code is properly formatted and free of linting errors. 41 | 42 | ## Test before commmit 43 | Please test before commits using unit tests. Make sure that you have proper `env.testing` file. 44 | run the tests using 45 | `sail artisan test --env=testing` 46 | ## Commit Message Guidelines 47 | 48 | When writing commit messages, please follow these guidelines: 49 | 50 | - Use clear and descriptive commit messages. 51 | - Start the message with a verb in the present tense (e.g., "Add," "Fix," "Update"). 52 | - Provide additional details in the commit body if necessary. 53 | 54 | ## Issue and Pull Request Guidelines 55 | 56 | - Before submitting an issue, please check if a similar issue has already been reported. 57 | - When opening a pull request, please reference the related issue(s) if applicable. 58 | - Follow the feedback and instructions provided by the project maintainers during the review process. 59 | 60 | ## Recognition 61 | 62 | Contributors who make significant contributions to the project will be recognized and acknowledged in the project's documentation. 63 | 64 | Thank you for your interest in contributing to the Hotel Manager App. We appreciate your support and look forward to your contributions! 65 | 66 | ## Modular Folder Structure # 67 | 68 | - Modules 69 | - Module 70 | - Configs: This directory holds module-specific configuration files. 71 | - Controllers: This directory contains the controllers responsible for handling HTTP requests within the User module. 72 | - Factories: This directory can contain factory classes for generating test data specific to the User module. 73 | - Migrations: This directory holds the database migration files specific to the User module. 74 | - Models: This directory contains the model classes representing the data structures used within the User module. 75 | - Repositories: This directory holds the repository classes responsible for data access within the User module. 76 | - Routes: This directory can contain route definitions specific to the User module. 77 | - Seeders: This directory can contain seeder classes for populating initial data specific to the User module. 78 | - Services: This directory contains the service classes that handle the business logic and coordination within the User module. 79 | - Support: This directory can be used to store any additional support files or utilities related to the User module. 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LaraEasy Hotel Management App 2 | ![Alt text](./docs/readme/Logo.png "a title") 3 | 4 | The LaraEasy Hotel Management App is an open-source web application designed to assist hoteliers in their day-to-day tasks. It provides a comprehensive solution for managing reservations, guest information, room allocation, billing, and more. 5 | 6 | ## Features 7 | 8 | - Reservation management: Create, update, and cancel reservations with ease. 9 | - Guest check-in/check-out: Streamline the guest registration and departure process. 10 | - Room allocation: Assign rooms to guests based on their preferences and availability. 11 | - Billing: Generate invoices and manage billing information. 12 | - Other Travel Agents (OTA) syncing. 13 | - Reporting: Generate reports on occupancy, revenue, and other key metrics. 14 | - User authentication and authorization: Secure access to the app's features based on user roles. 15 | 16 | ## Technology Stack 17 | 18 | - Backend: 19 | - PHP: Programming language for the backend. 20 | - Laravel: Lightweight HTTP framework for routing and request handling. 21 | - Rest: API layer for efficient data querying and manipulation. 22 | - MySql: Relational SQL database for data storage. 23 | 24 | - Frontend: 25 | - React: TypeScript-based web application framework for building the user interface. 26 | 27 | ## Prerequisites 28 | 29 | - Docker: [Installation Guide](https://docs.docker.com/get-docker/) 30 | - Docker Compose: [Installation Guide](https://docs.docker.com/compose/install/) 31 | 32 | ## Build and Run the Docker Containers 33 | 34 | To build and run the Docker containers for the Hotel Manager App, follow the steps below: 35 | 36 | 1. Clone the repository: 37 | 38 | `git clone https://github.com/ajithnow/hotel-manager-laravel.git` 39 | 40 | 2. Go to directory 41 | 42 | `cd hotel-manager-laravel` 43 | 44 | 3. Build the Docker images with sail: 45 | 46 | ``` 47 | docker run --rm \ 48 | -u "$(id -u):$(id -g)" \ 49 | -v "$(pwd):/var/www/html" \ 50 | -w /var/www/html \ 51 | laravelsail/php82-composer:latest \ 52 | composer install --ignore-platform-reqs 53 | 54 | ``` 55 | 56 | This command will build the Docker images for [Laravel Sail](https://laravel.com/docs/10.x/sail) based on the configuration specified in the `docker-compose.yml` file. 57 | 58 | 4. Configuring A Shell Alias 59 | 60 | `alias sail='[ -f sail ] && sh sail || sh vendor/bin/sail'` 61 | 62 | 5. Run the Docker containers: 63 | 64 | `sail up` 65 | 66 | This command will start the Docker containers for Laravel Sail. You should see the logs from each container displayed in the terminal. 67 | 68 | 6. Running Migrations 69 | 70 | `sail artisan migrate` 71 | 72 | 7. Generating API Documentation 73 | 74 | `sail artisan l5-swagger:generate` 75 | 76 | 8. Access the Hotel Manager App [DEV]: 77 | 78 | Once the containers are up and running, you can access the Hotel Manager App in your web browser at [http://localhost](http://localhost). 79 | 80 | 9. Acess the API Documentation 81 | 82 | Once the containers are up and running, you can access the Hotel Manager App APIs in your web browser at [http://localhost/api/documentation](http://localhost/api/documentation). 83 | 84 | 10. Stop the running containers: 85 | 86 | To stop the Docker containers, press `Ctrl + C` in the terminal where the containers are running. 87 | 88 | 89 | ## Contributing 90 | 91 | Contributions to the Hotelier App are welcome! If you'd like to contribute, please follow these guidelines: 92 | 93 | 1. Fork the repository and create your branch: 94 | 95 | `git checkout -b feature/your-feature-name` 96 | 97 | 2. Make your changes and commit them: 98 | 99 | `git commit -m "Add your commit message"` 100 | 101 | 3. Push your branch to your forked repository: 102 | 103 | `git push origin feature/your-feature-name` 104 | 105 | 4. Open a pull request in the main repository, describing your changes and the rationale behind them. 106 | 107 | Please ensure that your contributions adhere to our [Code of Conduct](./CODE_OF_CONDUCT.md) and [Contributing Guidelines](./CONTRIBUTING.md). By participating in this project, you agree to abide by these terms. 108 | 109 | Thank you for contributing to the Hotelier App! 110 | 111 | ## License 112 | 113 | The LaraEasy Hotel Management App is open-source and released under the [MIT License](LICENSE). Feel free to use, modify, and distribute the codebase as per the terms of the license. 114 | 115 | Feel free to modify and customize this README file according to your specific project requirements. 116 | .... 117 | -------------------------------------------------------------------------------- /config/logging.php: -------------------------------------------------------------------------------- 1 | env('LOG_CHANNEL', 'stack'), 22 | 23 | /* 24 | |-------------------------------------------------------------------------- 25 | | Deprecations Log Channel 26 | |-------------------------------------------------------------------------- 27 | | 28 | | This option controls the log channel that should be used to log warnings 29 | | regarding deprecated PHP and library features. This allows you to get 30 | | your application ready for upcoming major versions of dependencies. 31 | | 32 | */ 33 | 34 | 'deprecations' => [ 35 | 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), 36 | 'trace' => false, 37 | ], 38 | 39 | /* 40 | |-------------------------------------------------------------------------- 41 | | Log Channels 42 | |-------------------------------------------------------------------------- 43 | | 44 | | Here you may configure the log channels for your application. Out of 45 | | the box, Laravel uses the Monolog PHP logging library. This gives 46 | | you a variety of powerful log handlers / formatters to utilize. 47 | | 48 | | Available Drivers: "single", "daily", "slack", "syslog", 49 | | "errorlog", "monolog", 50 | | "custom", "stack" 51 | | 52 | */ 53 | 54 | 'channels' => [ 55 | 'stack' => [ 56 | 'driver' => 'stack', 57 | 'channels' => ['single'], 58 | 'ignore_exceptions' => false, 59 | ], 60 | 61 | 'single' => [ 62 | 'driver' => 'single', 63 | 'path' => storage_path('logs/laravel.log'), 64 | 'level' => env('LOG_LEVEL', 'debug'), 65 | 'replace_placeholders' => true, 66 | ], 67 | 68 | 'daily' => [ 69 | 'driver' => 'daily', 70 | 'path' => storage_path('logs/laravel.log'), 71 | 'level' => env('LOG_LEVEL', 'debug'), 72 | 'days' => 14, 73 | 'replace_placeholders' => true, 74 | ], 75 | 76 | 'slack' => [ 77 | 'driver' => 'slack', 78 | 'url' => env('LOG_SLACK_WEBHOOK_URL'), 79 | 'username' => 'Laravel Log', 80 | 'emoji' => ':boom:', 81 | 'level' => env('LOG_LEVEL', 'critical'), 82 | 'replace_placeholders' => true, 83 | ], 84 | 85 | 'papertrail' => [ 86 | 'driver' => 'monolog', 87 | 'level' => env('LOG_LEVEL', 'debug'), 88 | 'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class), 89 | 'handler_with' => [ 90 | 'host' => env('PAPERTRAIL_URL'), 91 | 'port' => env('PAPERTRAIL_PORT'), 92 | 'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'), 93 | ], 94 | 'processors' => [PsrLogMessageProcessor::class], 95 | ], 96 | 97 | 'stderr' => [ 98 | 'driver' => 'monolog', 99 | 'level' => env('LOG_LEVEL', 'debug'), 100 | 'handler' => StreamHandler::class, 101 | 'formatter' => env('LOG_STDERR_FORMATTER'), 102 | 'with' => [ 103 | 'stream' => 'php://stderr', 104 | ], 105 | 'processors' => [PsrLogMessageProcessor::class], 106 | ], 107 | 108 | 'syslog' => [ 109 | 'driver' => 'syslog', 110 | 'level' => env('LOG_LEVEL', 'debug'), 111 | 'facility' => LOG_USER, 112 | 'replace_placeholders' => true, 113 | ], 114 | 115 | 'errorlog' => [ 116 | 'driver' => 'errorlog', 117 | 'level' => env('LOG_LEVEL', 'debug'), 118 | 'replace_placeholders' => true, 119 | ], 120 | 121 | 'null' => [ 122 | 'driver' => 'monolog', 123 | 'handler' => NullHandler::class, 124 | ], 125 | 126 | 'emergency' => [ 127 | 'path' => storage_path('logs/laravel.log'), 128 | ], 129 | ], 130 | 131 | ]; 132 | -------------------------------------------------------------------------------- /config/database.php: -------------------------------------------------------------------------------- 1 | env('DB_CONNECTION', 'mysql'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Database Connections 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here are each of the database connections setup for your application. 26 | | Of course, examples of configuring each database platform that is 27 | | supported by Laravel is shown below to make development simple. 28 | | 29 | | 30 | | All database work in Laravel is done through the PHP PDO facilities 31 | | so make sure you have the driver for your particular database of 32 | | choice installed on your machine before you begin development. 33 | | 34 | */ 35 | 36 | 'connections' => [ 37 | 38 | 'sqlite' => [ 39 | 'driver' => 'sqlite', 40 | 'url' => env('DATABASE_URL'), 41 | 'database' => env('DB_DATABASE', database_path('database.sqlite')), 42 | 'prefix' => '', 43 | 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), 44 | ], 45 | 46 | 'mysql' => [ 47 | 'driver' => 'mysql', 48 | 'url' => env('DATABASE_URL'), 49 | 'host' => env('DB_HOST', '127.0.0.1'), 50 | 'port' => env('DB_PORT', '3306'), 51 | 'database' => env('DB_DATABASE', 'forge'), 52 | 'username' => env('DB_USERNAME', 'forge'), 53 | 'password' => env('DB_PASSWORD', ''), 54 | 'unix_socket' => env('DB_SOCKET', ''), 55 | 'charset' => 'utf8mb4', 56 | 'collation' => 'utf8mb4_unicode_ci', 57 | 'prefix' => '', 58 | 'prefix_indexes' => true, 59 | 'strict' => true, 60 | 'engine' => null, 61 | 'options' => extension_loaded('pdo_mysql') ? array_filter([ 62 | PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), 63 | ]) : [], 64 | ], 65 | 66 | 'pgsql' => [ 67 | 'driver' => 'pgsql', 68 | 'url' => env('DATABASE_URL'), 69 | 'host' => env('DB_HOST', '127.0.0.1'), 70 | 'port' => env('DB_PORT', '5432'), 71 | 'database' => env('DB_DATABASE', 'forge'), 72 | 'username' => env('DB_USERNAME', 'forge'), 73 | 'password' => env('DB_PASSWORD', ''), 74 | 'charset' => 'utf8', 75 | 'prefix' => '', 76 | 'prefix_indexes' => true, 77 | 'search_path' => 'public', 78 | 'sslmode' => 'prefer', 79 | ], 80 | 81 | 'sqlsrv' => [ 82 | 'driver' => 'sqlsrv', 83 | 'url' => env('DATABASE_URL'), 84 | 'host' => env('DB_HOST', 'localhost'), 85 | 'port' => env('DB_PORT', '1433'), 86 | 'database' => env('DB_DATABASE', 'forge'), 87 | 'username' => env('DB_USERNAME', 'forge'), 88 | 'password' => env('DB_PASSWORD', ''), 89 | 'charset' => 'utf8', 90 | 'prefix' => '', 91 | 'prefix_indexes' => true, 92 | // 'encrypt' => env('DB_ENCRYPT', 'yes'), 93 | // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'), 94 | ], 95 | 96 | ], 97 | 98 | /* 99 | |-------------------------------------------------------------------------- 100 | | Migration Repository Table 101 | |-------------------------------------------------------------------------- 102 | | 103 | | This table keeps track of all the migrations that have already run for 104 | | your application. Using this information, we can determine which of 105 | | the migrations on disk haven't actually been run in the database. 106 | | 107 | */ 108 | 109 | 'migrations' => 'migrations', 110 | 111 | /* 112 | |-------------------------------------------------------------------------- 113 | | Redis Databases 114 | |-------------------------------------------------------------------------- 115 | | 116 | | Redis is an open source, fast, and advanced key-value store that also 117 | | provides a richer body of commands than a typical key-value system 118 | | such as APC or Memcached. Laravel makes it easy to dig right in. 119 | | 120 | */ 121 | 122 | 'redis' => [ 123 | 124 | 'client' => env('REDIS_CLIENT', 'phpredis'), 125 | 126 | 'options' => [ 127 | 'cluster' => env('REDIS_CLUSTER', 'redis'), 128 | 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'), 129 | ], 130 | 131 | 'default' => [ 132 | 'url' => env('REDIS_URL'), 133 | 'host' => env('REDIS_HOST', '127.0.0.1'), 134 | 'username' => env('REDIS_USERNAME'), 135 | 'password' => env('REDIS_PASSWORD'), 136 | 'port' => env('REDIS_PORT', '6379'), 137 | 'database' => env('REDIS_DB', '0'), 138 | ], 139 | 140 | 'cache' => [ 141 | 'url' => env('REDIS_URL'), 142 | 'host' => env('REDIS_HOST', '127.0.0.1'), 143 | 'username' => env('REDIS_USERNAME'), 144 | 'password' => env('REDIS_PASSWORD'), 145 | 'port' => env('REDIS_PORT', '6379'), 146 | 'database' => env('REDIS_CACHE_DB', '1'), 147 | ], 148 | 149 | ], 150 | 151 | ]; 152 | -------------------------------------------------------------------------------- /config/permission.php: -------------------------------------------------------------------------------- 1 | [ 6 | 7 | /* 8 | * When using the "HasPermissions" trait from this package, we need to know which 9 | * Eloquent model should be used to retrieve your permissions. Of course, it 10 | * is often just the "Permission" model but you may use whatever you like. 11 | * 12 | * The model you want to use as a Permission model needs to implement the 13 | * `Spatie\Permission\Contracts\Permission` contract. 14 | */ 15 | 16 | 'permission' => Spatie\Permission\Models\Permission::class, 17 | 18 | /* 19 | * When using the "HasRoles" trait from this package, we need to know which 20 | * Eloquent model should be used to retrieve your roles. Of course, it 21 | * is often just the "Role" model but you may use whatever you like. 22 | * 23 | * The model you want to use as a Role model needs to implement the 24 | * `Spatie\Permission\Contracts\Role` contract. 25 | */ 26 | 27 | 'role' => Spatie\Permission\Models\Role::class, 28 | 29 | 'user' => App\Modules\User\Models\User::class, 30 | 31 | ], 32 | 33 | 'table_names' => [ 34 | 35 | /* 36 | * When using the "HasRoles" trait from this package, we need to know which 37 | * table should be used to retrieve your roles. We have chosen a basic 38 | * default value but you may easily change it to any table you like. 39 | */ 40 | 41 | 'roles' => 'roles', 42 | 43 | /* 44 | * When using the "HasPermissions" trait from this package, we need to know which 45 | * table should be used to retrieve your permissions. We have chosen a basic 46 | * default value but you may easily change it to any table you like. 47 | */ 48 | 49 | 'permissions' => 'permissions', 50 | 51 | /* 52 | * When using the "HasPermissions" trait from this package, we need to know which 53 | * table should be used to retrieve your models permissions. We have chosen a 54 | * basic default value but you may easily change it to any table you like. 55 | */ 56 | 57 | 'model_has_permissions' => 'model_has_permissions', 58 | 59 | /* 60 | * When using the "HasRoles" trait from this package, we need to know which 61 | * table should be used to retrieve your models roles. We have chosen a 62 | * basic default value but you may easily change it to any table you like. 63 | */ 64 | 65 | 'model_has_roles' => 'model_has_roles', 66 | 67 | /* 68 | * When using the "HasRoles" trait from this package, we need to know which 69 | * table should be used to retrieve your roles permissions. We have chosen a 70 | * basic default value but you may easily change it to any table you like. 71 | */ 72 | 73 | 'role_has_permissions' => 'role_has_permissions', 74 | ], 75 | 76 | 'column_names' => [ 77 | /* 78 | * Change this if you want to name the related pivots other than defaults 79 | */ 80 | 'role_pivot_key' => null, //default 'role_id', 81 | 'permission_pivot_key' => null, //default 'permission_id', 82 | 83 | /* 84 | * Change this if you want to name the related model primary key other than 85 | * `model_id`. 86 | * 87 | * For example, this would be nice if your primary keys are all UUIDs. In 88 | * that case, name this `model_uuid`. 89 | */ 90 | 91 | 'model_morph_key' => 'model_id', 92 | 93 | /* 94 | * Change this if you want to use the teams feature and your related model's 95 | * foreign key is other than `team_id`. 96 | */ 97 | 98 | 'team_foreign_key' => 'team_id', 99 | ], 100 | 101 | /* 102 | * When set to true, the method for checking permissions will be registered on the gate. 103 | * Set this to false, if you want to implement custom logic for checking permissions. 104 | */ 105 | 106 | 'register_permission_check_method' => true, 107 | 108 | /* 109 | * When set to true the package implements teams using the 'team_foreign_key'. If you want 110 | * the migrations to register the 'team_foreign_key', you must set this to true 111 | * before doing the migration. If you already did the migration then you must make a new 112 | * migration to also add 'team_foreign_key' to 'roles', 'model_has_roles', and 113 | * 'model_has_permissions'(view the latest version of package's migration file) 114 | */ 115 | 116 | 'teams' => false, 117 | 118 | /* 119 | * When set to true, the required permission names are added to the exception 120 | * message. This could be considered an information leak in some contexts, so 121 | * the default setting is false here for optimum safety. 122 | */ 123 | 124 | 'display_permission_in_exception' => false, 125 | 126 | /* 127 | * When set to true, the required role names are added to the exception 128 | * message. This could be considered an information leak in some contexts, so 129 | * the default setting is false here for optimum safety. 130 | */ 131 | 132 | 'display_role_in_exception' => false, 133 | 134 | /* 135 | * By default wildcard permission lookups are disabled. 136 | */ 137 | 138 | 'enable_wildcard_permission' => false, 139 | 140 | 'cache' => [ 141 | 142 | /* 143 | * By default all permissions are cached for 24 hours to speed up performance. 144 | * When permissions or roles are updated the cache is flushed automatically. 145 | */ 146 | 147 | 'expiration_time' => \DateInterval::createFromDateString('24 hours'), 148 | 149 | /* 150 | * The cache key used to store all permissions. 151 | */ 152 | 153 | 'key' => 'spatie.permission.cache', 154 | 155 | /* 156 | * You may optionally indicate a specific cache driver to use for permission and 157 | * role caching using any of the `store` drivers listed in the cache.php config 158 | * file. Using 'default' here means to use the `default` set in cache.php. 159 | */ 160 | 161 | 'store' => 'default', 162 | ], 163 | ]; 164 | -------------------------------------------------------------------------------- /config/telescope.php: -------------------------------------------------------------------------------- 1 | env('TELESCOPE_DOMAIN'), 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Telescope Path 24 | |-------------------------------------------------------------------------- 25 | | 26 | | This is the URI path where Telescope will be accessible from. Feel free 27 | | to change this path to anything you like. Note that the URI will not 28 | | affect the paths of its internal API that aren't exposed to users. 29 | | 30 | */ 31 | 32 | 'path' => env('TELESCOPE_PATH', 'telescope'), 33 | 34 | /* 35 | |-------------------------------------------------------------------------- 36 | | Telescope Storage Driver 37 | |-------------------------------------------------------------------------- 38 | | 39 | | This configuration options determines the storage driver that will 40 | | be used to store Telescope's data. In addition, you may set any 41 | | custom options as needed by the particular driver you choose. 42 | | 43 | */ 44 | 45 | 'driver' => env('TELESCOPE_DRIVER', 'database'), 46 | 47 | 'storage' => [ 48 | 'database' => [ 49 | 'connection' => env('DB_CONNECTION', 'mysql'), 50 | 'chunk' => 1000, 51 | ], 52 | ], 53 | 54 | /* 55 | |-------------------------------------------------------------------------- 56 | | Telescope Master Switch 57 | |-------------------------------------------------------------------------- 58 | | 59 | | This option may be used to disable all Telescope watchers regardless 60 | | of their individual configuration, which simply provides a single 61 | | and convenient way to enable or disable Telescope data storage. 62 | | 63 | */ 64 | 65 | 'enabled' => env('TELESCOPE_ENABLED', true), 66 | 67 | /* 68 | |-------------------------------------------------------------------------- 69 | | Telescope Route Middleware 70 | |-------------------------------------------------------------------------- 71 | | 72 | | These middleware will be assigned to every Telescope route, giving you 73 | | the chance to add your own middleware to this list or change any of 74 | | the existing middleware. Or, you can simply stick with this list. 75 | | 76 | */ 77 | 78 | 'middleware' => [ 79 | 'web', 80 | Authorize::class, 81 | ], 82 | 83 | /* 84 | |-------------------------------------------------------------------------- 85 | | Allowed / Ignored Paths & Commands 86 | |-------------------------------------------------------------------------- 87 | | 88 | | The following array lists the URI paths and Artisan commands that will 89 | | not be watched by Telescope. In addition to this list, some Laravel 90 | | commands, like migrations and queue commands, are always ignored. 91 | | 92 | */ 93 | 94 | 'only_paths' => [ 95 | // 'api/*' 96 | ], 97 | 98 | 'ignore_paths' => [ 99 | 'nova-api*', 100 | ], 101 | 102 | 'ignore_commands' => [ 103 | // 104 | ], 105 | 106 | /* 107 | |-------------------------------------------------------------------------- 108 | | Telescope Watchers 109 | |-------------------------------------------------------------------------- 110 | | 111 | | The following array lists the "watchers" that will be registered with 112 | | Telescope. The watchers gather the application's profile data when 113 | | a request or task is executed. Feel free to customize this list. 114 | | 115 | */ 116 | 117 | 'watchers' => [ 118 | Watchers\BatchWatcher::class => env('TELESCOPE_BATCH_WATCHER', true), 119 | 120 | Watchers\CacheWatcher::class => [ 121 | 'enabled' => env('TELESCOPE_CACHE_WATCHER', true), 122 | 'hidden' => [], 123 | ], 124 | 125 | Watchers\ClientRequestWatcher::class => env('TELESCOPE_CLIENT_REQUEST_WATCHER', true), 126 | 127 | Watchers\CommandWatcher::class => [ 128 | 'enabled' => env('TELESCOPE_COMMAND_WATCHER', true), 129 | 'ignore' => [], 130 | ], 131 | 132 | Watchers\DumpWatcher::class => [ 133 | 'enabled' => env('TELESCOPE_DUMP_WATCHER', true), 134 | 'always' => env('TELESCOPE_DUMP_WATCHER_ALWAYS', false), 135 | ], 136 | 137 | Watchers\EventWatcher::class => [ 138 | 'enabled' => env('TELESCOPE_EVENT_WATCHER', true), 139 | 'ignore' => [], 140 | ], 141 | 142 | Watchers\ExceptionWatcher::class => env('TELESCOPE_EXCEPTION_WATCHER', true), 143 | 144 | Watchers\GateWatcher::class => [ 145 | 'enabled' => env('TELESCOPE_GATE_WATCHER', true), 146 | 'ignore_abilities' => [], 147 | 'ignore_packages' => true, 148 | 'ignore_paths' => [], 149 | ], 150 | 151 | Watchers\JobWatcher::class => env('TELESCOPE_JOB_WATCHER', true), 152 | 153 | Watchers\LogWatcher::class => [ 154 | 'enabled' => env('TELESCOPE_LOG_WATCHER', true), 155 | 'level' => 'error', 156 | ], 157 | 158 | Watchers\MailWatcher::class => env('TELESCOPE_MAIL_WATCHER', true), 159 | 160 | Watchers\ModelWatcher::class => [ 161 | 'enabled' => env('TELESCOPE_MODEL_WATCHER', true), 162 | 'events' => ['eloquent.*'], 163 | 'hydrations' => true, 164 | ], 165 | 166 | Watchers\NotificationWatcher::class => env('TELESCOPE_NOTIFICATION_WATCHER', true), 167 | 168 | Watchers\QueryWatcher::class => [ 169 | 'enabled' => env('TELESCOPE_QUERY_WATCHER', true), 170 | 'ignore_packages' => true, 171 | 'ignore_paths' => [], 172 | 'slow' => 100, 173 | ], 174 | 175 | Watchers\RedisWatcher::class => env('TELESCOPE_REDIS_WATCHER', true), 176 | 177 | Watchers\RequestWatcher::class => [ 178 | 'enabled' => env('TELESCOPE_REQUEST_WATCHER', true), 179 | 'size_limit' => env('TELESCOPE_RESPONSE_SIZE_LIMIT', 64), 180 | 'ignore_http_methods' => [], 181 | 'ignore_status_codes' => [], 182 | ], 183 | 184 | Watchers\ScheduleWatcher::class => env('TELESCOPE_SCHEDULE_WATCHER', true), 185 | Watchers\ViewWatcher::class => env('TELESCOPE_VIEW_WATCHER', true), 186 | ], 187 | ]; 188 | -------------------------------------------------------------------------------- /database/migrations/2023_06_30_032145_create_permission_tables.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); // permission id 30 | $table->string('name'); // For MySQL 8.0 use string('name', 125); 31 | $table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125); 32 | $table->timestamps(); 33 | 34 | $table->unique(['name', 'guard_name']); 35 | }); 36 | 37 | Schema::create($tableNames['roles'], function (Blueprint $table) use ($teams, $columnNames) { 38 | $table->bigIncrements('id'); // role id 39 | if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing 40 | $table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable(); 41 | $table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index'); 42 | } 43 | $table->string('name'); // For MySQL 8.0 use string('name', 125); 44 | $table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125); 45 | $table->timestamps(); 46 | if ($teams || config('permission.testing')) { 47 | $table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']); 48 | } else { 49 | $table->unique(['name', 'guard_name']); 50 | } 51 | }); 52 | 53 | Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames, $columnNames, $teams) { 54 | $table->unsignedBigInteger(PermissionRegistrar::$pivotPermission); 55 | 56 | $table->string('model_type'); 57 | $table->unsignedBigInteger($columnNames['model_morph_key']); 58 | $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index'); 59 | 60 | $table->foreign(PermissionRegistrar::$pivotPermission) 61 | ->references('id') // permission id 62 | ->on($tableNames['permissions']) 63 | ->onDelete('cascade'); 64 | if ($teams) { 65 | $table->unsignedBigInteger($columnNames['team_foreign_key']); 66 | $table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index'); 67 | 68 | $table->primary([$columnNames['team_foreign_key'], PermissionRegistrar::$pivotPermission, $columnNames['model_morph_key'], 'model_type'], 69 | 'model_has_permissions_permission_model_type_primary'); 70 | } else { 71 | $table->primary([PermissionRegistrar::$pivotPermission, $columnNames['model_morph_key'], 'model_type'], 72 | 'model_has_permissions_permission_model_type_primary'); 73 | } 74 | 75 | }); 76 | 77 | Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use ($tableNames, $columnNames, $teams) { 78 | $table->unsignedBigInteger(PermissionRegistrar::$pivotRole); 79 | 80 | $table->string('model_type'); 81 | $table->unsignedBigInteger($columnNames['model_morph_key']); 82 | $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index'); 83 | 84 | $table->foreign(PermissionRegistrar::$pivotRole) 85 | ->references('id') // role id 86 | ->on($tableNames['roles']) 87 | ->onDelete('cascade'); 88 | if ($teams) { 89 | $table->unsignedBigInteger($columnNames['team_foreign_key']); 90 | $table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index'); 91 | 92 | $table->primary([$columnNames['team_foreign_key'], PermissionRegistrar::$pivotRole, $columnNames['model_morph_key'], 'model_type'], 93 | 'model_has_roles_role_model_type_primary'); 94 | } else { 95 | $table->primary([PermissionRegistrar::$pivotRole, $columnNames['model_morph_key'], 'model_type'], 96 | 'model_has_roles_role_model_type_primary'); 97 | } 98 | }); 99 | 100 | Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use ($tableNames) { 101 | $table->unsignedBigInteger(PermissionRegistrar::$pivotPermission); 102 | $table->unsignedBigInteger(PermissionRegistrar::$pivotRole); 103 | 104 | $table->foreign(PermissionRegistrar::$pivotPermission) 105 | ->references('id') // permission id 106 | ->on($tableNames['permissions']) 107 | ->onDelete('cascade'); 108 | 109 | $table->foreign(PermissionRegistrar::$pivotRole) 110 | ->references('id') // role id 111 | ->on($tableNames['roles']) 112 | ->onDelete('cascade'); 113 | 114 | $table->primary([PermissionRegistrar::$pivotPermission, PermissionRegistrar::$pivotRole], 'role_has_permissions_permission_id_role_id_primary'); 115 | }); 116 | 117 | app('cache') 118 | ->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null) 119 | ->forget(config('permission.cache.key')); 120 | } 121 | 122 | /** 123 | * Reverse the migrations. 124 | * 125 | * @return void 126 | */ 127 | public function down() 128 | { 129 | $tableNames = config('permission.table_names'); 130 | 131 | if (empty($tableNames)) { 132 | throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.'); 133 | } 134 | 135 | Schema::drop($tableNames['role_has_permissions']); 136 | Schema::drop($tableNames['model_has_roles']); 137 | Schema::drop($tableNames['model_has_permissions']); 138 | Schema::drop($tableNames['roles']); 139 | Schema::drop($tableNames['permissions']); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /app/Modules/User/Controllers/UserController.php: -------------------------------------------------------------------------------- 1 | create(user: $request->validated()); 58 | return new UserCreatedResource($user); 59 | } 60 | 61 | /** 62 | * @OA\Get( 63 | * path="/user/{id}", 64 | * tags={"Users"}, 65 | * summary="Get User by UUID", 66 | * description="Get a user by UUID.", 67 | * operationId="getUserByUUID", 68 | * @OA\Parameter( 69 | * name="id", 70 | * in="path", 71 | * required=true, 72 | * @OA\Schema( 73 | * type="string", 74 | * format="uuid" 75 | * ), 76 | * description="The UUID of the user to retrieve." 77 | * ), 78 | * @OA\Response( 79 | * response="200", 80 | * description="OK", 81 | * @OA\JsonContent( 82 | * @OA\Schema(ref="#/components/schemas/UserResource") 83 | * ) 84 | * ), 85 | * @OA\Response( 86 | * response="404", 87 | * description="Not Found" 88 | * ) 89 | * ) 90 | */ 91 | public function show(ShowUserRequest $request, UserRepo $repo) 92 | { 93 | $user = $repo->get(id: $request->id); 94 | return (new UserResource($user))->response()->setStatusCode(200); 95 | } 96 | 97 | /** 98 | * @OA\Delete( 99 | * path="/user/{id}", 100 | * operationId="deleteUserByUUID", 101 | * summary="Delete User by UUID", 102 | * description="Delete a user by UUID.", 103 | * tags={"Users"}, 104 | * @OA\Parameter( 105 | * name="id", 106 | * in="path", 107 | * required=true, 108 | * description="The UUID of the user to delete.", 109 | * @OA\Schema( 110 | * type="string", 111 | * format="uuid" 112 | * ) 113 | * ), 114 | * @OA\Response( 115 | * response="200", 116 | * description="User deleted successfully" 117 | * ), 118 | * @OA\Response( 119 | * response="404", 120 | * description="User not found" 121 | * ) 122 | * ) 123 | */ 124 | public function destroy(DeleteUserRequest $request, UserRepo $repo) 125 | { 126 | $user = $repo->delete(id :$request->id); 127 | return (new UserDeletedResource($user))->response()->setStatusCode(200); 128 | } 129 | 130 | /** 131 | * @OA\Post( 132 | * path="/user/profile", 133 | * summary="Create or update user profile", 134 | * description="Endpoint to create or update user profile details", 135 | * tags={"Users"}, 136 | * @OA\RequestBody( 137 | * required=true, 138 | * @OA\MediaType( 139 | * mediaType="application/json", 140 | * @OA\Schema( 141 | * @OA\Property( 142 | * property="user_id", 143 | * type="string", 144 | * example="uuid", 145 | * ), 146 | * @OA\Property( 147 | * property="address_line_1", 148 | * type="string", 149 | * ), 150 | * @OA\Property( 151 | * property="address_line_2", 152 | * type="string", 153 | * ), 154 | * @OA\Property( 155 | * property="city", 156 | * type="string", 157 | * ), 158 | * @OA\Property( 159 | * property="state", 160 | * type="string", 161 | * ), 162 | * @OA\Property( 163 | * property="country", 164 | * type="string", 165 | * ), 166 | * @OA\Property( 167 | * property="phone", 168 | * type="string", 169 | * ), 170 | * @OA\Property( 171 | * property="is_verified", 172 | * type="boolean", 173 | * example=false, 174 | * ), 175 | * ) 176 | * ) 177 | * ), 178 | * @OA\Response( 179 | * response=201, 180 | * description="User profile created/updated successfully" 181 | * ), 182 | * @OA\Response( 183 | * response=422, 184 | * description="Validation error" 185 | * ) 186 | * ) 187 | */ 188 | public function createProfile(CreateUserProfileRequest $request, UserProfileRepo $repo) 189 | { 190 | return (new UserProfileResource($repo->create($request->validated()))) 191 | ->response() 192 | ->setStatusCode(201); 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /config/app.php: -------------------------------------------------------------------------------- 1 | env('APP_NAME', 'Laravel'), 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Application Environment 24 | |-------------------------------------------------------------------------- 25 | | 26 | | This value determines the "environment" your application is currently 27 | | running in. This may determine how you prefer to configure various 28 | | services the application utilizes. Set this in your ".env" file. 29 | | 30 | */ 31 | 32 | 'env' => env('APP_ENV', 'production'), 33 | 34 | /* 35 | |-------------------------------------------------------------------------- 36 | | Application Debug Mode 37 | |-------------------------------------------------------------------------- 38 | | 39 | | When your application is in debug mode, detailed error messages with 40 | | stack traces will be shown on every error that occurs within your 41 | | application. If disabled, a simple generic error page is shown. 42 | | 43 | */ 44 | 45 | 'debug' => (bool) env('APP_DEBUG', false), 46 | 47 | /* 48 | |-------------------------------------------------------------------------- 49 | | Application URL 50 | |-------------------------------------------------------------------------- 51 | | 52 | | This URL is used by the console to properly generate URLs when using 53 | | the Artisan command line tool. You should set this to the root of 54 | | your application so that it is used when running Artisan tasks. 55 | | 56 | */ 57 | 58 | 'url' => env('APP_URL', 'http://localhost'), 59 | 60 | 'asset_url' => env('ASSET_URL'), 61 | 62 | /* 63 | |-------------------------------------------------------------------------- 64 | | Application Timezone 65 | |-------------------------------------------------------------------------- 66 | | 67 | | Here you may specify the default timezone for your application, which 68 | | will be used by the PHP date and date-time functions. We have gone 69 | | ahead and set this to a sensible default for you out of the box. 70 | | 71 | */ 72 | 73 | 'timezone' => 'UTC', 74 | 75 | /* 76 | |-------------------------------------------------------------------------- 77 | | Application Locale Configuration 78 | |-------------------------------------------------------------------------- 79 | | 80 | | The application locale determines the default locale that will be used 81 | | by the translation service provider. You are free to set this value 82 | | to any of the locales which will be supported by the application. 83 | | 84 | */ 85 | 86 | 'locale' => 'en', 87 | 88 | /* 89 | |-------------------------------------------------------------------------- 90 | | Application Fallback Locale 91 | |-------------------------------------------------------------------------- 92 | | 93 | | The fallback locale determines the locale to use when the current one 94 | | is not available. You may change the value to correspond to any of 95 | | the language folders that are provided through your application. 96 | | 97 | */ 98 | 99 | 'fallback_locale' => 'en', 100 | 101 | /* 102 | |-------------------------------------------------------------------------- 103 | | Faker Locale 104 | |-------------------------------------------------------------------------- 105 | | 106 | | This locale will be used by the Faker PHP library when generating fake 107 | | data for your database seeds. For example, this will be used to get 108 | | localized telephone numbers, street address information and more. 109 | | 110 | */ 111 | 112 | 'faker_locale' => 'en_US', 113 | 114 | /* 115 | |-------------------------------------------------------------------------- 116 | | Encryption Key 117 | |-------------------------------------------------------------------------- 118 | | 119 | | This key is used by the Illuminate encrypter service and should be set 120 | | to a random, 32 character string, otherwise these encrypted strings 121 | | will not be safe. Please do this before deploying an application! 122 | | 123 | */ 124 | 125 | 'key' => env('APP_KEY'), 126 | 127 | 'cipher' => 'AES-256-CBC', 128 | 129 | /* 130 | |-------------------------------------------------------------------------- 131 | | Maintenance Mode Driver 132 | |-------------------------------------------------------------------------- 133 | | 134 | | These configuration options determine the driver used to determine and 135 | | manage Laravel's "maintenance mode" status. The "cache" driver will 136 | | allow maintenance mode to be controlled across multiple machines. 137 | | 138 | | Supported drivers: "file", "cache" 139 | | 140 | */ 141 | 142 | 'maintenance' => [ 143 | 'driver' => 'file', 144 | // 'store' => 'redis', 145 | ], 146 | 147 | /* 148 | |-------------------------------------------------------------------------- 149 | | Autoloaded Service Providers 150 | |-------------------------------------------------------------------------- 151 | | 152 | | The service providers listed here will be automatically loaded on the 153 | | request to your application. Feel free to add your own services to 154 | | this array to grant expanded functionality to your applications. 155 | | 156 | */ 157 | 158 | 'providers' => ServiceProvider::defaultProviders()->merge([ 159 | /* 160 | * Package Service Providers... 161 | */ 162 | 163 | /* 164 | * Application Service Providers... 165 | */ 166 | App\Providers\AppServiceProvider::class, 167 | App\Providers\AuthServiceProvider::class, 168 | // App\Providers\BroadcastServiceProvider::class, 169 | App\Providers\EventServiceProvider::class, 170 | App\Providers\RouteServiceProvider::class, 171 | App\Providers\TelescopeServiceProvider::class, 172 | 173 | //custom app providers 174 | App\Providers\RepositoryServiceProvider::class, 175 | App\Providers\MigrationServiceProvider::class 176 | ])->toArray(), 177 | 178 | /* 179 | |-------------------------------------------------------------------------- 180 | | Class Aliases 181 | |-------------------------------------------------------------------------- 182 | | 183 | | This array of class aliases will be registered when this application 184 | | is started. However, feel free to register as many as you wish as 185 | | the aliases are "lazy" loaded so they don't hinder performance. 186 | | 187 | */ 188 | 189 | 'aliases' => Facade::defaultAliases()->merge([ 190 | // 'Example' => App\Facades\Example::class, 191 | ])->toArray(), 192 | 193 | ]; 194 | -------------------------------------------------------------------------------- /config/session.php: -------------------------------------------------------------------------------- 1 | env('SESSION_DRIVER', 'file'), 22 | 23 | /* 24 | |-------------------------------------------------------------------------- 25 | | Session Lifetime 26 | |-------------------------------------------------------------------------- 27 | | 28 | | Here you may specify the number of minutes that you wish the session 29 | | to be allowed to remain idle before it expires. If you want them 30 | | to immediately expire on the browser closing, set that option. 31 | | 32 | */ 33 | 34 | 'lifetime' => env('SESSION_LIFETIME', 120), 35 | 36 | 'expire_on_close' => false, 37 | 38 | /* 39 | |-------------------------------------------------------------------------- 40 | | Session Encryption 41 | |-------------------------------------------------------------------------- 42 | | 43 | | This option allows you to easily specify that all of your session data 44 | | should be encrypted before it is stored. All encryption will be run 45 | | automatically by Laravel and you can use the Session like normal. 46 | | 47 | */ 48 | 49 | 'encrypt' => false, 50 | 51 | /* 52 | |-------------------------------------------------------------------------- 53 | | Session File Location 54 | |-------------------------------------------------------------------------- 55 | | 56 | | When using the native session driver, we need a location where session 57 | | files may be stored. A default has been set for you but a different 58 | | location may be specified. This is only needed for file sessions. 59 | | 60 | */ 61 | 62 | 'files' => storage_path('framework/sessions'), 63 | 64 | /* 65 | |-------------------------------------------------------------------------- 66 | | Session Database Connection 67 | |-------------------------------------------------------------------------- 68 | | 69 | | When using the "database" or "redis" session drivers, you may specify a 70 | | connection that should be used to manage these sessions. This should 71 | | correspond to a connection in your database configuration options. 72 | | 73 | */ 74 | 75 | 'connection' => env('SESSION_CONNECTION'), 76 | 77 | /* 78 | |-------------------------------------------------------------------------- 79 | | Session Database Table 80 | |-------------------------------------------------------------------------- 81 | | 82 | | When using the "database" session driver, you may specify the table we 83 | | should use to manage the sessions. Of course, a sensible default is 84 | | provided for you; however, you are free to change this as needed. 85 | | 86 | */ 87 | 88 | 'table' => 'sessions', 89 | 90 | /* 91 | |-------------------------------------------------------------------------- 92 | | Session Cache Store 93 | |-------------------------------------------------------------------------- 94 | | 95 | | While using one of the framework's cache driven session backends you may 96 | | list a cache store that should be used for these sessions. This value 97 | | must match with one of the application's configured cache "stores". 98 | | 99 | | Affects: "apc", "dynamodb", "memcached", "redis" 100 | | 101 | */ 102 | 103 | 'store' => env('SESSION_STORE'), 104 | 105 | /* 106 | |-------------------------------------------------------------------------- 107 | | Session Sweeping Lottery 108 | |-------------------------------------------------------------------------- 109 | | 110 | | Some session drivers must manually sweep their storage location to get 111 | | rid of old sessions from storage. Here are the chances that it will 112 | | happen on a given request. By default, the odds are 2 out of 100. 113 | | 114 | */ 115 | 116 | 'lottery' => [2, 100], 117 | 118 | /* 119 | |-------------------------------------------------------------------------- 120 | | Session Cookie Name 121 | |-------------------------------------------------------------------------- 122 | | 123 | | Here you may change the name of the cookie used to identify a session 124 | | instance by ID. The name specified here will get used every time a 125 | | new session cookie is created by the framework for every driver. 126 | | 127 | */ 128 | 129 | 'cookie' => env( 130 | 'SESSION_COOKIE', 131 | Str::slug(env('APP_NAME', 'laravel'), '_').'_session' 132 | ), 133 | 134 | /* 135 | |-------------------------------------------------------------------------- 136 | | Session Cookie Path 137 | |-------------------------------------------------------------------------- 138 | | 139 | | The session cookie path determines the path for which the cookie will 140 | | be regarded as available. Typically, this will be the root path of 141 | | your application but you are free to change this when necessary. 142 | | 143 | */ 144 | 145 | 'path' => '/', 146 | 147 | /* 148 | |-------------------------------------------------------------------------- 149 | | Session Cookie Domain 150 | |-------------------------------------------------------------------------- 151 | | 152 | | Here you may change the domain of the cookie used to identify a session 153 | | in your application. This will determine which domains the cookie is 154 | | available to in your application. A sensible default has been set. 155 | | 156 | */ 157 | 158 | 'domain' => env('SESSION_DOMAIN'), 159 | 160 | /* 161 | |-------------------------------------------------------------------------- 162 | | HTTPS Only Cookies 163 | |-------------------------------------------------------------------------- 164 | | 165 | | By setting this option to true, session cookies will only be sent back 166 | | to the server if the browser has a HTTPS connection. This will keep 167 | | the cookie from being sent to you when it can't be done securely. 168 | | 169 | */ 170 | 171 | 'secure' => env('SESSION_SECURE_COOKIE'), 172 | 173 | /* 174 | |-------------------------------------------------------------------------- 175 | | HTTP Access Only 176 | |-------------------------------------------------------------------------- 177 | | 178 | | Setting this value to true will prevent JavaScript from accessing the 179 | | value of the cookie and the cookie will only be accessible through 180 | | the HTTP protocol. You are free to modify this option if needed. 181 | | 182 | */ 183 | 184 | 'http_only' => true, 185 | 186 | /* 187 | |-------------------------------------------------------------------------- 188 | | Same-Site Cookies 189 | |-------------------------------------------------------------------------- 190 | | 191 | | This option determines how your cookies behave when cross-site requests 192 | | take place, and can be used to mitigate CSRF attacks. By default, we 193 | | will set this value to "lax" since this is a secure default value. 194 | | 195 | | Supported: "lax", "strict", "none", null 196 | | 197 | */ 198 | 199 | 'same_site' => 'lax', 200 | 201 | ]; 202 | -------------------------------------------------------------------------------- /storage/api-docs/api-docs.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "title": "Api Documentation", 5 | "description": "Api Documentation", 6 | "contact": { 7 | "name": "Ajithkumar S", 8 | "email": "ajithkumarmailbox@gmail.com" 9 | }, 10 | "license": { 11 | "name": "Apache 2.0", 12 | "url": "http://www.apache.org/licenses/LICENSE-2.0.html" 13 | }, 14 | "version": "1.0.0" 15 | }, 16 | "servers": [ 17 | { 18 | "url": "/api" 19 | } 20 | ], 21 | "paths": { 22 | "/auth/login": { 23 | "post": { 24 | "tags": [ 25 | "Authentication" 26 | ], 27 | "summary": "User login", 28 | "operationId": "login", 29 | "requestBody": { 30 | "required": true, 31 | "content": { 32 | "application/json": { 33 | "schema": { 34 | "properties": { 35 | "user_name": { 36 | "type": "string", 37 | "example": "user@example.com" 38 | }, 39 | "password": { 40 | "type": "string", 41 | "example": "yourpassword" 42 | } 43 | }, 44 | "type": "object" 45 | } 46 | } 47 | } 48 | }, 49 | "responses": { 50 | "200": { 51 | "description": "Successful login", 52 | "content": { 53 | "application/json": { 54 | "schema": { 55 | "type": "string" 56 | } 57 | } 58 | } 59 | }, 60 | "503": { 61 | "description": "Invalid login", 62 | "content": { 63 | "application/json": { 64 | "schema": { 65 | "type": "string" 66 | } 67 | } 68 | } 69 | } 70 | } 71 | } 72 | }, 73 | "/room/type/create": { 74 | "post": { 75 | "tags": [ 76 | "Room Types" 77 | ], 78 | "summary": "Create a new room type", 79 | "description": "Creates a new room type and stores it in the database.", 80 | "operationId": "d30adad34fde5cdacbe0c7f435841d14", 81 | "requestBody": { 82 | "required": true, 83 | "content": { 84 | "application/json": { 85 | "schema": { 86 | "properties": { 87 | "name": { 88 | "description": "The name of the room type.", 89 | "type": "string", 90 | "maxLength": 255, 91 | "example": "Standard" 92 | }, 93 | "description": { 94 | "description": "The description of the room type.", 95 | "type": "string" 96 | }, 97 | "meta": { 98 | "description": "Additional metadata related to the room type.", 99 | "type": "object" 100 | } 101 | }, 102 | "type": "object" 103 | } 104 | } 105 | } 106 | }, 107 | "responses": { 108 | "201": { 109 | "description": "Room type created successfully" 110 | }, 111 | "422": { 112 | "description": "Validation error", 113 | "content": { 114 | "application/json": { 115 | "schema": { 116 | "properties": { 117 | "message": { 118 | "type": "string", 119 | "example": "The given data was invalid." 120 | }, 121 | "errors": { 122 | "type": "object" 123 | } 124 | }, 125 | "type": "object" 126 | } 127 | } 128 | } 129 | } 130 | } 131 | } 132 | }, 133 | "/user/create": { 134 | "post": { 135 | "tags": [ 136 | "Users" 137 | ], 138 | "summary": "Create a new user", 139 | "description": "Endpoint to create a new user", 140 | "operationId": "8c2c8cabb5876407d3e183306db583eb", 141 | "requestBody": { 142 | "required": true, 143 | "content": { 144 | "application/json": { 145 | "schema": { 146 | "properties": { 147 | "name": { 148 | "type": "string" 149 | }, 150 | "email": { 151 | "type": "string" 152 | }, 153 | "password": { 154 | "type": "string" 155 | } 156 | }, 157 | "type": "object" 158 | } 159 | } 160 | } 161 | }, 162 | "responses": { 163 | "201": { 164 | "description": "User created successfully" 165 | }, 166 | "422": { 167 | "description": "Validation error" 168 | } 169 | } 170 | } 171 | }, 172 | "/user/{id}": { 173 | "get": { 174 | "tags": [ 175 | "Users" 176 | ], 177 | "summary": "Get User by UUID", 178 | "description": "Get a user by UUID.", 179 | "operationId": "getUserByUUID", 180 | "parameters": [ 181 | { 182 | "name": "id", 183 | "in": "path", 184 | "description": "The UUID of the user to retrieve.", 185 | "required": true, 186 | "schema": { 187 | "type": "string", 188 | "format": "uuid" 189 | } 190 | } 191 | ], 192 | "responses": { 193 | "200": { 194 | "description": "OK", 195 | "content": { 196 | "application/json": { 197 | "schema": {} 198 | } 199 | } 200 | }, 201 | "404": { 202 | "description": "Not Found" 203 | } 204 | } 205 | }, 206 | "delete": { 207 | "tags": [ 208 | "Users" 209 | ], 210 | "summary": "Delete User by UUID", 211 | "description": "Delete a user by UUID.", 212 | "operationId": "deleteUserByUUID", 213 | "parameters": [ 214 | { 215 | "name": "id", 216 | "in": "path", 217 | "description": "The UUID of the user to delete.", 218 | "required": true, 219 | "schema": { 220 | "type": "string", 221 | "format": "uuid" 222 | } 223 | } 224 | ], 225 | "responses": { 226 | "200": { 227 | "description": "User deleted successfully" 228 | }, 229 | "404": { 230 | "description": "User not found" 231 | } 232 | } 233 | } 234 | }, 235 | "/user/profile": { 236 | "post": { 237 | "tags": [ 238 | "Users" 239 | ], 240 | "summary": "Create or update user profile", 241 | "description": "Endpoint to create or update user profile details", 242 | "operationId": "0f9f384be8d276182ff4b3c1ff756e53", 243 | "requestBody": { 244 | "required": true, 245 | "content": { 246 | "application/json": { 247 | "schema": { 248 | "properties": { 249 | "user_id": { 250 | "type": "string", 251 | "example": "uuid" 252 | }, 253 | "address_line_1": { 254 | "type": "string" 255 | }, 256 | "address_line_2": { 257 | "type": "string" 258 | }, 259 | "city": { 260 | "type": "string" 261 | }, 262 | "state": { 263 | "type": "string" 264 | }, 265 | "country": { 266 | "type": "string" 267 | }, 268 | "phone": { 269 | "type": "string" 270 | }, 271 | "is_verified": { 272 | "type": "boolean", 273 | "example": false 274 | } 275 | }, 276 | "type": "object" 277 | } 278 | } 279 | } 280 | }, 281 | "responses": { 282 | "201": { 283 | "description": "User profile created/updated successfully" 284 | }, 285 | "422": { 286 | "description": "Validation error" 287 | } 288 | } 289 | } 290 | } 291 | } 292 | } -------------------------------------------------------------------------------- /config/l5-swagger.php: -------------------------------------------------------------------------------- 1 | 'default', 5 | 'documentations' => [ 6 | 'default' => [ 7 | 'api' => [ 8 | 'title' => 'L5 Swagger UI', 9 | ], 10 | 11 | 'routes' => [ 12 | /* 13 | * Route for accessing api documentation interface 14 | */ 15 | 'api' => 'api/documentation', 16 | ], 17 | 'paths' => [ 18 | /* 19 | * Edit to include full URL in ui for assets 20 | */ 21 | 'use_absolute_path' => env('L5_SWAGGER_USE_ABSOLUTE_PATH', true), 22 | 23 | /* 24 | * File name of the generated json documentation file 25 | */ 26 | 'docs_json' => 'api-docs.json', 27 | 28 | /* 29 | * File name of the generated YAML documentation file 30 | */ 31 | 'docs_yaml' => 'api-docs.yaml', 32 | 33 | /* 34 | * Set this to `json` or `yaml` to determine which documentation file to use in UI 35 | */ 36 | 'format_to_use_for_docs' => env('L5_FORMAT_TO_USE_FOR_DOCS', 'json'), 37 | 38 | /* 39 | * Absolute paths to directory containing the swagger annotations are stored. 40 | */ 41 | 'annotations' => [ 42 | base_path('app'), 43 | ], 44 | 45 | ], 46 | ], 47 | ], 48 | 'defaults' => [ 49 | 'routes' => [ 50 | /* 51 | * Route for accessing parsed swagger annotations. 52 | */ 53 | 'docs' => 'docs', 54 | 55 | /* 56 | * Route for Oauth2 authentication callback. 57 | */ 58 | 'oauth2_callback' => 'api/oauth2-callback', 59 | 60 | /* 61 | * Middleware allows to prevent unexpected access to API documentation 62 | */ 63 | 'middleware' => [ 64 | 'api' => [], 65 | 'asset' => [], 66 | 'docs' => [], 67 | 'oauth2_callback' => [], 68 | ], 69 | 70 | /* 71 | * Route Group options 72 | */ 73 | 'group_options' => [], 74 | ], 75 | 76 | 'paths' => [ 77 | /* 78 | * Absolute path to location where parsed annotations will be stored 79 | */ 80 | 'docs' => storage_path('api-docs'), 81 | 82 | /* 83 | * Absolute path to directory where to export views 84 | */ 85 | 'views' => base_path('resources/views/vendor/l5-swagger'), 86 | 87 | /* 88 | * Edit to set the api's base path 89 | */ 90 | 'base' => env('L5_SWAGGER_BASE_PATH', null), 91 | 92 | /* 93 | * Edit to set path where swagger ui assets should be stored 94 | */ 95 | 'swagger_ui_assets_path' => env('L5_SWAGGER_UI_ASSETS_PATH', 'vendor/swagger-api/swagger-ui/dist/'), 96 | 97 | /* 98 | * Absolute path to directories that should be exclude from scanning 99 | * @deprecated Please use `scanOptions.exclude` 100 | * `scanOptions.exclude` overwrites this 101 | */ 102 | 'excludes' => [], 103 | ], 104 | 105 | 'scanOptions' => [ 106 | /** 107 | * analyser: defaults to \OpenApi\StaticAnalyser . 108 | * 109 | * @see \OpenApi\scan 110 | */ 111 | 'analyser' => null, 112 | 113 | /** 114 | * analysis: defaults to a new \OpenApi\Analysis . 115 | * 116 | * @see \OpenApi\scan 117 | */ 118 | 'analysis' => null, 119 | 120 | /** 121 | * Custom query path processors classes. 122 | * 123 | * @link https://github.com/zircote/swagger-php/tree/master/Examples/schema-query-parameter-processor 124 | * @see \OpenApi\scan 125 | */ 126 | 'processors' => [ 127 | // new \App\SwaggerProcessors\SchemaQueryParameter(), 128 | ], 129 | 130 | /** 131 | * pattern: string $pattern File pattern(s) to scan (default: *.php) . 132 | * 133 | * @see \OpenApi\scan 134 | */ 135 | 'pattern' => null, 136 | 137 | /* 138 | * Absolute path to directories that should be excluded from scanning 139 | * @note This option overwrites `paths.excludes` 140 | * @see \OpenApi\scan 141 | */ 142 | 'exclude' => [], 143 | 144 | /* 145 | * Allows to generate specs either for OpenAPI 3.0.0 or OpenAPI 3.1.0. 146 | * By default the spec will be in version 3.0.0 147 | */ 148 | 'open_api_spec_version' => env('L5_SWAGGER_OPEN_API_SPEC_VERSION', \L5Swagger\Generator::OPEN_API_DEFAULT_SPEC_VERSION), 149 | ], 150 | 151 | /* 152 | * API security definitions. Will be generated into documentation file. 153 | */ 154 | 'securityDefinitions' => [ 155 | 'securitySchemes' => [ 156 | /* 157 | * Examples of Security schemes 158 | */ 159 | /* 160 | 'api_key_security_example' => [ // Unique name of security 161 | 'type' => 'apiKey', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". 162 | 'description' => 'A short description for security scheme', 163 | 'name' => 'api_key', // The name of the header or query parameter to be used. 164 | 'in' => 'header', // The location of the API key. Valid values are "query" or "header". 165 | ], 166 | 'oauth2_security_example' => [ // Unique name of security 167 | 'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". 168 | 'description' => 'A short description for oauth2 security scheme.', 169 | 'flow' => 'implicit', // The flow used by the OAuth2 security scheme. Valid values are "implicit", "password", "application" or "accessCode". 170 | 'authorizationUrl' => 'http://example.com/auth', // The authorization URL to be used for (implicit/accessCode) 171 | //'tokenUrl' => 'http://example.com/auth' // The authorization URL to be used for (password/application/accessCode) 172 | 'scopes' => [ 173 | 'read:projects' => 'read your projects', 174 | 'write:projects' => 'modify projects in your account', 175 | ] 176 | ], 177 | */ 178 | 179 | /* Open API 3.0 support 180 | 'passport' => [ // Unique name of security 181 | 'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". 182 | 'description' => 'Laravel passport oauth2 security.', 183 | 'in' => 'header', 184 | 'scheme' => 'https', 185 | 'flows' => [ 186 | "password" => [ 187 | "authorizationUrl" => config('app.url') . '/oauth/authorize', 188 | "tokenUrl" => config('app.url') . '/oauth/token', 189 | "refreshUrl" => config('app.url') . '/token/refresh', 190 | "scopes" => [] 191 | ], 192 | ], 193 | ], 194 | 'sanctum' => [ // Unique name of security 195 | 'type' => 'apiKey', // Valid values are "basic", "apiKey" or "oauth2". 196 | 'description' => 'Enter token in format (Bearer )', 197 | 'name' => 'Authorization', // The name of the header or query parameter to be used. 198 | 'in' => 'header', // The location of the API key. Valid values are "query" or "header". 199 | ], 200 | */ 201 | ], 202 | 'security' => [ 203 | /* 204 | * Examples of Securities 205 | */ 206 | [ 207 | /* 208 | 'oauth2_security_example' => [ 209 | 'read', 210 | 'write' 211 | ], 212 | 213 | 'passport' => [] 214 | */ 215 | ], 216 | ], 217 | ], 218 | 219 | /* 220 | * Set this to `true` in development mode so that docs would be regenerated on each request 221 | * Set this to `false` to disable swagger generation on production 222 | */ 223 | 'generate_always' => env('L5_SWAGGER_GENERATE_ALWAYS', false), 224 | 225 | /* 226 | * Set this to `true` to generate a copy of documentation in yaml format 227 | */ 228 | 'generate_yaml_copy' => env('L5_SWAGGER_GENERATE_YAML_COPY', false), 229 | 230 | /* 231 | * Edit to trust the proxy's ip address - needed for AWS Load Balancer 232 | * string[] 233 | */ 234 | 'proxy' => false, 235 | 236 | /* 237 | * Configs plugin allows to fetch external configs instead of passing them to SwaggerUIBundle. 238 | * See more at: https://github.com/swagger-api/swagger-ui#configs-plugin 239 | */ 240 | 'additional_config_url' => null, 241 | 242 | /* 243 | * Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 244 | * 'method' (sort by HTTP method). 245 | * Default is the order returned by the server unchanged. 246 | */ 247 | 'operations_sort' => env('L5_SWAGGER_OPERATIONS_SORT', null), 248 | 249 | /* 250 | * Pass the validatorUrl parameter to SwaggerUi init on the JS side. 251 | * A null value here disables validation. 252 | */ 253 | 'validator_url' => null, 254 | 255 | /* 256 | * Swagger UI configuration parameters 257 | */ 258 | 'ui' => [ 259 | 'display' => [ 260 | /* 261 | * Controls the default expansion setting for the operations and tags. It can be : 262 | * 'list' (expands only the tags), 263 | * 'full' (expands the tags and operations), 264 | * 'none' (expands nothing). 265 | */ 266 | 'doc_expansion' => env('L5_SWAGGER_UI_DOC_EXPANSION', 'none'), 267 | 268 | /** 269 | * If set, enables filtering. The top bar will show an edit box that 270 | * you can use to filter the tagged operations that are shown. Can be 271 | * Boolean to enable or disable, or a string, in which case filtering 272 | * will be enabled using that string as the filter expression. Filtering 273 | * is case-sensitive matching the filter expression anywhere inside 274 | * the tag. 275 | */ 276 | 'filter' => env('L5_SWAGGER_UI_FILTERS', true), // true | false 277 | ], 278 | 279 | 'authorization' => [ 280 | /* 281 | * If set to true, it persists authorization data, and it would not be lost on browser close/refresh 282 | */ 283 | 'persist_authorization' => env('L5_SWAGGER_UI_PERSIST_AUTHORIZATION', false), 284 | 285 | 'oauth2' => [ 286 | /* 287 | * If set to true, adds PKCE to AuthorizationCodeGrant flow 288 | */ 289 | 'use_pkce_with_authorization_code_grant' => false, 290 | ], 291 | ], 292 | ], 293 | /* 294 | * Constants which can be used in annotations 295 | */ 296 | 'constants' => [ 297 | 'L5_SWAGGER_CONST_HOST' => env('L5_SWAGGER_CONST_HOST', 'http://my-default-host.com'), 298 | ], 299 | ], 300 | ]; 301 | --------------------------------------------------------------------------------