diff --git a/resources/lang/ru/messages.php b/resources/lang/ru/messages.php
new file mode 100644
index 0000000..e2e739c
--- /dev/null
+++ b/resources/lang/ru/messages.php
@@ -0,0 +1,151 @@
+ 'Магазин',
+ 'welcome' => 'Добро пожаловать в магазин!',
+
+ 'buy' => 'Купить',
+
+ 'free' => 'Бесплатно',
+
+ 'periods' => [
+ 'hours' => 'часов',
+ 'days' => 'дней',
+ 'weeks' => 'недель',
+ 'months' => 'месяцев',
+ 'years' => 'лет',
+ ],
+
+ 'fields' => [
+ 'balance' => 'Баланс',
+ 'category' => 'Категория',
+ 'code' => 'Код',
+ 'commands' => 'Команды',
+ 'currency' => 'Валюта',
+ 'discount' => 'Скидка',
+ 'expire_date' => 'Дата окончания',
+ 'gateways' => 'Платежные системы',
+ 'global_limit' => 'Глобальный лимит покупок',
+ 'original_balance' => 'Начальный баланс',
+ 'package' => 'Товар',
+ 'packages' => 'Товары',
+ 'payment_id' => 'ID платежа',
+ 'payments' => 'Платежи',
+ 'price' => 'Цена',
+ 'quantity' => 'Количество',
+ 'renewal_date' => 'Дата продления',
+ 'required' => 'Обязательно',
+ 'required_packages' => 'Необходимые товары',
+ 'required_roles' => 'Необходимая роль',
+ 'role' => 'Роль после покупки',
+ 'start_date' => 'Дата начала',
+ 'subscription' => 'Подписка',
+ 'subscription_id' => 'ID подписки',
+ 'total' => 'Итого',
+ 'user_id' => 'ID пользователя',
+ 'user_limit' => 'Лимит покупок пользователя',
+ ],
+
+ 'actions' => [
+ 'subscribe' => 'Подписаться',
+ 'manage' => 'Управлять подпиской',
+ 'move' => 'Переместить',
+ ],
+
+ 'goal' => [
+ 'title' => 'Цель месяца',
+ 'progress' => 'Выполнено: :count%',
+ ],
+
+ 'recent' => [
+ 'title' => 'Последние платежи',
+ 'empty' => 'Нет недавних платежей',
+ ],
+
+ 'top' => [
+ 'title' => 'Лучший покупатель',
+ ],
+
+ 'cart' => [
+ 'title' => 'Корзина',
+ 'success' => 'Покупка успешно завершена.',
+ 'guest' => 'Для покупки необходимо войти.',
+ 'empty' => 'Ваша корзина пуста.',
+ 'checkout' => 'Оформить',
+ 'clear' => 'Очистить корзину',
+ 'pay' => 'Оплатить',
+ 'back' => 'Назад в магазин',
+ 'total' => 'Итого: :total',
+ 'payable_total' => 'К оплате: :total',
+ 'credit' => 'Кредит',
+
+ 'confirm' => [
+ 'title' => 'Оплатить?',
+ 'price' => 'Вы уверены, что хотите купить корзину за :price?',
+ ],
+
+ 'errors' => [
+ 'money' => 'У вас недостаточно средств для покупки.',
+ 'execute' => 'Произошла ошибка при оплате, покупка отменена.',
+ ],
+ ],
+
+ 'coupons' => [
+ 'title' => 'Купоны',
+ 'add' => 'Добавить купон',
+ 'error' => 'Купон не существует, истёк или больше не может быть использован.',
+ 'cumulate' => 'Вы не можете использовать этот купон с другим.',
+ ],
+
+ 'payment' => [
+ 'title' => 'Оплата',
+ 'manual' => 'Ручная оплата',
+
+ 'empty' => 'Нет доступных методов оплаты.',
+
+ 'info' => 'Покупка №:id на :website: :items',
+ 'subscription' => ':package - Подписка (Пользователь #:user)',
+ 'error' => 'Не удалось выполнить платеж, попробуйте позже.',
+ 'giftcards' => 'Подарочные карты',
+
+ 'success' => 'Платеж завершён, вы получите покупку в игре менее чем через минуту.',
+ 'pending' => 'Платеж ожидает подтверждения, покупка будет доставлена после подтверждения.',
+
+ 'webhook' => 'Новый платеж в магазине',
+ 'webhook_info' => 'Сумма: :total, ID: :id (:gateway)',
+ 'webhook_chargeback' => 'Чарджбэк платежа в магазине',
+ 'webhook_refund' => 'Возврат платежа в магазине',
+ ],
+
+ 'categories' => [
+ 'empty' => 'Эта категория пуста.',
+ ],
+
+ 'packages' => [
+ 'limit' => 'Вы купили максимальное количество этого товара.',
+ 'requirements' => 'Вы не соответствуете требованиям для покупки этого товара.',
+ 'cumulate' => 'Вы не можете купить этот товар вместе с другим из той же категории в одной покупке.',
+ 'file' => 'Нажмите здесь, чтобы скачать файл :file',
+ ],
+
+ 'offers' => [
+ 'gateway' => 'Тип оплаты',
+ 'amount' => 'Сумма',
+
+ 'empty' => 'Нет доступных предложений.',
+ ],
+
+ 'profile' => [
+ 'payments' => 'Ваши платежи',
+ 'subscriptions' => 'Ваши подписки',
+ 'money' => 'Деньги: :balance',
+ ],
+
+ 'giftcards' => [
+ 'title' => 'Подарочные карты',
+ 'error' => 'Подарочная карта не существует, истекла или больше не может быть использована.',
+ 'add' => 'Добавить подарочную карту',
+ 'notification' => 'Вы получили подарочную карту, код: :code (:balance).',
+ 'pending' => 'Платеж для этой карты уже начат. Завершите платеж или подождите несколько минут.',
+ ],
+];
diff --git a/resources/views/admin/settings.blade.php b/resources/views/admin/settings.blade.php
index 766961f..b88e72c 100644
--- a/resources/views/admin/settings.blade.php
+++ b/resources/views/admin/settings.blade.php
@@ -29,6 +29,16 @@
{{ trans('shop::admin.settings.use_site_money_info') }}
+
+
+
+
+
+
+
+
+
+
diff --git a/routes/web.php b/routes/web.php
index aea28c5..c9f6dfa 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -9,6 +9,7 @@
use Azuriom\Plugin\Shop\Controllers\PaymentController;
use Azuriom\Plugin\Shop\Controllers\ProfileController;
use Azuriom\Plugin\Shop\Controllers\SubscriptionController;
+use Azuriom\Plugin\Shop\Controllers\CartAuthController;
use Illuminate\Support\Facades\Route;
/*
@@ -30,11 +31,11 @@
Route::resource('packages', PackageController::class)->only('show');
-Route::prefix('packages/{package}')->name('packages.')->middleware('auth')->group(function () {
+Route::prefix('packages/{package}')->name('packages.')->group(function () {
Route::post('/buy', [PackageController::class, 'buy'])->name('buy');
Route::get('/options', [PackageController::class, 'showVariables']);
Route::post('/options', [PackageController::class, 'buy'])->name('variables');
- Route::get('/files/{file}', [PackageController::class, 'downloadFile'])->name('file');
+ Route::get('/files/{file}', [PackageController::class, 'downloadFile'])->middleware('auth')->name('file');
});
Route::prefix('offers')->name('offers.')->middleware('verified')->group(function () {
@@ -43,9 +44,10 @@
Route::post('/{offer:id}/{gateway:type}', [OfferController::class, 'pay'])->name('pay');
});
-Route::prefix('cart')->name('cart.')->middleware('auth')->group(function () {
+Route::prefix('cart')->name('cart.')->group(function () {
Route::get('/', [CartController::class, 'index'])->name('index');
Route::post('/', [CartController::class, 'update'])->name('update');
+ Route::post('/register', [CartAuthController::class, 'register'])->name('register');
// TODO Match multiple methods is not really good here...
Route::match(['GET', 'POST'], '/remove/{package}', [CartController::class, 'remove'])->name('remove');
Route::post('/clear', [CartController::class, 'clear'])->name('clear');
diff --git a/src/Controllers/Admin/SettingController.php b/src/Controllers/Admin/SettingController.php
index de81ccb..7fd3aed 100644
--- a/src/Controllers/Admin/SettingController.php
+++ b/src/Controllers/Admin/SettingController.php
@@ -34,6 +34,8 @@ public function show()
'enableHome' => setting('shop.home.enabled', true),
'homeMessage' => setting('shop.home', ''),
'termsRequired' => old('terms_required', setting('shop.required_terms') !== null),
+ 'cartAuth' => setting('shop.cart_auth', false),
+ 'emailVerification' => setting('shop.email_verification', true),
]);
}
@@ -65,6 +67,8 @@ public function save(Request $request)
'shop.webhook' => $request->input('webhook'),
'shop.home' => $request->input('home_message'),
'shop.home.enabled' => $request->has('enable_home'),
+ 'shop.cart_auth' => $request->has('cart_auth'),
+ 'shop.email_verification' => $request->has('email_verification'),
'shop.commands' => is_array($commands) ? json_encode($commands) : null,
'shop.required_terms' => $request->filled('terms_required') ? $request->input('terms') : null,
]);
diff --git a/src/Controllers/CartAuthController.php b/src/Controllers/CartAuthController.php
new file mode 100644
index 0000000..4d7546b
--- /dev/null
+++ b/src/Controllers/CartAuthController.php
@@ -0,0 +1,74 @@
+validator($request->all())->validate();
+
+ $user = $this->create($request->all());
+
+ event(new Registered($user));
+
+ // Если подтверждение почты отключено, помечаем её подтвержденной
+ if (!setting('shop.email_verification', true)) {
+ $user->markEmailAsVerified();
+ }
+
+ Auth::login($user);
+
+ return redirect()->intended(route('shop.cart.index'));
+ }
+
+ /**
+ * Правила валидации при регистрации.
+ */
+ protected function validator(array $data)
+ {
+ $rules = [
+ 'name' => ['required', 'string', 'max:25', 'unique:users', new Username()],
+ 'email' => ['required', 'string', 'email', 'max:50', 'unique:users'],
+ 'password' => ['required', 'confirmed', Password::default()],
+ ];
+
+ // Проверяем имя пользователя через игру, если она установлена
+ if (game()->id() !== 'none') {
+ $rules['name'][] = new GameAuth();
+ }
+
+ return Validator::make($data, $rules);
+ }
+
+ /**
+ * Создание пользователя.
+ */
+ protected function create(array $data): User
+ {
+ return User::forceCreate([
+ 'name' => $data['name'],
+ 'email' => $data['email'],
+ 'password' => $data['password'],
+ 'role_id' => Role::defaultRoleId(),
+ 'game_id' => game()->getUserUniqueId($data['name']),
+ 'last_login_ip' => FacadesRequest::ip(),
+ 'last_login_at' => now(),
+ ]);
+ }
+}
diff --git a/src/Controllers/CartController.php b/src/Controllers/CartController.php
index 4eb6f89..dcd5a40 100644
--- a/src/Controllers/CartController.php
+++ b/src/Controllers/CartController.php
@@ -18,6 +18,16 @@ class CartController extends Controller
*/
public function index(Request $request)
{
+ // Если отключена гостевая корзина, перенаправляем на страницу входа
+ if (!setting('shop.cart_auth', false) && auth()->guest()) {
+ return redirect()->route('login');
+ }
+
+ // Запоминаем корзину как запрошенную страницу для перенаправления после входа
+ if (auth()->guest()) {
+ $request->session()->put('url.intended', route('shop.cart.index'));
+ }
+
$terms = setting('shop.required_terms');
if ($terms !== null) {
@@ -29,6 +39,9 @@ public function index(Request $request)
return view('shop::cart.index', [
'cart' => Cart::fromSession($request->session()),
'terms' => $terms,
+ // Передаем настройки капчи для форм авторизации и регистрации
+ 'captchaLogin' => (bool) setting('captcha.login'),
+ 'captchaRegister' => setting('captcha.type') !== null,
]);
}
@@ -37,6 +50,10 @@ public function index(Request $request)
*/
public function remove(Request $request, Package $package)
{
+ if (!setting('shop.cart_auth', false) && auth()->guest()) {
+ return redirect()->route('login');
+ }
+
$cart = Cart::fromSession($request->session());
$cart->remove($package);
@@ -49,6 +66,10 @@ public function remove(Request $request, Package $package)
*/
public function update(Request $request)
{
+ if (!setting('shop.cart_auth', false) && auth()->guest()) {
+ return redirect()->route('login');
+ }
+
$cart = Cart::fromSession($request->session());
foreach ($request->input('quantities', []) as $id => $quantity) {
@@ -69,6 +90,10 @@ public function update(Request $request)
*/
public function clear(Request $request)
{
+ if (!setting('shop.cart_auth', false) && auth()->guest()) {
+ return redirect()->route('login');
+ }
+
Cart::fromSession($request->session())->clear();
return to_route('shop.cart.index');
diff --git a/src/Controllers/PackageController.php b/src/Controllers/PackageController.php
index 05cf896..935682a 100644
--- a/src/Controllers/PackageController.php
+++ b/src/Controllers/PackageController.php
@@ -40,6 +40,15 @@ public function showVariables(Request $request, Package $package)
*/
public function buy(Request $request, Package $package)
{
+ // Если гостевая корзина отключена, требуем авторизацию
+ if (!setting('shop.cart_auth', false) && auth()->guest()) {
+ return redirect()->route('login');
+ }
+
+ if (auth()->guest()) {
+ $request->session()->put('url.intended', route('shop.cart.index'));
+ }
+
$this->validate($request, [
'quantity' => 'nullable|integer',
'price' => 'sometimes|nullable|numeric|min:'.$package->price,
@@ -53,11 +62,11 @@ public function buy(Request $request, Package $package)
$user = $request->user();
$cart = Cart::fromSession($request->session());
- if ($package->getMaxQuantity() < 1 || $package->category->hasReachLimit($user)) {
+ if ($package->getMaxQuantity() < 1 || ($user !== null && $package->category->hasReachLimit($user))) {
return redirect()->back()->with('error', trans('shop::messages.packages.limit'));
}
- if (! $package->hasBoughtRequirements() || ! $package->hasRequiredRole($user->role)) {
+ if ($user !== null && (! $package->hasBoughtRequirements() || ! $package->hasRequiredRole($user->role))) {
return redirect()->back()->with('error', trans('shop::messages.packages.requirements'));
}