├── .env.example
├── .gitattributes
├── .gitignore
├── .phpstorm.meta.php
├── Makefile
├── _ide_helper.php
├── app
├── Console
│ ├── Commands
│ │ ├── Advert
│ │ │ └── ExpireCommand.php
│ │ ├── Api
│ │ │ └── DocCommand.php
│ │ ├── Banner
│ │ │ └── ExpireCommand.php
│ │ ├── Search
│ │ │ ├── InitCommand.php
│ │ │ └── ReindexCommand.php
│ │ └── User
│ │ │ ├── RoleCommand.php
│ │ │ └── VerifyCommand.php
│ └── Kernel.php
├── Entity
│ ├── Adverts
│ │ ├── Advert
│ │ │ ├── Advert.php
│ │ │ ├── Dialog
│ │ │ │ ├── Dialog.php
│ │ │ │ └── Message.php
│ │ │ ├── Photo.php
│ │ │ └── Value.php
│ │ ├── Attribute.php
│ │ └── Category.php
│ ├── Banner
│ │ └── Banner.php
│ ├── Page.php
│ ├── Region.php
│ ├── Ticket
│ │ ├── Message.php
│ │ ├── Status.php
│ │ └── Ticket.php
│ └── User
│ │ ├── Network.php
│ │ └── User.php
├── Events
│ └── Advert
│ │ └── ModerationPassed.php
├── Exceptions
│ └── Handler.php
├── Http
│ ├── Controllers
│ │ ├── Admin
│ │ │ ├── Adverts
│ │ │ │ ├── AdvertController.php
│ │ │ │ ├── AttributeController.php
│ │ │ │ └── CategoryController.php
│ │ │ ├── BannerController.php
│ │ │ ├── HomeController.php
│ │ │ ├── PageController.php
│ │ │ ├── RegionController.php
│ │ │ ├── TicketController.php
│ │ │ ├── UploadController.php
│ │ │ └── UsersController.php
│ │ ├── Adverts
│ │ │ ├── AdvertController.php
│ │ │ └── FavoriteController.php
│ │ ├── Api
│ │ │ ├── Adverts
│ │ │ │ ├── AdvertController.php
│ │ │ │ └── FavoriteController.php
│ │ │ ├── Auth
│ │ │ │ └── RegisterController.php
│ │ │ ├── HomeController.php
│ │ │ └── User
│ │ │ │ ├── AdvertController.php
│ │ │ │ ├── FavoriteController.php
│ │ │ │ └── ProfileController.php
│ │ ├── Auth
│ │ │ ├── ForgotPasswordController.php
│ │ │ ├── LoginController.php
│ │ │ ├── NetworkController.php
│ │ │ ├── RegisterController.php
│ │ │ └── ResetPasswordController.php
│ │ ├── BannerController.php
│ │ ├── Cabinet
│ │ │ ├── Adverts
│ │ │ │ ├── AdvertController.php
│ │ │ │ ├── CreateController.php
│ │ │ │ └── ManageController.php
│ │ │ ├── Banners
│ │ │ │ ├── BannerController.php
│ │ │ │ └── CreateController.php
│ │ │ ├── FavoriteController.php
│ │ │ ├── HomeController.php
│ │ │ ├── PhoneController.php
│ │ │ ├── ProfileController.php
│ │ │ └── TicketController.php
│ │ ├── Controller.php
│ │ ├── HomeController.php
│ │ ├── PageController.php
│ │ └── PaymentController.php
│ ├── Kernel.php
│ ├── Middleware
│ │ ├── EncryptCookies.php
│ │ ├── FilledProfile.php
│ │ ├── RedirectIfAuthenticated.php
│ │ ├── TrimStrings.php
│ │ ├── TrustProxies.php
│ │ └── VerifyCsrfToken.php
│ ├── Requests
│ │ ├── Admin
│ │ │ ├── Pages
│ │ │ │ └── PageRequest.php
│ │ │ └── Users
│ │ │ │ ├── CreateRequest.php
│ │ │ │ └── UpdateRequest.php
│ │ ├── Adverts
│ │ │ ├── AttributesRequest.php
│ │ │ ├── CreateRequest.php
│ │ │ ├── EditRequest.php
│ │ │ ├── PhotosRequest.php
│ │ │ ├── RejectRequest.php
│ │ │ └── SearchRequest.php
│ │ ├── Auth
│ │ │ ├── LoginRequest.php
│ │ │ └── RegisterRequest.php
│ │ ├── Banner
│ │ │ ├── CreateRequest.php
│ │ │ ├── EditRequest.php
│ │ │ ├── FileRequest.php
│ │ │ └── RejectRequest.php
│ │ ├── Cabinet
│ │ │ ├── PhoneVerifyRequest.php
│ │ │ └── ProfileEditRequest.php
│ │ └── Ticket
│ │ │ ├── CreateRequest.php
│ │ │ ├── EditRequest.php
│ │ │ └── MessageRequest.php
│ ├── Resources
│ │ ├── Adverts
│ │ │ ├── AdvertDetailResource.php
│ │ │ └── AdvertListResource.php
│ │ └── User
│ │ │ └── ProfileResource.php
│ ├── Router
│ │ ├── AdvertsPath.php
│ │ └── PagePath.php
│ └── ViewComposers
│ │ └── MenuPagesComposer.php
├── Jobs
│ └── Advert
│ │ └── ReindexAdvert.php
├── Listeners
│ └── Advert
│ │ ├── AdvertChangedListener.php
│ │ └── ModerationPassedListener.php
├── Mail
│ └── Auth
│ │ └── VerifyMail.php
├── Notifications
│ ├── Advert
│ │ └── ModerationPassedNotification.php
│ └── SmsChannel.php
├── Providers
│ ├── AppServiceProvider.php
│ ├── AuthServiceProvider.php
│ ├── BroadcastServiceProvider.php
│ ├── CacheServiceProvider.php
│ ├── ComposerServiceProvider.php
│ ├── EventServiceProvider.php
│ ├── RouteServiceProvider.php
│ ├── SearchServiceProvider.php
│ └── SmsServiceProvider.php
├── Services
│ ├── Banner
│ │ └── CostCalculator.php
│ ├── Search
│ │ ├── AdvertIndexer.php
│ │ └── BannerIndexer.php
│ └── Sms
│ │ ├── ArraySender.php
│ │ ├── SmsRu.php
│ │ └── SmsSender.php
├── UseCases
│ ├── Adverts
│ │ ├── AdvertService.php
│ │ ├── FavoriteService.php
│ │ ├── SearchResult.php
│ │ └── SearchService.php
│ ├── Auth
│ │ ├── NetworkService.php
│ │ └── RegisterService.php
│ ├── Banners
│ │ └── BannerService.php
│ ├── Profile
│ │ ├── PhoneService.php
│ │ └── ProfileService.php
│ └── Tickets
│ │ └── TicketService.php
└── helpers.php
├── artisan
├── bootstrap
├── app.php
└── cache
│ └── .gitignore
├── composer.json
├── composer.lock
├── config
├── app.php
├── auth.php
├── banner.php
├── broadcasting.php
├── cache.php
├── database.php
├── elasticsearch.php
├── filesystems.php
├── hashing.php
├── horizon.php
├── ide-helper.php
├── logging.php
├── mail.php
├── purifier.php
├── queue.php
├── services.php
├── session.php
├── sms.php
└── view.php
├── database
├── .gitignore
├── factories
│ ├── AdvertsCategoryFactory.php
│ ├── RegionFactory.php
│ └── UserFactory.php
├── migrations
│ ├── 2014_10_12_000000_create_users_table.php
│ ├── 2014_10_12_100000_create_password_resets_table.php
│ ├── 2016_06_01_000001_create_oauth_auth_codes_table.php
│ ├── 2016_06_01_000002_create_oauth_access_tokens_table.php
│ ├── 2016_06_01_000003_create_oauth_refresh_tokens_table.php
│ ├── 2016_06_01_000004_create_oauth_clients_table.php
│ ├── 2016_06_01_000005_create_oauth_personal_access_clients_table.php
│ ├── 2018_03_03_193348_add_user_verification.php
│ ├── 2018_03_08_100246_add_user_role.php
│ ├── 2018_03_08_161503_create_regions_table.php
│ ├── 2018_03_08_171503_create_advert_categories_table.php
│ ├── 2018_03_10_132930_create_advert_attributes_table.php
│ ├── 2018_03_12_083000_add_user_last_name.php
│ ├── 2018_03_12_090001_add_user_phone.php
│ ├── 2018_03_12_124830_add_user_phone_auth.php
│ ├── 2018_03_15_135243_create_adverts_tables.php
│ ├── 2018_03_19_123423_create_advert_favorites_table.php
│ ├── 2018_03_22_090624_create_banners_table.php
│ ├── 2018_03_25_183121_add_networks_auth.php
│ ├── 2018_03_29_174253_create_pages_table.php
│ └── 2018_03_30_132456_create_tickets_tables.php
└── seeds
│ ├── AdvertCategoriesTableSeeder.php
│ ├── DatabaseSeeder.php
│ ├── RegionsTableSeeder.php
│ └── UsersTableSeeder.php
├── docker-compose.yml
├── docker
├── nginx.docker
├── nginx
│ ├── default.conf
│ └── ssl
│ │ ├── ssl-cert-snakeoil.key
│ │ └── ssl-cert-snakeoil.pem
├── php-cli.docker
└── php-fpm.docker
├── package.json
├── phpunit.xml
├── public
├── .htaccess
├── docs
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── index.html
│ ├── oauth2-redirect.html
│ ├── swagger-ui-bundle.js
│ ├── swagger-ui-bundle.js.map
│ ├── swagger-ui-standalone-preset.js
│ ├── swagger-ui-standalone-preset.js.map
│ ├── swagger-ui.css
│ ├── swagger-ui.css.map
│ ├── swagger-ui.js
│ ├── swagger-ui.js.map
│ └── swagger.json
├── favicon.ico
├── index.php
├── robots.txt
├── vendor
│ └── horizon
│ │ ├── css
│ │ ├── app.css
│ │ └── app.css.map
│ │ ├── img
│ │ ├── favicon.png
│ │ ├── horizon.svg
│ │ └── sprite.svg
│ │ ├── js
│ │ ├── app.js
│ │ └── app.js.map
│ │ └── mix-manifest.json
└── web.config
├── readme.md
├── resources
├── assets
│ ├── js
│ │ ├── app.js
│ │ └── bootstrap.js
│ └── sass
│ │ ├── _variables.scss
│ │ └── app.scss
├── lang
│ └── en
│ │ ├── auth.php
│ │ ├── pagination.php
│ │ ├── passwords.php
│ │ └── validation.php
└── views
│ ├── admin
│ ├── _nav.blade.php
│ ├── adverts
│ │ ├── adverts
│ │ │ ├── _nav.blade.php
│ │ │ ├── index.blade.php
│ │ │ └── reject.blade.php
│ │ └── categories
│ │ │ ├── _nav.blade.php
│ │ │ ├── attributes
│ │ │ ├── create.blade.php
│ │ │ ├── edit.blade.php
│ │ │ └── show.blade.php
│ │ │ ├── create.blade.php
│ │ │ ├── edit.blade.php
│ │ │ ├── index.blade.php
│ │ │ └── show.blade.php
│ ├── banners
│ │ ├── _nav.blade.php
│ │ ├── index.blade.php
│ │ ├── reject.blade.php
│ │ └── show.blade.php
│ ├── home.blade.php
│ ├── pages
│ │ ├── _nav.blade.php
│ │ ├── create.blade.php
│ │ ├── edit.blade.php
│ │ ├── index.blade.php
│ │ └── show.blade.php
│ ├── regions
│ │ ├── _list.blade.php
│ │ ├── _nav.blade.php
│ │ ├── create.blade.php
│ │ ├── edit.blade.php
│ │ ├── index.blade.php
│ │ └── show.blade.php
│ ├── tickets
│ │ ├── _nav.blade.php
│ │ ├── edit.blade.php
│ │ ├── index.blade.php
│ │ └── show.blade.php
│ └── users
│ │ ├── _nav.blade.php
│ │ ├── create.blade.php
│ │ ├── edit.blade.php
│ │ ├── index.blade.php
│ │ └── show.blade.php
│ ├── adverts
│ ├── edit
│ │ ├── advert.blade.php
│ │ ├── attributes.blade.php
│ │ └── photos.blade.php
│ ├── index.blade.php
│ └── show.blade.php
│ ├── auth
│ ├── login.blade.php
│ ├── passwords
│ │ ├── email.blade.php
│ │ └── reset.blade.php
│ ├── phone.blade.php
│ └── register.blade.php
│ ├── banner
│ └── get.blade.php
│ ├── cabinet
│ ├── adverts
│ │ ├── _nav.blade.php
│ │ ├── create
│ │ │ ├── _categories.blade.php
│ │ │ ├── advert.blade.php
│ │ │ ├── category.blade.php
│ │ │ └── region.blade.php
│ │ └── index.blade.php
│ ├── banners
│ │ ├── _nav.blade.php
│ │ ├── create
│ │ │ ├── _categories.blade.php
│ │ │ ├── banner.blade.php
│ │ │ ├── category.blade.php
│ │ │ └── region.blade.php
│ │ ├── edit.blade.php
│ │ ├── file.blade.php
│ │ ├── index.blade.php
│ │ └── show.blade.php
│ ├── favorites
│ │ ├── _nav.blade.php
│ │ └── index.blade.php
│ ├── home.blade.php
│ ├── profile
│ │ ├── _nav.blade.php
│ │ ├── edit.blade.php
│ │ ├── home.blade.php
│ │ └── phone.blade.php
│ └── tickets
│ │ ├── _nav.blade.php
│ │ ├── create.blade.php
│ │ ├── index.blade.php
│ │ └── show.blade.php
│ ├── emails
│ └── auth
│ │ └── register
│ │ └── verify.blade.php
│ ├── home.blade.php
│ ├── layouts
│ ├── app.blade.php
│ └── partials
│ │ ├── flash.blade.php
│ │ └── search.blade.php
│ └── page.blade.php
├── routes
├── api.php
├── breadcrumbs.php
├── channels.php
├── console.php
└── web.php
├── server.php
├── storage
├── app
│ ├── .gitignore
│ └── public
│ │ └── .gitignore
├── debugbar
│ └── .gitignore
├── docker
│ └── .gitignore
├── framework
│ ├── .gitignore
│ ├── cache
│ │ └── .gitignore
│ ├── sessions
│ │ └── .gitignore
│ ├── testing
│ │ └── .gitignore
│ └── views
│ │ └── .gitignore
└── logs
│ └── .gitignore
├── tests
├── CreatesApplication.php
├── Feature
│ ├── Auth
│ │ ├── LoginTest.php
│ │ └── RegisterTest.php
│ └── ExampleTest.php
├── TestCase.php
└── Unit
│ └── Entity
│ └── User
│ ├── CreateTest.php
│ ├── PhoneTest.php
│ ├── RegisterTest.php
│ └── RoleTest.php
├── webpack.mix.js
└── yarn.lock
/.env.example:
--------------------------------------------------------------------------------
1 | APP_NAME=Laravel
2 | APP_ENV=local
3 | APP_KEY=
4 | APP_DEBUG=true
5 | APP_URL=https://localhost:8080
6 |
7 | LOG_CHANNEL=stack
8 |
9 | DB_CONNECTION=mysql
10 | DB_HOST=127.0.0.1
11 | DB_PORT=33061
12 | DB_DATABASE=app
13 | DB_USERNAME=app
14 | DB_PASSWORD=secret
15 |
16 | BROADCAST_DRIVER=log
17 | CACHE_DRIVER=redis
18 | SESSION_DRIVER=redis
19 | SESSION_LIFETIME=120
20 | QUEUE_DRIVER=redis
21 |
22 | REDIS_HOST=127.0.0.1
23 | REDIS_PASSWORD=null
24 | REDIS_PORT=63791
25 |
26 | MAIL_DRIVER=smtp
27 | MAIL_HOST=smtp.mailtrap.io
28 | MAIL_PORT=2525
29 | MAIL_USERNAME=null
30 | MAIL_PASSWORD=null
31 | MAIL_ENCRYPTION=null
32 |
33 | PUSHER_APP_ID=
34 | PUSHER_APP_KEY=
35 | PUSHER_APP_SECRET=
36 | PUSHER_APP_CLUSTER=mt1
37 |
38 | MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
39 | MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
40 |
41 | SMS_DRIVER=sms.ru
42 | SMS_SMS_RU_APP_ID=
43 | SMS_SMS_RU_APP_URL=
44 |
45 | BANNER_COST_PER_MILE=
46 |
47 | ELASTICSEARCH_HOSTS=127.0.0.1:9201
48 |
49 | FACEBOOK_CLIENT_ID=
50 | FACEBOOK_CLIENT_SECRET=
51 |
52 | TWITTER_CLIENT_ID=
53 | TWITTER_CLIENT_SECRET=
54 |
--------------------------------------------------------------------------------
/.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/build
3 | /public/storage
4 | /storage/*.key
5 | /vendor
6 | /.idea
7 | /.vscode
8 | /.vagrant
9 | Homestead.json
10 | Homestead.yaml
11 | npm-debug.log
12 | yarn-error.log
13 | .env
14 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | docker-up: memory
2 | docker-compose up -d
3 |
4 | docker-down:
5 | docker-compose down
6 |
7 | docker-build: memory
8 | docker-compose up --build -d
9 |
10 | test:
11 | docker-compose exec php-cli vendor/bin/phpunit
12 |
13 | assets-install:
14 | docker-compose exec node yarn install
15 |
16 | assets-rebuild:
17 | docker-compose exec node npm rebuild node-sass --force
18 |
19 | assets-dev:
20 | docker-compose exec node yarn run dev
21 |
22 | assets-watch:
23 | docker-compose exec node yarn run watch
24 |
25 | queue:
26 | docker-compose exec php-cli php artisan queue:work
27 |
28 | horizon:
29 | docker-compose exec php-cli php artisan horizon
30 |
31 | horizon-pause:
32 | docker-compose exec php-cli php artisan horizon:pause
33 |
34 | horizon-continue:
35 | docker-compose exec php-cli php artisan horizon:continue
36 |
37 | horizon-terminate:
38 | docker-compose exec php-cli php artisan horizon:terminate
39 |
40 | memory:
41 | sudo sysctl -w vm.max_map_count=262144
42 |
43 | perm:
44 | sudo chgrp -R www-data storage bootstrap/cache
45 | sudo chmod -R ug+rwx storage bootstrap/cache
--------------------------------------------------------------------------------
/app/Console/Commands/Advert/ExpireCommand.php:
--------------------------------------------------------------------------------
1 | service = $service;
20 | }
21 |
22 | public function handle(): bool
23 | {
24 | $success = true;
25 |
26 | foreach (Advert::active()->where('expired_at', '<', Carbon::now())->cursor() as $advert) {
27 | try {
28 | $this->service->expire($advert);
29 | } catch (\DomainException $e) {
30 | $this->error($e->getMessage());
31 | $success = false;
32 | }
33 | }
34 |
35 | return $success;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/Console/Commands/Api/DocCommand.php:
--------------------------------------------------------------------------------
1 | client = $client;
20 | }
21 |
22 | public function handle(): bool
23 | {
24 | $success = true;
25 |
26 | foreach (Banner::active()->whereRaw('`limit` - views < 100')->with('user')->cursor() as $banner) {
27 | $key = 'banner_notify_' . $banner->id;
28 | if ($this->client->get($key)) {
29 | continue;
30 | }
31 | Mail::to($banner->user->email)->queue(new BannerExpiresSoonMail($banner));
32 | $this->client->set($key, true);
33 | }
34 |
35 | return $success;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/Console/Commands/Search/ReindexCommand.php:
--------------------------------------------------------------------------------
1 | adverts = $adverts;
22 | $this->banners = $banners;
23 | }
24 |
25 | public function handle(): bool
26 | {
27 | $this->adverts->clear();
28 |
29 | foreach (Advert::active()->orderBy('id')->cursor() as $advert) {
30 | $this->adverts->index($advert);
31 | }
32 |
33 | $this->banners->clear();
34 |
35 | foreach (Banner::active()->orderBy('id')->cursor() as $banner) {
36 | $this->banners->index($banner);
37 | }
38 |
39 | return true;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/Console/Commands/User/RoleCommand.php:
--------------------------------------------------------------------------------
1 | argument('email');
17 | $role = $this->argument('role');
18 |
19 | /** @var User $user */
20 | if (!$user = User::where('email', $email)->first()) {
21 | $this->error('Undefined user with email ' . $email);
22 | return false;
23 | }
24 |
25 | try {
26 | $user->changeRole($role);
27 | } catch (\DomainException $e) {
28 | $this->error($e->getMessage());
29 | return false;
30 | }
31 |
32 | $this->info('Role is successfully changed');
33 | return true;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/Console/Commands/User/VerifyCommand.php:
--------------------------------------------------------------------------------
1 | service = $service;
22 | }
23 |
24 | public function handle(): bool
25 | {
26 | $email = $this->argument('email');
27 |
28 | /** @var User $user */
29 | if (!$user = User::where('email', $email)->first()) {
30 | $this->error('Undefined user with email ' . $email);
31 | return false;
32 | }
33 |
34 | try {
35 | $this->service->verify($user->id);
36 | } catch (\DomainException $e) {
37 | $this->error($e->getMessage());
38 | return false;
39 | }
40 |
41 | $this->info('User is successfully verified');
42 | return true;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/Console/Kernel.php:
--------------------------------------------------------------------------------
1 | command('banner:expire')->daily();
17 | $schedule->command('advert:expire')->hourly();
18 | }
19 |
20 | protected function commands()
21 | {
22 | $this->load(__DIR__.'/Commands');
23 |
24 | require base_path('routes/console.php');
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/Entity/Adverts/Advert/Dialog/Dialog.php:
--------------------------------------------------------------------------------
1 | messages()->create([
28 | 'user_id' => $userId,
29 | 'message' => $message,
30 | ]);
31 | $this->client_new_messages++;
32 | $this->save();
33 | }
34 |
35 | public function writeMessageByClient(int $userId, string $message): void
36 | {
37 | $this->messages()->create([
38 | 'user_id' => $userId,
39 | 'message' => $message,
40 | ]);
41 | $this->user_new_messages++;
42 | $this->save();
43 | }
44 |
45 | public function readByOwner(): void
46 | {
47 | $this->update(['user_new_messages' => 0]);
48 | }
49 |
50 | public function readByClient(): void
51 | {
52 | $this->update(['client_new_messages' => 0]);
53 | }
54 |
55 | public function client()
56 | {
57 | return $this->belongsTo(User::class, 'client_id', 'id');
58 | }
59 |
60 | public function messages()
61 | {
62 | return $this->hasMany(Message::class, 'dialog_id', 'id');
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/Entity/Adverts/Advert/Dialog/Message.php:
--------------------------------------------------------------------------------
1 | belongsTo(User::class, 'user_id', 'id');
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/Entity/Adverts/Advert/Photo.php:
--------------------------------------------------------------------------------
1 | 'array',
31 | ];
32 |
33 | public static function typesList(): array
34 | {
35 | return [
36 | self::TYPE_STRING => 'String',
37 | self::TYPE_INTEGER => 'Integer',
38 | self::TYPE_FLOAT => 'Float',
39 | ];
40 | }
41 |
42 | public function isString(): bool
43 | {
44 | return $this->type === self::TYPE_STRING;
45 | }
46 |
47 | public function isInteger(): bool
48 | {
49 | return $this->type === self::TYPE_INTEGER;
50 | }
51 |
52 | public function isFloat(): bool
53 | {
54 | return $this->type === self::TYPE_FLOAT;
55 | }
56 |
57 | public function isNumber(): bool
58 | {
59 | return $this->isInteger() || $this->isFloat();
60 | }
61 |
62 | public function isSelect(): bool
63 | {
64 | return \count($this->variants) > 0;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/Entity/Adverts/Category.php:
--------------------------------------------------------------------------------
1 | ancestors()->defaultOrder()->pluck('slug')->toArray(), [$this->slug]));
32 | }
33 |
34 | public function parentAttributes(): array
35 | {
36 | return $this->parent ? $this->parent->allAttributes() : [];
37 | }
38 |
39 | /**
40 | * @return Attribute[]
41 | */
42 | public function allAttributes(): array
43 | {
44 | return array_merge($this->parentAttributes(), $this->attributes()->orderBy('sort')->getModels());
45 | }
46 |
47 | public function attributes()
48 | {
49 | return $this->hasMany(Attribute::class, 'category_id', 'id');
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/app/Entity/Page.php:
--------------------------------------------------------------------------------
1 | ancestors()->defaultOrder()->pluck('slug')->toArray(), [$this->slug]));
32 | }
33 |
34 | public function getMenuTitle(): string
35 | {
36 | return $this->menu_title ?: $this->title;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/Entity/Region.php:
--------------------------------------------------------------------------------
1 | parent ? $this->parent->getPath() . '/' : '') . $this->slug;
26 | }
27 |
28 | public function getAddress(): string
29 | {
30 | return ($this->parent ? $this->parent->getAddress() . ', ' : '') . $this->name;
31 | }
32 |
33 | public function parent()
34 | {
35 | return $this->belongsTo(static::class, 'parent_id', 'id');
36 | }
37 |
38 | public function children()
39 | {
40 | return $this->hasMany(static::class, 'parent_id', 'id');
41 | }
42 |
43 | public function scopeRoots(Builder $query)
44 | {
45 | return $query->where('parent_id', null);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/Entity/Ticket/Message.php:
--------------------------------------------------------------------------------
1 | belongsTo(User::class, 'user_id', 'id');
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/Entity/Ticket/Status.php:
--------------------------------------------------------------------------------
1 | 'Open',
31 | self::APPROVED => 'Approved',
32 | self::CLOSED => 'Closed',
33 | ];
34 | }
35 |
36 | public function isOpen(): bool
37 | {
38 | return $this->status === self::OPEN;
39 | }
40 |
41 | public function isApproved(): bool
42 | {
43 | return $this->status === self::APPROVED;
44 | }
45 |
46 | public function isClosed(): bool
47 | {
48 | return $this->status === self::CLOSED;
49 | }
50 |
51 | public function user()
52 | {
53 | return $this->belongsTo(User::class, 'user_id', 'id');
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/Entity/User/Network.php:
--------------------------------------------------------------------------------
1 | advert = $advert;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/Exceptions/Handler.php:
--------------------------------------------------------------------------------
1 | expectsJson()) {
28 | return response()->json([
29 | 'message' => $exception->getMessage(),
30 | ], Response::HTTP_BAD_REQUEST);
31 | }
32 |
33 | return parent::render($request, $exception);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Admin/HomeController.php:
--------------------------------------------------------------------------------
1 | validate($request, [
14 | 'file' => 'required|image|mimes:jpg,jpeg,png',
15 | ]);
16 |
17 | $file = $request->file('file');
18 | $path = $file->store('images', 'public');
19 |
20 | return Storage::disk('public')->url($path);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Adverts/FavoriteController.php:
--------------------------------------------------------------------------------
1 | service = $service;
22 | $this->middleware('auth');
23 | }
24 |
25 | public function add(Advert $advert)
26 | {
27 | try {
28 | $this->service->add(Auth::id(), $advert->id);
29 | } catch (\DomainException $e) {
30 | return back()->with('error', $e->getMessage());
31 | }
32 |
33 | return redirect()->route('adverts.show', $advert)->with('success', 'Advert is added to your favorites.');
34 | }
35 |
36 | public function remove(Advert $advert)
37 | {
38 | try {
39 | $this->service->remove(Auth::id(), $advert->id);
40 | } catch (\DomainException $e) {
41 | return back()->with('error', $e->getMessage());
42 | }
43 |
44 | return redirect()->route('adverts.show', $advert);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Api/Adverts/FavoriteController.php:
--------------------------------------------------------------------------------
1 | service = $service;
18 | }
19 |
20 | /**
21 | * @SWG\Post(
22 | * path="/adverts/{advertId}/favorite",
23 | * tags={"Adverts"},
24 | * @SWG\Parameter(name="advertId", in="path", required=true, type="integer"),
25 | * @SWG\Response(
26 | * response=201,
27 | * description="Success response",
28 | * ),
29 | * security={{"Bearer": {}, "OAuth2": {}}}
30 | * )
31 | */
32 | public function add(Advert $advert)
33 | {
34 | $this->service->add(Auth::id(), $advert->id);
35 | return response()->json([], Response::HTTP_CREATED);
36 | }
37 |
38 | /**
39 | * @SWG\Delete(
40 | * path="/adverts/{advertId}/favorite",
41 | * tags={"Adverts"},
42 | * @SWG\Parameter(name="advertId", in="path", required=true, type="integer"),
43 | * @SWG\Response(
44 | * response=204,
45 | * description="Success response",
46 | * ),
47 | * security={{"Bearer": {}, "OAuth2": {}}}
48 | * )
49 | */
50 | public function remove(Advert $advert)
51 | {
52 | $this->service->remove(Auth::id(), $advert->id);
53 | return response()->json([], Response::HTTP_NO_CONTENT);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Api/Auth/RegisterController.php:
--------------------------------------------------------------------------------
1 | service = $service;
17 | }
18 |
19 | /**
20 | * @SWG\Post(
21 | * path="/register",
22 | * tags={"Profile"},
23 | * @SWG\Parameter(name="body", in="body", required=true, @SWG\Schema(ref="#/definitions/RegisterRequest")),
24 | * @SWG\Response(
25 | * response=201,
26 | * description="Success response",
27 | * )
28 | * )
29 | */
30 | public function register(RegisterRequest $request)
31 | {
32 | $this->service->register($request);
33 |
34 | return response()->json([
35 | 'success' => 'Check your email and click on the link to verify.'
36 | ], Response::HTTP_CREATED);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Api/HomeController.php:
--------------------------------------------------------------------------------
1 | 'Board API',
64 | ];
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Api/User/FavoriteController.php:
--------------------------------------------------------------------------------
1 | service = $service;
18 | $this->middleware('auth');
19 | }
20 |
21 | /**
22 | * @SWG\Get(
23 | * path="/user/favorites",
24 | * tags={"Favorites"},
25 | * @SWG\Response(
26 | * response=200,
27 | * description="Success response",
28 | * @SWG\Schema(
29 | * type="array",
30 | * @SWG\Items(ref="#/definitions/AdvertList")
31 | * ),
32 | * ),
33 | * security={{"Bearer": {}, "OAuth2": {}}}
34 | * )
35 | */
36 | public function index()
37 | {
38 | $adverts = Advert::favoredByUser(Auth::user())->orderByDesc('id')->paginate(20);
39 |
40 | return AdvertDetailResource::collection($adverts);
41 | }
42 |
43 | /**
44 | * @SWG\Delete(
45 | * path="/user/favorites/{advertId}",
46 | * tags={"Favorites"},
47 | * @SWG\Parameter(name="advertId", in="path", required=true, type="integer"),
48 | * @SWG\Response(
49 | * response=204,
50 | * description="Success response",
51 | * ),
52 | * security={{"Bearer": {}, "OAuth2": {}}}
53 | * )
54 | */
55 | public function remove(Advert $advert)
56 | {
57 | try {
58 | $this->service->remove(Auth::id(), $advert->id);
59 | } catch (\DomainException $e) {
60 | return back()->with('error', $e->getMessage());
61 | }
62 |
63 | return redirect()->route('cabinet.favorites.index');
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Api/User/ProfileController.php:
--------------------------------------------------------------------------------
1 | service = $service;
19 | }
20 |
21 | /**
22 | * @SWG\Get(
23 | * path="/user",
24 | * tags={"Profile"},
25 | * @SWG\Response(
26 | * response=200,
27 | * description="Success response",
28 | * @SWG\Schema(ref="#/definitions/Profile"),
29 | * ),
30 | * security={{"Bearer": {}, "OAuth2": {}}}
31 | * )
32 | */
33 | public function show(Request $request)
34 | {
35 | return new ProfileResource($request->user());
36 | }
37 |
38 | /**
39 | * @SWG\Put(
40 | * path="/user",
41 | * tags={"Profile"},
42 | * @SWG\Parameter(name="body", in="body", required=true, @SWG\Schema(ref="#/definitions/ProfileEditRequest")),
43 | * @SWG\Response(
44 | * response=200,
45 | * description="Success response",
46 | * ),
47 | * security={{"Bearer": {}, "OAuth2": {}}}
48 | * )
49 | */
50 | public function update(ProfileEditRequest $request)
51 | {
52 | $this->service->edit($request->user()->id, $request);
53 |
54 | $user = User::findOrFail($request->user()->id);
55 | return new ProfileResource($user);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/ForgotPasswordController.php:
--------------------------------------------------------------------------------
1 | middleware('guest');
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/NetworkController.php:
--------------------------------------------------------------------------------
1 | service = $service;
17 | }
18 |
19 | public function redirect(string $network)
20 | {
21 | return Socialite::driver($network)->redirect();
22 | }
23 |
24 | public function callback(string $network)
25 | {
26 | $data = Socialite::driver($network)->user();
27 |
28 | try {
29 | $user = $this->service->auth($network, $data);
30 | Auth::login($user);
31 | return redirect()->intended();
32 | } catch (\DomainException $e) {
33 | return redirect()->route('login')->with('error', $e->getMessage());
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/RegisterController.php:
--------------------------------------------------------------------------------
1 | middleware('guest');
17 | $this->service = $service;
18 | }
19 |
20 | public function showRegistrationForm()
21 | {
22 | return view('auth.register');
23 | }
24 |
25 | public function register(RegisterRequest $request)
26 | {
27 | $this->service->register($request);
28 |
29 | return redirect()->route('login')
30 | ->with('success', 'Check your email and click on the link to verify.');
31 | }
32 |
33 | public function verify($token)
34 | {
35 | if (!$user = User::where('verify_token', $token)->first()) {
36 | return redirect()->route('login')
37 | ->with('error', 'Sorry your link cannot be identified.');
38 | }
39 |
40 | try {
41 | $this->service->verify($user->id);
42 | return redirect()->route('login')->with('success', 'Your e-mail is verified. You can now login.');
43 | } catch (\DomainException $e) {
44 | return redirect()->route('login')->with('error', $e->getMessage());
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/ResetPasswordController.php:
--------------------------------------------------------------------------------
1 | middleware('guest');
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/Http/Controllers/BannerController.php:
--------------------------------------------------------------------------------
1 | service = $service;
16 | }
17 |
18 | public function get(Request $request)
19 | {
20 | $format = $request['format'];
21 | $category = $request['category'];
22 | $region = $request['region'];
23 |
24 | if (!$banner = $this->service->getRandomForView($category, $region, $format)) {
25 | return '';
26 | }
27 |
28 | return view('banner.get', compact('banner'));
29 | }
30 |
31 | public function click(Banner $banner)
32 | {
33 | $this->service->click($banner);
34 | return redirect($banner->url);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Cabinet/Adverts/AdvertController.php:
--------------------------------------------------------------------------------
1 | orderByDesc('id')->paginate(20);
14 |
15 | return view('cabinet.adverts.index', compact('adverts'));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Cabinet/Adverts/CreateController.php:
--------------------------------------------------------------------------------
1 | service = $service;
19 | }
20 |
21 | public function category()
22 | {
23 | $categories = Category::defaultOrder()->withDepth()->get()->toTree();
24 |
25 | return view('cabinet.adverts.create.category', compact('categories'));
26 | }
27 |
28 | public function region(Category $category, Region $region = null)
29 | {
30 | $regions = Region::where('parent_id', $region ? $region->id : null)->orderBy('name')->get();
31 |
32 | return view('cabinet.adverts.create.region', compact('category', 'region', 'regions'));
33 | }
34 |
35 | public function advert(Category $category, Region $region = null)
36 | {
37 | return view('cabinet.adverts.create.advert', compact('category', 'region'));
38 | }
39 |
40 | public function store(CreateRequest $request, Category $category, Region $region = null)
41 | {
42 | try {
43 | $advert = $this->service->create(
44 | Auth::id(),
45 | $category->id,
46 | $region ? $region->id : null,
47 | $request
48 | );
49 | } catch (\DomainException $e) {
50 | return back()->with('error', $e->getMessage());
51 | }
52 |
53 | return redirect()->route('adverts.show', $advert);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Cabinet/Banners/CreateController.php:
--------------------------------------------------------------------------------
1 | service = $service;
20 | }
21 |
22 | public function category()
23 | {
24 | $categories = Category::defaultOrder()->withDepth()->get()->toTree();
25 |
26 | return view('cabinet.banners.create.category', compact('categories'));
27 | }
28 |
29 | public function region(Category $category, Region $region = null)
30 | {
31 | $regions = Region::where('parent_id', $region ? $region->id : null)->orderBy('name')->get();
32 |
33 | return view('cabinet.banners.create.region', compact('category', 'region', 'regions'));
34 | }
35 |
36 | public function banner(Category $category, Region $region = null)
37 | {
38 | $formats = Banner::formatsList();
39 |
40 | return view('cabinet.banners.create.banner', compact('category', 'region', 'formats'));
41 | }
42 |
43 | public function store(CreateRequest $request, Category $category, Region $region = null)
44 | {
45 | try {
46 | $banner = $this->service->create(
47 | Auth::user(),
48 | $category,
49 | $region,
50 | $request
51 | );
52 | } catch (\DomainException $e) {
53 | return back()->with('error', $e->getMessage());
54 | }
55 |
56 | return redirect()->route('cabinet.banners.show', $banner);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Cabinet/FavoriteController.php:
--------------------------------------------------------------------------------
1 | service = $service;
17 | $this->middleware('auth');
18 | }
19 |
20 | public function index()
21 | {
22 | $adverts = Advert::favoredByUser(Auth::user())->orderByDesc('id')->paginate(20);
23 |
24 | return view('cabinet.favorites.index', compact('adverts'));
25 | }
26 |
27 | public function remove(Advert $advert)
28 | {
29 | try {
30 | $this->service->remove(Auth::id(), $advert->id);
31 | } catch (\DomainException $e) {
32 | return back()->with('error', $e->getMessage());
33 | }
34 |
35 | return redirect()->route('cabinet.favorites.index');
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Cabinet/HomeController.php:
--------------------------------------------------------------------------------
1 | service = $service;
17 | }
18 |
19 | public function request()
20 | {
21 | try {
22 | $this->service->request(Auth::id());
23 | } catch (\DomainException $e) {
24 | return redirect()->back()->with('error', $e->getMessage());
25 | }
26 |
27 | return redirect()->route('cabinet.profile.phone');
28 | }
29 |
30 | public function form()
31 | {
32 | $user = Auth::user();
33 |
34 | return view('cabinet.profile.phone', compact('user'));
35 | }
36 |
37 | public function verify(PhoneVerifyRequest $request)
38 | {
39 | try {
40 | $this->service->verify(Auth::id(), $request);
41 | } catch (\DomainException $e) {
42 | return redirect()->route('cabinet.profile.phone')->with('error', $e->getMessage());
43 | }
44 |
45 | return redirect()->route('cabinet.profile.home');
46 | }
47 |
48 | public function auth()
49 | {
50 | $this->service->toggleAuth(Auth::id());
51 |
52 | return redirect()->route('cabinet.profile.home');
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Cabinet/ProfileController.php:
--------------------------------------------------------------------------------
1 | service = $service;
18 | }
19 |
20 | public function index()
21 | {
22 | $user = Auth::user();
23 |
24 | return view('cabinet.profile.home', compact('user'));
25 | }
26 |
27 | public function edit()
28 | {
29 | $user = Auth::user();
30 |
31 | return view('cabinet.profile.edit', compact('user'));
32 | }
33 |
34 | public function update(ProfileEditRequest $request)
35 | {
36 | try {
37 | $this->service->edit(Auth::id(), $request);
38 | } catch (\DomainException $e) {
39 | return redirect()->back()->with('error', $e->getMessage());
40 | }
41 | return redirect()->route('cabinet.profile.home');
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Controller.php:
--------------------------------------------------------------------------------
1 | orderBy('name')->getModels();
13 |
14 | $categories = Category::whereIsRoot()->defaultOrder()->getModels();
15 |
16 | return view('home', compact('regions', 'categories'));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/Http/Controllers/PageController.php:
--------------------------------------------------------------------------------
1 | page;
12 |
13 | return view('page', compact('page'));
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/Http/Controllers/PaymentController.php:
--------------------------------------------------------------------------------
1 | pay(Carbon::now());
30 |
31 | return 'OK' . $inv_id;
32 | }
33 |
34 | public function success(Request $request)
35 | {
36 |
37 | }
38 |
39 | public function fail(Request $request)
40 | {
41 |
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/Http/Kernel.php:
--------------------------------------------------------------------------------
1 | [
19 | \App\Http\Middleware\EncryptCookies::class,
20 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
21 | \Illuminate\Session\Middleware\StartSession::class,
22 | \Illuminate\Session\Middleware\AuthenticateSession::class,
23 | \Illuminate\View\Middleware\ShareErrorsFromSession::class,
24 | \App\Http\Middleware\VerifyCsrfToken::class,
25 | \Illuminate\Routing\Middleware\SubstituteBindings::class,
26 | ],
27 |
28 | 'api' => [
29 | 'throttle:60,1',
30 | 'bindings',
31 | ],
32 | ];
33 |
34 | protected $routeMiddleware = [
35 | 'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
36 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
37 | 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
38 | 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
39 | 'can' => \Illuminate\Auth\Middleware\Authorize::class,
40 | 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
41 | 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
42 | ];
43 | }
44 |
--------------------------------------------------------------------------------
/app/Http/Middleware/EncryptCookies.php:
--------------------------------------------------------------------------------
1 | hasFilledProfile()) {
14 | return redirect()
15 | ->route('cabinet.profile.home')
16 | ->with('error', 'Please fill your profile and verify your phone.');
17 | }
18 |
19 | return $next($request);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/Http/Middleware/RedirectIfAuthenticated.php:
--------------------------------------------------------------------------------
1 | check()) {
13 | return redirect()->route('home');
14 | }
15 |
16 | return $next($request);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/Http/Middleware/TrimStrings.php:
--------------------------------------------------------------------------------
1 | 'required|string|max:255',
18 | 'slug' => 'required|string|max:255',
19 | 'menu_title' => 'required|string|max:255',
20 | 'parent' => 'nullable|integer|exists:pages,id',
21 | 'content' => 'nullable|string',
22 | 'description' => 'nullable|string',
23 | ];
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/Http/Requests/Admin/Users/CreateRequest.php:
--------------------------------------------------------------------------------
1 | 'required|string|max:255',
18 | 'email' => 'required|string|email|max:255|unique:users',
19 | ];
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/Http/Requests/Admin/Users/UpdateRequest.php:
--------------------------------------------------------------------------------
1 | 'required|string|max:255',
23 | 'email' => 'required|string|email|max:255|unique:users,id,' . $this->user->id,
24 | 'role' => ['required', 'string', Rule::in(array_keys(User::rolesList()))]
25 | ];
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/Http/Requests/Adverts/AttributesRequest.php:
--------------------------------------------------------------------------------
1 | advert->category->allAttributes() as $attribute) {
24 | $rules = [
25 | $attribute->required ? 'required' : 'nullable',
26 | ];
27 | if ($attribute->isInteger()) {
28 | $rules[] = 'integer';
29 | } elseif ($attribute->isFloat()) {
30 | $rules[] = 'numeric';
31 | } else {
32 | $rules[] = 'string';
33 | $rules[] = 'max:255';
34 | }
35 | if ($attribute->isSelect()) {
36 | $rules[] = Rule::in($attribute->variants);
37 | }
38 | $items['attribute.' . $attribute->id] = $rules;
39 | }
40 |
41 | return $items;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/Http/Requests/Adverts/CreateRequest.php:
--------------------------------------------------------------------------------
1 | category->allAttributes() as $attribute) {
26 | $rules = [
27 | $attribute->required ? 'required' : 'nullable',
28 | ];
29 | if ($attribute->isInteger()) {
30 | $rules[] = 'integer';
31 | } elseif ($attribute->isFloat()) {
32 | $rules[] = 'numeric';
33 | } else {
34 | $rules[] = 'string';
35 | $rules[] = 'max:255';
36 | }
37 | if ($attribute->isSelect()) {
38 | $rules[] = Rule::in($attribute->variants);
39 | }
40 | $items['attribute.' . $attribute->id] = $rules;
41 | }
42 |
43 | return array_merge([
44 | 'title' => 'required|string',
45 | 'content' => 'required|string',
46 | 'price' => 'required|integer',
47 | 'address' => 'required|string',
48 | ], $items);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/Http/Requests/Adverts/EditRequest.php:
--------------------------------------------------------------------------------
1 | 'required|string',
25 | 'content' => 'required|string',
26 | 'price' => 'required|integer',
27 | 'address' => 'required|string',
28 | ];
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/Http/Requests/Adverts/PhotosRequest.php:
--------------------------------------------------------------------------------
1 | 'required|image|mimes:jpg,jpeg,png',
18 | ];
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/Http/Requests/Adverts/RejectRequest.php:
--------------------------------------------------------------------------------
1 | 'required|string',
18 | ];
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/Http/Requests/Adverts/SearchRequest.php:
--------------------------------------------------------------------------------
1 | 'nullable|string',
18 | 'attrs.*.equals' => 'nullable|string',
19 | 'attrs.*.from' => 'nullable|numeric',
20 | 'attrs.*.to' => 'nullable|numeric',
21 | ];
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/Http/Requests/Auth/LoginRequest.php:
--------------------------------------------------------------------------------
1 | 'required|string',
18 | 'password' => 'required|string',
19 | ];
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/Http/Requests/Auth/RegisterRequest.php:
--------------------------------------------------------------------------------
1 | 'required|string|max:255',
18 | 'email' => 'required|string|email|max:255|unique:users',
19 | 'password' => 'required|string|min:6|confirmed',
20 | ];
21 | }
22 | }
23 |
24 | /**
25 | * @SWG\Definition(
26 | * definition="RegisterRequest",
27 | * type="object",
28 | * @SWG\Property(property="name", type="string"),
29 | * @SWG\Property(property="email", type="string"),
30 | * @SWG\Property(property="password", type="string"),
31 | * @SWG\Property(property="password_confirmation", type="string"),
32 | * )
33 | */
--------------------------------------------------------------------------------
/app/Http/Requests/Banner/CreateRequest.php:
--------------------------------------------------------------------------------
1 | input('format')) {
20 | [$width, $height] = explode('x', $format);
21 | }
22 |
23 | return [
24 | 'name' => 'required|string',
25 | 'limit' => 'required|integer',
26 | 'url' => 'required|url',
27 | 'format' => ['required', 'string', Rule::in(Banner::formatsList())],
28 | 'file' => 'required|image|mimes:jpg,jpeg,png|dimensions:width=' . $width . ',height=' . $height,
29 | ];
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/Http/Requests/Banner/EditRequest.php:
--------------------------------------------------------------------------------
1 | 'required|string',
18 | 'limit' => 'required|integer',
19 | 'url' => 'required|url',
20 | ];
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/Http/Requests/Banner/FileRequest.php:
--------------------------------------------------------------------------------
1 | input('format')) {
20 | [$width, $height] = explode('x', $format);
21 | }
22 |
23 | return [
24 | 'format' => ['required', 'string', Rule::in(Banner::formatsList())],
25 | 'file' => 'required|image|mimes:jpg,jpeg,png|dimensions:width=' . $width . ',height=' . $height,
26 | ];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/Http/Requests/Banner/RejectRequest.php:
--------------------------------------------------------------------------------
1 | 'required|string',
18 | ];
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/Http/Requests/Cabinet/PhoneVerifyRequest.php:
--------------------------------------------------------------------------------
1 | 'required|string|max:255',
18 | ];
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/Http/Requests/Cabinet/ProfileEditRequest.php:
--------------------------------------------------------------------------------
1 | 'required|string|max:255',
18 | 'last_name' => 'required|string|max:255',
19 | 'phone' => 'required|string|max:255|regex:/^\d+$/s',
20 | ];
21 | }
22 | }
23 |
24 | /**
25 | * @SWG\Definition(
26 | * definition="ProfileEditRequest",
27 | * type="object",
28 | * @SWG\Property(property="name", type="string"),
29 | * @SWG\Property(property="last_name", type="string"),
30 | * @SWG\Property(property="phone", type="string"),
31 | * )
32 | */
--------------------------------------------------------------------------------
/app/Http/Requests/Ticket/CreateRequest.php:
--------------------------------------------------------------------------------
1 | 'required|string|max:255',
18 | 'content' => 'required|string',
19 | ];
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/Http/Requests/Ticket/EditRequest.php:
--------------------------------------------------------------------------------
1 | 'required|string|max:255',
18 | 'content' => 'required|string',
19 | ];
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/Http/Requests/Ticket/MessageRequest.php:
--------------------------------------------------------------------------------
1 | 'required|string',
18 | ];
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/Http/Resources/User/ProfileResource.php:
--------------------------------------------------------------------------------
1 | $this->id,
21 | 'email' => $this->email,
22 | 'phone' => [
23 | 'number' => $this->phone,
24 | 'verified' => $this->phone_verified,
25 | ],
26 | 'name' => [
27 | 'first' => $this->name,
28 | 'last' => $this->last_name,
29 | ],
30 | ];
31 | }
32 | }
33 |
34 | /**
35 | * @SWG\Definition(
36 | * definition="Profile",
37 | * type="object",
38 | * @SWG\Property(property="id", type="integer"),
39 | * @SWG\Property(property="email", type="string"),
40 | * @SWG\Property(property="phone", type="object",
41 | * @SWG\Property(property="number", type="string"),
42 | * @SWG\Property(property="verified", type="boolean"),
43 | * ),
44 | * @SWG\Property(property="name", type="object",
45 | * @SWG\Property(property="first", type="string"),
46 | * @SWG\Property(property="last", type="string"),
47 | * ),
48 | * )
49 | */
--------------------------------------------------------------------------------
/app/Http/Router/PagePath.php:
--------------------------------------------------------------------------------
1 | page = $page;
20 | return $clone;
21 | }
22 |
23 | public function getRouteKey()
24 | {
25 | if (!$this->page) {
26 | throw new \BadMethodCallException('Empty page.');
27 | }
28 |
29 | return Cache::tags(Page::class)->rememberForever('page_path_' . $this->page->id, function () {
30 | return $this->page->getPath();
31 | });
32 | }
33 |
34 | public function getRouteKeyName(): string
35 | {
36 | return 'page_path';
37 | }
38 |
39 | public function resolveRouteBinding($value)
40 | {
41 | $chunks = explode('/', $value);
42 |
43 | /** @var Page|null $page */
44 | $page = null;
45 | do {
46 | $slug = reset($chunks);
47 | if ($slug && $next = Page::where('slug', $slug)->where('parent_id', $page ? $page->id : null)->first()) {
48 | $page = $next;
49 | array_shift($chunks);
50 | }
51 | } while (!empty($slug) && !empty($next));
52 |
53 | if (!empty($chunks)) {
54 | abort(404);
55 | }
56 |
57 | return $this
58 | ->withPage($page);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/Http/ViewComposers/MenuPagesComposer.php:
--------------------------------------------------------------------------------
1 | with('menuPages', Page::whereIsRoot()->defaultOrder()->getModels());
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/Jobs/Advert/ReindexAdvert.php:
--------------------------------------------------------------------------------
1 | advert = $advert;
22 | }
23 |
24 | public function handle(AdvertIndexer $indexer): void
25 | {
26 | $indexer->index($this->advert);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/Listeners/Advert/AdvertChangedListener.php:
--------------------------------------------------------------------------------
1 | advert);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/Listeners/Advert/ModerationPassedListener.php:
--------------------------------------------------------------------------------
1 | advert;
13 | $advert->user->notify(new ModerationPassedNotification($advert));
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/Mail/Auth/VerifyMail.php:
--------------------------------------------------------------------------------
1 | user = $user;
18 | }
19 |
20 | public function build()
21 | {
22 | return $this
23 | ->subject('Signup Confirmation')
24 | ->markdown('emails.auth.register.verify');
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/Notifications/Advert/ModerationPassedNotification.php:
--------------------------------------------------------------------------------
1 | advert = $advert;
22 | }
23 |
24 | public function via($notifiable)
25 | {
26 | return ['mail', SmsChannel::class];
27 | }
28 |
29 | public function toMail($notifiable): MailMessage
30 | {
31 | return (new MailMessage)
32 | ->subject('Moderation is passed')
33 | ->greeting('Hello!')
34 | ->line('Your advert successfully passed a moderation.')
35 | ->action('View Advert', route('adverts.show', $this->advert))
36 | ->line('Thank you for using our application!');
37 | }
38 |
39 | public function toSms(): string
40 | {
41 | return 'Your advert successfully passed a moderation.';
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/Notifications/SmsChannel.php:
--------------------------------------------------------------------------------
1 | sender = $sender;
16 | }
17 |
18 | public function send(User $notifiable, Notification $notification): void
19 | {
20 | if (!$notifiable->isPhoneVerified()) {
21 | return;
22 | }
23 | $message = $notification->toSms($notifiable);
24 | $this->sender->send($notifiable->phone, $message);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/Providers/AppServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->singleton(CostCalculator::class, function (Application $app) {
20 | $config = $app->make('config')->get('banner');
21 | return new CostCalculator($config['price']);
22 | });
23 |
24 | Passport::ignoreMigrations();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/Providers/BroadcastServiceProvider.php:
--------------------------------------------------------------------------------
1 | classes as $class) {
22 | $this->registerFlusher($class);
23 | }
24 | }
25 |
26 | private function registerFlusher($class): void
27 | {
28 | $flush = function() use ($class) {
29 | Cache::tags($class)->flush();
30 | };
31 |
32 | /** @var Model $class */
33 | $class::created($flush);
34 | $class::saved($flush);
35 | $class::updated($flush);
36 | $class::deleted($flush);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/Providers/ComposerServiceProvider.php:
--------------------------------------------------------------------------------
1 | [
14 | AdvertChangedListener::class,
15 | ModerationPassedListener::class,
16 | ],
17 | ];
18 | }
19 |
--------------------------------------------------------------------------------
/app/Providers/RouteServiceProvider.php:
--------------------------------------------------------------------------------
1 | mapApiRoutes();
25 |
26 | $this->mapWebRoutes();
27 |
28 | //
29 | }
30 |
31 | protected function mapWebRoutes(): void
32 | {
33 | Route::middleware('web')
34 | ->namespace($this->namespace)
35 | ->group(base_path('routes/web.php'));
36 | }
37 |
38 | protected function mapApiRoutes()
39 | {
40 | Route::prefix('api')
41 | ->middleware('api')
42 | ->namespace($this->namespace)
43 | ->group(base_path('routes/api.php'));
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/Providers/SearchServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->singleton(Client::class, function (Application $app) {
15 | $config = $app->make('config')->get('elasticsearch');
16 | return ClientBuilder::create()
17 | ->setHosts($config['hosts'])
18 | ->setRetries($config['retries'])
19 | ->build();
20 | });
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/Providers/SmsServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->singleton(SmsSender::class, function (Application $app) {
16 | $config = $app->make('config')->get('sms');
17 |
18 | switch ($config['driver']) {
19 | case 'sms.ru':
20 | $params = $config['drivers']['sms.ru'];
21 | if (!empty($params['url'])) {
22 | return new SmsRu($params['app_id'], $params['url']);
23 | }
24 | return new SmsRu($params['app_id']);
25 | case 'array':
26 | return new ArraySender();
27 | default:
28 | throw new \InvalidArgumentException('Undefined SMS driver ' . $config['driver']);
29 | }
30 | });
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/Services/Banner/CostCalculator.php:
--------------------------------------------------------------------------------
1 | price = $price;
12 | }
13 |
14 | public function calc(int $views): int
15 | {
16 | return floor($this->price * ($views / 1000));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/Services/Search/BannerIndexer.php:
--------------------------------------------------------------------------------
1 | client = $client;
16 | }
17 |
18 | public function clear(): void
19 | {
20 | $this->client->deleteByQuery([
21 | 'index' => 'banners',
22 | 'type' => 'banner',
23 | 'body' => [
24 | 'query' => [
25 | 'match_all' => new \stdClass(),
26 | ],
27 | ],
28 | ]);
29 | }
30 |
31 | public function index(Banner $banner): void
32 | {
33 | $regionIds = [0];
34 | if ($banner->region) {
35 | $regionIds = [$banner->region->id];
36 | $childrenIds = $regionIds;
37 | while ($childrenIds = Region::whereIn('parent_id', $childrenIds)->pluck('id')->toArray()) {
38 | $regionIds = array_merge($regionIds, $childrenIds);
39 | }
40 | }
41 |
42 | $this->client->index([
43 | 'index' => 'banners',
44 | 'type' => 'banner',
45 | 'id' => $banner->id,
46 | 'body' => [
47 | 'id' => $banner->id,
48 | 'status' => $banner->status,
49 | 'format' => $banner->format,
50 | 'categories' => array_merge(
51 | [$banner->category->id],
52 | $banner->category->descendants()->pluck('id')->toArray()
53 | ),
54 | 'regions' => $regionIds,
55 | ],
56 | ]);
57 | }
58 |
59 | public function remove(Banner $banner): void
60 | {
61 | $this->client->delete([
62 | 'index' => 'banners',
63 | 'type' => 'banner',
64 | 'id' => $banner->id,
65 | ]);
66 | }
67 | }
--------------------------------------------------------------------------------
/app/Services/Sms/ArraySender.php:
--------------------------------------------------------------------------------
1 | messages[] = [
12 | 'to' => '+' . trim($number, '+'),
13 | 'text' => $text
14 | ];
15 | }
16 |
17 | public function getMessages(): array
18 | {
19 | return $this->messages;
20 | }
21 | }
--------------------------------------------------------------------------------
/app/Services/Sms/SmsRu.php:
--------------------------------------------------------------------------------
1 | appId = $appId;
20 | $this->url = $url;
21 | $this->client = new Client();
22 | }
23 |
24 | public function send($number, $text): void
25 | {
26 | $this->client->post($this->url, [
27 | 'form_params' => [
28 | 'api_id' => $this->appId,
29 | 'to' => '+' . trim($number, '+'),
30 | 'text' => $text
31 | ],
32 | ]);
33 | }
34 | }
--------------------------------------------------------------------------------
/app/Services/Sms/SmsSender.php:
--------------------------------------------------------------------------------
1 | getUser($userId);
13 | $advert = $this->getAdvert($advertId);
14 |
15 | $user->addToFavorites($advert->id);
16 | }
17 |
18 | public function remove($userId, $advertId): void
19 | {
20 | $user = $this->getUser($userId);
21 | $advert = $this->getAdvert($advertId);
22 |
23 | $user->removeFromFavorites($advert->id);
24 | }
25 |
26 | private function getUser($userId): User
27 | {
28 | return User::findOrFail($userId);
29 | }
30 |
31 | private function getAdvert($advertId): Advert
32 | {
33 | return Advert::findOrFail($advertId);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/UseCases/Adverts/SearchResult.php:
--------------------------------------------------------------------------------
1 | adverts = $adverts;
16 | $this->regionsCounts = $regionsCounts;
17 | $this->categoriesCounts = $categoriesCounts;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/UseCases/Auth/NetworkService.php:
--------------------------------------------------------------------------------
1 | getId())->first()) {
15 | return $user;
16 | }
17 |
18 | if ($data->getEmail() && $user = User::where('email', $data->getEmail())->exists()) {
19 | throw new \DomainException('User with this email is already registered.');
20 | }
21 |
22 | $user = DB::transaction(function () use ($network, $data) {
23 | return User::registerByNetwork($network, $data->getId());
24 | });
25 |
26 | event(new Registered($user));
27 |
28 | return $user;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/UseCases/Auth/RegisterService.php:
--------------------------------------------------------------------------------
1 | mailer = $mailer;
20 | $this->dispatcher = $dispatcher;
21 | }
22 |
23 | public function register(RegisterRequest $request): void
24 | {
25 | $user = User::register(
26 | $request['name'],
27 | $request['email'],
28 | $request['password']
29 | );
30 |
31 | $this->mailer->to($user->email)->send(new VerifyMail($user));
32 | $this->dispatcher->dispatch(new Registered($user));
33 | }
34 |
35 | public function verify($id): void
36 | {
37 | /** @var User $user */
38 | $user = User::findOrFail($id);
39 | $user->verify();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/UseCases/Profile/PhoneService.php:
--------------------------------------------------------------------------------
1 | sms = $sms;
17 | }
18 |
19 | public function request($id)
20 | {
21 | $user = $this->getUser($id);
22 |
23 | $token = $user->requestPhoneVerification(Carbon::now());
24 | $this->sms->send($user->phone, 'Phone verification token: ' . $token);
25 | }
26 |
27 | public function verify($id, PhoneVerifyRequest $request)
28 | {
29 | $user = $this->getUser($id);
30 | $user->verifyPhone($request['token'], Carbon::now());
31 | }
32 |
33 | public function toggleAuth($id): bool
34 | {
35 | $user = $this->getUser($id);
36 | if ($user->isPhoneAuthEnabled()) {
37 | $user->disablePhoneAuth();
38 | } else {
39 | $user->enablePhoneAuth();
40 | }
41 | return $user->isPhoneAuthEnabled();
42 | }
43 |
44 | private function getUser($id): User
45 | {
46 | return User::findOrFail($id);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/UseCases/Profile/ProfileService.php:
--------------------------------------------------------------------------------
1 | phone;
15 | $user->update($request->only('name', 'last_name', 'phone'));
16 | if ($user->phone !== $oldPhone) {
17 | $user->unverifyPhone();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/UseCases/Tickets/TicketService.php:
--------------------------------------------------------------------------------
1 | getTicket($id);
20 | $ticket->edit(
21 | $request['subject'],
22 | $request['content']
23 | );
24 | }
25 |
26 | public function message(int $userId, int $id, MessageRequest $request): void
27 | {
28 | $ticket = $this->getTicket($id);
29 | $ticket->addMessage($userId, $request['message']);
30 | }
31 |
32 | public function approve(int $userId, int $id): void
33 | {
34 | $ticket = $this->getTicket($id);
35 | $ticket->approve($userId);
36 | }
37 |
38 | public function close(int $userId, int $id): void
39 | {
40 | $ticket = $this->getTicket($id);
41 | $ticket->close($userId);
42 | }
43 |
44 | public function reopen(int $userId, int $id): void
45 | {
46 | $ticket = $this->getTicket($id);
47 | $ticket->reopen($userId);
48 | }
49 |
50 | public function removeByOwner(int $id): void
51 | {
52 | $ticket = $this->getTicket($id);
53 | if (!$ticket->canBeRemoved()) {
54 | throw new \DomainException('Unable to remove active ticket');
55 | }
56 | $ticket->delete();
57 | }
58 |
59 | public function removeByAdmin(int $id): void
60 | {
61 | $ticket = $this->getTicket($id);
62 | $ticket->delete();
63 | }
64 |
65 | private function getTicket($id): Ticket
66 | {
67 | return Ticket::findOrFail($id);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/helpers.php:
--------------------------------------------------------------------------------
1 | make(AdvertsPath::class)
14 | ->withRegion($region)
15 | ->withCategory($category);
16 | }
17 | }
18 |
19 | if (! function_exists('page_path')) {
20 |
21 | function page_path(Page $page)
22 | {
23 | return app()->make(PagePath::class)
24 | ->withPage($page);
25 | }
26 | }
--------------------------------------------------------------------------------
/artisan:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | make(Illuminate\Contracts\Console\Kernel::class);
34 |
35 | $status = $kernel->handle(
36 | $input = new Symfony\Component\Console\Input\ArgvInput,
37 | new Symfony\Component\Console\Output\ConsoleOutput
38 | );
39 |
40 | /*
41 | |--------------------------------------------------------------------------
42 | | Shutdown The Application
43 | |--------------------------------------------------------------------------
44 | |
45 | | Once Artisan has finished running, we will fire off the shutdown events
46 | | so that any final work may be done by the application before we shut
47 | | down the process. This is the last thing to happen to the request.
48 | |
49 | */
50 |
51 | $kernel->terminate($input, $status);
52 |
53 | exit($status);
54 |
--------------------------------------------------------------------------------
/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/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/config/banner.php:
--------------------------------------------------------------------------------
1 | env('BANNER_COST_PER_MILE')
5 | ];
--------------------------------------------------------------------------------
/config/broadcasting.php:
--------------------------------------------------------------------------------
1 | env('BROADCAST_DRIVER', 'null'),
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Broadcast Connections
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may define all of the broadcast connections that will be used
26 | | to broadcast events to other systems or over websockets. Samples of
27 | | each available type of connection are provided inside this array.
28 | |
29 | */
30 |
31 | 'connections' => [
32 |
33 | 'pusher' => [
34 | 'driver' => 'pusher',
35 | 'key' => env('PUSHER_APP_KEY'),
36 | 'secret' => env('PUSHER_APP_SECRET'),
37 | 'app_id' => env('PUSHER_APP_ID'),
38 | 'options' => [
39 | 'cluster' => env('PUSHER_APP_CLUSTER'),
40 | 'encrypted' => true,
41 | ],
42 | ],
43 |
44 | 'redis' => [
45 | 'driver' => 'redis',
46 | 'connection' => 'default',
47 | ],
48 |
49 | 'log' => [
50 | 'driver' => 'log',
51 | ],
52 |
53 | 'null' => [
54 | 'driver' => 'null',
55 | ],
56 |
57 | ],
58 |
59 | ];
60 |
--------------------------------------------------------------------------------
/config/elasticsearch.php:
--------------------------------------------------------------------------------
1 | explode(',', env('ELASTICSEARCH_HOSTS')),
5 | 'retries' => 1,
6 | ];
7 |
--------------------------------------------------------------------------------
/config/hashing.php:
--------------------------------------------------------------------------------
1 | 'bcrypt',
19 |
20 | ];
21 |
--------------------------------------------------------------------------------
/config/services.php:
--------------------------------------------------------------------------------
1 | [
18 | 'domain' => env('MAILGUN_DOMAIN'),
19 | 'secret' => env('MAILGUN_SECRET'),
20 | ],
21 |
22 | 'ses' => [
23 | 'key' => env('SES_KEY'),
24 | 'secret' => env('SES_SECRET'),
25 | 'region' => 'us-east-1',
26 | ],
27 |
28 | 'sparkpost' => [
29 | 'secret' => env('SPARKPOST_SECRET'),
30 | ],
31 |
32 | 'stripe' => [
33 | 'model' => \App\Entity\User\User::class,
34 | 'key' => env('STRIPE_KEY'),
35 | 'secret' => env('STRIPE_SECRET'),
36 | ],
37 |
38 | 'facebook' => [
39 | 'client_id' => env('FACEBOOK_CLIENT_ID'),
40 | 'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
41 | 'redirect' => env('APP_URL') . '/login/facebook/callback',
42 | ],
43 |
44 | 'twitter' => [
45 | 'client_id' => env('TWITTER_CLIENT_ID'),
46 | 'client_secret' => env('TWITTER_CLIENT_SECRET'),
47 | 'redirect' => env('APP_URL') . '/login/twitter/callback',
48 | ],
49 | ];
50 |
--------------------------------------------------------------------------------
/config/sms.php:
--------------------------------------------------------------------------------
1 | env('SMS_DRIVER', 'sms.ru'),
6 |
7 | 'drivers' => [
8 | 'sms.ru' => [
9 | 'app_id' => env('SMS_SMS_RU_APP_ID'),
10 | 'url' => env('SMS_SMS_RU_URL'),
11 | ],
12 | ],
13 | ];
--------------------------------------------------------------------------------
/config/view.php:
--------------------------------------------------------------------------------
1 | [
17 | resource_path('views'),
18 | ],
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Compiled View Path
23 | |--------------------------------------------------------------------------
24 | |
25 | | This option determines where all the compiled Blade templates will be
26 | | stored for your application. Typically, this is within the storage
27 | | directory. However, as usual, you are free to change this value.
28 | |
29 | */
30 |
31 | 'compiled' => realpath(storage_path('framework/views')),
32 |
33 | ];
34 |
--------------------------------------------------------------------------------
/database/.gitignore:
--------------------------------------------------------------------------------
1 | *.sqlite
2 |
--------------------------------------------------------------------------------
/database/factories/AdvertsCategoryFactory.php:
--------------------------------------------------------------------------------
1 | define(App\Entity\Adverts\Category::class, function (Faker $faker) {
8 | return [
9 | 'name' => $faker->unique()->name,
10 | 'slug' => $faker->unique()->slug(2),
11 | 'parent_id' => null,
12 | ];
13 | });
14 |
--------------------------------------------------------------------------------
/database/factories/RegionFactory.php:
--------------------------------------------------------------------------------
1 | define(\App\Entity\Region::class, function (Faker $faker) {
8 | return [
9 | 'name' => $faker->unique()->city,
10 | 'slug' => $faker->unique()->slug(2),
11 | 'parent_id' => null,
12 | ];
13 | });
14 |
--------------------------------------------------------------------------------
/database/factories/UserFactory.php:
--------------------------------------------------------------------------------
1 | define(User::class, function (Faker $faker) {
22 | $active = $faker->boolean;
23 | $phoneActive = $faker->boolean;
24 | return [
25 | 'name' => $faker->name,
26 | 'last_name' => $faker->lastName,
27 | 'email' => $faker->unique()->safeEmail,
28 | 'phone' => $faker->unique()->phoneNumber,
29 | 'phone_verified' => $phoneActive,
30 | 'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
31 | 'remember_token' => str_random(10),
32 | 'verify_token' => $active ? null : Str::uuid(),
33 | 'phone_verify_token' => $phoneActive ? null : Str::uuid(),
34 | 'phone_verify_token_expire' => $phoneActive ? null : Carbon::now()->addSeconds(300),
35 | 'role' => $active ? $faker->randomElement([User::ROLE_USER, User::ROLE_ADMIN]) : User::ROLE_USER,
36 | 'status' => $active ? User::STATUS_ACTIVE : User::STATUS_WAIT,
37 | ];
38 | });
39 |
--------------------------------------------------------------------------------
/database/migrations/2014_10_12_000000_create_users_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->string('name');
19 | $table->string('email')->unique();
20 | $table->string('password');
21 | $table->rememberToken();
22 | $table->timestamps();
23 | });
24 | }
25 |
26 | /**
27 | * Reverse the migrations.
28 | *
29 | * @return void
30 | */
31 | public function down()
32 | {
33 | Schema::dropIfExists('users');
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/database/migrations/2014_10_12_100000_create_password_resets_table.php:
--------------------------------------------------------------------------------
1 | string('email')->index();
18 | $table->string('token');
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/2016_06_01_000001_create_oauth_auth_codes_table.php:
--------------------------------------------------------------------------------
1 | string('id', 100)->primary();
18 | $table->integer('user_id');
19 | $table->integer('client_id');
20 | $table->text('scopes')->nullable();
21 | $table->boolean('revoked');
22 | $table->dateTime('expires_at')->nullable();
23 | });
24 | }
25 |
26 | /**
27 | * Reverse the migrations.
28 | *
29 | * @return void
30 | */
31 | public function down()
32 | {
33 | Schema::drop('oauth_auth_codes');
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/database/migrations/2016_06_01_000002_create_oauth_access_tokens_table.php:
--------------------------------------------------------------------------------
1 | string('id', 100)->primary();
18 | $table->integer('user_id')->index()->nullable();
19 | $table->integer('client_id');
20 | $table->string('name')->nullable();
21 | $table->text('scopes')->nullable();
22 | $table->boolean('revoked');
23 | $table->timestamps();
24 | $table->dateTime('expires_at')->nullable();
25 | });
26 | }
27 |
28 | /**
29 | * Reverse the migrations.
30 | *
31 | * @return void
32 | */
33 | public function down()
34 | {
35 | Schema::drop('oauth_access_tokens');
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/database/migrations/2016_06_01_000003_create_oauth_refresh_tokens_table.php:
--------------------------------------------------------------------------------
1 | string('id', 100)->primary();
18 | $table->string('access_token_id', 100)->index();
19 | $table->boolean('revoked');
20 | $table->dateTime('expires_at')->nullable();
21 | });
22 | }
23 |
24 | /**
25 | * Reverse the migrations.
26 | *
27 | * @return void
28 | */
29 | public function down()
30 | {
31 | Schema::drop('oauth_refresh_tokens');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/database/migrations/2016_06_01_000004_create_oauth_clients_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->integer('user_id')->index()->nullable();
19 | $table->string('name');
20 | $table->string('secret', 100);
21 | $table->text('redirect');
22 | $table->boolean('personal_access_client');
23 | $table->boolean('password_client');
24 | $table->boolean('revoked');
25 | $table->timestamps();
26 | });
27 | }
28 |
29 | /**
30 | * Reverse the migrations.
31 | *
32 | * @return void
33 | */
34 | public function down()
35 | {
36 | Schema::drop('oauth_clients');
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/database/migrations/2016_06_01_000005_create_oauth_personal_access_clients_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->integer('client_id')->index();
19 | $table->timestamps();
20 | });
21 | }
22 |
23 | /**
24 | * Reverse the migrations.
25 | *
26 | * @return void
27 | */
28 | public function down()
29 | {
30 | Schema::drop('oauth_personal_access_clients');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/database/migrations/2018_03_03_193348_add_user_verification.php:
--------------------------------------------------------------------------------
1 | string('status', 16);
18 | $table->string('verify_token')->nullable()->unique();
19 | });
20 |
21 | DB::table('users')->update([
22 | 'status' => 'active',
23 | ]);
24 | }
25 |
26 | /**
27 | * Reverse the migrations.
28 | *
29 | * @return void
30 | */
31 | public function down()
32 | {
33 | Schema::table('users', function (Blueprint $table) {
34 | $table->dropColumn('status');
35 | $table->dropColumn('verify_token');
36 | });
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/database/migrations/2018_03_08_100246_add_user_role.php:
--------------------------------------------------------------------------------
1 | string('role', 16);
18 | });
19 |
20 | DB::table('users')->update([
21 | 'role' => 'user',
22 | ]);
23 | }
24 |
25 | /**
26 | * Reverse the migrations.
27 | *
28 | * @return void
29 | */
30 | public function down()
31 | {
32 | Schema::table('users', function (Blueprint $table) {
33 | $table->dropColumn('role');
34 | });
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/database/migrations/2018_03_08_161503_create_regions_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->string('name')->index();
19 | $table->string('slug');
20 | $table->unsignedInteger('parent_id')->nullable();
21 | $table->timestamps();
22 | $table->unique(['parent_id', 'slug']);
23 | $table->unique(['parent_id', 'name']);
24 | });
25 |
26 | Schema::table('regions', function (Blueprint $table) {
27 | $table->foreign('parent_id')->references('id')->on('regions')->onDelete('CASCADE');
28 | });
29 | }
30 |
31 | /**
32 | * Reverse the migrations.
33 | *
34 | * @return void
35 | */
36 | public function down()
37 | {
38 | Schema::dropIfExists('regions');
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/database/migrations/2018_03_08_171503_create_advert_categories_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
19 | $table->string('name')->index();
20 | $table->string('slug');
21 | NestedSet::columns($table);
22 | });
23 | }
24 |
25 | /**
26 | * Reverse the migrations.
27 | *
28 | * @return void
29 | */
30 | public function down()
31 | {
32 | Schema::dropIfExists('advert_categories');
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/database/migrations/2018_03_10_132930_create_advert_attributes_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
13 | $table->unsignedInteger('category_id');
14 | $table->foreign('category_id')->references('id')->on('advert_categories')->onDelete('CASCADE');
15 | $table->string('name');
16 | $table->string('type');
17 | $table->boolean('required');
18 | $table->json('variants');
19 | $table->integer('sort');
20 | });
21 | }
22 |
23 | public function down()
24 | {
25 | Schema::dropIfExists('advert_attributes');
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/database/migrations/2018_03_12_083000_add_user_last_name.php:
--------------------------------------------------------------------------------
1 | string('last_name')->nullable()->after('name');
13 | });
14 | }
15 |
16 | public function down()
17 | {
18 | Schema::table('users', function (Blueprint $table) {
19 | $table->dropColumn('last_name');
20 | });
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/database/migrations/2018_03_12_090001_add_user_phone.php:
--------------------------------------------------------------------------------
1 | string('phone')->nullable()->after('email');
13 | $table->boolean('phone_verified')->default(false)->after('phone');
14 | $table->string('phone_verify_token')->nullable()->after('verify_token');
15 | $table->timestamp('phone_verify_token_expire')->nullable()->after('phone_verify_token');
16 | });
17 | }
18 |
19 | public function down()
20 | {
21 | Schema::table('users', function (Blueprint $table) {
22 | $table->dropColumn('phone_verify_token_expire');
23 | $table->dropColumn('phone_verify_token');
24 | $table->dropColumn('phone_verified');
25 | $table->dropColumn('phone');
26 | });
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/database/migrations/2018_03_12_124830_add_user_phone_auth.php:
--------------------------------------------------------------------------------
1 | boolean('phone_auth')->default(false)->after('phone');
13 | });
14 | }
15 |
16 | public function down()
17 | {
18 | Schema::table('users', function (Blueprint $table) {
19 | $table->dropColumn('phone_auth');
20 | });
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/database/migrations/2018_03_19_123423_create_advert_favorites_table.php:
--------------------------------------------------------------------------------
1 | unsignedInteger('user_id');
13 | $table->foreign('user_id')->references('id')->on('users')->onDelete('CASCADE');
14 | $table->unsignedInteger('advert_id');
15 | $table->foreign('advert_id')->references('id')->on('advert_adverts')->onDelete('CASCADE');
16 | $table->primary(['user_id', 'advert_id']);
17 | });
18 | }
19 |
20 | public function down()
21 | {
22 | Schema::dropIfExists('advert_favorites');
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/database/migrations/2018_03_22_090624_create_banners_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
13 |
14 | $table->unsignedInteger('user_id');
15 | $table->foreign('user_id')->references('id')->on('users')->onDelete('CASCADE');
16 | $table->unsignedInteger('category_id');
17 | $table->foreign('category_id')->references('id')->on('advert_categories');
18 | $table->unsignedInteger('region_id')->nullable();
19 | $table->foreign('region_id')->references('id')->on('regions');
20 | $table->string('name');
21 | $table->integer('views')->nullable();
22 | $table->integer('limit');
23 | $table->integer('clicks')->nullable();
24 | $table->integer('cost')->nullable();
25 | $table->string('url');
26 | $table->string('format');
27 | $table->string('file');
28 | $table->string('status', 16);
29 |
30 | $table->timestamps();
31 | $table->timestamp('published_at')->nullable();
32 | });
33 | }
34 |
35 | public function down()
36 | {
37 | Schema::dropIfExists('banner_banners');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/database/migrations/2018_03_25_183121_add_networks_auth.php:
--------------------------------------------------------------------------------
1 | string('email')->nullable()->change();
13 | $table->string('password')->nullable()->change();
14 | });
15 |
16 | Schema::create('user_networks', function (Blueprint $table) {
17 | $table->unsignedInteger('user_id');
18 | $table->foreign('user_id')->references('id')->on('users')->onDelete('CASCADE');
19 | $table->string('network');
20 | $table->string('identity');
21 | $table->primary(['user_id', 'identity']);
22 | });
23 | }
24 |
25 | public function down()
26 | {
27 | Schema::dropIfExists('user_networks');
28 |
29 | Schema::table('users', function (Blueprint $table) {
30 | $table->string('email')->change();
31 | $table->string('password')->change();
32 | });
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/database/migrations/2018_03_29_174253_create_pages_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
19 | $table->string('title');
20 | $table->string('menu_title')->nullable();
21 | $table->string('slug');
22 | $table->mediumText('content');
23 | $table->text('description')->nullable();
24 | $table->timestamps();
25 | NestedSet::columns($table);
26 | });
27 | }
28 |
29 | /**
30 | * Reverse the migrations.
31 | *
32 | * @return void
33 | */
34 | public function down()
35 | {
36 | Schema::dropIfExists('pages');
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/database/migrations/2018_03_30_132456_create_tickets_tables.php:
--------------------------------------------------------------------------------
1 | increments('id');
13 | $table->unsignedInteger('user_id');
14 | $table->foreign('user_id')->references('id')->on('users')->onDelete('CASCADE');
15 | $table->string('subject');
16 | $table->text('content');
17 | $table->string('status', 16);
18 | $table->timestamps();
19 | });
20 |
21 | Schema::create('ticket_statuses', function (Blueprint $table) {
22 | $table->increments('id');
23 | $table->unsignedInteger('ticket_id');
24 | $table->foreign('ticket_id')->references('id')->on('ticket_tickets')->onDelete('CASCADE');
25 | $table->unsignedInteger('user_id');
26 | $table->foreign('user_id')->references('id')->on('users')->onDelete('CASCADE');
27 | $table->string('status', 16);
28 | $table->timestamps();
29 | });
30 |
31 | Schema::create('ticket_messages', function (Blueprint $table) {
32 | $table->increments('id');
33 | $table->unsignedInteger('ticket_id');
34 | $table->foreign('ticket_id')->references('id')->on('ticket_tickets')->onDelete('CASCADE');
35 | $table->unsignedInteger('user_id');
36 | $table->foreign('user_id')->references('id')->on('users')->onDelete('CASCADE');
37 | $table->text('message');
38 | $table->timestamps();
39 | });
40 | }
41 |
42 | public function down()
43 | {
44 | Schema::dropIfExists('ticket_messages');
45 | Schema::dropIfExists('ticket_statuses');
46 | Schema::dropIfExists('ticket_tickets');
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/database/seeds/AdvertCategoriesTableSeeder.php:
--------------------------------------------------------------------------------
1 | create()->each(function(Category $category) {
11 | $counts = [0, random_int(3, 7)];
12 | $category->children()->saveMany(factory(Category::class, $counts[array_rand($counts)])->create()->each(function(Category $category) {
13 | $counts = [0, random_int(3, 7)];
14 | $category->children()->saveMany(factory(Category::class, $counts[array_rand($counts)])->create());
15 | }));
16 | });
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/database/seeds/DatabaseSeeder.php:
--------------------------------------------------------------------------------
1 | call(UsersTableSeeder::class);
10 | $this->call(RegionsTableSeeder::class);
11 | $this->call(AdvertCategoriesTableSeeder::class);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/database/seeds/RegionsTableSeeder.php:
--------------------------------------------------------------------------------
1 | create()->each(function(Region $region) {
11 | $region->children()->saveMany(factory(Region::class, random_int(3, 10))->create()->each(function(Region $region) {
12 | $region->children()->saveMany(factory(Region::class, random_int(3, 10))->make());
13 | }));
14 | });
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/database/seeds/UsersTableSeeder.php:
--------------------------------------------------------------------------------
1 | create();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/docker/nginx.docker:
--------------------------------------------------------------------------------
1 | FROM nginx:1.10
2 |
3 | ADD ./docker/nginx/default.conf /etc/nginx/conf.d/default.conf
4 | WORKDIR /var/www
5 |
--------------------------------------------------------------------------------
/docker/nginx/default.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 443 ssl;
3 | index index.php index.html;
4 | root /var/www/public;
5 |
6 | ssl on;
7 | ssl_certificate /etc/nginx/ssl/ssl-cert-snakeoil.pem;
8 | ssl_certificate_key /etc/nginx/ssl/ssl-cert-snakeoil.key;
9 |
10 | index index.html;
11 |
12 | location / {
13 | try_files $uri /index.php?$args;
14 | }
15 |
16 | location /docs {
17 | try_files $uri $uri/;
18 | }
19 |
20 | location ~ \.php$ {
21 | fastcgi_split_path_info ^(.+\.php)(/.+)$;
22 | fastcgi_pass php-fpm:9000;
23 | fastcgi_index index.php;
24 | include fastcgi_params;
25 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
26 | fastcgi_param PATH_INFO $fastcgi_path_info;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/docker/nginx/ssl/ssl-cert-snakeoil.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDAvZeSu9zk2Bx3
3 | RPR6I7Bz6YG9zqpLiWJjRoWzJrLAGEcE/5vYZScC9xEwQXR6uefzJtYgDtiWFZvG
4 | UYtG9uCadiTbFyy50EOVaZAnmgBIh3C8APyARwMkUUh+UXJA+HEY5VLzSq++qxkZ
5 | dDm341VN5X1DTbhREJPwjo16vc0MQv1BTOZQifMYykP6/NM34hAUBWOkW+n/l4z5
6 | 4lE5+KAnEB/owKvPMN3fhmojWXo9DDhOOcQcuL4JrcuA1jPtEATHJEikq9ZbIn5D
7 | Q8PQ2vTQ2+crfWg1lGNydlDC0ENmt+zrwJndX/aU0a7DiT7p/2TiMHiQbdwUqSIl
8 | 0WcEYve9AgMBAAECggEBALyzIgmr2alHGB+BKCXIeUISlE5jXoDTwbrWWaG7Ongt
9 | jKKNKmRjLB2QDIkFHGfnSPraw/rg7hWKlFdGkKhqnh07m/vQJZ7KEtDeaB8NfEeG
10 | Ks413QAuBhpxZhsd3FFVq0yngF3nekafNtSf4L5zWJoKG2hgWBststlqh4Nq/ayI
11 | 2jFg9d9VanonL5RzYpEuoXb4spmGbgs8k/+dgUnYyiCPd99iM1by7mV9CUUDrQMW
12 | TVW0SZOR5CCG2ADmBgwoWlcQFuSL+ij7M53GuFHCCtCTkk7TuQS3C5TFFxGLxamn
13 | yT9YBRploZ0cKh8zD42cEqPxY0VOFHGA9iUPli0vloECgYEA5nA6hc/OG4UuQSou
14 | 9L7dp1Kao7z32O5igdYDX2pjAMmdvmj3rFzOyAB1OYQpFx+Wt6ypVQvzGdfWKKN2
15 | PguM6rALasg9xD+4EEfWrY1xM61Wcgh8+xdUbUCxmMToLm8SyzVf7Ou075/+kz2P
16 | 54BAM0TScyYi60tC1Qx6+quFgyECgYEA1h7baG/+x8ZKKRh5SdM18ce3X0fz7Q5n
17 | Yuhme9eIKzxCzODWcdfFlzNGYy1Hgx1RbsGxHxkGcASV8P6qe56b4X0ckcOqYd48
18 | 9H3cTqx65YDwFyeMyhRkBUrt/oaQK0HDMgzfTaMX37innxAX7rqgWO0xHVr/j8Ju
19 | ho9/avm8fR0CgYA4wf/IIaz0XlNMPaWfJrvVkKUCG3M4fU7KB/qAr+V+tioiUhxe
20 | 2eUcofA9oG22glNPHjn+9piEDwNyswBWu+WTkJTfUj7UbZVafTdFPAdb4R/fqnOO
21 | LOrglgSoSied+EG6x4S/CDdiphfAEHO3Y4Fsn1Duh8AmED1/2DkaMNELwQKBgHqe
22 | wzGk6XhIkxHDxTnE7eCfaeDz2LoKBKT8yCvlu0JfSTYBEG2zjqFPKOEE/i4U7RyL
23 | ab6QW0JtLd0MSl9u7oAMYP8M2ZcgaTHuneqkFeE2nMf1y0eys7DgPzkCoK9VAs63
24 | 1m2kl7h0C/IoijwZvlgOxZC1GyOdyiPfK638hLf1AoGAMw7c6o8i7r27hooMDMNZ
25 | OVOnpdPOJA/jmKYtoYPmVX9esi1f4fCQFYOPClu0byn3NvVKqZGeExaUVz8ilckr
26 | he6uNaTZI/MU0z/+ijYDuuC/oOpXdmJqDL4s+VbAWLrYrvZ1b0yUJE+14SCPbrjH
27 | GieGGl8IqMpaFSIOILfbgUw=
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/docker/nginx/ssl/ssl-cert-snakeoil.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICsjCCAZqgAwIBAgIJALb0BZ+VhG3pMA0GCSqGSIb3DQEBBQUAMBExDzANBgNV
3 | BAMTBnVidW50dTAeFw0xMzA1MzAxNjM1NTZaFw0yMzA1MjgxNjM1NTZaMBExDzAN
4 | BgNVBAMTBnVidW50dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMC9
5 | l5K73OTYHHdE9HojsHPpgb3OqkuJYmNGhbMmssAYRwT/m9hlJwL3ETBBdHq55/Mm
6 | 1iAO2JYVm8ZRi0b24Jp2JNsXLLnQQ5VpkCeaAEiHcLwA/IBHAyRRSH5RckD4cRjl
7 | UvNKr76rGRl0ObfjVU3lfUNNuFEQk/COjXq9zQxC/UFM5lCJ8xjKQ/r80zfiEBQF
8 | Y6Rb6f+XjPniUTn4oCcQH+jAq88w3d+GaiNZej0MOE45xBy4vgmty4DWM+0QBMck
9 | SKSr1lsifkNDw9Da9NDb5yt9aDWUY3J2UMLQQ2a37OvAmd1f9pTRrsOJPun/ZOIw
10 | eJBt3BSpIiXRZwRi970CAwEAAaMNMAswCQYDVR0TBAIwADANBgkqhkiG9w0BAQUF
11 | AAOCAQEAVQoXrlGlJkYob3h9sQmuF9B086j9+ejh+GB2ILTWDP7DHOOSFh5yCLVu
12 | 2m251uXfRSy40RTM4ZfiQRZGtq6qCxIEaDieHCG/86tTCktl5XvoQjz4Loz11iDo
13 | RTLXolb4OBCeOc/bVud4O0ql14/QuLh+kIGfYoFYW4uiPEWV+N3awpodItQpYPgj
14 | zjSoPj5Ppj0sAeZ6SVmucSMQNPy8lm7JqNPBvBZSk1YXDvCiukaDXNPjFNhb1mMN
15 | kW3l/T61SlOFvQoq72dod/JKga4BGN5SFrMIaLYkXoxgK8yaFRMuyAG4+Jc806ad
16 | W7D/YjYYGZeCh6wssbb6+RFZw2g6kA==
17 | -----END CERTIFICATE-----
18 |
--------------------------------------------------------------------------------
/docker/php-cli.docker:
--------------------------------------------------------------------------------
1 | FROM php:7.1-cli
2 |
3 | RUN apt-get update && apt-get install -y libmcrypt-dev mariadb-client wget unzip \
4 | && docker-php-ext-install mcrypt pdo_mysql pcntl
5 |
6 | RUN wget https://getcomposer.org/installer -O - -q | php -- --version=1.9.1 --install-dir=/bin --filename=composer --quiet
7 |
8 | ENV COMPOSER_ALLOW_SUPERUSER 1
9 |
10 | WORKDIR /var/www
11 |
--------------------------------------------------------------------------------
/docker/php-fpm.docker:
--------------------------------------------------------------------------------
1 | FROM php:7.1-fpm
2 |
3 | RUN apt-get update && apt-get install -y libmcrypt-dev mariadb-client \
4 | && docker-php-ext-install mcrypt pdo_mysql
5 |
6 | WORKDIR /var/www
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "dev": "npm run development",
5 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
6 | "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
7 | "watch-poll": "npm run watch -- --watch-poll",
8 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
9 | "prod": "npm run production",
10 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
11 | },
12 | "devDependencies": {
13 | "axios": "^0.17",
14 | "bootstrap": "^4.0.0",
15 | "cross-env": "^5.1",
16 | "font-awesome": "^4.7.0",
17 | "jquery": "^3.2",
18 | "laravel-mix": "^2.0",
19 | "lodash": "^4.17.4",
20 | "popper.js": "^1.12",
21 | "summernote": "^0.8.10"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
ID | {{ $category->id }} | 19 |
---|---|
Name | {{ $category->name }} | 22 |
Slug | {{ $category->slug }} | 25 |
ID | {{ $page->id }} | 19 |
---|---|
Title | {{ $page->title }} | 22 |
Menu Title | {{ $page->menu_title }} | 25 |
Slug | {{ $page->slug }} | 28 |
Description | {{ $page->description }} | 31 |
Name | 5 |Slug | 6 |
---|---|
{{ $region->name }} | 13 |{{ $region->slug }} | 14 |
ID | {{ $region->id }} | 19 |
---|---|
Name | {{ $region->name }} | 22 |
Slug | {{ $region->slug }} | 25 |
ID | {{ $user->id }} | 27 |
---|---|
Name | {{ $user->name }} | 30 |
{{ $user->email }} | 33 ||
Status | 36 |37 | @if ($user->isWait()) 38 | Waiting 39 | @endif 40 | @if ($user->isActive()) 41 | Active 42 | @endif 43 | | 44 |
Role | 47 |48 | @if ($user->isAdmin()) 49 | Admin 50 | @else 51 | User 52 | @endif 53 | | 54 |
Choose category:
7 | 8 | @include('cabinet.adverts.create._categories', ['categories' => $categories]) 9 | 10 | @endsection -------------------------------------------------------------------------------- /resources/views/cabinet/adverts/create/region.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 | @include('cabinet.adverts._nav') 5 | 6 | @if ($region) 7 |8 | Add Advert for {{ $region->name }} 9 |
10 | @else 11 |12 | Add Advert for all regions 13 |
14 | @endif 15 | 16 |Or choose nested region:
17 | 18 |ID | 10 |Updated | 11 |Title | 12 |Region | 13 |Category | 14 |Status | 15 |
---|---|---|---|---|---|
{{ $advert->id }} | 22 |{{ $advert->updated_at }} | 23 |{{ $advert->title }} | 24 |25 | @if ($advert->region) 26 | {{ $advert->region->name }} 27 | @endif 28 | | 29 |{{ $advert->category->name }} | 30 |31 | @if ($advert->isDraft()) 32 | Draft 33 | @elseif ($advert->isOnModeration()) 34 | Moderation 35 | @elseif ($advert->isActive()) 36 | Active 37 | @elseif ($advert->isClosed()) 38 | Closed 39 | @endif 40 | | 41 |
Choose category:
7 | 8 | @include('cabinet.banners.create._categories', ['categories' => $categories]) 9 | 10 | @endsection -------------------------------------------------------------------------------- /resources/views/cabinet/banners/create/region.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 | @include('cabinet.banners._nav') 5 | 6 | @if ($region) 7 |8 | Add Advert for {{ $region->name }} 9 |
10 | @else 11 |12 | Add Advert for all regions 13 |
14 | @endif 15 | 16 |Or choose nested region:
17 | 18 |ID | 10 |Updated | 11 |Title | 12 |Region | 13 |Category | 14 |15 | |
---|---|---|---|---|---|
{{ $advert->id }} | 22 |{{ $advert->updated_at }} | 23 |{{ $advert->title }} | 24 |25 | @if ($advert->region) 26 | {{ $advert->region->name }} 27 | @endif 28 | | 29 |{{ $advert->category->name }} | 30 |31 | 36 | | 37 |
First Name | {{ $user->name }} | 14 |
---|---|
Last Name | {{ $user->last_name }} | 17 |
{{ $user->email }} | 20 ||
Phone |
23 | @if ($user->phone)
24 | {{ $user->phone }}
25 | @if (!$user->isPhoneVerified())
26 | (is not verified) 27 | 31 | @endif 32 | @endif 33 | |
34 |
Two Factor Auth | 38 | 46 | | 47 |
ID | 12 |Created | 13 |Updated | 14 |Subject | 15 |Status | 16 |
---|---|---|---|---|
{{ $ticket->id }} | 23 |{{ $ticket->created_at }} | 24 |{{ $ticket->updated_at }} | 25 |{{ $ticket->subject }} | 26 |27 | @if ($ticket->isOpen()) 28 | Open 29 | @elseif ($ticket->isApproved()) 30 | Approved 31 | @elseif ($ticket->isClosed()) 32 | Closed 33 | @endif 34 | | 35 |