commit 851454db11f0500ebe5af4ffa8efd8d3c776ce36 Author: Behzad Babaei Date: Sat Mar 28 17:02:54 2020 +0430 initial commit diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..1040133 --- /dev/null +++ b/.env.example @@ -0,0 +1,21 @@ +APP_NAME=OrdersApi +APP_ENV=local +APP_KEY= +APP_DEBUG=true +APP_URL=http://localhost +APP_TIMEZONE=UTC + +LOG_CHANNEL=stack +LOG_SLACK_WEBHOOK_URL= + +DB_CONNECTION=mysql +DB_HOST=127.0.0.1 +DB_PORT=3306 +DB_DATABASE=lu-ms1-orders_api +DB_USERNAME= +DB_PASSWORD= + +CACHE_DRIVER=file +QUEUE_CONNECTION=sync + +ALLOWED_SECRETS= diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..287ffd6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/vendor +/.idea +Homestead.json +Homestead.yaml +.env +composer.lock diff --git a/app/Console/Commands/.gitkeep b/app/Console/Commands/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php new file mode 100644 index 0000000..ad6e311 --- /dev/null +++ b/app/Console/Kernel.php @@ -0,0 +1,29 @@ +getStatusCode(); + $errorMessage = Response::$statusTexts[$errorCode]; + return $this->errorResponse($errorMessage, $errorCode); + } + + if ($exception instanceof ModelNotFoundException) { + $model = strtolower(class_basename($exception->getModel())); + return $this->errorResponse( + "Does not exist any instance of {$model} with a given id", + Response::HTTP_NOT_FOUND); + } + + if ($exception instanceof AuthorizationException) { + return $this->errorResponse( + $exception->getMessage(), + Response::HTTP_FORBIDDEN); + } + + if ($exception instanceof AuthenticationException) { + return $this->errorResponse( + $exception->getMessage(), + Response::HTTP_UNAUTHORIZED); + } + + if ($exception instanceof ValidationException) { + $errors = $exception->validator->errors()->getMessages(); + return $this->errorResponse( + $errors, + Response::HTTP_UNPROCESSABLE_ENTITY); + } + + if(env('APP_DEBUG',false)){ + return parent::render($request, $exception); + } + + return $this->errorResponse( + "Unexpected error. Please try later or contact the support team", + Response::HTTP_INTERNAL_SERVER_ERROR); + + } +} diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php new file mode 100644 index 0000000..72350ce --- /dev/null +++ b/app/Http/Controllers/Controller.php @@ -0,0 +1,11 @@ +successResponse($orders); + } + + public function show($order) + { + $order = Order::findOrFail($order); + return $this->successResponse($order); + } + + public function store(Request $request) + { + $rules = [ + 'quantity' => 'required|numeric|min:1|max:100', + 'product_id' => 'required|integer', + 'total_price' => 'required|numeric|min:1', + 'discount' => 'numeric' + ]; + + $this->validate($request, $rules); + $order = Order::create($request->all()); + return $this->successResponse($order); + + } + + public function update(Request $request, $order) + { + $rules = [ + 'quantity' => 'numeric|min:1|max:100', + 'product_id' => 'integer', + 'total_price' => 'numeric|min:1', + 'discount' => 'numeric' + ]; + + $this->validate($request, $rules); + $order = Order::findOrFail($order); + $order = $order->fill($request->all()); + + if ($order->isClean()) { + return $this->errorResponse('at least one value must be change', + Response::HTTP_UNPROCESSABLE_ENTITY); + } + + $order->save(); + return $this->successResponse($order); + } + + + public function destroy($order) + { + + $order = Order::findOrFail($order); + $order->delete(); + return $this->successResponse($order); + } + + +} \ No newline at end of file diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php new file mode 100644 index 0000000..361a11e --- /dev/null +++ b/app/Http/Middleware/Authenticate.php @@ -0,0 +1,44 @@ +auth = $auth; + } + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @param string|null $guard + * @return mixed + */ + public function handle($request, Closure $next, $guard = null) + { + if ($this->auth->guard($guard)->guest()) { + return response('Unauthorized.', 401); + } + + return $next($request); + } +} diff --git a/app/Http/Middleware/AuthenticateAccess.php b/app/Http/Middleware/AuthenticateAccess.php new file mode 100644 index 0000000..69f2411 --- /dev/null +++ b/app/Http/Middleware/AuthenticateAccess.php @@ -0,0 +1,27 @@ +header('Authorization'), $allowedSecrets)) { + return $next($request); + } + + abort(Response::HTTP_UNAUTHORIZED); + } +} diff --git a/app/Http/Middleware/ExampleMiddleware.php b/app/Http/Middleware/ExampleMiddleware.php new file mode 100644 index 0000000..166581c --- /dev/null +++ b/app/Http/Middleware/ExampleMiddleware.php @@ -0,0 +1,20 @@ +app['auth']->viaRequest('api', function ($request) { + if ($request->input('api_token')) { + return User::where('api_token', $request->input('api_token'))->first(); + } + }); + } +} diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php new file mode 100644 index 0000000..a3d284f --- /dev/null +++ b/app/Providers/EventServiceProvider.php @@ -0,0 +1,19 @@ + [ + 'App\Listeners\ExampleListener', + ], + ]; +} diff --git a/app/Traits/ApiResponse.php b/app/Traits/ApiResponse.php new file mode 100644 index 0000000..2c7cf46 --- /dev/null +++ b/app/Traits/ApiResponse.php @@ -0,0 +1,19 @@ +json(['data' => $data], $statusCode); + } + + public function errorResponse($errorMessage, $statusCode) + { + return response()->json(['error' => $errorMessage, 'error_code' => $statusCode], $statusCode); + } +} \ No newline at end of file diff --git a/artisan b/artisan new file mode 100755 index 0000000..6a9d095 --- /dev/null +++ b/artisan @@ -0,0 +1,35 @@ +#!/usr/bin/env php +make( + 'Illuminate\Contracts\Console\Kernel' +); + +exit($kernel->handle(new ArgvInput, new ConsoleOutput)); diff --git a/bootstrap/app.php b/bootstrap/app.php new file mode 100644 index 0000000..b92520e --- /dev/null +++ b/bootstrap/app.php @@ -0,0 +1,102 @@ +load(); +} catch (Dotenv\Exception\InvalidPathException $e) { + // +} + +/* +|-------------------------------------------------------------------------- +| Create The Application +|-------------------------------------------------------------------------- +| +| Here we will load the environment and create the application instance +| that serves as the central piece of this framework. We'll use this +| application as an "IoC" container and router for this framework. +| +*/ + +$app = new Laravel\Lumen\Application( + dirname(__DIR__) +); + + $app->withFacades(); + + $app->withEloquent(); + +/* +|-------------------------------------------------------------------------- +| Register Container Bindings +|-------------------------------------------------------------------------- +| +| Now we will register a few bindings in the service container. We will +| register the exception handler and the console kernel. You may add +| your own bindings here if you like or you can make another file. +| +*/ + +$app->singleton( + Illuminate\Contracts\Debug\ExceptionHandler::class, + App\Exceptions\Handler::class +); + +$app->singleton( + Illuminate\Contracts\Console\Kernel::class, + App\Console\Kernel::class +); + +/* +|-------------------------------------------------------------------------- +| Register Middleware +|-------------------------------------------------------------------------- +| +| Next, we will register the middleware with the application. These can +| be global middleware that run before and after each request into a +| route or middleware that'll be assigned to some specific routes. +| +*/ + + $app->middleware([ + App\Http\Middleware\AuthenticateAccess::class + ]); + +// $app->routeMiddleware([ +// 'auth' => App\Http\Middleware\Authenticate::class, +// ]); + +/* +|-------------------------------------------------------------------------- +| Register Service Providers +|-------------------------------------------------------------------------- +| +| Here we will register all of the application's service providers which +| are used to bind services into the container. Service providers are +| totally optional, so you are not required to uncomment this line. +| +*/ + +// $app->register(App\Providers\AppServiceProvider::class); +// $app->register(App\Providers\AuthServiceProvider::class); +// $app->register(App\Providers\EventServiceProvider::class); + +/* +|-------------------------------------------------------------------------- +| Load The Application Routes +|-------------------------------------------------------------------------- +| +| Next we will include the routes file so that they can all be added to +| the application. This will provide all of the URLs the application +| can respond to, as well as the controllers that may handle them. +| +*/ + +$app->router->group([ + 'namespace' => 'App\Http\Controllers', +], function ($router) { + require __DIR__.'/../routes/web.php'; +}); + +return $app; diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..e9fbf1a --- /dev/null +++ b/composer.json @@ -0,0 +1,43 @@ +{ + "name": "laravel/lumen", + "description": "The Laravel Lumen Framework.", + "keywords": ["framework", "laravel", "lumen"], + "license": "MIT", + "type": "project", + "require": { + "php": ">=7.1.3", + "laravel/lumen-framework": "5.7.*", + "vlucas/phpdotenv": "~2.2" + }, + "require-dev": { + "fzaninotto/faker": "~1.4", + "phpunit/phpunit": "~7.0", + "mockery/mockery": "~1.0" + }, + "autoload": { + "classmap": [ + "database/seeds", + "database/factories" + ], + "psr-4": { + "App\\": "app/" + } + }, + "autoload-dev": { + "classmap": [ + "tests/" + ] + }, + "scripts": { + "post-root-package-install": [ + "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" + ] + }, + "config": { + "preferred-install": "dist", + "sort-packages": true, + "optimize-autoloader": true + }, + "minimum-stability": "dev", + "prefer-stable": true +} diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php new file mode 100644 index 0000000..a9078e0 --- /dev/null +++ b/database/factories/ModelFactory.php @@ -0,0 +1,22 @@ +define(App\Order::class, function (Faker\Generator $faker) { + $quantity = $faker->numberBetween(1, 10); + return [ + 'quantity' => $quantity, + 'discount' => $faker->numberBetween(1, 30), + 'total_price' => ($quantity * $faker->numberBetween(1, 200)), + 'product_id' => $faker->numberBetween(1, 50), + ]; +}); diff --git a/database/migrations/.gitkeep b/database/migrations/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/database/migrations/2020_03_14_083218_create_orders_table.php b/database/migrations/2020_03_14_083218_create_orders_table.php new file mode 100644 index 0000000..86946f6 --- /dev/null +++ b/database/migrations/2020_03_14_083218_create_orders_table.php @@ -0,0 +1,35 @@ +increments('id'); + $table->integer('quantity')->unsigned(); + $table->decimal('total_price')->unsigned(); + $table->decimal('discount')->unsigned()->default(0); + $table->integer('product_id')->unsigned(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('orders'); + } +} diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php new file mode 100644 index 0000000..75ec69d --- /dev/null +++ b/database/seeds/DatabaseSeeder.php @@ -0,0 +1,16 @@ +create(); + } +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..b8c2751 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,26 @@ + + + + + ./tests + + + + + ./app + + + + + + + + diff --git a/public/.htaccess b/public/.htaccess new file mode 100644 index 0000000..b75525b --- /dev/null +++ b/public/.htaccess @@ -0,0 +1,21 @@ + + + Options -MultiViews -Indexes + + + RewriteEngine On + + # Handle Authorization Header + RewriteCond %{HTTP:Authorization} . + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + # Redirect Trailing Slashes If Not A Folder... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} (.+)/$ + RewriteRule ^ %1 [L,R=301] + + # Handle Front Controller... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..04aa086 --- /dev/null +++ b/public/index.php @@ -0,0 +1,28 @@ +run(); diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..f3e7478 --- /dev/null +++ b/readme.md @@ -0,0 +1,3 @@ +# OrdersApi +for running a project please run following command on your terminal: +php -S 127.0.0.1:8200 -t public \ No newline at end of file diff --git a/resources/views/.gitkeep b/resources/views/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/routes/web.php b/routes/web.php new file mode 100644 index 0000000..ef77d6e --- /dev/null +++ b/routes/web.php @@ -0,0 +1,24 @@ +group(['prefix' => 'api'], function () use ($router) { + + $router->group(['prefix' => 'order'], function () use ($router) { + $router->get('/', ['uses' => 'OrderController@index']); + $router->post('/', ['uses' => 'OrderController@store']); + $router->get('/{order}', ['uses' => 'OrderController@show']); + $router->patch('/{order}', ['uses' => 'OrderController@update']); + $router->delete('/{order}', ['uses' => 'OrderController@destroy']); + }); + +}); \ No newline at end of file diff --git a/storage/app/.gitignore b/storage/app/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/app/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/cache/.gitignore b/storage/framework/cache/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/cache/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/views/.gitignore b/storage/framework/views/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/views/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/logs/.gitignore b/storage/logs/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/logs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/tests/ExampleTest.php b/tests/ExampleTest.php new file mode 100644 index 0000000..1bad6ef --- /dev/null +++ b/tests/ExampleTest.php @@ -0,0 +1,21 @@ +get('/'); + + $this->assertEquals( + $this->app->version(), $this->response->getContent() + ); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..89a058d --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,14 @@ +