feat: Add IT Support catalog and related migrations, seeders, and email templates
- Created migration to add 'group_label' to 'product_type_fields' table. - Implemented ItSupportCatalogSeeder to populate IT Support features and tiers. - Added ProductCategorySeeder for initial product categories. - Developed ProductMockupSeeder for mockup products in various categories. - Introduced ProductTypeFieldSeeder to define fields for different product types. - Created email templates for VPS service information and service renewal reminders.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -6,37 +6,17 @@ use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\OrderRequest;
|
||||
use App\Http\Requests\UpdateOrderRequest;
|
||||
use App\Http\Resources\Api\Admin\OrderResource;
|
||||
use App\Jobs\Hosting\CreateHostingJobs;
|
||||
use App\Jobs\VirtualMachine\Create\CreateVMJobs;
|
||||
use App\Jobs\VirtualMachine\Upgrade\UpgradeVirtualMachine;
|
||||
use App\Models\Order;
|
||||
use App\Repositories\Addon\AddonRepositoryInterface;
|
||||
use App\Repositories\Invoice\InvoiceRepositoryInterface;
|
||||
use App\Repositories\InvoiceItem\InvoiceItemRepositoryInterface;
|
||||
use App\Repositories\Module\Hosting\HostingRepositoryInterface as ModuleHostingRepositoryInterface;
|
||||
use App\Repositories\Module\HostingServer\HostingServerRepositoryInterface;
|
||||
use App\Repositories\Module\IpAddress\IpAddressRepositoryInterface;
|
||||
use App\Repositories\Module\Vmware\VmwareRepositoryInterface;
|
||||
use App\Repositories\Order\OrderRepositoryInterface;
|
||||
use App\Repositories\Os\OsRepositoryInterface;
|
||||
use App\Services\OrderService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class OrderController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly OrderRepositoryInterface $orderRepository,
|
||||
private readonly InvoiceRepositoryInterface $invoiceRepository,
|
||||
private readonly InvoiceItemRepositoryInterface $invoiceItemRepository,
|
||||
private readonly ModuleHostingRepositoryInterface $moduleHostingRepository,
|
||||
private readonly VmwareRepositoryInterface $moduleVmwareRepository,
|
||||
private readonly HostingServerRepositoryInterface $moduleHostingServerRepository,
|
||||
private readonly OsRepositoryInterface $osRepository,
|
||||
private readonly IpAddressRepositoryInterface $ipAddressRepository,
|
||||
private readonly AddonRepositoryInterface $addonRepository,
|
||||
private readonly OrderService $orderService,
|
||||
) {}
|
||||
|
||||
@@ -83,12 +63,7 @@ class OrderController extends Controller
|
||||
{
|
||||
$order = $this->orderRepository->findByOrderNum($order_num);
|
||||
|
||||
if (!$order) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => "Can't find order by ID #" . $order_num,
|
||||
], 404);
|
||||
}
|
||||
abort_if(!$order, 404, "Can't find order by ID #{$order_num}");
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
@@ -100,173 +75,48 @@ class OrderController extends Controller
|
||||
{
|
||||
$order = $this->orderRepository->findWithRelationships($id, ['invoice', 'orderItem']);
|
||||
|
||||
if (!$order) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => "Can't find order by ID #" . $id,
|
||||
], 404);
|
||||
}
|
||||
abort_if(!$order, 404, "Can't find order by ID #{$id}");
|
||||
|
||||
$status = match ($request->action) {
|
||||
"accept" => 1,
|
||||
"cancel" => 2,
|
||||
default => 0
|
||||
match ($request->action) {
|
||||
'accept' => $this->orderService->confirmOrder($order, (bool) $request->module),
|
||||
'cancel' => $this->orderService->setStatus($order, 2),
|
||||
default => $this->orderService->setStatus($order, 0),
|
||||
};
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
$this->orderRepository->update($id, ['status' => $status]);
|
||||
|
||||
if ($status === 1 && $request->module == 1) {
|
||||
$jobs = [];
|
||||
$addon = [];
|
||||
$product = 0;
|
||||
|
||||
foreach ($order->orderItem as $key => $item) {
|
||||
switch ((int) $item->type_id) {
|
||||
case 1:
|
||||
$itemData = $this->addonRepository->find($item->relid);
|
||||
if ($itemData) {
|
||||
$price = match ((int) $item->billing) {
|
||||
2 => $item->amount / 1,
|
||||
3 => $item->amount / 3,
|
||||
4 => $item->amount / 6,
|
||||
5 => $item->amount / 12,
|
||||
default => 0
|
||||
};
|
||||
$addon[strtolower($itemData->name)] = (int) $price / $itemData->price;
|
||||
$product = $item->parent_id;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
$hostingServer = $this->moduleHostingServerRepository->get_active();
|
||||
if ($hostingServer) {
|
||||
$this->moduleHostingRepository->update($item->relid, ['module_server_id' => $hostingServer->first()->id]);
|
||||
$jobs[] = new CreateHostingJobs($item->relid);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
$product = $this->moduleVmwareRepository->find($item->relid);
|
||||
|
||||
if ($product && $product->os_id) {
|
||||
$os = $this->osRepository->findWithRelationships($product->os_id, ['osGroup']);
|
||||
if (!$os || !$os->osGroup->isNotEmpty()) break;
|
||||
|
||||
$ip_address = $this->ipAddressRepository->filter([
|
||||
'module_host_id' => $os->osGroup->module_host_id,
|
||||
'status' => 0,
|
||||
]);
|
||||
|
||||
if (count($ip_address) > 0) {
|
||||
$this->moduleVmwareRepository->update($item->relid, [
|
||||
'module_ipaddress_id' => $ip_address->first()->id,
|
||||
]);
|
||||
$this->ipAddressRepository->update($ip_address->first()->id, ['status' => 1]);
|
||||
$jobs[] = new CreateVMJobs($product->id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($order->orderItem) === count($addon)) {
|
||||
dispatch(new UpgradeVirtualMachine($product, $addon, $order->id))->delay(now()->addSeconds(10));
|
||||
}
|
||||
|
||||
foreach ($jobs as $item) {
|
||||
dispatch($item)->delay(now()->addSeconds(10));
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json(['error' => false, 'message' => 'Order updated successfully']);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json(['error' => true, 'message' => $e->getMessage()], 500);
|
||||
}
|
||||
return response()->json(['error' => false, 'message' => 'Order updated successfully']);
|
||||
}
|
||||
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$order = Order::with('Invoice', 'Invoice.InvoiceItem')->find($id);
|
||||
$order = Order::with('invoice', 'invoice.invoiceItem')->find($id);
|
||||
|
||||
if (!$order) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => "Can't find order by ID #" . $id,
|
||||
], 404);
|
||||
}
|
||||
abort_if(!$order, 404, "Can't find order by ID #{$id}");
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
$this->orderService->deleteOrder($order);
|
||||
|
||||
if ($order->Invoice) {
|
||||
$order->Invoice->delete();
|
||||
|
||||
if ($order->Invoice->InvoiceItem->count()) {
|
||||
foreach ($order->Invoice->InvoiceItem->all() as $item) {
|
||||
$item->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$order->delete();
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json(['error' => false, 'message' => 'Order deleted successfully']);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json(['error' => true, 'message' => $e->getMessage()], 500);
|
||||
}
|
||||
return response()->json(['error' => false, 'message' => 'Order deleted successfully']);
|
||||
}
|
||||
|
||||
public function accept(int $id): JsonResponse
|
||||
{
|
||||
$order = $this->orderRepository->findWithRelationships($id, ['invoice', 'orderItem']);
|
||||
$order = $this->orderRepository->find($id);
|
||||
|
||||
if (!$order) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => "Can't find order by ID #" . $id,
|
||||
], 404);
|
||||
}
|
||||
abort_if(!$order, 404, "Can't find order by ID #{$id}");
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
$this->orderRepository->update($id, ['status' => 1]);
|
||||
DB::commit();
|
||||
$this->orderService->setStatus($order, 1);
|
||||
|
||||
return response()->json(['error' => false, 'message' => 'Order accepted successfully']);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json(['error' => true, 'message' => $e->getMessage()], 500);
|
||||
}
|
||||
return response()->json(['error' => false, 'message' => 'Order accepted successfully']);
|
||||
}
|
||||
|
||||
public function cancel(int $id): JsonResponse
|
||||
{
|
||||
$order = $this->orderRepository->find($id);
|
||||
|
||||
if (!$order) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => "Can't find order by ID #" . $id,
|
||||
], 404);
|
||||
}
|
||||
abort_if(!$order, 404, "Can't find order by ID #{$id}");
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
$this->orderRepository->update($id, ['status' => 2]);
|
||||
DB::commit();
|
||||
$this->orderService->setStatus($order, 2);
|
||||
|
||||
return response()->json(['error' => false, 'message' => 'Order cancelled successfully']);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json(['error' => true, 'message' => $e->getMessage()], 500);
|
||||
}
|
||||
return response()->json(['error' => false, 'message' => 'Order cancelled successfully']);
|
||||
}
|
||||
|
||||
public function uploadProof(Request $request): JsonResponse
|
||||
|
||||
@@ -72,6 +72,7 @@ class ProductController extends Controller
|
||||
'ram' => 'nullable|numeric|min:0',
|
||||
'disk' => 'nullable|numeric|min:0',
|
||||
'bandwidth' => 'nullable|numeric|min:0',
|
||||
'domain_count' => 'nullable|integer|min:0',
|
||||
'billing_type' => 'nullable|string|in:recurring,onetime',
|
||||
'currency' => 'nullable|string|max:10',
|
||||
'price_monthly' => 'nullable|numeric|min:0',
|
||||
@@ -81,6 +82,7 @@ class ProductController extends Controller
|
||||
'price_biennially' => 'nullable|numeric|min:0',
|
||||
'price_triennially' => 'nullable|numeric|min:0',
|
||||
'price_onetime' => 'nullable|numeric|min:0',
|
||||
'features' => 'nullable|array',
|
||||
]);
|
||||
|
||||
$productType = $validated['product_type'] ?? null;
|
||||
@@ -103,6 +105,8 @@ class ProductController extends Controller
|
||||
'ram' => $validated['ram'] ?? null,
|
||||
'disk' => $validated['disk'] ?? null,
|
||||
'bandwidth' => $validated['bandwidth'] ?? null,
|
||||
'domain_count' => $validated['domain_count'] ?? null,
|
||||
'features' => $validated['features'] ?? null,
|
||||
]);
|
||||
|
||||
$this->savePricings($product, $validated);
|
||||
@@ -135,6 +139,7 @@ class ProductController extends Controller
|
||||
'ram' => 'nullable|numeric|min:0',
|
||||
'disk' => 'nullable|numeric|min:0',
|
||||
'bandwidth' => 'nullable|numeric|min:0',
|
||||
'domain_count' => 'nullable|integer|min:0',
|
||||
'os_ids' => 'nullable|array',
|
||||
'os_ids.*' => 'integer|exists:os,id',
|
||||
'module_host_id' => 'nullable|integer|exists:module_host,id',
|
||||
@@ -148,6 +153,7 @@ class ProductController extends Controller
|
||||
'price_biennially' => 'nullable|numeric|min:0',
|
||||
'price_triennially' => 'nullable|numeric|min:0',
|
||||
'price_onetime' => 'nullable|numeric|min:0',
|
||||
'features' => 'nullable|array',
|
||||
]);
|
||||
|
||||
if (isset($validated['name']) && $validated['name'] !== $product->name) {
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin\Product;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ProductTypeField\ProductTypeFieldRequest;
|
||||
use App\Http\Resources\Api\Admin\ProductTypeFieldResource;
|
||||
use App\Models\ProductTypeField;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProductTypeFieldController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$items = ProductTypeField::query()
|
||||
->when($request->get('product_type'), fn ($q, $type) => $q->where('product_type', $type))
|
||||
->orderBy('sort_order')
|
||||
->orderBy('id')
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => ProductTypeFieldResource::collection($items),
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(ProductTypeFieldRequest $request): JsonResponse
|
||||
{
|
||||
$field = ProductTypeField::create($request->validated());
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Tạo field thành công.',
|
||||
'data' => new ProductTypeFieldResource($field),
|
||||
], 201);
|
||||
}
|
||||
|
||||
public function update(ProductTypeFieldRequest $request, int $id): JsonResponse
|
||||
{
|
||||
$field = ProductTypeField::find($id);
|
||||
|
||||
if (!$field) {
|
||||
return response()->json(['error' => true, 'message' => 'Không tìm thấy field.'], 404);
|
||||
}
|
||||
|
||||
$field->update($request->validated());
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Cập nhật field thành công.',
|
||||
'data' => new ProductTypeFieldResource($field),
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$field = ProductTypeField::find($id);
|
||||
|
||||
if (!$field) {
|
||||
return response()->json(['error' => true, 'message' => 'Không tìm thấy field.'], 404);
|
||||
}
|
||||
|
||||
$field->delete();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Xoá field thành công.',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
namespace App\Http\Controllers\Api\Admin\Service;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Jobs\VirtualMachine\Provision\ResendVmCredentialsEmailJob;
|
||||
use App\Models\ModuleVmware;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -34,9 +36,11 @@ class ServiceController extends Controller
|
||||
|
||||
public function show(int $id): JsonResponse
|
||||
{
|
||||
$service = Service::with(['customer', 'product', 'orderItem', 'invoice', 'vmware', 'addons'])
|
||||
$service = Service::with(['customer', 'product', 'orderItem', 'invoice', 'vmware.os.osGroup', 'addons'])
|
||||
->findOrFail($id);
|
||||
|
||||
ModuleVmware::resolveVirtualMachineIds([$service->vmware]);
|
||||
|
||||
return response()->json(['error' => false, 'data' => $service]);
|
||||
}
|
||||
|
||||
@@ -47,4 +51,15 @@ class ServiceController extends Controller
|
||||
|
||||
return response()->json(['error' => false, 'message' => 'Đã gỡ khách hàng khỏi dịch vụ.']);
|
||||
}
|
||||
|
||||
public function resendCredentials(int $id): JsonResponse
|
||||
{
|
||||
$service = Service::findOrFail($id);
|
||||
|
||||
abort_if(!$service->vm_id, 422, 'Dịch vụ chưa gắn VM.');
|
||||
|
||||
ResendVmCredentialsEmailJob::dispatch($service->vm_id);
|
||||
|
||||
return response()->json(['error' => false, 'message' => 'Đã xếp hàng gửi lại thông tin VPS cho khách hàng.']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,7 @@ use App\Http\Resources\Api\Client\ClientResource;
|
||||
use App\Services\ActivityLogger;
|
||||
use App\Services\Api\Client\ClientAuthService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Tymon\JWTAuth\Facades\JWTAuth;
|
||||
use Tymon\JWTAuth\Exceptions\JWTException;
|
||||
|
||||
/**
|
||||
* @OA\Tag(
|
||||
@@ -390,80 +387,37 @@ class ClientController extends Controller
|
||||
'email' => ['required', 'email', 'max:255'],
|
||||
]);
|
||||
|
||||
$email = strtolower(trim((string) $request->input('email')));
|
||||
|
||||
$customer = \App\Models\Customer::whereRaw('LOWER(email) = ?', [$email])->first();
|
||||
|
||||
if (! $customer) {
|
||||
// Do not disclose whether the email exists.
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Nếu email tồn tại, mật khẩu mới đã được gửi đến hộp thư của bạn.',
|
||||
]);
|
||||
}
|
||||
|
||||
$alphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789!@#$%^&*';
|
||||
$newPassword = '';
|
||||
$max = strlen($alphabet) - 1;
|
||||
for ($i = 0; $i < 16; $i++) {
|
||||
$newPassword .= $alphabet[random_int(0, $max)];
|
||||
}
|
||||
|
||||
try {
|
||||
\Illuminate\Support\Facades\DB::beginTransaction();
|
||||
|
||||
$customer->password = Hash::make($newPassword);
|
||||
$customer->save();
|
||||
|
||||
\Illuminate\Support\Facades\Mail::to($customer->email)->later(
|
||||
now()->addSeconds(5),
|
||||
new \App\Mail\Customer\PasswordResetByAdmin([
|
||||
'fullname' => $customer->fullname,
|
||||
'email' => $customer->email,
|
||||
'password' => $newPassword,
|
||||
])
|
||||
);
|
||||
$customer = $this->authService->resetForgottenPassword($request->input('email'));
|
||||
|
||||
if ($customer) {
|
||||
$this->activityLogger->log(
|
||||
event: 'password_forgot',
|
||||
logName: 'Customer',
|
||||
description: "Customer {$customer->email} yêu cầu cấp lại mật khẩu",
|
||||
subject: $customer,
|
||||
);
|
||||
|
||||
\Illuminate\Support\Facades\DB::commit();
|
||||
} catch (\Throwable) {
|
||||
\Illuminate\Support\Facades\DB::rollBack();
|
||||
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => 'Không thể gửi email, vui lòng thử lại sau.',
|
||||
], 500);
|
||||
}
|
||||
|
||||
// Do not disclose whether the email exists.
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Mật khẩu mới đã được gửi đến email của bạn.',
|
||||
'message' => 'Nếu email tồn tại, mật khẩu mới đã được gửi đến hộp thư của bạn.',
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(ClientUpdateRequest $request)
|
||||
{
|
||||
$user = auth('client')->user();
|
||||
$result = $this->authService->updateProfile(auth('client')->user(), $request->validated());
|
||||
$user = $result['client'];
|
||||
|
||||
$oldValues = array_intersect_key($user->toArray(), $request->validated());
|
||||
$user->fill($request->validated());
|
||||
$dirty = $user->getDirty();
|
||||
$user->save();
|
||||
|
||||
if (!empty($dirty)) {
|
||||
if (!empty($result['dirty'])) {
|
||||
$this->activityLogger->log(
|
||||
event: 'profile_update',
|
||||
logName: 'Customer',
|
||||
description: "Customer {$user->email} cập nhật thông tin cá nhân: " . implode(', ', array_keys($dirty)),
|
||||
description: "Customer {$user->email} cập nhật thông tin cá nhân: " . implode(', ', array_keys($result['dirty'])),
|
||||
subject: $user,
|
||||
oldValues: array_intersect_key($oldValues, $dirty),
|
||||
newValues: array_diff_key($dirty, array_flip(['password', 'remember_token'])),
|
||||
oldValues: $result['old'],
|
||||
newValues: array_diff_key($result['dirty'], array_flip(['password', 'remember_token'])),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -478,29 +432,25 @@ class ClientController extends Controller
|
||||
|
||||
public function updateCccd(ClientUpdateCccdRequest $request)
|
||||
{
|
||||
$user = auth('client')->user();
|
||||
$frontUrl = Storage::disk('public')->url($request->file('cmnd_before')->store('cccd', 'public'));
|
||||
$backUrl = Storage::disk('public')->url($request->file('cmnd_after')->store('cccd', 'public'));
|
||||
|
||||
$oldValues = array_intersect_key($user->toArray(), $request->validated());
|
||||
|
||||
$user->identity_number = $request->validated('cmnd');
|
||||
$user->front_identity_number = Storage::disk('public')->url(
|
||||
$request->file('cmnd_before')->store('cccd', 'public')
|
||||
);
|
||||
$user->back_identity_number = Storage::disk('public')->url(
|
||||
$request->file('cmnd_after')->store('cccd', 'public')
|
||||
$result = $this->authService->updateCccd(
|
||||
auth('client')->user(),
|
||||
$request->validated('cmnd'),
|
||||
$frontUrl,
|
||||
$backUrl,
|
||||
);
|
||||
$user = $result['client'];
|
||||
|
||||
$dirty = $user->getDirty();
|
||||
$user->save();
|
||||
|
||||
if (!empty($dirty)) {
|
||||
if (!empty($result['dirty'])) {
|
||||
$this->activityLogger->log(
|
||||
event: 'cccd_update',
|
||||
logName: 'Customer',
|
||||
description: "Customer {$user->email} cập nhật chứng minh thư",
|
||||
subject: $user,
|
||||
oldValues: array_intersect_key($oldValues, $dirty),
|
||||
newValues: $dirty,
|
||||
oldValues: $result['old'],
|
||||
newValues: $result['dirty'],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -517,16 +467,19 @@ class ClientController extends Controller
|
||||
{
|
||||
$user = auth('client')->user();
|
||||
|
||||
if (!Hash::check($request->input('current_password'), $user->password)) {
|
||||
try {
|
||||
$this->authService->changePassword(
|
||||
$user,
|
||||
$request->input('current_password'),
|
||||
$request->input('password'),
|
||||
);
|
||||
} catch (\Illuminate\Validation\ValidationException $e) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => 'Mật khẩu hiện tại không chính xác',
|
||||
'message' => collect($e->errors())->flatten()->first(),
|
||||
], 422);
|
||||
}
|
||||
|
||||
$user->password = bcrypt($request->input('password'));
|
||||
$user->save();
|
||||
|
||||
$this->activityLogger->log(
|
||||
event: 'password_change',
|
||||
logName: 'Customer',
|
||||
|
||||
@@ -7,6 +7,7 @@ use Illuminate\Http\JsonResponse;
|
||||
use Laravel\Horizon\Contracts\JobRepository;
|
||||
use Laravel\Horizon\Contracts\MetricsRepository;
|
||||
use Laravel\Horizon\Contracts\WorkloadRepository;
|
||||
use Laravel\Horizon\Jobs\RetryFailedJob;
|
||||
|
||||
class QueueMonitorController extends Controller
|
||||
{
|
||||
@@ -70,6 +71,19 @@ class QueueMonitorController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/queue/jobs/failed/{id}/retry
|
||||
* Re-queue a failed job by its Horizon job ID.
|
||||
*/
|
||||
public function retry(string $id): JsonResponse
|
||||
{
|
||||
abort_if(!$this->jobs->findFailed($id), 404, "Can't find failed job #{$id}");
|
||||
|
||||
dispatch(new RetryFailedJob($id));
|
||||
|
||||
return response()->json(['success' => true, 'message' => 'Job đã được đưa lại vào hàng đợi']);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/queue/jobs/metrics
|
||||
* Queue throughput, runtime, and per-queue/per-job breakdown.
|
||||
|
||||
@@ -442,6 +442,19 @@ class VCenterManagerController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
public function powerState(Request $request)
|
||||
{
|
||||
$vmId = (int) $request->input('vm_id');
|
||||
|
||||
$vm = VirtualMachines::find($vmId);
|
||||
|
||||
if (!$vm) {
|
||||
return response()->json(['error' => true, 'message' => 'VM not found'], 404);
|
||||
}
|
||||
|
||||
return response()->json(['error' => false, 'data' => ['power_state' => $vm->power_state]]);
|
||||
}
|
||||
|
||||
public function powerOn(Request $request)
|
||||
{
|
||||
$vmId = (int) $request->input('vm_id');
|
||||
|
||||
Reference in New Issue
Block a user