├── .env.example
├── .gitattributes
├── .gitignore
├── Homestead.yaml
├── Vagrantfile
├── app
├── Buyer.php
├── Category.php
├── Console
│ └── Kernel.php
├── Exceptions
│ └── Handler.php
├── Http
│ ├── Controllers
│ │ ├── ApiController.php
│ │ ├── Auth
│ │ │ ├── ForgotPasswordController.php
│ │ │ ├── LoginController.php
│ │ │ └── ResetPasswordController.php
│ │ ├── Buyer
│ │ │ ├── BuyerCategoryController.php
│ │ │ ├── BuyerController.php
│ │ │ ├── BuyerProductController.php
│ │ │ ├── BuyerSellerController.php
│ │ │ └── BuyerTransactionController.php
│ │ ├── Category
│ │ │ ├── CategoryBuyerController.php
│ │ │ ├── CategoryController.php
│ │ │ ├── CategoryProductController.php
│ │ │ ├── CategorySellerController.php
│ │ │ └── CategoryTransactionController.php
│ │ ├── Controller.php
│ │ ├── HomeController.php
│ │ ├── Product
│ │ │ ├── ProductBuyerController.php
│ │ │ ├── ProductBuyerTransactionController.php
│ │ │ ├── ProductCategoryController.php
│ │ │ ├── ProductController.php
│ │ │ └── ProductTransactionController.php
│ │ ├── Seller
│ │ │ ├── SellerBuyerController.php
│ │ │ ├── SellerCategoryController.php
│ │ │ ├── SellerController.php
│ │ │ ├── SellerProductController.php
│ │ │ └── SellerTransactionController.php
│ │ ├── Transaction
│ │ │ ├── TransactionCategoryController.php
│ │ │ ├── TransactionController.php
│ │ │ └── TransactionSellerController.php
│ │ └── User
│ │ │ └── UserController.php
│ ├── Kernel.php
│ └── Middleware
│ │ ├── Authenticate.php
│ │ ├── CustomThrottleRequests.php
│ │ ├── EncryptCookies.php
│ │ ├── RedirectIfAuthenticated.php
│ │ ├── SignatureMiddleware.php
│ │ ├── TransformInput.php
│ │ ├── TrimStrings.php
│ │ ├── TrustProxies.php
│ │ └── VerifyCsrfToken.php
├── Mail
│ ├── UserCreated.php
│ └── UserMailChanged.php
├── Policies
│ ├── BuyerPolicy.php
│ ├── ProductPolicy.php
│ ├── SellerPolicy.php
│ ├── TransactionPolicy.php
│ └── UserPolicy.php
├── Product.php
├── Providers
│ ├── AppServiceProvider.php
│ ├── AuthServiceProvider.php
│ ├── BroadcastServiceProvider.php
│ ├── EventServiceProvider.php
│ └── RouteServiceProvider.php
├── Scopes
│ ├── BuyerScope.php
│ └── SellerScope.php
├── Seller.php
├── Traits
│ ├── AdminActions.php
│ └── ApiResponser.php
├── Transaction.php
├── Transformers
│ ├── BuyerTransformer.php
│ ├── CategoryTransformer.php
│ ├── ProductTransformer.php
│ ├── SellerTransformer.php
│ ├── TransactionTransformer.php
│ └── UserTransformer.php
└── User.php
├── artisan
├── bootstrap
├── app.php
├── autoload.php
└── cache
│ └── .gitignore
├── composer.json
├── composer.lock
├── config
├── app.php
├── auth.php
├── broadcasting.php
├── cache.php
├── cors.php
├── database.php
├── filesystems.php
├── hashing.php
├── logging.php
├── mail.php
├── queue.php
├── sentry.php
├── services.php
├── session.php
└── view.php
├── database
├── .gitignore
├── factories
│ └── ModelFactory.php
├── migrations
│ ├── 2014_10_12_000000_create_users_table.php
│ ├── 2014_10_12_100000_create_password_resets_table.php
│ ├── 2017_02_15_060634_create_categories_table.php
│ ├── 2017_02_15_060644_create_products_table.php
│ ├── 2017_02_15_060654_create_transactions_table.php
│ └── 2017_02_17_034324_category_product_table.php
└── seeders
│ └── DatabaseSeeder.php
├── package.json
├── phpunit.xml
├── public
├── .htaccess
├── css
│ └── app.css
├── favicon.ico
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ ├── glyphicons-halflings-regular.woff
│ └── glyphicons-halflings-regular.woff2
├── img
│ ├── .gitignore
│ ├── 1.jpg
│ ├── 2.jpg
│ └── 3.jpg
├── index.php
├── js
│ └── app.js
├── mix-manifest.json
├── robots.txt
└── web.config
├── readme.md
├── resources
├── assets
│ ├── js
│ │ ├── app.js
│ │ ├── bootstrap.js
│ │ └── components
│ │ │ └── passport
│ │ │ ├── AuthorizedClients.vue
│ │ │ ├── Clients.vue
│ │ │ └── PersonalAccessTokens.vue
│ └── sass
│ │ ├── _variables.scss
│ │ └── app.scss
├── lang
│ └── en
│ │ ├── auth.php
│ │ ├── pagination.php
│ │ ├── passwords.php
│ │ └── validation.php
└── views
│ ├── auth
│ ├── login.blade.php
│ ├── passwords
│ │ ├── email.blade.php
│ │ └── reset.blade.php
│ └── register.blade.php
│ ├── emails
│ ├── confirm.blade.php
│ └── welcome.blade.php
│ ├── home.blade.php
│ ├── home
│ ├── authorized-clients.blade.php
│ ├── personal-clients.blade.php
│ └── personal-tokens.blade.php
│ ├── layouts
│ └── app.blade.php
│ └── welcome.blade.php
├── routes
├── api.php
├── channels.php
├── console.php
└── web.php
├── server.php
├── storage
├── app
│ ├── .gitignore
│ └── public
│ │ └── .gitignore
├── framework
│ ├── .gitignore
│ ├── cache
│ │ └── .gitignore
│ ├── sessions
│ │ └── .gitignore
│ └── views
│ │ └── .gitignore
└── logs
│ └── .gitignore
├── tests
├── CreatesApplication.php
├── Feature
│ └── ExampleTest.php
├── TestCase.php
└── Unit
│ └── ExampleTest.php
└── webpack.mix.js
/.env.example:
--------------------------------------------------------------------------------
1 | APP_ENV=local
2 | APP_KEY=
3 | APP_DEBUG=true
4 | APP_LOG_LEVEL=debug
5 | APP_URL=http://localhost
6 |
7 | LOG_CHANNEL=stack
8 |
9 | DB_CONNECTION=mysql
10 | DB_HOST=127.0.0.1
11 | DB_PORT=3306
12 | DB_DATABASE=homestead
13 | DB_USERNAME=homestead
14 | DB_PASSWORD=secret
15 |
16 | BROADCAST_DRIVER=log
17 | CACHE_DRIVER=file
18 | SESSION_DRIVER=file
19 | QUEUE_DRIVER=sync
20 |
21 | REDIS_HOST=127.0.0.1
22 | REDIS_PASSWORD=null
23 | REDIS_PORT=6379
24 |
25 | MAIL_DRIVER=smtp
26 | MAIL_HOST=mailtrap.io
27 | MAIL_PORT=2525
28 | MAIL_USERNAME=null
29 | MAIL_PASSWORD=null
30 | MAIL_ENCRYPTION=null
31 |
32 | MAILGUN_DOMAIN=null
33 | MAILGUN_SECRET=null
34 | SPARKPOST_SECRET=null
35 |
36 | MAIL_FROM_ADDRESS=postmaster@restfulapi.dev
37 | MAIL_FROM_NAME="RESTful API"
38 |
39 | PUSHER_APP_ID=
40 | PUSHER_APP_KEY=
41 | PUSHER_APP_SECRET=
42 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.css linguist-vendored
3 | *.scss linguist-vendored
4 | *.js linguist-vendored
5 | CHANGELOG.md export-ignore
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /public/storage
3 | /public/hot
4 | /storage/*.key
5 | /vendor
6 | /.idea
7 | /.vagrant
8 | Homestead.json
9 | .env
10 | *.sublime-*
--------------------------------------------------------------------------------
/Homestead.yaml:
--------------------------------------------------------------------------------
1 | ip: 192.168.10.14
2 | memory: 512
3 | cpus: 1
4 | provider: virtualbox
5 | authorize: ~/.ssh/id_rsa.pub
6 | keys:
7 | - ~/.ssh/id_rsa
8 | folders:
9 | -
10 | map: 'C:\RESTfulAPI'
11 | to: /home/vagrant/restfulapi
12 | sites:
13 | -
14 | map: restfulapi.test
15 | to: /home/vagrant/restfulapi/public
16 | databases:
17 | - homestead
18 | name: restfulapi
19 | hostname: restfulapi
20 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | require 'json'
5 | require 'yaml'
6 |
7 | VAGRANTFILE_API_VERSION ||= "2"
8 | confDir = $confDir ||= File.expand_path("vendor/laravel/homestead", File.dirname(__FILE__))
9 |
10 | homesteadYamlPath = "Homestead.yaml"
11 | homesteadJsonPath = "Homestead.json"
12 | afterScriptPath = "after.sh"
13 | aliasesPath = "aliases"
14 |
15 | require File.expand_path(confDir + '/scripts/homestead.rb')
16 |
17 | Vagrant.require_version '>= 1.9.0'
18 |
19 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
20 | if File.exist? aliasesPath then
21 | config.vm.provision "file", source: aliasesPath, destination: "/tmp/bash_aliases"
22 | config.vm.provision "shell" do |s|
23 | s.inline = "awk '{ sub(\"\r$\", \"\"); print }' /tmp/bash_aliases > /home/vagrant/.bash_aliases"
24 | end
25 | end
26 |
27 | if File.exist? homesteadYamlPath then
28 | settings = YAML::load(File.read(homesteadYamlPath))
29 | elsif File.exist? homesteadJsonPath then
30 | settings = JSON.parse(File.read(homesteadJsonPath))
31 | else
32 | abort "Homestead settings file not found in #{confDir}"
33 | end
34 |
35 | Homestead.configure(config, settings)
36 |
37 | if File.exist? afterScriptPath then
38 | config.vm.provision "shell", path: afterScriptPath, privileged: false
39 | end
40 |
41 | if defined? VagrantPlugins::HostsUpdater
42 | config.hostsupdater.aliases = settings['sites'].map { |site| site['map'] }
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/app/Buyer.php:
--------------------------------------------------------------------------------
1 | hasMany(Transaction::class);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/Category.php:
--------------------------------------------------------------------------------
1 | belongsToMany(Product::class);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/Console/Kernel.php:
--------------------------------------------------------------------------------
1 | command('inspire')
28 | // ->hourly();
29 | }
30 |
31 | /**
32 | * Register the Closure based commands for the application.
33 | *
34 | * @return void
35 | */
36 | protected function commands()
37 | {
38 | require base_path('routes/console.php');
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/Exceptions/Handler.php:
--------------------------------------------------------------------------------
1 | handleException($request, $exception);
67 |
68 | app(CorsService::class)->addActualRequestHeaders($response, $request);
69 |
70 | return $response;
71 |
72 | }
73 |
74 | public function handleException($request, Throwable $exception)
75 | {
76 | if ($exception instanceof OAuthServerException) {
77 | return $this->errorResponse(
78 | $exception->getMessage(),
79 | $exception->statusCode()
80 | );
81 | }
82 |
83 | if ($exception instanceof ValidationException) {
84 | return $this->convertValidationExceptionToResponse($exception, $request);
85 | }
86 |
87 | if ($exception instanceof ModelNotFoundException) {
88 | $modelName = strtolower(class_basename($exception->getModel()));
89 |
90 | return $this->errorResponse("Does not exists any {$modelName} with the specified identificator", 404);
91 | }
92 |
93 | if ($exception instanceof AuthenticationException) {
94 | return $this->unauthenticated($request, $exception);
95 | }
96 |
97 | if ($exception instanceof AuthorizationException) {
98 | return $this->errorResponse($exception->getMessage(), 403);
99 | }
100 |
101 | if ($exception instanceof MethodNotAllowedHttpException) {
102 | return $this->errorResponse('The specified method for the request is invalid', 405);
103 | }
104 |
105 | if ($exception instanceof NotFoundHttpException) {
106 | return $this->errorResponse('The specified URL cannot be found', 404);
107 | }
108 |
109 | if ($exception instanceof HttpException) {
110 | return $this->errorResponse($exception->getMessage(), $exception->getStatusCode());
111 | }
112 |
113 | if ($exception instanceof QueryException) {
114 | $errorCode = $exception->errorInfo[1];
115 |
116 | if ($errorCode == 1451) {
117 | return $this->errorResponse('Cannot remove this resource permanently. It is related with any other resource', 409);
118 | }
119 | }
120 |
121 | if ($exception instanceof TokenMismatchException) {
122 | return redirect()->back()->withInput($request->input());
123 | }
124 |
125 | if (config('app.debug')) {
126 | return parent::render($request, $exception);
127 | }
128 |
129 | if (app()->environment('production') && app()->bound('sentry') && $this->shouldReport($exception)) {
130 | app('sentry')->captureException($exception);
131 | }
132 |
133 | return $this->errorResponse('Unexpected Exception. Try later', 500);
134 | }
135 |
136 | /**
137 | * Convert an authentication exception into an unauthenticated response.
138 | *
139 | * @param \Illuminate\Http\Request $request
140 | * @param \Illuminate\Auth\AuthenticationException $exception
141 | * @return \Illuminate\Http\Response
142 | */
143 | protected function unauthenticated($request, AuthenticationException $exception)
144 | {
145 | if ($this->isFrontend($request)) {
146 | return redirect()->guest('login');
147 | }
148 |
149 | return $this->errorResponse('Unauthenticated.', 401);
150 | }
151 |
152 | /**
153 | * Create a response object from the given validation exception.
154 | *
155 | * @param \Illuminate\Validation\ValidationException $e
156 | * @param \Illuminate\Http\Request $request
157 | * @return \Symfony\Component\HttpFoundation\Response
158 | */
159 | protected function convertValidationExceptionToResponse(ValidationException $e, $request)
160 | {
161 | $errors = $e->validator->errors()->getMessages();
162 |
163 | if ($this->isFrontend($request)) {
164 | return $request->ajax() ? response()->json($errors, 422) : redirect()
165 | ->back()
166 | ->withInput($request->input())
167 | ->withErrors($errors);
168 | }
169 |
170 | return $this->errorResponse($errors, 422);
171 | }
172 |
173 | private function isFrontend($request)
174 | {
175 | return $request->acceptsHtml() && collect($request->route()->middleware())->contains('web');
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/app/Http/Controllers/ApiController.php:
--------------------------------------------------------------------------------
1 | middleware('auth:api');
17 | }
18 |
19 | protected function allowedAdminAction()
20 | {
21 | if (Gate::denies('admin-action')) {
22 | throw new AuthorizationException('This action is unauthorized');
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/ForgotPasswordController.php:
--------------------------------------------------------------------------------
1 | middleware('guest');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/LoginController.php:
--------------------------------------------------------------------------------
1 | middleware('guest', ['except' => 'logout']);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/ResetPasswordController.php:
--------------------------------------------------------------------------------
1 | middleware('guest');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Buyer/BuyerCategoryController.php:
--------------------------------------------------------------------------------
1 | middleware('scope:read-general')->only('index');
15 | $this->middleware('can:view,buyer')->only('index');
16 | }
17 |
18 | /**
19 | * Display a listing of the resource.
20 | *
21 | * @return \Illuminate\Http\Response
22 | */
23 | public function index(Buyer $buyer)
24 | {
25 | $sellers = $buyer->transactions()->with('product.categories')
26 | ->get()
27 | ->pluck('product.categories')
28 | ->collapse()
29 | ->unique('id')
30 | ->values();
31 |
32 | return $this->showAll($sellers);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Buyer/BuyerController.php:
--------------------------------------------------------------------------------
1 | middleware('scope:read-general')->only('index');
15 | $this->middleware('can:view,buyer')->only('show');
16 | }
17 |
18 | /**
19 | * Display a listing of the resource.
20 | *
21 | * @return \Illuminate\Http\Response
22 | */
23 | public function index()
24 | {
25 | $this->allowedAdminAction();
26 |
27 | $buyers = Buyer::has('transactions')->get();
28 |
29 | return $this->showAll($buyers);
30 | }
31 |
32 | /**
33 | * Display the specified resource.
34 | *
35 | * @param int $id
36 | * @return \Illuminate\Http\Response
37 | */
38 | public function show(Buyer $buyer)
39 | {
40 | // $buyer = Buyer::has('transactions')->findOrFail($id);
41 | return $this->showOne($buyer);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Buyer/BuyerProductController.php:
--------------------------------------------------------------------------------
1 | middleware('scope:read-general')->only('index');
15 | $this->middleware('can:view,buyer')->only('index');
16 | }
17 |
18 | /**
19 | * Display a listing of the resource.
20 | *
21 | * @return \Illuminate\Http\Response
22 | */
23 | public function index(Buyer $buyer)
24 | {
25 | $products = $buyer->transactions()->with('product')
26 | ->get()
27 | ->pluck('product');
28 |
29 | return $this->showAll($products);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Buyer/BuyerSellerController.php:
--------------------------------------------------------------------------------
1 | allowedAdminAction();
24 |
25 | $sellers = $buyer->transactions()->with('product.seller')
26 | ->get()
27 | ->pluck('product.seller')
28 | ->unique('id')
29 | ->values();
30 |
31 | return $this->showAll($sellers);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Buyer/BuyerTransactionController.php:
--------------------------------------------------------------------------------
1 | middleware('scope:read-general')->only('index');
15 | $this->middleware('can:view,buyer')->only('index');
16 | }
17 |
18 | /**
19 | * Display a listing of the resource.
20 | *
21 | * @return \Illuminate\Http\Response
22 | */
23 | public function index(Buyer $buyer)
24 | {
25 | $transactions = $buyer->transactions;
26 |
27 | return $this->showAll($transactions);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Category/CategoryBuyerController.php:
--------------------------------------------------------------------------------
1 | allowedAdminAction();
24 |
25 | $buyers = $category->products()
26 | ->whereHas('transactions')
27 | ->with('transactions.buyer')
28 | ->get()
29 | ->pluck('transactions')
30 | ->collapse()
31 | ->pluck('buyer')
32 | ->unique('id')
33 | ->values();
34 |
35 | return $this->showAll($buyers);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Category/CategoryController.php:
--------------------------------------------------------------------------------
1 | middleware('client.credentials')->only(['index', 'show']);
15 | $this->middleware('auth:api')->except(['index', 'show']);
16 | $this->middleware('transform.input:' . CategoryTransformer::class)->only(['store', 'update']);
17 | }
18 |
19 | /**
20 | * Display a listing of the resource.
21 | *
22 | * @return \Illuminate\Http\Response
23 | */
24 | public function index()
25 | {
26 | $categories = Category::all();
27 |
28 | return $this->showAll($categories);
29 | }
30 |
31 | /**
32 | * Store a newly created resource in storage.
33 | *
34 | * @param \Illuminate\Http\Request $request
35 | * @return \Illuminate\Http\Response
36 | */
37 | public function store(Request $request)
38 | {
39 | $this->allowedAdminAction();
40 |
41 | $rules = [
42 | 'name' => 'required',
43 | 'description' => 'required',
44 | ];
45 |
46 | $this->validate($request, $rules);
47 |
48 | $newCategory = Category::create($request->all());
49 |
50 | return $this->showOne($newCategory, 201);
51 | }
52 |
53 | /**
54 | * Display the specified resource.
55 | *
56 | * @param \App\Category $category
57 | * @return \Illuminate\Http\Response
58 | */
59 | public function show(Category $category)
60 | {
61 | return $this->showOne($category);
62 | }
63 |
64 | /**
65 | * Update the specified resource in storage.
66 | *
67 | * @param \Illuminate\Http\Request $request
68 | * @param \App\Category $category
69 | * @return \Illuminate\Http\Response
70 | */
71 | public function update(Request $request, Category $category)
72 | {
73 | $this->allowedAdminAction();
74 |
75 | $category->fill($request->only([
76 | 'name',
77 | 'description',
78 | ]));
79 |
80 | if ($category->isClean()) {
81 | return $this->errorResponse('You need to specify any different value to update', 422);
82 | }
83 |
84 | $category->save();
85 |
86 | return $this->showOne($category);
87 | }
88 |
89 | /**
90 | * Remove the specified resource from storage.
91 | *
92 | * @param \App\Category $category
93 | * @return \Illuminate\Http\Response
94 | */
95 | public function destroy(Category $category)
96 | {
97 | $this->allowedAdminAction();
98 |
99 | $category->delete();
100 |
101 | return $this->showOne($category);
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Category/CategoryProductController.php:
--------------------------------------------------------------------------------
1 | middleware('client.credentials')->only(['index']);
14 | }
15 |
16 | /**
17 | * Display a listing of the resource.
18 | *
19 | * @return \Illuminate\Http\Response
20 | */
21 | public function index(Category $category)
22 | {
23 | $products = $category->products;
24 |
25 | return $this->showAll($products);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Category/CategorySellerController.php:
--------------------------------------------------------------------------------
1 | allowedAdminAction();
24 |
25 | $sellers = $category->products()
26 | ->with('seller')
27 | ->get()
28 | ->pluck('seller')
29 | ->unique()
30 | ->values();
31 |
32 | return $this->showAll($sellers);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Category/CategoryTransactionController.php:
--------------------------------------------------------------------------------
1 | allowedAdminAction();
24 |
25 | $transactions = $category->products()
26 | ->whereHas('transactions')
27 | ->with('transactions')
28 | ->get()
29 | ->pluck('transactions')
30 | ->collapse();
31 |
32 | return $this->showAll($transactions);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Controller.php:
--------------------------------------------------------------------------------
1 | middleware('auth');
17 | }
18 |
19 | /**
20 | * Show the application dashboard.
21 | *
22 | * @return \Illuminate\Http\Response
23 | */
24 | public function index()
25 | {
26 | return view('home');
27 | }
28 |
29 | public function getTokens()
30 | {
31 | return view('home.personal-tokens');
32 | }
33 |
34 | public function getAuthorizedClients()
35 | {
36 | return view('home.authorized-clients');
37 | }
38 |
39 |
40 | public function getClients()
41 | {
42 | return view('home.personal-clients');
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Product/ProductBuyerController.php:
--------------------------------------------------------------------------------
1 | allowedAdminAction();
24 |
25 | $buyers = $product->transactions()
26 | ->with('buyer')
27 | ->get()
28 | ->pluck('buyer')
29 | ->unique('id')
30 | ->values();
31 |
32 | return $this->showAll($buyers);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Product/ProductBuyerTransactionController.php:
--------------------------------------------------------------------------------
1 | middleware('transform.input:' . TransactionTransformer::class)->only(['store']);
20 | $this->middleware('scope:purchase-product')->only(['store']);
21 | $this->middleware('can:purchase,buyer')->only('store');
22 | }
23 |
24 | /**
25 | * Store a newly created resource in storage.
26 | *
27 | * @param \Illuminate\Http\Request $request
28 | * @return \Illuminate\Http\Response
29 | */
30 | public function store(Request $request, Product $product, User $buyer)
31 | {
32 | $rules = [
33 | 'quantity' => 'required|integer|min:1',
34 | ];
35 |
36 | $this->validate($request, $rules);
37 |
38 | if ($buyer->id == $product->seller_id) {
39 | return $this->errorResponse('The buyer must be different from the seller', 409);
40 | }
41 |
42 | /*if (!$buyer->isVerified()) {
43 | return $this->errorResponse('The buyer must be a verified user', 409);
44 | }
45 |
46 | if (!$product->seller->isVerified()) {
47 | return $this->errorResponse('The seller must be a verified user', 409);
48 | }*/
49 |
50 | if (!$product->isAvailable()) {
51 | return $this->errorResponse('The product is not available', 409);
52 | }
53 |
54 | if ($product->quantity < $request->quantity) {
55 | return $this->errorResponse('The product does not have enough units for this transaction', 409);
56 | }
57 |
58 | return DB::transaction(function () use ($request, $product, $buyer) {
59 | $product->quantity -= $request->quantity;
60 | $product->save();
61 |
62 | $transaction = Transaction::create([
63 | 'quantity' => $request->quantity,
64 | 'buyer_id' => $buyer->id,
65 | 'product_id' => $product->id,
66 | ]);
67 |
68 | return $this->showOne($transaction, 201);
69 | });
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Product/ProductCategoryController.php:
--------------------------------------------------------------------------------
1 | middleware('client.credentials')->only(['index']);
15 | $this->middleware('auth:api')->except(['index']);
16 | $this->middleware('scope:manage-products')->except('index');
17 | $this->middleware('can:add-category,product')->only('update');
18 | $this->middleware('can:delete-category,product')->only('destroy');
19 | }
20 |
21 | /**
22 | * Display a listing of the resource.
23 | *
24 | * @return \Illuminate\Http\Response
25 | */
26 | public function index(Product $product)
27 | {
28 | $categories = $product->categories;
29 |
30 | return $this->showAll($categories);
31 | }
32 |
33 | /**
34 | * Update the specified resource in storage.
35 | *
36 | * @param \Illuminate\Http\Request $request
37 | * @param \App\Product $product
38 | * @return \Illuminate\Http\Response
39 | */
40 | public function update(Request $request, Product $product, Category $category)
41 | {
42 | //attach, sync, syncWithoutDetach
43 | $product->categories()->syncWithoutDetaching([$category->id]);
44 |
45 | return $this->showAll($product->categories);
46 | }
47 |
48 | /**
49 | * Remove the specified resource from storage.
50 | *
51 | * @param \App\Product $product
52 | * @return \Illuminate\Http\Response
53 | */
54 | public function destroy(Product $product, Category $category)
55 | {
56 | if (!$product->categories()->find($category->id)) {
57 | return $this->errorResponse('The specified category is not a category of this product', 404);
58 | }
59 |
60 | $product->categories()->detach($category->id);
61 |
62 | return $this->showAll($product->categories);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Product/ProductController.php:
--------------------------------------------------------------------------------
1 | middleware('client.credentials')->only(['index', 'show']);
14 | }
15 |
16 | /**
17 | * Display a listing of the resource.
18 | *
19 | * @return \Illuminate\Http\Response
20 | */
21 | public function index()
22 | {
23 | $products = Product::all();
24 |
25 | return $this->showAll($products);
26 | }
27 |
28 | /**
29 | * Display the specified resource.
30 | *
31 | * @param \App\Product $product
32 | * @return \Illuminate\Http\Response
33 | */
34 | public function show(Product $product)
35 | {
36 | return $this->showOne($product);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Product/ProductTransactionController.php:
--------------------------------------------------------------------------------
1 | allowedAdminAction();
24 |
25 | $transactions = $product->transactions;
26 |
27 | return $this->showAll($transactions);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Seller/SellerBuyerController.php:
--------------------------------------------------------------------------------
1 | allowedAdminAction();
24 |
25 | $buyers = $seller->products()
26 | ->whereHas('transactions')
27 | ->with('transactions.buyer')
28 | ->get()
29 | ->pluck('transactions')
30 | ->collapse()
31 | ->pluck('buyer')
32 | ->unique('id')
33 | ->values();
34 |
35 | return $this->showAll($buyers);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Seller/SellerCategoryController.php:
--------------------------------------------------------------------------------
1 | middleware('scope:read-general')->only('index');
15 | $this->middleware('can:view,seller')->only('index');
16 | }
17 |
18 | /**
19 | * Display a listing of the resource.
20 | *
21 | * @return \Illuminate\Http\Response
22 | */
23 | public function index(Seller $seller)
24 | {
25 | $categories = $seller->products()
26 | ->whereHas('categories')
27 | ->with('categories')
28 | ->get()
29 | ->pluck('categories')
30 | ->collapse()
31 | ->unique('id')
32 | ->values();
33 |
34 | return $this->showAll($categories);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Seller/SellerController.php:
--------------------------------------------------------------------------------
1 | middleware('scope:read-general')->only('show');
15 | $this->middleware('can:view,seller')->only('show');
16 | }
17 |
18 | /**
19 | * Display a listing of the resource.
20 | *
21 | * @return \Illuminate\Http\Response
22 | */
23 | public function index()
24 | {
25 | $this->allowedAdminAction();
26 |
27 | $sellers = Seller::has('products')->get();
28 |
29 | return $this->showAll($sellers);
30 | }
31 |
32 | /**
33 | * Display the specified resource.
34 | *
35 | * @param int $id
36 | * @return \Illuminate\Http\Response
37 | */
38 | public function show(Seller $seller)
39 | {
40 | return $this->showOne($seller);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Seller/SellerProductController.php:
--------------------------------------------------------------------------------
1 | middleware('transform.input:' . ProductTransformer::class)->only(['store', 'update']);
22 | $this->middleware('scope:manage-products')->except('index');
23 |
24 | $this->middleware('can:view,seller')->only('index');
25 | $this->middleware('can:sale,seller')->only('store');
26 | $this->middleware('can:edit-product,seller')->only('update');
27 | $this->middleware('can:delete-product,seller')->only('destroy');
28 | }
29 |
30 | /**
31 | * Display a listing of the resource.
32 | *
33 | * @return \Illuminate\Http\Response
34 | */
35 | public function index(Seller $seller)
36 | {
37 | if (request()->user()->tokenCan('read-general') || request()->user()->tokenCan('manage-products')) {
38 | $products = $seller->products;
39 |
40 | return $this->showAll($products);
41 | }
42 |
43 | throw new AuthorizationException('Invalid scope(s)');
44 |
45 | }
46 |
47 | /**
48 | * Store a newly created resource in storage.
49 | *
50 | * @param \Illuminate\Http\Request $request
51 | * @return \Illuminate\Http\Response
52 | */
53 | public function store(Request $request, User $seller)
54 | {
55 | $rules = [
56 | 'name' => 'required',
57 | 'description' => 'required',
58 | 'quantity' => 'required|integer|min:1',
59 | 'image' => 'required|image',
60 | ];
61 |
62 | $this->validate($request, $rules);
63 |
64 | $data = $request->all();
65 |
66 | $data['status'] = Product::UNAVAILABLE_PRODUCT;
67 | $data['image'] = $request->image->store('');
68 | $data['seller_id'] = $seller->id;
69 |
70 | $product = Product::create($data);
71 |
72 | return $this->showOne($product);
73 | }
74 |
75 | /**
76 | * Update the specified resource in storage.
77 | *
78 | * @param \Illuminate\Http\Request $request
79 | * @param \App\Seller $seller
80 | * @return \Illuminate\Http\Response
81 | */
82 | public function update(Request $request, Seller $seller, Product $product)
83 | {
84 | $rules = [
85 | 'quantity' => 'integer|min:1',
86 | 'status' => 'in:' . Product::AVAILABLE_PRODUCT . ',' . Product::UNAVAILABLE_PRODUCT,
87 | 'image' => 'image',
88 | ];
89 |
90 | $this->validate($request, $rules);
91 |
92 | $this->checkSeller($seller, $product);
93 |
94 | $product->fill($request->only([
95 | 'name',
96 | 'description',
97 | 'quantity',
98 | ]));
99 |
100 | if ($request->has('status')) {
101 | $product->status = $request->status;
102 |
103 | if ($product->isAvailable() && $product->categories()->count() == 0) {
104 | return $this->errorResponse('An active product must have at least one category', 409);
105 | }
106 | }
107 |
108 | if ($request->hasFile('image')) {
109 | Storage::delete($product->image);
110 |
111 | $product->image = $request->image->store('');
112 | }
113 |
114 | if ($product->isClean()) {
115 | return $this->errorResponse('You need to specify a different value to update', 422);
116 | }
117 |
118 | $product->save();
119 |
120 | return $this->showOne($product);
121 | }
122 |
123 | /**
124 | * Remove the specified resource from storage.
125 | *
126 | * @param \App\Seller $seller
127 | * @return \Illuminate\Http\Response
128 | */
129 | public function destroy(Seller $seller, Product $product)
130 | {
131 | $this->checkSeller($seller, $product);
132 |
133 | $product->delete();
134 | Storage::delete($product->image);
135 |
136 | return $this->showOne($product);
137 | }
138 |
139 | protected function checkSeller(Seller $seller, Product $product)
140 | {
141 | if ($seller->id != $product->seller_id) {
142 | throw new HttpException(422, 'The specified seller is not the actual seller of the product');
143 | }
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Seller/SellerTransactionController.php:
--------------------------------------------------------------------------------
1 | middleware('scope:read-general')->only('index');
15 | $this->middleware('can:view,seller')->only('index');
16 | }
17 |
18 | /**
19 | * Display a listing of the resource.
20 | *
21 | * @return \Illuminate\Http\Response
22 | */
23 | public function index(Seller $seller)
24 | {
25 | $transactions = $seller->products()
26 | ->whereHas('transactions')
27 | ->with('transactions')
28 | ->get()
29 | ->pluck('transactions')
30 | ->collapse();
31 |
32 | return $this->showAll($transactions);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Transaction/TransactionCategoryController.php:
--------------------------------------------------------------------------------
1 | middleware('client.credentials')->only(['index']);
14 | }
15 |
16 | /**
17 | * Display a listing of the resource.
18 | *
19 | * @return \Illuminate\Http\Response
20 | */
21 | public function index(Transaction $transaction)
22 | {
23 | $categories = $transaction->product->categories;
24 |
25 | return $this->showAll($categories);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Transaction/TransactionController.php:
--------------------------------------------------------------------------------
1 | middleware('scope:read-general')->only('show');
15 | $this->middleware('can:view,transaction')->only('show');
16 | }
17 |
18 | /**
19 | * Display a listing of the resource.
20 | *
21 | * @return \Illuminate\Http\Response
22 | */
23 | public function index()
24 | {
25 | $this->allowedAdminAction();
26 |
27 | $transactions = Transaction::all();
28 |
29 | return $this->showAll($transactions);
30 | }
31 |
32 | /**
33 | * Display the specified resource.
34 | *
35 | * @param \App\Transaction $transaction
36 | * @return \Illuminate\Http\Response
37 | */
38 | public function show(Transaction $transaction)
39 | {
40 | return $this->showOne($transaction);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Transaction/TransactionSellerController.php:
--------------------------------------------------------------------------------
1 | middleware('scope:read-general')->only('index');
15 | $this->middleware('can:view,transaction')->only('index');
16 | }
17 |
18 | /**
19 | * Display a listing of the resource.
20 | *
21 | * @return \Illuminate\Http\Response
22 | */
23 | public function index(Transaction $transaction)
24 | {
25 | $seller = $transaction->product->seller;
26 |
27 | return $this->showOne($seller);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/Http/Controllers/User/UserController.php:
--------------------------------------------------------------------------------
1 | middleware('client.credentials')->only(['resend']);
18 | $this->middleware('auth:api')->except(['showRegisterForm', 'store', 'verify', 'resend']);
19 | $this->middleware('transform.input:' . UserTransformer::class)->only(['update']);
20 | $this->middleware('scope:manage-account')->only(['show', 'update']);
21 | $this->middleware('can:view,user')->only('show');
22 | $this->middleware('can:update,user')->only('update');
23 | $this->middleware('can:delete,user')->only('destroy');
24 | }
25 |
26 | /**
27 | * Display a listing of the resource.
28 | *
29 | * @return \Illuminate\Http\Response
30 | */
31 | public function index()
32 | {
33 | $this->allowedAdminAction();
34 |
35 | $users = User::all();
36 |
37 | return $this->showAll($users);
38 | // return $users;
39 | }
40 |
41 | /**
42 | * Store a newly created resource in storage.
43 | *
44 | * @param \Illuminate\Http\Request $request
45 | * @return \Illuminate\Http\Response
46 | */
47 | public function store(Request $request)
48 | {
49 | $rules = [
50 | 'name' => 'required',
51 | 'email' => 'required|email|unique:users',
52 | 'password' => 'required|min:6|confirmed',
53 | ];
54 |
55 | $this->validate($request, $rules);
56 |
57 | $data = $request->all();
58 | $data['password'] = bcrypt($request->password);
59 | $data['verified'] = User::UNVERIFIED_USER;
60 | $data['verification_token'] = User::generateVerificationCode();
61 | $data['admin'] = User::REGULAR_USER;
62 |
63 | $user = User::create($data);
64 |
65 | Auth::login($user);
66 |
67 | return redirect('/home');
68 | }
69 |
70 | public function showRegisterForm()
71 | {
72 | return view('auth.register');
73 | }
74 |
75 | /**
76 | * Display the specified resource.
77 | *
78 | * @param int $id
79 | * @return \Illuminate\Http\Response
80 | */
81 | public function show(User $user)
82 | {
83 | return $this->showOne($user);
84 | }
85 |
86 | /**
87 | * Update the specified resource in storage.
88 | *
89 | * @param \Illuminate\Http\Request $request
90 | * @param int $id
91 | * @return \Illuminate\Http\Response
92 | */
93 | public function update(Request $request, User $user)
94 | {
95 | $rules = [
96 | 'email' => 'email|unique:users,email,' . $user->id,
97 | 'password' => 'min:6|confirmed',
98 | 'admin' => 'in:' . User::ADMIN_USER . ',' . User::REGULAR_USER,
99 | ];
100 |
101 | if ($request->has('name')) {
102 | $user->name = $request->name;
103 | }
104 |
105 | if ($request->has('email') && $user->email != $request->email) {
106 | $user->verified = User::UNVERIFIED_USER;
107 | $user->verification_token = User::generateVerificationCode();
108 | $user->email = $request->email;
109 | }
110 |
111 | if ($request->has('password')) {
112 | $user->password = bcrypt($request->password);
113 | }
114 |
115 | if ($request->has('admin')) {
116 | $this->allowedAdminAction();
117 |
118 | if (!$user->isVerified()) {
119 | return $this->errorResponse('Only verified users can modify the admin field', 409);
120 | }
121 |
122 | $user->admin = $request->admin;
123 | }
124 |
125 | if (!$user->isDirty()) {
126 | return $this->errorResponse('You need to specify a different value to update', 422);
127 | }
128 |
129 | $user->save();
130 |
131 | return $this->showOne($user);
132 | }
133 |
134 | /**
135 | * Remove the specified resource from storage.
136 | *
137 | * @param int $id
138 | * @return \Illuminate\Http\Response
139 | */
140 | public function destroy(User $user)
141 | {
142 | $user->delete();
143 |
144 | return $this->showOne($user);
145 | }
146 |
147 | public function me(Request $request)
148 | {
149 | $user = $request->user();
150 |
151 | return $this->showOne($user);
152 | }
153 |
154 | public function verify($token)
155 | {
156 | $user = User::where('verification_token', $token)->firstOrFail();
157 |
158 | $user->verified = User::VERIFIED_USER;
159 | $user->verification_token = null;
160 |
161 | $user->save();
162 |
163 | return $this->showMessage('The account has been verified succesfully');
164 | }
165 |
166 | public function resend(User $user)
167 | {
168 | if ($user->isVerified()) {
169 | return $this->errorResponse('This user is already verified', 409);
170 | }
171 |
172 | retry(5, function() use ($user) {
173 | Mail::to($user)->send(new UserCreated($user));
174 | }, 100);
175 |
176 | return $this->showMessage('The verification email has been resend');
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/app/Http/Kernel.php:
--------------------------------------------------------------------------------
1 | [
31 | \Fruitcake\Cors\HandleCors::class,
32 | 'signature:X-Application-Name',
33 | \App\Http\Middleware\EncryptCookies::class,
34 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
35 | \Illuminate\Session\Middleware\StartSession::class,
36 | // \Illuminate\Session\Middleware\AuthenticateSession::class,
37 | \Illuminate\View\Middleware\ShareErrorsFromSession::class,
38 | \App\Http\Middleware\VerifyCsrfToken::class,
39 | \Illuminate\Routing\Middleware\SubstituteBindings::class,
40 | ],
41 |
42 | 'api' => [
43 | 'signature:X-Application-Name',
44 | 'throttle:90,1',
45 | 'bindings',
46 | ],
47 | ];
48 |
49 | /**
50 | * The application's route middleware.
51 | *
52 | * These middleware may be assigned to groups or used individually.
53 | *
54 | * @var array
55 | */
56 | protected $routeMiddleware = [
57 | 'auth' => \App\Http\Middleware\Authenticate::class,
58 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
59 | 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
60 | 'can' => \Illuminate\Auth\Middleware\Authorize::class,
61 | 'client.credentials' => \Laravel\Passport\Http\Middleware\CheckClientCredentials::class,
62 | 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
63 | 'throttle' => \App\Http\Middleware\CustomThrottleRequests::class,
64 | 'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class,
65 | 'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class,
66 | 'signature' => \App\Http\Middleware\SignatureMiddleware::class,
67 | 'transform.input' => \App\Http\Middleware\TransformInput::class,
68 | ];
69 |
70 | /**
71 | * The priority-sorted list of middleware.
72 | *
73 | * This forces the listed middleware to always be in the given order.
74 | *
75 | * @var array
76 | */
77 | protected $middlewarePriority = [
78 | \Illuminate\Session\Middleware\StartSession::class,
79 | \Illuminate\View\Middleware\ShareErrorsFromSession::class,
80 | \App\Http\Middleware\Authenticate::class,
81 | \Illuminate\Session\Middleware\AuthenticateSession::class,
82 | \Illuminate\Routing\Middleware\SubstituteBindings::class,
83 | \Illuminate\Auth\Middleware\Authorize::class,
84 | ];
85 | }
86 |
--------------------------------------------------------------------------------
/app/Http/Middleware/Authenticate.php:
--------------------------------------------------------------------------------
1 | expectsJson()) {
18 | return route('login');
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/Http/Middleware/CustomThrottleRequests.php:
--------------------------------------------------------------------------------
1 | errorResponse('Too Many Attempts.', 429);
22 |
23 | $retryAfter = $this->limiter->availableIn($key);
24 |
25 | return $this->addHeaders(
26 | $response, $maxAttempts,
27 | $this->calculateRemainingAttempts($key, $maxAttempts, $retryAfter),
28 | $retryAfter
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/Http/Middleware/EncryptCookies.php:
--------------------------------------------------------------------------------
1 | check()) {
21 | return redirect('/home');
22 | }
23 |
24 | return $next($request);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/Http/Middleware/SignatureMiddleware.php:
--------------------------------------------------------------------------------
1 | headers->set($headerName, config('app.name'));
21 |
22 | return $response;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/Http/Middleware/TransformInput.php:
--------------------------------------------------------------------------------
1 | all();
21 | $queryParams = $request->query();
22 | $transformableFields = array_diff($allFields, $queryParams);
23 | foreach ($transformableFields as $input => $value) {
24 | $transformedInput[$transformer::originalAttribute($input)] = $value;
25 | }
26 | $request->replace($transformedInput);
27 | $response = $next($request);
28 | if (isset($response->exception) && $response->exception instanceof ValidationException) {
29 | $data = $response->getData();
30 | $transformedErrors = [];
31 | foreach ($data->error as $field => $error) {
32 | $transformedField = $transformer::transformedAttribute($field);
33 | $transformedErrors[$transformedField] = str_replace($field, $transformedField, $error);
34 | }
35 | $data->error = $transformedErrors;
36 | $response->setData($data);
37 | }
38 | return $response;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/Http/Middleware/TrimStrings.php:
--------------------------------------------------------------------------------
1 | user = $user;
25 | }
26 |
27 | /**
28 | * Build the message.
29 | *
30 | * @return $this
31 | */
32 | public function build()
33 | {
34 | return $this->markdown('emails.welcome')->subject('Please confirm your account');
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/Mail/UserMailChanged.php:
--------------------------------------------------------------------------------
1 | user = $user;
25 | }
26 |
27 | /**
28 | * Build the message.
29 | *
30 | * @return $this
31 | */
32 | public function build()
33 | {
34 | return $this->markdown('emails.confirm')->subject('Please confirm your new email');
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/Policies/BuyerPolicy.php:
--------------------------------------------------------------------------------
1 | id === $buyer->id;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/Policies/ProductPolicy.php:
--------------------------------------------------------------------------------
1 | id === $product->seller->id;
24 | }
25 |
26 | /**
27 | * Determine whether the user can delete the product.
28 | *
29 | * @param \App\User $user
30 | * @param \App\Product $product
31 | * @return mixed
32 | */
33 | public function deleteCategory(User $user, Product $product)
34 | {
35 | return $user->id === $product->seller->id;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/Policies/SellerPolicy.php:
--------------------------------------------------------------------------------
1 | id === $seller->id;
24 | }
25 |
26 | /**
27 | * Determine whether the user can update a product.
28 | *
29 | * @param \App\User $user
30 | * @param \App\Seller $seller
31 | * @return mixed
32 | */
33 | public function editProduct(User $user, Seller $seller)
34 | {
35 | return $user->id === $seller->id;
36 | }
37 |
38 | /**
39 | * Determine whether the user can delete a product.
40 | *
41 | * @param \App\User $user
42 | * @param \App\Seller $seller
43 | * @return mixed
44 | */
45 | public function deleteProduct(User $user, Seller $seller)
46 | {
47 | return $user->id === $seller->id;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/Policies/TransactionPolicy.php:
--------------------------------------------------------------------------------
1 | id === $transaction->buyer->id || $user->id === $transaction->product->seller->id;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/Policies/UserPolicy.php:
--------------------------------------------------------------------------------
1 | id === $user->id;
23 | }
24 |
25 | /**
26 | * Determine whether the user can update the user.
27 | *
28 | * @param \App\User $user
29 | * @param \App\User $user
30 | * @return mixed
31 | */
32 | public function update(User $authenticatedUser, User $user)
33 | {
34 | return $authenticatedUser->id === $user->id;
35 | }
36 |
37 | /**
38 | * Determine whether the user can delete the user.
39 | *
40 | * @param \App\User $user
41 | * @param \App\User $user
42 | * @return mixed
43 | */
44 | public function delete(User $authenticatedUser, User $user)
45 | {
46 | return $authenticatedUser->id === $user->id && $authenticatedUser->token()->client->personal_access_client;
47 | }
48 |
49 | /**
50 | * Determine whether the user can sale product.
51 | *
52 | * @param \App\User $user
53 | * @return mixed
54 | */
55 | public function sale(User $user, User $seller)
56 | {
57 | return $user->id === $seller->id;
58 | }
59 |
60 | /**
61 | * Determine whether the user can purchase something.
62 | *
63 | * @param \App\User $user
64 | * @param \App\Buyer $buyer
65 | * @return mixed
66 | */
67 | public function purchase(User $user, User $buyer)
68 | {
69 | return $user->id === $buyer->id;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/Product.php:
--------------------------------------------------------------------------------
1 | status == Product::AVAILABLE_PRODUCT;
36 | }
37 |
38 | public function seller()
39 | {
40 | return $this->belongsTo(Seller::class);
41 | }
42 |
43 | public function transactions()
44 | {
45 | return $this->hasMany(Transaction::class);
46 | }
47 |
48 | public function categories()
49 | {
50 | return $this->belongsToMany(Category::class);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/Providers/AppServiceProvider.php:
--------------------------------------------------------------------------------
1 | send(new UserCreated($user));
23 | }, 100);
24 | });
25 |
26 | User::updated(function($user) {
27 | if ($user->isDirty('email')) {
28 | retry(5, function() use ($user) {
29 | Mail::to($user)->send(new UserMailChanged($user));
30 | }, 100);
31 | }
32 | });*/
33 |
34 | Product::updated(function ($product) {
35 | if ($product->quantity == 0 && $product->isAvailable()) {
36 | $product->status = Product::UNAVAILABLE_PRODUCT;
37 |
38 | $product->save();
39 | }
40 | });
41 | }
42 |
43 | /**
44 | * Register any application services.
45 | *
46 | * @return void
47 | */
48 | public function register()
49 | {
50 | //
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/Providers/AuthServiceProvider.php:
--------------------------------------------------------------------------------
1 | BuyerPolicy::class,
29 | Seller::class => SellerPolicy::class,
30 | User::class => UserPolicy::class,
31 | Transaction::class => TransactionPolicy::class,
32 | Product::class => ProductPolicy::class,
33 | ];
34 |
35 | /**
36 | * Register any authentication / authorization services.
37 | *
38 | * @return void
39 | */
40 | public function boot()
41 | {
42 | $this->registerPolicies();
43 |
44 | Gate::define('admin-action', function ($user) {
45 | return $user->isAdmin();
46 | });
47 |
48 | Passport::routes();
49 | Passport::tokensExpireIn(Carbon::now()->addMinutes(5));
50 | Passport::refreshTokensExpireIn(Carbon::now()->addDays(30));
51 | Passport::enableImplicitGrant();
52 |
53 | Passport::tokensCan([
54 | 'purchase-product' => 'Create a new transaction for a specific product',
55 | 'manage-products' => 'Create, reade, update, and delete products (CRUD)',
56 | 'manage-account' => 'Read your account data, id, name, email, if verified, and if admin (cannot read password). Modify your account data (email, and password). Cannot delete your account',
57 | 'read-general' => 'Read general information like purchasing categories, purchased products, selling products, selling categories, your transactions (purchases and sales)',
58 | ]);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/Providers/BroadcastServiceProvider.php:
--------------------------------------------------------------------------------
1 | [
17 | 'App\Listeners\EventListener',
18 | ],
19 | ];
20 |
21 | /**
22 | * Register any events for your application.
23 | *
24 | * @return void
25 | */
26 | public function boot()
27 | {
28 | parent::boot();
29 |
30 | //
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/Providers/RouteServiceProvider.php:
--------------------------------------------------------------------------------
1 | mapApiRoutes();
39 |
40 | $this->mapWebRoutes();
41 |
42 | //
43 | }
44 |
45 | /**
46 | * Define the "web" routes for the application.
47 | *
48 | * These routes all receive session state, CSRF protection, etc.
49 | *
50 | * @return void
51 | */
52 | protected function mapWebRoutes()
53 | {
54 | Route::middleware('web')
55 | ->namespace($this->namespace)
56 | ->group(base_path('routes/web.php'));
57 | }
58 |
59 | /**
60 | * Define the "api" routes for the application.
61 | *
62 | * These routes are typically stateless.
63 | *
64 | * @return void
65 | */
66 | protected function mapApiRoutes()
67 | {
68 | Route::middleware('api')
69 | ->namespace($this->namespace)
70 | ->group(base_path('routes/api.php'));
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/Scopes/BuyerScope.php:
--------------------------------------------------------------------------------
1 | has('transactions');
14 | }
15 |
16 | }
--------------------------------------------------------------------------------
/app/Scopes/SellerScope.php:
--------------------------------------------------------------------------------
1 | has('products');
14 | }
15 | }
--------------------------------------------------------------------------------
/app/Seller.php:
--------------------------------------------------------------------------------
1 | hasMany(Product::class);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/Traits/AdminActions.php:
--------------------------------------------------------------------------------
1 | isAdmin()) {
10 | return true;
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/app/Traits/ApiResponser.php:
--------------------------------------------------------------------------------
1 | json($data, $code);
16 | }
17 |
18 | protected function errorResponse($message, $code)
19 | {
20 | return response()->json(['error' => $message, 'code' => $code], $code);
21 | }
22 |
23 | protected function showAll(Collection $collection, $code = 200)
24 | {
25 | if ($collection->isEmpty()) {
26 | return $this->successResponse(['data' => $collection], $code);
27 | }
28 |
29 | $transformer = $collection->first()->transformer;
30 |
31 | $collection = $this->filterData($collection, $transformer);
32 | $collection = $this->sortData($collection, $transformer);
33 | $collection = $this->paginate($collection);
34 | $collection = $this->transformData($collection, $transformer);
35 | $collection = $this->cacheResponse($collection);
36 |
37 | return $this->successResponse($collection, $code);
38 | }
39 |
40 | protected function showOne(Model $instance, $code = 200)
41 | {
42 | $transformer = $instance->transformer;
43 |
44 | $instance = $this->transformData($instance, $transformer);
45 |
46 | return $this->successResponse($instance, $code);
47 | }
48 |
49 | protected function showMessage($message, $code = 200)
50 | {
51 | return $this->successResponse(['data' => $message], $code);
52 | }
53 |
54 | protected function filterData(Collection $collection, $transformer)
55 | {
56 | foreach (request()->query() as $query => $value) {
57 | $attribute = $transformer::originalAttribute($query);
58 |
59 | if (isset($attribute, $value)) {
60 | $collection = $collection->where($attribute, $value);
61 | }
62 | }
63 |
64 | return $collection;
65 | }
66 |
67 | protected function sortData(Collection $collection, $transformer)
68 | {
69 | if (request()->has('sort_by')) {
70 | $attribute = $transformer::originalAttribute(request()->sort_by);
71 |
72 | $collection = $collection->sortBy->{$attribute};
73 | }
74 |
75 | return $collection;
76 | }
77 |
78 | protected function paginate(Collection $collection)
79 | {
80 | $rules = [
81 | 'per_page' => 'integer|min:2|max:50',
82 | ];
83 |
84 | Validator::validate(request()->all(), $rules);
85 |
86 | $page = LengthAwarePaginator::resolveCurrentPage();
87 |
88 | $perPage = 15;
89 | if (request()->has('per_page')) {
90 | $perPage = (int) request()->per_page;
91 | }
92 |
93 | $results = $collection->slice(($page - 1) * $perPage, $perPage)->values();
94 |
95 | $paginated = new LengthAwarePaginator($results, $collection->count(), $perPage, $page, [
96 | 'path' => LengthAwarePaginator::resolveCurrentPath(),
97 | ]);
98 |
99 | $paginated->appends(request()->all());
100 |
101 | return $paginated;
102 |
103 | }
104 |
105 | protected function transformData($data, $transformer)
106 | {
107 | $transformation = fractal($data, new $transformer);
108 |
109 | return $transformation->toArray();
110 | }
111 |
112 | protected function cacheResponse($data)
113 | {
114 | $url = request()->url();
115 | $queryParams = request()->query();
116 |
117 | ksort($queryParams);
118 |
119 | $queryString = http_build_query($queryParams);
120 |
121 | $fullUrl = "{$url}?{$queryString}";
122 |
123 | return Cache::remember($fullUrl, 30/60, function() use($data) {
124 | return $data;
125 | });
126 | }
127 | }
--------------------------------------------------------------------------------
/app/Transaction.php:
--------------------------------------------------------------------------------
1 | belongsTo(Buyer::class);
26 | }
27 |
28 | public function product()
29 | {
30 | return $this->belongsTo(Product::class);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/Transformers/BuyerTransformer.php:
--------------------------------------------------------------------------------
1 | (int)$buyer->id,
19 | 'name' => (string)$buyer->name,
20 | 'email' => (string)$buyer->email,
21 | 'isVerified' => (int)$buyer->verified,
22 | 'creationDate' => (string)$buyer->created_at,
23 | 'lastChange' => (string)$buyer->updated_at,
24 | 'deletedDate' => isset($buyer->deleted_at) ? (string) $buyer->deleted_at : null,
25 |
26 | 'links' => [
27 | [
28 | 'rel' => 'self',
29 | 'href' => route('buyers.show', $buyer->id),
30 | ],
31 | [
32 | 'rel' => 'buyer.categories',
33 | 'href' => route('buyers.categories.index', $buyer->id),
34 | ],
35 | [
36 | 'rel' => 'buyer.products',
37 | 'href' => route('buyers.products.index', $buyer->id),
38 | ],
39 | [
40 | 'rel' => 'buyer.sellers',
41 | 'href' => route('buyers.sellers.index', $buyer->id),
42 | ],
43 | [
44 | 'rel' => 'buyer.transactions',
45 | 'href' => route('buyers.transactions.index', $buyer->id),
46 | ],
47 | [
48 | 'rel' => 'user',
49 | 'href' => route('users.show', $buyer->id),
50 | ],
51 | ],
52 | ];
53 | }
54 |
55 | public static function originalAttribute($index)
56 | {
57 | $attributes = [
58 | 'identifier' => 'id',
59 | 'name' => 'name',
60 | 'email' => 'email',
61 | 'isVerified' => 'verified',
62 | 'creationDate' => 'created_at',
63 | 'lastChange' => 'updated_at',
64 | 'deletedDate' => 'deleted_at',
65 | ];
66 |
67 | return isset($attributes[$index]) ? $attributes[$index] : null;
68 | }
69 |
70 | public static function transformedAttribute($index)
71 | {
72 | $attributes = [
73 | 'id' => 'identifier',
74 | 'name' => 'name',
75 | 'email' => 'email',
76 | 'verified' => 'isVerified',
77 | 'created_at' => 'creationDate',
78 | 'updated_at' => 'lastChange',
79 | 'deleted_at' => 'deletedDate',
80 | ];
81 |
82 | return isset($attributes[$index]) ? $attributes[$index] : null;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/Transformers/CategoryTransformer.php:
--------------------------------------------------------------------------------
1 | (int)$category->id,
19 | 'title' => (string)$category->name,
20 | 'details' => (string)$category->description,
21 | 'creationDate' => (string)$category->created_at,
22 | 'lastChange' => (string)$category->updated_at,
23 | 'deletedDate' => isset($category->deleted_at) ? (string) $category->deleted_at : null,
24 |
25 | 'links' => [
26 | [
27 | 'rel' => 'self',
28 | 'href' => route('categories.show', $category->id),
29 | ],
30 | [
31 | 'rel' => 'category.buyers',
32 | 'href' => route('categories.buyers.index', $category->id),
33 | ],
34 | [
35 | 'rel' => 'category.products',
36 | 'href' => route('categories.products.index', $category->id),
37 | ],
38 | [
39 | 'rel' => 'category.sellers',
40 | 'href' => route('categories.sellers.index', $category->id),
41 | ],
42 | [
43 | 'rel' => 'category.transactions',
44 | 'href' => route('categories.transactions.index', $category->id),
45 | ],
46 | ]
47 | ];
48 | }
49 |
50 | public static function originalAttribute($index)
51 | {
52 | $attributes = [
53 | 'identifier' => 'id',
54 | 'title' => 'name',
55 | 'details' => 'description',
56 | 'creationDate' => 'created_at',
57 | 'lastChange' => 'updated_at',
58 | 'deletedDate' => 'deleted_at',
59 | ];
60 |
61 | return isset($attributes[$index]) ? $attributes[$index] : null;
62 | }
63 |
64 | public static function transformedAttribute($index)
65 | {
66 | $attributes = [
67 | 'id' => 'identifier',
68 | 'name' => 'title',
69 | 'description' => 'details',
70 | 'created_at' => 'creationDate',
71 | 'updated_at' => 'lastChange',
72 | 'deleted_at' => 'deletedDate',
73 | ];
74 |
75 | return isset($attributes[$index]) ? $attributes[$index] : null;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/Transformers/ProductTransformer.php:
--------------------------------------------------------------------------------
1 | (int)$product->id,
19 | 'title' => (string)$product->name,
20 | 'details' => (string)$product->description,
21 | 'stock' => (int)$product->quantity,
22 | 'situation' => (string)$product->status,
23 | 'picture' => url("img/{$product->image}"),
24 | 'seller' => (int)$product->seller_id,
25 | 'creationDate' => (string)$product->created_at,
26 | 'lastChange' => (string)$product->updated_at,
27 | 'deletedDate' => isset($product->deleted_at) ? (string) $product->deleted_at : null,
28 |
29 | 'links' => [
30 | [
31 | 'rel' => 'self',
32 | 'href' => route('products.show', $product->id),
33 | ],
34 | [
35 | 'rel' => 'product.buyers',
36 | 'href' => route('products.buyers.index', $product->id),
37 | ],
38 | [
39 | 'rel' => 'product.categories',
40 | 'href' => route('products.categories.index', $product->id),
41 | ],
42 | [
43 | 'rel' => 'product.transactions',
44 | 'href' => route('products.transactions.index', $product->id),
45 | ],
46 | [
47 | 'rel' => 'seller',
48 | 'href' => route('sellers.show', $product->seller_id),
49 | ],
50 | ]
51 | ];
52 | }
53 |
54 | public static function originalAttribute($index)
55 | {
56 | $attributes = [
57 | 'identifier' => 'id',
58 | 'title' => 'name',
59 | 'details' => 'description',
60 | 'stock' => 'quantity',
61 | 'situation' => 'status',
62 | 'picture' => 'image',
63 | 'seller' => 'seller_id',
64 | 'creationDate' => 'created_at',
65 | 'lastChange' => 'updated_at',
66 | 'deletedDate' => 'deleted_at',
67 | ];
68 |
69 | return isset($attributes[$index]) ? $attributes[$index] : null;
70 | }
71 |
72 | public static function transformedAttribute($index)
73 | {
74 | $attributes = [
75 | 'id' => 'identifier',
76 | 'name' => 'title',
77 | 'description' => 'details',
78 | 'quantity' => 'stock',
79 | 'status' => 'situation',
80 | 'image' => 'picture',
81 | 'seller_id' => 'seller',
82 | 'created_at' => 'creationDate',
83 | 'updated_at' => 'lastChange',
84 | 'deleted_at' => 'deletedDate',
85 | ];
86 |
87 | return isset($attributes[$index]) ? $attributes[$index] : null;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/app/Transformers/SellerTransformer.php:
--------------------------------------------------------------------------------
1 | (int)$seller->id,
19 | 'name' => (string)$seller->name,
20 | 'email' => (string)$seller->email,
21 | 'isVerified' => (int)$seller->verified,
22 | 'creationDate' => (string)$seller->created_at,
23 | 'lastChange' => (string)$seller->updated_at,
24 | 'deletedDate' => isset($seller->deleted_at) ? (string) $seller->deleted_at : null,
25 |
26 | 'links' => [
27 | [
28 | 'rel' => 'self',
29 | 'href' => route('sellers.show', $seller->id),
30 | ],
31 | [
32 | 'rel' => 'seller.buyers',
33 | 'href' => route('sellers.buyers.index', $seller->id),
34 | ],
35 | [
36 | 'rel' => 'seller.categories',
37 | 'href' => route('sellers.categories.index', $seller->id),
38 | ],
39 | [
40 | 'rel' => 'seller.products',
41 | 'href' => route('sellers.products.index', $seller->id),
42 | ],
43 | [
44 | 'rel' => 'seller.transactions',
45 | 'href' => route('sellers.transactions.index', $seller->id),
46 | ],
47 | [
48 | 'rel' => 'user',
49 | 'href' => route('users.show', $seller->id),
50 | ],
51 | ],
52 | ];
53 | }
54 |
55 | public static function originalAttribute($index)
56 | {
57 | $attributes = [
58 | 'identifier' => 'id',
59 | 'name' => 'name',
60 | 'email' => 'email',
61 | 'isVerified' => 'verified',
62 | 'creationDate' => 'created_at',
63 | 'lastChange' => 'updated_at',
64 | 'deletedDate' => 'deleted_at',
65 | ];
66 |
67 | return isset($attributes[$index]) ? $attributes[$index] : null;
68 | }
69 |
70 | public static function transformedAttribute($index)
71 | {
72 | $attributes = [
73 | 'id' => 'identifier',
74 | 'name' => 'name',
75 | 'email' => 'email',
76 | 'verified' => 'isVerified',
77 | 'created_at' => 'creationDate',
78 | 'updated_at' => 'lastChange',
79 | 'deleted_at' => 'deletedDate',
80 | ];
81 |
82 | return isset($attributes[$index]) ? $attributes[$index] : null;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/Transformers/TransactionTransformer.php:
--------------------------------------------------------------------------------
1 | (int)$transaction->id,
19 | 'quantity' => (int)$transaction->quantity,
20 | 'buyer' => (int)$transaction->buyer_id,
21 | 'product' => (int)$transaction->product_id,
22 | 'creationDate' => (string)$transaction->created_at,
23 | 'lastChange' => (string)$transaction->updated_at,
24 | 'deletedDate' => isset($transaction->deleted_at) ? (string) $transaction->deleted_at : null,
25 |
26 | 'links' => [
27 | [
28 | 'rel' => 'self',
29 | 'href' => route('transactions.show', $transaction->id),
30 | ],
31 | [
32 | 'rel' => 'transaction.categories',
33 | 'href' => route('transactions.categories.index', $transaction->id),
34 | ],
35 | [
36 | 'rel' => 'transaction.seller',
37 | 'href' => route('transactions.sellers.index', $transaction->id),
38 | ],
39 | [
40 | 'rel' => 'buyer',
41 | 'href' => route('buyers.show', $transaction->buyer_id),
42 | ],
43 | [
44 | 'rel' => 'product',
45 | 'href' => route('products.show', $transaction->product_id),
46 | ],
47 | ]
48 | ];
49 | }
50 |
51 | public static function originalAttribute($index)
52 | {
53 | $attributes = [
54 | 'identifier' => 'id',
55 | 'quantity' => 'quantity',
56 | 'buyer' => 'buyer_id',
57 | 'product' => 'product_id',
58 | 'creationDate' => 'created_at',
59 | 'lastChange' => 'updated_at',
60 | 'deletedDate' => 'deleted_at',
61 | ];
62 |
63 | return isset($attributes[$index]) ? $attributes[$index] : null;
64 | }
65 |
66 | public static function transformedAttribute($index)
67 | {
68 | $attributes = [
69 | 'id' => 'identifier',
70 | 'quantity' => 'quantity',
71 | 'buyer_id' => 'buyer',
72 | 'product_id' => 'product',
73 | 'created_at' => 'creationDate',
74 | 'updated_at' => 'lastChange',
75 | 'deleted_at' => 'deletedDate',
76 | ];
77 |
78 | return isset($attributes[$index]) ? $attributes[$index] : null;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/Transformers/UserTransformer.php:
--------------------------------------------------------------------------------
1 | (int)$user->id,
19 | 'name' => (string)$user->name,
20 | 'email' => (string)$user->email,
21 | 'isVerified' => (int)$user->verified,
22 | 'isAdmin' => ($user->admin === 'true'),
23 | 'creationDate' => (string)$user->created_at,
24 | 'lastChange' => (string)$user->updated_at,
25 | 'deletedDate' => isset($user->deleted_at) ? (string) $user->deleted_at : null,
26 |
27 | 'links' => [
28 | [
29 | 'rel' => 'self',
30 | 'href' => route('users.show', $user->id),
31 | ],
32 | ]
33 | ];
34 | }
35 |
36 | public static function originalAttribute($index)
37 | {
38 | $attributes = [
39 | 'identifier' => 'id',
40 | 'name' => 'name',
41 | 'email' => 'email',
42 | 'isVerified' => 'verified',
43 | 'isAdmin' => 'admin',
44 | 'creationDate' => 'created_at',
45 | 'lastChange' => 'updated_at',
46 | 'deletedDate' => 'deleted_at',
47 | ];
48 |
49 | return isset($attributes[$index]) ? $attributes[$index] : null;
50 | }
51 |
52 | public static function transformedAttribute($index)
53 | {
54 | $attributes = [
55 | 'id' => 'identifier',
56 | 'name' => 'name',
57 | 'email' => 'email',
58 | 'verified' => 'isVerified',
59 | 'admin' => 'isAdmin',
60 | 'created_at' => 'creationDate',
61 | 'updated_at' => 'lastChange',
62 | 'deleted_at' => 'deletedDate',
63 | ];
64 |
65 | return isset($attributes[$index]) ? $attributes[$index] : null;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/app/User.php:
--------------------------------------------------------------------------------
1 | attributes['name'] = strtolower($name);
54 | }
55 |
56 | public function getNameAttribute($name)
57 | {
58 | return ucwords($name);
59 | }
60 |
61 | public function setEmailAttribute($email)
62 | {
63 | $this->attributes['email'] = strtolower($email);
64 | }
65 |
66 | public function isVerified()
67 | {
68 | return $this->verified == User::VERIFIED_USER;
69 | }
70 |
71 | public function isAdmin()
72 | {
73 | return $this->admin == User::ADMIN_USER;
74 | }
75 |
76 | public static function generateVerificationCode()
77 | {
78 | return Str::random(40);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/artisan:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | make(Illuminate\Contracts\Console\Kernel::class);
32 |
33 | $status = $kernel->handle(
34 | $input = new Symfony\Component\Console\Input\ArgvInput,
35 | new Symfony\Component\Console\Output\ConsoleOutput
36 | );
37 |
38 | /*
39 | |--------------------------------------------------------------------------
40 | | Shutdown The Application
41 | |--------------------------------------------------------------------------
42 | |
43 | | Once Artisan has finished running. We will fire off the shutdown events
44 | | so that any final work may be done by the application before we shut
45 | | down the process. This is the last thing to happen to the request.
46 | |
47 | */
48 |
49 | $kernel->terminate($input, $status);
50 |
51 | exit($status);
52 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/bootstrap/autoload.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", "token"
35 | |
36 | */
37 |
38 | 'guards' => [
39 | 'web' => [
40 | 'driver' => 'session',
41 | 'provider' => 'users',
42 | ],
43 |
44 | 'api' => [
45 | 'driver' => 'passport',
46 | 'provider' => 'users',
47 | ],
48 | ],
49 |
50 | /*
51 | |--------------------------------------------------------------------------
52 | | User Providers
53 | |--------------------------------------------------------------------------
54 | |
55 | | All authentication drivers have a user provider. This defines how the
56 | | users are actually retrieved out of your database or other storage
57 | | mechanisms used by this application to persist your user's data.
58 | |
59 | | If you have multiple user tables or models you may configure multiple
60 | | sources which represent each model / table. These sources may then
61 | | be assigned to any extra authentication guards you have defined.
62 | |
63 | | Supported: "database", "eloquent"
64 | |
65 | */
66 |
67 | 'providers' => [
68 | 'users' => [
69 | 'driver' => 'eloquent',
70 | 'model' => App\User::class,
71 | ],
72 |
73 | // 'users' => [
74 | // 'driver' => 'database',
75 | // 'table' => 'users',
76 | // ],
77 | ],
78 |
79 | /*
80 | |--------------------------------------------------------------------------
81 | | Resetting Passwords
82 | |--------------------------------------------------------------------------
83 | |
84 | | You may specify multiple password reset configurations if you have more
85 | | than one user table or model in the application and you want to have
86 | | separate password reset settings based on the specific user types.
87 | |
88 | | The expire time is the number of minutes that the reset token should be
89 | | considered valid. This security feature keeps tokens short-lived so
90 | | they have less time to be guessed. You may change this as needed.
91 | |
92 | */
93 |
94 | 'passwords' => [
95 | 'users' => [
96 | 'provider' => 'users',
97 | 'table' => 'password_resets',
98 | 'expire' => 60,
99 | ],
100 | ],
101 |
102 | ];
103 |
--------------------------------------------------------------------------------
/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 | //
40 | ],
41 | ],
42 |
43 | 'redis' => [
44 | 'driver' => 'redis',
45 | 'connection' => 'default',
46 | ],
47 |
48 | 'log' => [
49 | 'driver' => 'log',
50 | ],
51 |
52 | 'null' => [
53 | 'driver' => 'null',
54 | ],
55 |
56 | ],
57 |
58 | ];
59 |
--------------------------------------------------------------------------------
/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 | */
30 |
31 | 'stores' => [
32 |
33 | 'apc' => [
34 | 'driver' => 'apc',
35 | ],
36 |
37 | 'array' => [
38 | 'driver' => 'array',
39 | ],
40 |
41 | 'database' => [
42 | 'driver' => 'database',
43 | 'table' => 'cache',
44 | 'connection' => null,
45 | ],
46 |
47 | 'file' => [
48 | 'driver' => 'file',
49 | 'path' => storage_path('framework/cache/data'),
50 | ],
51 |
52 | 'memcached' => [
53 | 'driver' => 'memcached',
54 | 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
55 | 'sasl' => [
56 | env('MEMCACHED_USERNAME'),
57 | env('MEMCACHED_PASSWORD'),
58 | ],
59 | 'options' => [
60 | // Memcached::OPT_CONNECT_TIMEOUT => 2000,
61 | ],
62 | 'servers' => [
63 | [
64 | 'host' => env('MEMCACHED_HOST', '127.0.0.1'),
65 | 'port' => env('MEMCACHED_PORT', 11211),
66 | 'weight' => 100,
67 | ],
68 | ],
69 | ],
70 |
71 | 'redis' => [
72 | 'driver' => 'redis',
73 | 'connection' => 'default',
74 | ],
75 |
76 | ],
77 |
78 | /*
79 | |--------------------------------------------------------------------------
80 | | Cache Key Prefix
81 | |--------------------------------------------------------------------------
82 | |
83 | | When utilizing a RAM based store such as APC or Memcached, there might
84 | | be other applications utilizing the same cache. So, we'll specify a
85 | | value to get prefixed to all our keys so we can avoid collisions.
86 | |
87 | */
88 |
89 | 'prefix' => 'laravel',
90 |
91 | ];
92 |
--------------------------------------------------------------------------------
/config/cors.php:
--------------------------------------------------------------------------------
1 | ['*'],
25 |
26 | /*
27 | * Matches the request method. `['*']` allows all methods.
28 | */
29 | 'allowed_methods' => ['*'],
30 |
31 | /*
32 | * Matches the request origin. `['*']` allows all origins. Wildcards can be used, eg `*.mydomain.com`
33 | */
34 | 'allowed_origins' => ['*'],
35 |
36 | /*
37 | * Patterns that can be used with `preg_match` to match the origin.
38 | */
39 | 'allowed_origins_patterns' => [],
40 |
41 | /*
42 | * Sets the Access-Control-Allow-Headers response header. `['*']` allows all headers.
43 | */
44 | 'allowed_headers' => ['*'],
45 |
46 | /*
47 | * Sets the Access-Control-Expose-Headers response header with these headers.
48 | */
49 | 'exposed_headers' => [],
50 |
51 | /*
52 | * Sets the Access-Control-Max-Age response header when > 0.
53 | */
54 | 'max_age' => 0,
55 |
56 | /*
57 | * Sets the Access-Control-Allow-Credentials header.
58 | */
59 | 'supports_credentials' => true,
60 | ];
61 |
--------------------------------------------------------------------------------
/config/database.php:
--------------------------------------------------------------------------------
1 | env('DB_CONNECTION', 'mysql'),
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Database Connections
21 | |--------------------------------------------------------------------------
22 | |
23 | | Here are each of the database connections setup for your application.
24 | | Of course, examples of configuring each database platform that is
25 | | supported by Laravel is shown below to make development simple.
26 | |
27 | |
28 | | All database work in Laravel is done through the PHP PDO facilities
29 | | so make sure you have the driver for your particular database of
30 | | choice installed on your machine before you begin development.
31 | |
32 | */
33 |
34 | 'connections' => [
35 |
36 | 'sqlite' => [
37 | 'driver' => 'sqlite',
38 | 'database' => env('DB_DATABASE', database_path('database.sqlite')),
39 | 'prefix' => '',
40 | 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
41 | ],
42 |
43 | 'mysql' => [
44 | 'driver' => 'mysql',
45 | 'host' => env('DB_HOST', '127.0.0.1'),
46 | 'port' => env('DB_PORT', '3306'),
47 | 'database' => env('DB_DATABASE', 'forge'),
48 | 'username' => env('DB_USERNAME', 'forge'),
49 | 'password' => env('DB_PASSWORD', ''),
50 | 'unix_socket' => env('DB_SOCKET', ''),
51 | 'charset' => 'utf8mb4',
52 | 'collation' => 'utf8mb4_unicode_ci',
53 | 'prefix' => '',
54 | 'prefix_indexes' => true,
55 | 'strict' => true,
56 | 'engine' => null,
57 | ],
58 |
59 | 'pgsql' => [
60 | 'driver' => 'pgsql',
61 | 'host' => env('DB_HOST', '127.0.0.1'),
62 | 'port' => env('DB_PORT', '5432'),
63 | 'database' => env('DB_DATABASE', 'forge'),
64 | 'username' => env('DB_USERNAME', 'forge'),
65 | 'password' => env('DB_PASSWORD', ''),
66 | 'charset' => 'utf8',
67 | 'prefix' => '',
68 | 'prefix_indexes' => true,
69 | 'schema' => 'public',
70 | 'sslmode' => 'prefer',
71 | ],
72 |
73 | 'sqlsrv' => [
74 | 'driver' => 'sqlsrv',
75 | 'host' => env('DB_HOST', 'localhost'),
76 | 'port' => env('DB_PORT', '1433'),
77 | 'database' => env('DB_DATABASE', 'forge'),
78 | 'username' => env('DB_USERNAME', 'forge'),
79 | 'password' => env('DB_PASSWORD', ''),
80 | 'charset' => 'utf8',
81 | 'prefix' => '',
82 | 'prefix_indexes' => true,
83 | ],
84 |
85 | ],
86 |
87 | /*
88 | |--------------------------------------------------------------------------
89 | | Migration Repository Table
90 | |--------------------------------------------------------------------------
91 | |
92 | | This table keeps track of all the migrations that have already run for
93 | | your application. Using this information, we can determine which of
94 | | the migrations on disk haven't actually been run in the database.
95 | |
96 | */
97 |
98 | 'migrations' => 'migrations',
99 |
100 | /*
101 | |--------------------------------------------------------------------------
102 | | Redis Databases
103 | |--------------------------------------------------------------------------
104 | |
105 | | Redis is an open source, fast, and advanced key-value store that also
106 | | provides a richer set of commands than a typical key-value systems
107 | | such as APC or Memcached. Laravel makes it easy to dig right in.
108 | |
109 | */
110 |
111 | 'redis' => [
112 |
113 | 'client' => 'predis',
114 |
115 | 'default' => [
116 | 'host' => env('REDIS_HOST', '127.0.0.1'),
117 | 'password' => env('REDIS_PASSWORD', null),
118 | 'port' => env('REDIS_PORT', 6379),
119 | 'database' => env('REDIS_DB', 0),
120 | ],
121 |
122 | 'cache' => [
123 | 'host' => env('REDIS_HOST', '127.0.0.1'),
124 | 'password' => env('REDIS_PASSWORD', null),
125 | 'port' => env('REDIS_PORT', 6379),
126 | 'database' => env('REDIS_CACHE_DB', 1),
127 | ],
128 |
129 | ],
130 |
131 | ];
132 |
--------------------------------------------------------------------------------
/config/filesystems.php:
--------------------------------------------------------------------------------
1 | 'images',
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Default Cloud Filesystem Disk
21 | |--------------------------------------------------------------------------
22 | |
23 | | Many applications store files both locally and in the cloud. For this
24 | | reason, you may specify a default "cloud" driver here. This driver
25 | | will be bound as the Cloud disk implementation in the container.
26 | |
27 | */
28 |
29 | 'cloud' => 's3',
30 |
31 | /*
32 | |--------------------------------------------------------------------------
33 | | Filesystem Disks
34 | |--------------------------------------------------------------------------
35 | |
36 | | Here you may configure as many filesystem "disks" as you wish, and you
37 | | may even configure multiple disks of the same driver. Defaults have
38 | | been setup for each driver as an example of the required options.
39 | |
40 | | Supported Drivers: "local", "ftp", "s3", "rackspace"
41 | |
42 | */
43 |
44 | 'disks' => [
45 |
46 | 'local' => [
47 | 'driver' => 'local',
48 | 'root' => storage_path('app'),
49 | ],
50 |
51 | 'public' => [
52 | 'driver' => 'local',
53 | 'root' => storage_path('app/public'),
54 | 'url' => env('APP_URL').'/storage',
55 | 'visibility' => 'public',
56 | ],
57 |
58 | 'images' => [
59 | 'driver' => 'local',
60 | 'root' => public_path('img'),
61 | 'visibility' => 'public',
62 | ],
63 |
64 | 's3' => [
65 | 'driver' => 's3',
66 | 'key' => env('AWS_KEY'),
67 | 'secret' => env('AWS_SECRET'),
68 | 'region' => env('AWS_REGION'),
69 | 'bucket' => env('AWS_BUCKET'),
70 | ],
71 |
72 | ],
73 |
74 | ];
75 |
--------------------------------------------------------------------------------
/config/hashing.php:
--------------------------------------------------------------------------------
1 | 'bcrypt',
19 |
20 | ];
--------------------------------------------------------------------------------
/config/logging.php:
--------------------------------------------------------------------------------
1 | env('LOG_CHANNEL', 'stack'),
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Log Channels
21 | |--------------------------------------------------------------------------
22 | |
23 | | Here you may configure the log channels for your application. Out of
24 | | the box, Laravel uses the Monolog PHP logging library. This gives
25 | | you a variety of powerful log handlers / formatters to utilize.
26 | |
27 | | Available Drivers: "single", "daily", "slack", "syslog",
28 | | "errorlog", "custom", "stack"
29 | |
30 | */
31 |
32 | 'channels' => [
33 | 'stack' => [
34 | 'driver' => 'stack',
35 | 'channels' => ['single'],
36 | ],
37 |
38 | 'single' => [
39 | 'driver' => 'single',
40 | 'path' => storage_path('logs/laravel.log'),
41 | 'level' => 'debug',
42 | ],
43 |
44 | 'daily' => [
45 | 'driver' => 'daily',
46 | 'path' => storage_path('logs/laravel.log'),
47 | 'level' => 'debug',
48 | 'days' => 7,
49 | ],
50 |
51 | 'slack' => [
52 | 'driver' => 'slack',
53 | 'url' => env('LOG_SLACK_WEBHOOK_URL'),
54 | 'username' => 'Laravel Log',
55 | 'emoji' => ':boom:',
56 | 'level' => 'critical',
57 | ],
58 |
59 | 'syslog' => [
60 | 'driver' => 'syslog',
61 | 'level' => 'debug',
62 | ],
63 |
64 | 'errorlog' => [
65 | 'driver' => 'errorlog',
66 | 'level' => 'debug',
67 | ],
68 | ],
69 |
70 | ];
--------------------------------------------------------------------------------
/config/mail.php:
--------------------------------------------------------------------------------
1 | env('MAIL_DRIVER', 'smtp'),
20 |
21 | /*
22 | |--------------------------------------------------------------------------
23 | | SMTP Host Address
24 | |--------------------------------------------------------------------------
25 | |
26 | | Here you may provide the host address of the SMTP server used by your
27 | | applications. A default option is provided that is compatible with
28 | | the Mailgun mail service which will provide reliable deliveries.
29 | |
30 | */
31 |
32 | 'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
33 |
34 | /*
35 | |--------------------------------------------------------------------------
36 | | SMTP Host Port
37 | |--------------------------------------------------------------------------
38 | |
39 | | This is the SMTP port used by your application to deliver e-mails to
40 | | users of the application. Like the host we have set this value to
41 | | stay compatible with the Mailgun e-mail application by default.
42 | |
43 | */
44 |
45 | 'port' => env('MAIL_PORT', 587),
46 |
47 | /*
48 | |--------------------------------------------------------------------------
49 | | Global "From" Address
50 | |--------------------------------------------------------------------------
51 | |
52 | | You may wish for all e-mails sent by your application to be sent from
53 | | the same address. Here, you may specify a name and address that is
54 | | used globally for all e-mails that are sent by your application.
55 | |
56 | */
57 |
58 | 'from' => [
59 | 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
60 | 'name' => env('MAIL_FROM_NAME', 'Example'),
61 | ],
62 |
63 | /*
64 | |--------------------------------------------------------------------------
65 | | E-Mail Encryption Protocol
66 | |--------------------------------------------------------------------------
67 | |
68 | | Here you may specify the encryption protocol that should be used when
69 | | the application send e-mail messages. A sensible default using the
70 | | transport layer security protocol should provide great security.
71 | |
72 | */
73 |
74 | 'encryption' => env('MAIL_ENCRYPTION', 'tls'),
75 |
76 | /*
77 | |--------------------------------------------------------------------------
78 | | SMTP Server Username
79 | |--------------------------------------------------------------------------
80 | |
81 | | If your SMTP server requires a username for authentication, you should
82 | | set it here. This will get used to authenticate with your server on
83 | | connection. You may also set the "password" value below this one.
84 | |
85 | */
86 |
87 | 'username' => env('MAIL_USERNAME'),
88 |
89 | 'password' => env('MAIL_PASSWORD'),
90 |
91 | /*
92 | |--------------------------------------------------------------------------
93 | | Sendmail System Path
94 | |--------------------------------------------------------------------------
95 | |
96 | | When using the "sendmail" driver to send e-mails, we will need to know
97 | | the path to where Sendmail lives on this server. A default path has
98 | | been provided here, which will work well on most of your systems.
99 | |
100 | */
101 |
102 | 'sendmail' => '/usr/sbin/sendmail -bs',
103 |
104 | /*
105 | |--------------------------------------------------------------------------
106 | | Markdown Mail Settings
107 | |--------------------------------------------------------------------------
108 | |
109 | | If you are using Markdown based email rendering, you may configure your
110 | | theme and component paths here, allowing you to customize the design
111 | | of the emails. Or, you may simply stick with the Laravel defaults!
112 | |
113 | */
114 |
115 | 'markdown' => [
116 | 'theme' => 'default',
117 |
118 | 'paths' => [
119 | resource_path('views/vendor/mail'),
120 | ],
121 | ],
122 |
123 | ];
124 |
--------------------------------------------------------------------------------
/config/queue.php:
--------------------------------------------------------------------------------
1 | env('QUEUE_DRIVER', 'sync'),
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Queue Connections
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may configure the connection information for each server that
26 | | is used by your application. A default configuration has been added
27 | | for each back-end shipped with Laravel. You are free to add more.
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 | ],
43 |
44 | 'beanstalkd' => [
45 | 'driver' => 'beanstalkd',
46 | 'host' => 'localhost',
47 | 'queue' => 'default',
48 | 'retry_after' => 90,
49 | ],
50 |
51 | 'sqs' => [
52 | 'driver' => 'sqs',
53 | 'key' => 'your-public-key',
54 | 'secret' => 'your-secret-key',
55 | 'prefix' => 'https://sqs.us-east-1.amazonaws.com/your-account-id',
56 | 'queue' => 'your-queue-name',
57 | 'region' => 'us-east-1',
58 | ],
59 |
60 | 'redis' => [
61 | 'driver' => 'redis',
62 | 'connection' => 'default',
63 | 'queue' => 'default',
64 | 'retry_after' => 90,
65 | ],
66 |
67 | ],
68 |
69 | /*
70 | |--------------------------------------------------------------------------
71 | | Failed Queue Jobs
72 | |--------------------------------------------------------------------------
73 | |
74 | | These options configure the behavior of failed queue job logging so you
75 | | can control which database and table are used to store the jobs that
76 | | have failed. You may change them to any database / table you wish.
77 | |
78 | */
79 |
80 | 'failed' => [
81 | 'database' => env('DB_CONNECTION', 'mysql'),
82 | 'table' => 'failed_jobs',
83 | ],
84 |
85 | ];
86 |
--------------------------------------------------------------------------------
/config/sentry.php:
--------------------------------------------------------------------------------
1 | env('SENTRY_LARAVEL_DSN', env('SENTRY_DSN')),
12 |
13 | // The release version of your application
14 | // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
15 | 'release' => env('SENTRY_RELEASE'),
16 |
17 | // When left empty or `null` the Laravel environment will be used (usually discovered from `APP_ENV` in your `.env`)
18 | 'environment' => env('SENTRY_ENVIRONMENT'),
19 |
20 | // @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#sample-rate
21 | 'sample_rate' => env('SENTRY_SAMPLE_RATE') === null ? 1.0 : (float)env('SENTRY_SAMPLE_RATE'),
22 |
23 | // @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#traces-sample-rate
24 | 'traces_sample_rate' => env('SENTRY_TRACES_SAMPLE_RATE') === null ? null : (float)env('SENTRY_TRACES_SAMPLE_RATE'),
25 |
26 | // @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#profiles-sample-rate
27 | 'profiles_sample_rate' => env('SENTRY_PROFILES_SAMPLE_RATE') === null ? null : (float)env('SENTRY_PROFILES_SAMPLE_RATE'),
28 |
29 | // @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#send-default-pii
30 | 'send_default_pii' => env('SENTRY_SEND_DEFAULT_PII', false),
31 |
32 | // @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#ignore-exceptions
33 | // 'ignore_exceptions' => [],
34 |
35 | // @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#ignore-transactions
36 | // 'ignore_transactions' => [],
37 |
38 | // Breadcrumb specific configuration
39 | 'breadcrumbs' => [
40 | // Capture Laravel logs as breadcrumbs
41 | 'logs' => env('SENTRY_BREADCRUMBS_LOGS_ENABLED', true),
42 |
43 | // Capture Laravel cache events (hits, writes etc.) as breadcrumbs
44 | 'cache' => env('SENTRY_BREADCRUMBS_CACHE_ENABLED', true),
45 |
46 | // Capture Livewire components like routes as breadcrumbs
47 | 'livewire' => env('SENTRY_BREADCRUMBS_LIVEWIRE_ENABLED', true),
48 |
49 | // Capture SQL queries as breadcrumbs
50 | 'sql_queries' => env('SENTRY_BREADCRUMBS_SQL_QUERIES_ENABLED', true),
51 |
52 | // Capture SQL query bindings (parameters) in SQL query breadcrumbs
53 | 'sql_bindings' => env('SENTRY_BREADCRUMBS_SQL_BINDINGS_ENABLED', false),
54 |
55 | // Capture queue job information as breadcrumbs
56 | 'queue_info' => env('SENTRY_BREADCRUMBS_QUEUE_INFO_ENABLED', true),
57 |
58 | // Capture command information as breadcrumbs
59 | 'command_info' => env('SENTRY_BREADCRUMBS_COMMAND_JOBS_ENABLED', true),
60 |
61 | // Capture HTTP client request information as breadcrumbs
62 | 'http_client_requests' => env('SENTRY_BREADCRUMBS_HTTP_CLIENT_REQUESTS_ENABLED', true),
63 | ],
64 |
65 | // Performance monitoring specific configuration
66 | 'tracing' => [
67 | // Trace queue jobs as their own transactions (this enables tracing for queue jobs)
68 | 'queue_job_transactions' => env('SENTRY_TRACE_QUEUE_ENABLED', false),
69 |
70 | // Capture queue jobs as spans when executed on the sync driver
71 | 'queue_jobs' => env('SENTRY_TRACE_QUEUE_JOBS_ENABLED', true),
72 |
73 | // Capture SQL queries as spans
74 | 'sql_queries' => env('SENTRY_TRACE_SQL_QUERIES_ENABLED', true),
75 |
76 | // Capture SQL query bindings (parameters) in SQL query spans
77 | 'sql_bindings' => env('SENTRY_TRACE_SQL_BINDINGS_ENABLED', false),
78 |
79 | // Capture where the SQL query originated from on the SQL query spans
80 | 'sql_origin' => env('SENTRY_TRACE_SQL_ORIGIN_ENABLED', true),
81 |
82 | // Capture views rendered as spans
83 | 'views' => env('SENTRY_TRACE_VIEWS_ENABLED', true),
84 |
85 | // Capture Livewire components as spans
86 | 'livewire' => env('SENTRY_TRACE_LIVEWIRE_ENABLED', true),
87 |
88 | // Capture HTTP client requests as spans
89 | 'http_client_requests' => env('SENTRY_TRACE_HTTP_CLIENT_REQUESTS_ENABLED', true),
90 |
91 | // Capture Redis operations as spans (this enables Redis events in Laravel)
92 | 'redis_commands' => env('SENTRY_TRACE_REDIS_COMMANDS', false),
93 |
94 | // Capture where the Redis command originated from on the Redis command spans
95 | 'redis_origin' => env('SENTRY_TRACE_REDIS_ORIGIN_ENABLED', true),
96 |
97 | // Enable tracing for requests without a matching route (404's)
98 | 'missing_routes' => env('SENTRY_TRACE_MISSING_ROUTES_ENABLED', false),
99 |
100 | // Configures if the performance trace should continue after the response has been sent to the user until the application terminates
101 | // This is required to capture any spans that are created after the response has been sent like queue jobs dispatched using `dispatch(...)->afterResponse()` for example
102 | 'continue_after_response' => env('SENTRY_TRACE_CONTINUE_AFTER_RESPONSE', true),
103 |
104 | // Enable the tracing integrations supplied by Sentry (recommended)
105 | 'default_integrations' => env('SENTRY_TRACE_DEFAULT_INTEGRATIONS_ENABLED', true),
106 | ],
107 |
108 | ];
109 |
--------------------------------------------------------------------------------
/config/services.php:
--------------------------------------------------------------------------------
1 | [
18 | 'domain' => env('MAILGUN_DOMAIN'),
19 | 'secret' => env('MAILGUN_SECRET'),
20 | 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),
21 | ],
22 |
23 | 'ses' => [
24 | 'key' => env('SES_KEY'),
25 | 'secret' => env('SES_SECRET'),
26 | 'region' => env('SES_REGION', 'us-east-1'),
27 | ],
28 |
29 | 'sparkpost' => [
30 | 'secret' => env('SPARKPOST_SECRET'),
31 | ],
32 |
33 | 'stripe' => [
34 | 'model' => App\User::class,
35 | 'key' => env('STRIPE_KEY'),
36 | 'secret' => env('STRIPE_SECRET'),
37 | 'webhook' => [
38 | 'secret' => env('STRIPE_WEBHOOK_SECRET'),
39 | 'tolerance' => env('STRIPE_WEBHOOK_TOLERANCE', 300),
40 | ],
41 | ],
42 |
43 | ];
44 |
--------------------------------------------------------------------------------
/config/view.php:
--------------------------------------------------------------------------------
1 | [
17 | realpath(base_path('resources/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' => realpath(storage_path('framework/views')),
32 |
33 | ];
34 |
--------------------------------------------------------------------------------
/database/.gitignore:
--------------------------------------------------------------------------------
1 | *.sqlite
2 |
--------------------------------------------------------------------------------
/database/factories/ModelFactory.php:
--------------------------------------------------------------------------------
1 | define(User::class, function (Faker\Generator $faker) {
23 | static $password;
24 |
25 | return [
26 | 'name' => $faker->name,
27 | 'email' => $faker->unique()->safeEmail,
28 | 'password' => $password ?: $password = bcrypt('secret'),
29 | 'remember_token' => Str::random(10),
30 | 'verified' => $verified = $faker->randomElement([User::VERIFIED_USER, User::UNVERIFIED_USER]),
31 | 'verification_token' => $verified == User::VERIFIED_USER ? null : User::generateVerificationCode(),
32 | 'admin' => $verified = $faker->randomElement([User::ADMIN_USER, User::REGULAR_USER]),
33 | ];
34 | });
35 |
36 | $factory->define(Category::class, function (Faker\Generator $faker) {
37 | return [
38 | 'name' => $faker->word,
39 | 'description' => $faker->paragraph(1),
40 | ];
41 | });
42 |
43 | $factory->define(Product::class, function (Faker\Generator $faker) {
44 | return [
45 | 'name' => $faker->word,
46 | 'description' => $faker->paragraph(1),
47 | 'quantity' => $faker->numberBetween(1, 10),
48 | 'status' => $faker->randomElement([Product::AVAILABLE_PRODUCT, Product::UNAVAILABLE_PRODUCT]),
49 | 'image' => $faker->randomElement(['1.jpg', '2.jpg', '3.jpg']),
50 | 'seller_id' => User::all()->random()->id,
51 | // User::inRandomOrder()->first()->id
52 | ];
53 | });
54 |
55 | $factory->define(Transaction::class, function (Faker\Generator $faker) {
56 | $seller = Seller::has('products')->get()->random();
57 | $buyer = User::all()->except($seller->id)->random();
58 |
59 | return [
60 | 'quantity' => $faker->numberBetween(1, 3),
61 | 'buyer_id' => $buyer->id,
62 | 'product_id' => $seller->products->random()->id,
63 | // User::inRandomOrder()->first()->id
64 | ];
65 | });
66 |
--------------------------------------------------------------------------------
/database/migrations/2014_10_12_000000_create_users_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
19 | $table->string('name');
20 | $table->string('email')->unique();
21 | $table->string('password');
22 | $table->rememberToken();
23 | $table->string('verified')->default(User::UNVERIFIED_USER);
24 | $table->string('verification_token')->nullable();
25 | $table->string('admin')->default(User::REGULAR_USER);
26 | $table->timestamps();
27 | $table->softDeletes();//deleted_at
28 | });
29 | }
30 |
31 | /**
32 | * Reverse the migrations.
33 | *
34 | * @return void
35 | */
36 | public function down()
37 | {
38 | Schema::dropIfExists('users');
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/database/migrations/2014_10_12_100000_create_password_resets_table.php:
--------------------------------------------------------------------------------
1 | string('email')->index();
18 | $table->string('token')->index();
19 | $table->timestamp('created_at')->nullable();
20 | });
21 | }
22 |
23 | /**
24 | * Reverse the migrations.
25 | *
26 | * @return void
27 | */
28 | public function down()
29 | {
30 | Schema::dropIfExists('password_resets');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/database/migrations/2017_02_15_060634_create_categories_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->string('name');
19 | $table->string('description', 1000);
20 | $table->timestamps();
21 | $table->softDeletes();
22 | });
23 | }
24 |
25 | /**
26 | * Reverse the migrations.
27 | *
28 | * @return void
29 | */
30 | public function down()
31 | {
32 | Schema::dropIfExists('categories');
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/database/migrations/2017_02_15_060644_create_products_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
19 | $table->string('name');
20 | $table->string('description', 1000);
21 | $table->integer('quantity')->unsigned();
22 | $table->string('status')->default(Product::UNAVAILABLE_PRODUCT);
23 | $table->string('image');
24 | $table->integer('seller_id')->unsigned();
25 | $table->timestamps();
26 | $table->softDeletes();
27 |
28 | $table->foreign('seller_id')->references('id')->on('users');
29 | });
30 | }
31 |
32 | /**
33 | * Reverse the migrations.
34 | *
35 | * @return void
36 | */
37 | public function down()
38 | {
39 | Schema::dropIfExists('products');
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/database/migrations/2017_02_15_060654_create_transactions_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->integer('quantity')->unsigned();
19 | $table->integer('buyer_id')->unsigned();
20 | $table->integer('product_id')->unsigned();
21 | $table->timestamps();
22 | $table->softDeletes();
23 |
24 | $table->foreign('buyer_id')->references('id')->on('users');
25 | $table->foreign('product_id')->references('id')->on('products');
26 | });
27 | }
28 |
29 | /**
30 | * Reverse the migrations.
31 | *
32 | * @return void
33 | */
34 | public function down()
35 | {
36 | Schema::dropIfExists('transactions');
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/database/migrations/2017_02_17_034324_category_product_table.php:
--------------------------------------------------------------------------------
1 | integer('category_id')->unsigned();
18 | $table->integer('product_id')->unsigned();
19 |
20 | $table->foreign('category_id')->references('id')->on('categories');
21 | $table->foreign('product_id')->references('id')->on('products');
22 | });
23 | }
24 |
25 | /**
26 | * Reverse the migrations.
27 | *
28 | * @return void
29 | */
30 | public function down()
31 | {
32 | Schema::dropIfExists('category_product');
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/database/seeders/DatabaseSeeder.php:
--------------------------------------------------------------------------------
1 | truncate();
31 |
32 | User::flushEventListeners();
33 | Category::flushEventListeners();
34 | Product::flushEventListeners();
35 | Transaction::flushEventListeners();
36 |
37 | $usersQuantity = 1000;
38 | $categoriesQuantity = 30;
39 | $productsQuantity = 1000;
40 | $transactionsQuantity = 1000;
41 |
42 | factory(User::class, $usersQuantity)->create();
43 | factory(Category::class, $categoriesQuantity)->create();
44 |
45 | factory(Product::class, $productsQuantity)->create()->each(
46 | function ($product) {
47 | $categories = Category::all()->random(mt_rand(1, 5))->pluck('id');
48 |
49 | $product->categories()->attach($categories);
50 | });
51 |
52 | factory(Transaction::class, $transactionsQuantity)->create();
53 |
54 | Passport::client()->forceCreate([
55 | 'user_id' => null,
56 | 'name' => '',
57 | 'secret' => 'secret',
58 | 'redirect' => '',
59 | 'personal_access_client' => true,
60 | 'password_client' => true,
61 | 'revoked' => false,
62 | ]);
63 |
64 | $personalClient = Passport::client()->forceCreate([
65 | 'user_id' => null,
66 | 'name' => '',
67 | 'secret' => 'secret',
68 | 'redirect' => '',
69 | 'personal_access_client' => true,
70 | 'password_client' => false,
71 | 'revoked' => false,
72 | ]);
73 |
74 | Passport::personalAccessClient()->forceCreate([
75 | 'client_id' => $personalClient->id,
76 | ]);
77 |
78 | Schema::enableForeignKeyConstraints();
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "dev": "node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
5 | "watch": "node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
6 | "watch-poll": "node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --watch-poll --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
7 | "hot": "node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
8 | "production": "node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
9 | },
10 | "devDependencies": {
11 | "axios": "^0.18.1",
12 | "bootstrap-sass": "^3.3.7",
13 | "jquery": "^3.1.1",
14 | "laravel-mix": "^0.8.1",
15 | "lodash": "^4.17.4",
16 | "vue": "^2.1.10"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
51 |
22 |
26 |
27 |
28 |
29 | Name
23 | Scopes
24 |
25 |
30 |
31 |
49 |
50 |
32 | {{ token.client.name }}
33 |
34 |
35 |
36 |
37 |
38 | {{ token.scopes.join(', ') }}
39 |
40 |
41 |
42 |
43 |
44 |
45 | Revoke
46 |
47 |
48 |