This commit is contained in:
2025-09-25 03:03:31 +05:00
commit ae480cf2f6
2768 changed files with 1485826 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
<?php
namespace App\Providers;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\ServiceProvider;
use Spatie\Translatable\HasTranslations;
class ApiServiceProvider extends ServiceProvider
{
/**
* Register services.
*/
public function register(): void
{
//
}
/**
* Bootstrap services.
*/
public function boot(): void
{
/**
* REST response (JSON syntactic-sugar)
*
* @param mixed $data
* @param int $status_code
* @param string $message
* @return \Illuminate\Http\JsonResponse
*/
Response::macro('rest', function (mixed $data = [], int $code = 200, string $message = 'success'): JsonResponse {
return response()->json(['message' => $message, 'data' => $data], $code);
});
/**
* REST response (JSON syntactic-sugar)
*
* @param mixed $data
* @param int $status_code
* @param string $message
* @return \Illuminate\Http\JsonResponse
*/
Response::macro('rest_paginate', function (mixed $data, int $code = 200, string $message = 'success'): JsonResponse {
return response()->json([
'message' => $message,
'data' => $data->items(),
'pagination' => [
'page' => $data->currentPage(),
'perPage' => $data->perPage(),
'count' => $data->count(),
'first_page_url' => $data->url(1),
'next_page_url' => $data->nextPageUrl(),
'prev_page_url' => $data->previousPageUrl(),
],
], $code);
});
/**
* Order by translation for spatie/laravel-translatable
*
* @param string $field
* @param string $order
* @param string $locale
* @return \Illuminate\Database\Eloquent\Builder
*/
Builder::macro('orderByTranslation', function (string $field, string $order = 'asc', ?string $locale = null) {
if (
in_array(HasTranslations::class, class_uses($this->model))
&& in_array($field, $this->model->translatable)
&& config('database.default') === 'pgsql'
) {
$locale = $locale ?? app()->getLocale();
$this->query->orderByRaw("$field->>'$locale' $order");
} else {
$this->query->orderBy($field, $order);
}
return $this;
});
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Providers;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Model::shouldBeStrict(! app()->isProduction());
Relation::morphMap(config('ecommerce.models'));
$this->loadMigrationsFrom($this->findModuleMigrations());
// $this->listenDB();
}
/**
* Find Module migrations
*
* @return array<int, string>
*/
public function findModuleMigrations(): array
{
/** @var array<int, string> */
$modulesDir = scandir(modules_path());
$migrationDirectories = [];
foreach ($modulesDir as $module) {
if (is_dir(modules_path($module.'/Database/Migrations'))) {
$migrationDirectories[] = modules_path($module.'/Database/Migrations');
}
}
return $migrationDirectories;
}
public function listenDB(): void
{
if (! app()->isLocal()) {
return;
}
DB::listen(function ($query) {
Log::info($query->sql, $query->bindings, $query->time);
});
}
}

View File

@@ -0,0 +1,141 @@
<?php
namespace App\Providers;
use App\Models\CMS\Forms\ContactUS;
use App\Models\CMS\Marketing\Newsletter;
use App\Models\CMS\Marketing\NewsletterUser;
use App\Models\CMS\Media\Banner;
use App\Models\CMS\Media\Carousel;
use App\Models\CMS\Media\Gallery;
use App\Models\Ecommerce\Channel\Channel;
use App\Models\Ecommerce\Payouts\Payout;
use App\Models\Ecommerce\Product\Brand\Brand;
use App\Models\Ecommerce\Product\Category\Category;
use App\Models\Ecommerce\Product\Collection\Collection;
use App\Models\Ecommerce\Product\Coupon\Coupon;
use App\Models\Ecommerce\Product\Inventory\Inventory;
use App\Models\Ecommerce\Product\Order\Order;
use App\Models\Ecommerce\Product\Order\OrderItem;
use App\Models\Ecommerce\Product\Product\Product;
use App\Models\Ecommerce\Product\Property\Attribute;
use App\Models\Ecommerce\Product\Review\Review;
use App\Models\Legal\LegalPage;
use App\Models\Post\PostBranch;
use App\Models\System\Roles\Permission;
use App\Models\System\Roles\Role;
use App\Models\System\Settings\Location\Province;
use App\Models\System\Settings\Payments\PaymentType;
use App\Models\System\VersionManagement\AppVersion;
use App\Models\User;
use App\Policies\CMS\Forms\ContactUSPolicy;
use App\Policies\CMS\Marketing\NewsletterPolicy;
use App\Policies\CMS\Marketing\NewsletterUserPolicy;
use App\Policies\CMS\Media\BannerPolicy;
use App\Policies\CMS\Media\CarouselPolicy;
use App\Policies\CMS\Media\GalleryPolicy;
use App\Policies\Ecommerce\Channel\ChannelPolicy;
use App\Policies\Ecommerce\Payout\PayoutPolicy;
use App\Policies\Ecommerce\Product\Brand\BrandPolicy;
use App\Policies\Ecommerce\Product\Category\CategoryPolicy;
use App\Policies\Ecommerce\Product\Collection\CollectionPolicy;
use App\Policies\Ecommerce\Product\Coupon\CouponPolicy;
use App\Policies\Ecommerce\Product\Inventory\InventoryPolicy;
use App\Policies\Ecommerce\Product\Order\OrderItemPolicy;
use App\Policies\Ecommerce\Product\Order\OrderPolicy;
use App\Policies\Ecommerce\Product\Product\ProductPolicy;
use App\Policies\Ecommerce\Product\Property\AttributePolicy;
use App\Policies\Ecommerce\Product\Review\ReviewPolicy;
use App\Policies\Legal\LegalPagePolicy;
use App\Policies\Post\PostBranchPolicy;
use App\Policies\System\Roles\PermissionPolicy;
use App\Policies\System\Roles\RolePolicy;
use App\Policies\System\Settings\Location\ProvincePolicy;
use App\Policies\System\Settings\Payments\PaymentTypePolicy;
use App\Policies\System\VersionManagement\AppVersionPolicy;
use App\Policies\UserPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
class AuthServiceProvider extends ServiceProvider
{
/**
* The model to policy mappings for the application.
*
* @var array<class-string, class-string>
*/
protected $policies = [
// Orders...
Order::class => OrderPolicy::class,
OrderItem::class => OrderItemPolicy::class,
// Products...
Product::class => ProductPolicy::class,
Coupon::class => CouponPolicy::class,
Review::class => ReviewPolicy::class,
// Product Attributes...
Attribute::class => AttributePolicy::class,
// Inventories...
Inventory::class => InventoryPolicy::class,
// Channels...
Channel::class => ChannelPolicy::class,
// Collectons...
Collection::class => CollectionPolicy::class,
// Categories...
Category::class => CategoryPolicy::class,
// Brands...
Brand::class => BrandPolicy::class,
// Users...
User::class => UserPolicy::class,
// Carousels...
Carousel::class => CarouselPolicy::class,
Payout::class => PayoutPolicy::class,
// CMS...
Gallery::class => GalleryPolicy::class,
LegalPage::class => LegalPagePolicy::class,
ContactUS::class => ContactUSPolicy::class,
// Marketing...
Newsletter::class => NewsletterPolicy::class,
NewsletterUser::class => NewsletterUserPolicy::class,
// Banners...
Banner::class => BannerPolicy::class,
// Permissions (settings)...
Role::class => RolePolicy::class,
Permission::class => PermissionPolicy::class,
// Location (settings)...
Province::class => ProvincePolicy::class,
PostBranch::class => PostBranchPolicy::class,
// App settings...
AppVersion::class => AppVersionPolicy::class,
// Order settings...
PaymentType::class => PaymentTypePolicy::class,
];
/**
* Register any authentication / authorization services.
*/
public function boot(): void
{
Gate::define('isMe', fn ($user) => $user->isMe());
Gate::define('isAdmin', fn ($user) => $user->isAdmin());
Gate::define('systemUser', fn ($user) => $user->isMe() || $user->hasRole(['admin', 'manager']));
Gate::define('vendor', fn ($user) => $user->hasRole('vendor'));
Gate::define('isVendor', fn ($user) => $user->hasRole('vendor'));
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;
class BroadcastServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Broadcast::routes();
require base_path('routes/channels.php');
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace App\Providers;
use App\Events\Ecommerce\Channel\ChannelActiveStateChanged;
use App\Events\Ecommerce\Product\Category\CategoryTaxChanged;
use App\Events\Ecommerce\Product\Order\OrderCreated;
use App\Listeners\Ecommerce\Category\UpdateCategoryProductsPriceByTax;
use App\Listeners\Ecommerce\Channel\HideChannelProducts;
use App\Listeners\Ecommerce\Order\SendOrderCreatedNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event to listener mappings for the application.
*
* @var array<class-string, array<int, class-string>>
*/
protected $listen = [
// Orders...
OrderCreated::class => [
SendOrderCreatedNotification::class,
],
// Categories...
CategoryTaxChanged::class => [
UpdateCategoryProductsPriceByTax::class,
],
// Channel is active state changed...
ChannelActiveStateChanged::class => [
HideChannelProducts::class,
],
];
/**
* Register any events for your application.
*/
public function boot(): void
{
//
}
/**
* Determine if events and listeners should be automatically discovered.
*/
public function shouldDiscoverEvents(): bool
{
return false;
}
}

View File

@@ -0,0 +1,269 @@
<?php
namespace App\Providers;
use App\Modules\GlobalOrder\Nova\Resources\GlobalOrderResource;
use App\Nova\Dashboards\Main;
use App\Nova\Resources\CMS\Forms\ContactUS;
use App\Nova\Resources\CMS\Marketing\Newsletter;
use App\Nova\Resources\CMS\Marketing\NewsletterUser;
use App\Nova\Resources\CMS\Media\Banner;
use App\Nova\Resources\CMS\Media\Carousel;
use App\Nova\Resources\CMS\Media\Gallery;
use App\Nova\Resources\Ecommerce\Channel\Channel;
use App\Nova\Resources\Ecommerce\Payout\PayoutResource;
use App\Nova\Resources\Ecommerce\Product\Attribute\Attribute;
use App\Nova\Resources\Ecommerce\Product\Brand\Brand;
use App\Nova\Resources\Ecommerce\Product\Category\Category;
use App\Nova\Resources\Ecommerce\Product\Collection\Collection;
use App\Nova\Resources\Ecommerce\Product\Coupon\Coupon;
use App\Nova\Resources\Ecommerce\Product\Inventory\Inventory;
use App\Nova\Resources\Ecommerce\Product\Inventory\InventoryHistoryRemovedResource;
use App\Nova\Resources\Ecommerce\Product\Inventory\InventoryHistoryResource;
use App\Nova\Resources\Ecommerce\Product\Order\Order;
use App\Nova\Resources\Ecommerce\Product\Product\Product;
use App\Nova\Resources\Ecommerce\Product\Review\Review;
use App\Nova\Resources\Legal\LegalPage;
use App\Nova\Resources\Post\PostBranch\PostBranch;
use App\Nova\Resources\System\Payments\PaymentType;
use App\Nova\Resources\System\Roles\Permission;
use App\Nova\Resources\System\Roles\Role;
use App\Nova\Resources\System\Settings\Location\Province\Province;
use App\Nova\Resources\System\VersionManagement\AppVersion;
use App\Nova\Seller\Seller;
use App\Nova\User;
use App\Repositories\Nova\NovaRepo;
use Eolica\NovaLocaleSwitcher\LocaleSwitcher;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Laravel\Nova\Events\ServingNova;
use Laravel\Nova\Fields\Field;
use Laravel\Nova\Menu\MenuGroup;
use Laravel\Nova\Menu\MenuItem;
use Laravel\Nova\Menu\MenuSection;
use Laravel\Nova\Nova;
use Laravel\Nova\NovaApplicationServiceProvider;
class NovaServiceProvider extends NovaApplicationServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
parent::boot();
Nova::withoutNotificationCenter();
Nova::withBreadcrumbs(NovaRepo::breadcrumbs());
Nova::footer(NovaRepo::footer());
$this->setupNavigation();
$this->setupUserSettings();
$this->addAssets();
$this->setupFieldMacros();
}
/**
* Register the Nova routes.
*/
protected function routes(): void
{
Nova::routes()
->withAuthenticationRoutes()
->withPasswordResetRoutes()
->register();
}
/**
* Register the Nova gate.
*
* This gate determines who can access Nova in non-local environments.
*/
protected function gate(): void
{
Gate::define('viewNova', NovaRepo::canViewNova());
Gate::define('viewLogs', fn ($user) => $user->isMe());
Gate::define('downloadLogs', fn ($user) => $user->isMe());
Gate::define('deleteLogs', fn ($user) => $user->isMe());
}
/**
* Get the dashboards that should be listed in the Nova sidebar.
*/
protected function dashboards(): array
{
return [
new Main,
];
}
/**
* Get the tools that should be listed in the Nova sidebar.
*/
public function tools(): array
{
return [
LocaleSwitcher::make()
->setLocales(config('app.locales'))
->onSwitchLocale(NovaRepo::localeSwitcherSave()),
];
}
/**
* Setup user settings
*/
public function setupUserSettings(): void
{
Nova::serving(fn (ServingNova $event) => NovaRepo::serving($event));
}
/**
* Setup navigation
*/
public function setupNavigation(): void
{
Nova::mainMenu(function (Request $request) {
return [
MenuSection::dashboard(Main::class)->icon('chart-bar'),
MenuSection::make(__('Orders'), [
MenuItem::resource(Order::class),
])->icon('shopping-cart')->collapsedByDefault(),
MenuSection::make(__('E-commerce'), [
MenuSection::make(__('Products'), [
MenuItem::resource(Product::class),
MenuItem::resource(Review::class),
])->icon('cube'),
MenuSection::make(__('Inventory'), [
MenuItem::resource(Inventory::class),
MenuItem::resource(InventoryHistoryResource::class),
MenuItem::resource(InventoryHistoryRemovedResource::class),
])->icon('office-building'),
MenuSection::make(__('Category'), [
MenuItem::resource(Channel::class),
MenuItem::resource(Collection::class),
MenuItem::resource(Category::class),
MenuItem::resource(Brand::class),
MenuItem::resource(Attribute::class),
])->icon('color-swatch'),
])->icon('shopping-bag')->collapsedByDefault(),
MenuSection::make(__('Users'), [
MenuItem::resource(Seller::class),
MenuItem::resource(User::class),
])->icon('users')->collapsedByDefault(),
MenuSection::make(__('Global orders'), [
MenuItem::resource(GlobalOrderResource::class),
])->icon('globe')->collapsedByDefault(),
MenuSection::make(__('Payouts'), [
MenuItem::resource(PayoutResource::class),
])->icon('credit-card')->collapsedByDefault(),
MenuSection::make(__('CMS'), [
MenuGroup::make(__('Media'), [
MenuItem::resource(Banner::class),
MenuItem::resource(Carousel::class),
MenuItem::resource(Gallery::class),
])->collapsedByDefault(),
MenuGroup::make(__('Legal'), [
MenuItem::resource(LegalPage::class),
])->collapsedByDefault(),
])->icon('newspaper')->collapsedByDefault(),
MenuSection::make(__('Marketing'), [
MenuItem::resource(NewsletterUser::class),
MenuItem::resource(Newsletter::class),
MenuItem::resource(Coupon::class),
])->icon('presentation-chart-bar')->collapsedByDefault(),
MenuSection::make('Hatlar', [
MenuItem::resource(ContactUS::class),
])->icon('inbox-in')->collapsedByDefault(),
MenuSection::make(__('System'), [
MenuGroup::make(__('User'), [
MenuItem::resource(Role::class),
MenuItem::resource(Permission::class),
])->collapsedByDefault(),
MenuGroup::make(__('Location'), [
MenuItem::resource(Province::class),
MenuItem::resource(PostBranch::class),
])->collapsedByDefault(),
MenuGroup::make(__('Payment types'), [
MenuItem::resource(PaymentType::class),
])->collapsedByDefault(),
MenuGroup::make(__('App'), [
MenuItem::resource(AppVersion::class),
])->collapsedByDefault(),
])->icon('cog')->collapsedByDefault(),
];
});
}
/**
* Add custom assets
*/
public function addAssets(): void
{
Nova::style('additional', public_path('assets/panel/css/additional.css'));
Nova::script('additional', public_path('assets/panel/js/additional.js'));
}
/**
* Setup macros of fields
*/
public function setupFieldMacros(): void
{
Field::macro('defaultStringRules', function () {
$this->rules('required', 'string', 'max:255');
return $this;
});
Field::macro('phoneNumberRule', function () {
$this->rules('required', 'integer', 'between:61000000,71999999');
return $this;
});
Field::macro('turkmenDate', function () {
$this->displayUsing(fn ($value) => $value?->format('H:i, d.m.Y'));
return $this;
});
Field::macro('showWhen', function ($condition) {
$condition === true ? $this->show() : $this->hide();
return $this;
});
}
/**
* Register the application's Nova resources.
*/
protected function resources(): void
{
Nova::resourcesIn(app_path('Nova'));
Nova::resourcesIn(app_path('Modules'));
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace App\Providers;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
/**
* The path to your application's "home" route.
*
* Typically, users are redirected here after authentication.
*
* @var string
*/
public const HOME = '/';
/**
* Define your route model bindings, pattern filters, and other route configuration.
*/
public function boot(): void
{
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(1000)->by($request->user()?->id ?: $request->ip());
});
$this->routes(function () {
Route::middleware('api')
->prefix('api')
->group(base_path('routes/api/base_api.php'));
Route::middleware(['api', 'api_token', 'set_lang'])
->prefix('api/v1')
->name('api.')
->group(base_path('routes/api/v1/v1-api.php'));
Route::middleware(['api', 'api_token', 'set_lang'])
->prefix('api/v1/vendor')
->name('api.vendor.')
->group(base_path('routes/api/v1/vendor/vendor-api.php'));
Route::middleware('web')
->group(base_path('routes/web.php'));
});
}
}