- Introduced a new POST route 'bulk-update-gateway' for bulk updating gateways. - This route is protected by the 'module-vcenter.manager' permission middleware.
144 lines
5.4 KiB
PHP
144 lines
5.4 KiB
PHP
<?php
|
|
|
|
namespace App\Imports;
|
|
|
|
use App\Models\IpPool;
|
|
use App\Models\ModuleNetwork;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Support\Str;
|
|
use Maatwebsite\Excel\Concerns\ToModel;
|
|
use Maatwebsite\Excel\Concerns\WithHeadingRow;
|
|
use Maatwebsite\Excel\Concerns\WithUpsertColumns;
|
|
use Maatwebsite\Excel\Concerns\WithUpserts;
|
|
use Maatwebsite\Excel\Concerns\WithValidation;
|
|
|
|
class IpPoolImport implements ToModel, WithHeadingRow, WithValidation, WithUpserts, WithUpsertColumns
|
|
{
|
|
/** @var array<string, ModuleNetwork> */
|
|
private array $networkCache = [];
|
|
|
|
public function model(array $row)
|
|
{
|
|
$network = $this->resolveNetwork($row['ten_mang'] ?? null, $row['cidr'] ?? null);
|
|
|
|
return new IpPool([
|
|
// uuid has no DB default and must be set on insert; excluded from upsertColumns() so it's never overwritten
|
|
'uuid' => (string) Str::uuid(),
|
|
'ip_address' => $row['ip_address'],
|
|
'module_network_id' => $network?->id,
|
|
// ip_pools.cidr is NOT NULL; fall back to the network's own prefix (or 24) when the row omits it
|
|
'cidr' => $this->parsePrefixLength($row['cidr'] ?? null)
|
|
?? $this->parsePrefixLength($network?->network)
|
|
?? 24,
|
|
'gateway' => $row['gateway'] ?? null,
|
|
'netmask' => $row['subnet_mask'] ?? null,
|
|
'owner_type' => $row['owner_type'] ?? null,
|
|
'ip_role' => $row['ip_role'] ?? null,
|
|
'parent_ip' => $row['parent_ip'] ?? null,
|
|
'customer_name' => $row['ten_khach_hang'] ?? null,
|
|
'service_name' => $row['ten_dich_vu'] ?? null,
|
|
'allocated_at' => $this->parseDate($row['ngay_cap_phat'] ?? null),
|
|
'revoked_at' => $this->parseDate($row['ngay_thu_hoi'] ?? null),
|
|
'allocation_status' => $row['trang_thai'] ?? null,
|
|
'contact_email' => $row['contact_email'] ?? null,
|
|
'contact_cc' => $row['contact_cc'] ?? null,
|
|
'contact_phone' => $row['contact_phone'] ?? null,
|
|
'monthly_cost' => $row['monthly_cost'] ?: null,
|
|
'selling_price' => $row['selling_price'] ?: null,
|
|
'additional_info' => $row['thong_tin_bo_sung'] ?? null,
|
|
'last_email_type' => $row['last_email_type'] ?? null,
|
|
'last_email_at' => $this->parseDate($row['last_email_at'] ?? null),
|
|
'updated_by' => $row['updated_by'] ?? null,
|
|
'note' => $row['ghi_chu'] ?? null,
|
|
]);
|
|
}
|
|
|
|
public function rules(): array
|
|
{
|
|
$multiEmail = function (string $attribute, mixed $value, \Closure $fail) {
|
|
foreach (preg_split('/[,;]+/', (string) $value) as $email) {
|
|
$email = trim($email);
|
|
if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
|
$fail("Email không hợp lệ: {$email}");
|
|
}
|
|
}
|
|
};
|
|
|
|
return [
|
|
'ten_mang' => 'required|string|max:255',
|
|
'cidr' => 'nullable|string|max:45',
|
|
'ip_address' => 'required|ip',
|
|
'contact_email' => ['nullable', 'string', $multiEmail],
|
|
'contact_cc' => ['nullable', 'string', $multiEmail],
|
|
'monthly_cost' => 'nullable|numeric',
|
|
'selling_price' => 'nullable|numeric',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* CSV dates come as "dd/mm/yyyy" or "dd/mm/yyyy H:i:s" (Vietnamese sheet export).
|
|
*/
|
|
private function parseDate(?string $value): ?string
|
|
{
|
|
$value = trim((string) $value);
|
|
if ($value === '') {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
return Carbon::createFromFormat('d/m/Y H:i:s', $value)->toDateTimeString();
|
|
} catch (\Throwable) {
|
|
// not a datetime, try date-only below
|
|
}
|
|
|
|
try {
|
|
return Carbon::createFromFormat('d/m/Y', $value)->startOfDay()->toDateTimeString();
|
|
} catch (\Throwable) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* CSV gives CIDR as "/22"; the ip_pools.cidr column only stores the prefix length.
|
|
*/
|
|
private function parsePrefixLength(?string $cidr): ?int
|
|
{
|
|
// "/22" or "111.111.111.0/22" -> 22
|
|
return preg_match('/(\d+)$/', (string) $cidr, $m) ? (int) $m[1] : null;
|
|
}
|
|
|
|
public function uniqueBy(): array
|
|
{
|
|
return ['ip_address', 'module_network_id'];
|
|
}
|
|
|
|
public function upsertColumns(): array
|
|
{
|
|
return [
|
|
'cidr', 'gateway', 'netmask', 'owner_type', 'ip_role', 'parent_ip',
|
|
'customer_name', 'service_name', 'allocated_at', 'revoked_at', 'allocation_status',
|
|
'contact_email', 'contact_cc', 'contact_phone', 'monthly_cost', 'selling_price',
|
|
'additional_info', 'last_email_type', 'last_email_at', 'updated_by', 'note',
|
|
];
|
|
}
|
|
|
|
private function resolveNetwork(?string $name, ?string $cidr): ?ModuleNetwork
|
|
{
|
|
if (!$name) {
|
|
return null;
|
|
}
|
|
|
|
$key = $name . '|' . $cidr;
|
|
|
|
if (isset($this->networkCache[$key])) {
|
|
return $this->networkCache[$key];
|
|
}
|
|
|
|
$network = ModuleNetwork::where('name', $name)->first()
|
|
?? ($cidr ? ModuleNetwork::where('network', $cidr)->first() : null)
|
|
?? ModuleNetwork::create(['name' => $name, 'network' => $cidr]);
|
|
|
|
return $this->networkCache[$key] = $network;
|
|
}
|
|
}
|