From 48a6571d4b0b88cbc82c6a2e50a5afd068f591d0 Mon Sep 17 00:00:00 2001
From: SofianeLasri <alasri250@gmail.com>
Date: Wed, 19 Feb 2025 14:24:50 +0100
Subject: [PATCH 1/9] feat: add IpAdressMetadata model and factory with
 migration

- Created the IpAdressMetadata model with fillable fields and a relationship to the IpAddress model.
- Implemented a factory for generating fake IpAdressMetadata data.
- Added a migration for creating the ip_adress_metadata table with necessary fields and constraints.
---
 app/Models/IpAdressMetadata.php               | 29 +++++++++++++++++++
 .../factories/IpAdressMetadataFactory.php     | 23 +++++++++++++++
 ...141925_create_ip_adress_metadata_table.php | 24 +++++++++++++++
 3 files changed, 76 insertions(+)
 create mode 100644 app/Models/IpAdressMetadata.php
 create mode 100644 database/factories/IpAdressMetadataFactory.php
 create mode 100644 database/migrations/2025_02_19_141925_create_ip_adress_metadata_table.php

diff --git a/app/Models/IpAdressMetadata.php b/app/Models/IpAdressMetadata.php
new file mode 100644
index 0000000..74c9495
--- /dev/null
+++ b/app/Models/IpAdressMetadata.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use SlProjects\LaravelRequestLogger\app\Models\IpAddress;
+
+class IpAdressMetadata extends Model
+{
+    use HasFactory;
+
+    public $timestamps = false;
+
+    protected $fillable = [
+        'ip_address_id',
+        'country_code',
+        'lat',
+        'lon',
+    ];
+
+    const COUNTRY_CODES = ['AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ', 'BA', 'BB', 'BC', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BK', 'BL', 'BM', 'BN', 'BO', 'BP', 'BQ', 'BR', 'BS', 'BT', 'BU', 'BV', 'BW', 'BX', 'BY', 'BZ', 'CA', 'CB', 'CC', 'CD', 'CE', 'CF', 'CG', 'CH', 'CI', 'CJ', 'CK', 'CL', 'CM', 'CN', 'CO', 'CP', 'CQ', 'CR', 'CS', 'CT', 'CU', 'CV', 'CW', 'CX', 'CY', 'CZ', 'DA', 'DB', 'DC', 'DD', 'DE', 'DF', 'DG', 'DH', 'DI', 'DJ', 'DK', 'DL', 'DM', 'DN', 'DO', 'DP', 'DQ', 'DR', 'DS', 'DT', 'DU', 'DV', 'DW', 'DX', 'DY', 'DZ', 'EA', 'EB', 'EC', 'ED', 'EE', 'EF', 'EG', 'EH', 'EI', 'EJ', 'EK', 'EL', 'EM', 'EN', 'EO', 'EP', 'EQ', 'ER', 'ES', 'ET', 'EU', 'EV', 'EW', 'EX', 'EY', 'EZ', 'FA', 'FB', 'FC', 'FD', 'FE', 'FF', 'FG', 'FH', 'FI', 'FJ', 'FK', 'FL', 'FM', 'FN', 'FO', 'FP', 'FQ', 'FR', 'FS', 'FT', 'FU', 'FV', 'FW', 'FX', 'FY', 'FZ', 'GA', 'GB', 'GC', 'GD', 'GE', 'GF', 'GG', 'GH', 'GI', 'GJ', 'GK', 'GL', 'GM', 'GN', 'GO', 'GP', 'GQ', 'GR', 'GS', 'GT', 'GU', 'GV', 'GW', 'GX', 'GY', 'GZ', 'HA', 'HB', 'HC', 'HD', 'HE', 'HF', 'HG', 'HH', 'HI', 'HJ', 'HK', 'HL', 'HM', 'HN', 'HO', 'HP', 'HQ', 'HR', 'HS', 'HT', 'HU', 'HV', 'HW', 'HX', 'HY', 'HZ', 'IA', 'IB', 'IC', 'ID', 'IE', 'IF', 'IG', 'IH', 'II', 'IJ', 'IK', 'IL', 'IM', 'IN', 'IO', 'IP', 'IQ', 'IR', 'IS', 'IT', 'IU', 'IV', 'IW', 'IX', 'IY', 'IZ', 'JA', 'JB', 'JC', 'JD', 'JE', 'JF', 'JG', 'JH', 'JI', 'JJ', 'JK', 'JL', 'JM', 'JN', 'JO', 'JP', 'JQ', 'JR', 'JS', 'JT', 'JU', 'JV', 'JW', 'JX', 'JY', 'JZ', 'KA', 'KB', 'KC', 'KD', 'KE', 'KF', 'KG', 'KH', 'KI', 'KJ', 'KK', 'KL', 'KM', 'KN', 'KO', 'KP', 'KQ', 'KR', 'KS', 'KT', 'KU', 'KV', 'KW', 'KX', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LD', 'LE', 'LF', 'LG', 'LH', 'LI', 'LJ', 'LK', 'LL', 'LM', 'LN', 'LO', 'LP', 'LQ', 'LR', 'LS', 'LT', 'LU', 'LV', 'LW', 'LX', 'LY', 'LZ', 'MA', 'MB', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MI', 'MJ', 'MK', 'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA', 'NB', 'NC', 'ND', 'NE', 'NF', 'NG', 'NH', 'NI', 'NJ', 'NK', 'NL', 'NM', 'NN', 'NO', 'NP', 'NQ', 'NR', 'NS', 'NT', 'NU', 'NV', 'NW', 'NX', 'NY', 'NZ', 'OA', 'OB', 'OC', 'OD', 'OE', 'OF', 'OG', 'OH', 'OI', 'OJ', 'OK', 'OL', 'OM', 'ON', 'OO', 'OP', 'OQ', 'OR', 'OS', 'OT', 'OU', 'OV', 'OW', 'OX', 'OY', 'OZ', 'PA', 'PB', 'PC', 'PD', 'PE', 'PF', 'PG', 'PH', 'PI', 'PJ', 'PK', 'PL', 'PM', 'PN', 'PO', 'PP', 'PQ', 'PR', 'PS', 'PT', 'PU', 'PV', 'PW', 'PX', 'PY', 'PZ', 'QA', 'QB', 'QC', 'QD', 'QE', 'QF', 'QG', 'QH', 'QI', 'QJ', 'QK', 'QL', 'QM', 'QN', 'QO', 'QP', 'QQ', 'QR', 'QS', 'QT', 'QU', 'QV', 'QW', 'QX', 'QY', 'QZ', 'RA', 'RB', 'RC', 'RD', 'RE', 'RF', 'RG', 'RH', 'RI', 'RJ', 'RK', 'RL', 'RM', 'RN', 'RO', 'RP', 'RQ', 'RR', 'RS', 'RT', 'RU', 'RV', 'RW', 'RX', 'RY', 'RZ', 'SA', 'SB', 'SC', 'SD', 'SE', 'SF', 'SG', 'SH', 'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SP', 'SQ', 'SR', 'SS', 'ST', 'SU', 'SV', 'SW', 'SX', 'SY', 'SZ', 'TA', 'TB', 'TC', 'TD', 'TE', 'TF', 'TG', 'TH', 'TI', 'TJ', 'TK', 'TL', 'TM', 'TN', 'TO', 'TP', 'TQ', 'TR', 'TS', 'TT', 'TU', 'TV', 'TW', 'TX', 'TY', 'TZ', 'UA', 'UB', 'UC', 'UD', 'UE', 'UF', 'UG', 'UH', 'UI', 'UJ', 'UK', 'UL', 'UM', 'UN', 'UO', 'UP', 'UQ', 'UR', 'US', 'UT', 'UU', 'UV', 'UW', 'UX', 'UY', 'UZ', 'VA', 'VB', 'VC', 'VD', 'VE', 'VF', 'VG', 'VH', 'VI', 'VJ', 'VK', 'VL', 'VM', 'VN', 'VO', 'VP', 'VQ', 'VR', 'VS', 'VT', 'VU', 'VV', 'VW', 'VX', 'VY', 'VZ', 'WA', 'WB', 'WC', 'WD', 'WE', 'WF', 'WG', 'WH', 'WI', 'WJ', 'WK', 'WL', 'WM', 'WN', 'WO', 'WP', 'WQ', 'WR', 'WS', 'WT', 'WU', 'WV', 'WW', 'WX', 'WY', 'WZ', 'XA', 'XB', 'XC', 'XD', 'XE', 'XF', 'XG', 'XH', 'XI', 'XJ', 'XK', 'XL', 'XM', 'XN', 'XO', 'XP', 'XQ', 'XR', 'XS', 'XT', 'XU', 'XV', 'XW', 'XX', 'XY', 'XZ', 'YA', 'YB', 'YC', 'YD', 'YE', 'YF', 'YG', 'YH', 'YI', 'YJ', 'YK', 'YL', 'YM', 'YN', 'YO', 'YP', 'YQ', 'YR', 'YS', 'YT', 'YU', 'YV', 'YW', 'YX', 'YY', 'YZ', 'ZA', 'ZB', 'ZC', 'ZD', 'ZE', 'ZF', 'ZG', 'ZH', 'ZI', 'ZJ', 'ZK', 'ZL', 'ZM', 'ZN', 'ZO', 'ZP', 'ZQ', 'ZR', 'ZS', 'ZT', 'ZU', 'ZV', 'ZW', 'ZX', 'ZY', 'ZZ'];
+
+    public function ipAddress(): BelongsTo
+    {
+        return $this->belongsTo(IpAddress::class);
+    }
+}
diff --git a/database/factories/IpAdressMetadataFactory.php b/database/factories/IpAdressMetadataFactory.php
new file mode 100644
index 0000000..bb013a0
--- /dev/null
+++ b/database/factories/IpAdressMetadataFactory.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Database\Factories;
+
+use App\Models\IpAdressMetadata;
+use Illuminate\Database\Eloquent\Factories\Factory;
+use SlProjects\LaravelRequestLogger\app\Models\IpAddress;
+
+class IpAdressMetadataFactory extends Factory
+{
+    protected $model = IpAdressMetadata::class;
+
+    public function definition(): array
+    {
+        return [
+            'country_code' => $this->faker->randomElement(IpAdressMetadata::COUNTRY_CODES),
+            'lat' => $this->faker->latitude(),
+            'lon' => $this->faker->longitude(),
+
+            'ip_address_id' => IpAddress::factory(),
+        ];
+    }
+}
diff --git a/database/migrations/2025_02_19_141925_create_ip_adress_metadata_table.php b/database/migrations/2025_02_19_141925_create_ip_adress_metadata_table.php
new file mode 100644
index 0000000..aea959b
--- /dev/null
+++ b/database/migrations/2025_02_19_141925_create_ip_adress_metadata_table.php
@@ -0,0 +1,24 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    public function up(): void
+    {
+        Schema::create('ip_adress_metadata', function (Blueprint $table) {
+            $table->id();
+            $table->foreignId('ip_address_id')->constrained('ip_addresses');
+            $table->enum('country_code', ['AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ', 'BA', 'BB', 'BC', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BK', 'BL', 'BM', 'BN', 'BO', 'BP', 'BQ', 'BR', 'BS', 'BT', 'BU', 'BV', 'BW', 'BX', 'BY', 'BZ', 'CA', 'CB', 'CC', 'CD', 'CE', 'CF', 'CG', 'CH', 'CI', 'CJ', 'CK', 'CL', 'CM', 'CN', 'CO', 'CP', 'CQ', 'CR', 'CS', 'CT', 'CU', 'CV', 'CW', 'CX', 'CY', 'CZ', 'DA', 'DB', 'DC', 'DD', 'DE', 'DF', 'DG', 'DH', 'DI', 'DJ', 'DK', 'DL', 'DM', 'DN', 'DO', 'DP', 'DQ', 'DR', 'DS', 'DT', 'DU', 'DV', 'DW', 'DX', 'DY', 'DZ', 'EA', 'EB', 'EC', 'ED', 'EE', 'EF', 'EG', 'EH', 'EI', 'EJ', 'EK', 'EL', 'EM', 'EN', 'EO', 'EP', 'EQ', 'ER', 'ES', 'ET', 'EU', 'EV', 'EW', 'EX', 'EY', 'EZ', 'FA', 'FB', 'FC', 'FD', 'FE', 'FF', 'FG', 'FH', 'FI', 'FJ', 'FK', 'FL', 'FM', 'FN', 'FO', 'FP', 'FQ', 'FR', 'FS', 'FT', 'FU', 'FV', 'FW', 'FX', 'FY', 'FZ', 'GA', 'GB', 'GC', 'GD', 'GE', 'GF', 'GG', 'GH', 'GI', 'GJ', 'GK', 'GL', 'GM', 'GN', 'GO', 'GP', 'GQ', 'GR', 'GS', 'GT', 'GU', 'GV', 'GW', 'GX', 'GY', 'GZ', 'HA', 'HB', 'HC', 'HD', 'HE', 'HF', 'HG', 'HH', 'HI', 'HJ', 'HK', 'HL', 'HM', 'HN', 'HO', 'HP', 'HQ', 'HR', 'HS', 'HT', 'HU', 'HV', 'HW', 'HX', 'HY', 'HZ', 'IA', 'IB', 'IC', 'ID', 'IE', 'IF', 'IG', 'IH', 'II', 'IJ', 'IK', 'IL', 'IM', 'IN', 'IO', 'IP', 'IQ', 'IR', 'IS', 'IT', 'IU', 'IV', 'IW', 'IX', 'IY', 'IZ', 'JA', 'JB', 'JC', 'JD', 'JE', 'JF', 'JG', 'JH', 'JI', 'JJ', 'JK', 'JL', 'JM', 'JN', 'JO', 'JP', 'JQ', 'JR', 'JS', 'JT', 'JU', 'JV', 'JW', 'JX', 'JY', 'JZ', 'KA', 'KB', 'KC', 'KD', 'KE', 'KF', 'KG', 'KH', 'KI', 'KJ', 'KK', 'KL', 'KM', 'KN', 'KO', 'KP', 'KQ', 'KR', 'KS', 'KT', 'KU', 'KV', 'KW', 'KX', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LD', 'LE', 'LF', 'LG', 'LH', 'LI', 'LJ', 'LK', 'LL', 'LM', 'LN', 'LO', 'LP', 'LQ', 'LR', 'LS', 'LT', 'LU', 'LV', 'LW', 'LX', 'LY', 'LZ', 'MA', 'MB', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MI', 'MJ', 'MK', 'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA', 'NB', 'NC', 'ND', 'NE', 'NF', 'NG', 'NH', 'NI', 'NJ', 'NK', 'NL', 'NM', 'NN', 'NO', 'NP', 'NQ', 'NR', 'NS', 'NT', 'NU', 'NV', 'NW', 'NX', 'NY', 'NZ', 'OA', 'OB', 'OC', 'OD', 'OE', 'OF', 'OG', 'OH', 'OI', 'OJ', 'OK', 'OL', 'OM', 'ON', 'OO', 'OP', 'OQ', 'OR', 'OS', 'OT', 'OU', 'OV', 'OW', 'OX', 'OY', 'OZ', 'PA', 'PB', 'PC', 'PD', 'PE', 'PF', 'PG', 'PH', 'PI', 'PJ', 'PK', 'PL', 'PM', 'PN', 'PO', 'PP', 'PQ', 'PR', 'PS', 'PT', 'PU', 'PV', 'PW', 'PX', 'PY', 'PZ', 'QA', 'QB', 'QC', 'QD', 'QE', 'QF', 'QG', 'QH', 'QI', 'QJ', 'QK', 'QL', 'QM', 'QN', 'QO', 'QP', 'QQ', 'QR', 'QS', 'QT', 'QU', 'QV', 'QW', 'QX', 'QY', 'QZ', 'RA', 'RB', 'RC', 'RD', 'RE', 'RF', 'RG', 'RH', 'RI', 'RJ', 'RK', 'RL', 'RM', 'RN', 'RO', 'RP', 'RQ', 'RR', 'RS', 'RT', 'RU', 'RV', 'RW', 'RX', 'RY', 'RZ', 'SA', 'SB', 'SC', 'SD', 'SE', 'SF', 'SG', 'SH', 'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SP', 'SQ', 'SR', 'SS', 'ST', 'SU', 'SV', 'SW', 'SX', 'SY', 'SZ', 'TA', 'TB', 'TC', 'TD', 'TE', 'TF', 'TG', 'TH', 'TI', 'TJ', 'TK', 'TL', 'TM', 'TN', 'TO', 'TP', 'TQ', 'TR', 'TS', 'TT', 'TU', 'TV', 'TW', 'TX', 'TY', 'TZ', 'UA', 'UB', 'UC', 'UD', 'UE', 'UF', 'UG', 'UH', 'UI', 'UJ', 'UK', 'UL', 'UM', 'UN', 'UO', 'UP', 'UQ', 'UR', 'US', 'UT', 'UU', 'UV', 'UW', 'UX', 'UY', 'UZ', 'VA', 'VB', 'VC', 'VD', 'VE', 'VF', 'VG', 'VH', 'VI', 'VJ', 'VK', 'VL', 'VM', 'VN', 'VO', 'VP', 'VQ', 'VR', 'VS', 'VT', 'VU', 'VV', 'VW', 'VX', 'VY', 'VZ', 'WA', 'WB', 'WC', 'WD', 'WE', 'WF', 'WG', 'WH', 'WI', 'WJ', 'WK', 'WL', 'WM', 'WN', 'WO', 'WP', 'WQ', 'WR', 'WS', 'WT', 'WU', 'WV', 'WW', 'WX', 'WY', 'WZ', 'XA', 'XB', 'XC', 'XD', 'XE', 'XF', 'XG', 'XH', 'XI', 'XJ', 'XK', 'XL', 'XM', 'XN', 'XO', 'XP', 'XQ', 'XR', 'XS', 'XT', 'XU', 'XV', 'XW', 'XX', 'XY', 'XZ', 'YA', 'YB', 'YC', 'YD', 'YE', 'YF', 'YG', 'YH', 'YI', 'YJ', 'YK', 'YL', 'YM', 'YN', 'YO', 'YP', 'YQ', 'YR', 'YS', 'YT', 'YU', 'YV', 'YW', 'YX', 'YY', 'YZ', 'ZA', 'ZB', 'ZC', 'ZD', 'ZE', 'ZF', 'ZG', 'ZH', 'ZI', 'ZJ', 'ZK', 'ZL', 'ZM', 'ZN', 'ZO', 'ZP', 'ZQ', 'ZR', 'ZS', 'ZT', 'ZU', 'ZV', 'ZW', 'ZX', 'ZY', 'ZZ']);
+            $table->float('lat')->nullable();
+            $table->float('lon')->nullable();
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('ip_adress_metadata');
+    }
+};
-- 
GitLab


From c7b8de557d9fbcd2f046da87e4df49a9073620d5 Mon Sep 17 00:00:00 2001
From: SofianeLasri <alasri250@gmail.com>
Date: Wed, 19 Feb 2025 14:27:31 +0100
Subject: [PATCH 2/9] fix: correct spelling of 'IpAdress' to 'IpAddress' in
 model, factory, and migration files

---
 .../{IpAdressMetadata.php => IpAddressMetadata.php}       | 2 +-
 ...ssMetadataFactory.php => IpAddressMetadataFactory.php} | 8 ++++----
 ...025_02_19_141925_create_ip_address_metadata_table.php} | 4 ++--
 3 files changed, 7 insertions(+), 7 deletions(-)
 rename app/Models/{IpAdressMetadata.php => IpAddressMetadata.php} (99%)
 rename database/factories/{IpAdressMetadataFactory.php => IpAddressMetadataFactory.php} (63%)
 rename database/migrations/{2025_02_19_141925_create_ip_adress_metadata_table.php => 2025_02_19_141925_create_ip_address_metadata_table.php} (97%)

diff --git a/app/Models/IpAdressMetadata.php b/app/Models/IpAddressMetadata.php
similarity index 99%
rename from app/Models/IpAdressMetadata.php
rename to app/Models/IpAddressMetadata.php
index 74c9495..6c0f619 100644
--- a/app/Models/IpAdressMetadata.php
+++ b/app/Models/IpAddressMetadata.php
@@ -7,7 +7,7 @@
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use SlProjects\LaravelRequestLogger\app\Models\IpAddress;
 
-class IpAdressMetadata extends Model
+class IpAddressMetadata extends Model
 {
     use HasFactory;
 
diff --git a/database/factories/IpAdressMetadataFactory.php b/database/factories/IpAddressMetadataFactory.php
similarity index 63%
rename from database/factories/IpAdressMetadataFactory.php
rename to database/factories/IpAddressMetadataFactory.php
index bb013a0..5581b81 100644
--- a/database/factories/IpAdressMetadataFactory.php
+++ b/database/factories/IpAddressMetadataFactory.php
@@ -2,18 +2,18 @@
 
 namespace Database\Factories;
 
-use App\Models\IpAdressMetadata;
+use App\Models\IpAddressMetadata;
 use Illuminate\Database\Eloquent\Factories\Factory;
 use SlProjects\LaravelRequestLogger\app\Models\IpAddress;
 
-class IpAdressMetadataFactory extends Factory
+class IpAddressMetadataFactory extends Factory
 {
-    protected $model = IpAdressMetadata::class;
+    protected $model = IpAddressMetadata::class;
 
     public function definition(): array
     {
         return [
-            'country_code' => $this->faker->randomElement(IpAdressMetadata::COUNTRY_CODES),
+            'country_code' => $this->faker->randomElement(IpAddressMetadata::COUNTRY_CODES),
             'lat' => $this->faker->latitude(),
             'lon' => $this->faker->longitude(),
 
diff --git a/database/migrations/2025_02_19_141925_create_ip_adress_metadata_table.php b/database/migrations/2025_02_19_141925_create_ip_address_metadata_table.php
similarity index 97%
rename from database/migrations/2025_02_19_141925_create_ip_adress_metadata_table.php
rename to database/migrations/2025_02_19_141925_create_ip_address_metadata_table.php
index aea959b..387e34b 100644
--- a/database/migrations/2025_02_19_141925_create_ip_adress_metadata_table.php
+++ b/database/migrations/2025_02_19_141925_create_ip_address_metadata_table.php
@@ -8,7 +8,7 @@
 {
     public function up(): void
     {
-        Schema::create('ip_adress_metadata', function (Blueprint $table) {
+        Schema::create('ip_address_metadata', function (Blueprint $table) {
             $table->id();
             $table->foreignId('ip_address_id')->constrained('ip_addresses');
             $table->enum('country_code', ['AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ', 'BA', 'BB', 'BC', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BK', 'BL', 'BM', 'BN', 'BO', 'BP', 'BQ', 'BR', 'BS', 'BT', 'BU', 'BV', 'BW', 'BX', 'BY', 'BZ', 'CA', 'CB', 'CC', 'CD', 'CE', 'CF', 'CG', 'CH', 'CI', 'CJ', 'CK', 'CL', 'CM', 'CN', 'CO', 'CP', 'CQ', 'CR', 'CS', 'CT', 'CU', 'CV', 'CW', 'CX', 'CY', 'CZ', 'DA', 'DB', 'DC', 'DD', 'DE', 'DF', 'DG', 'DH', 'DI', 'DJ', 'DK', 'DL', 'DM', 'DN', 'DO', 'DP', 'DQ', 'DR', 'DS', 'DT', 'DU', 'DV', 'DW', 'DX', 'DY', 'DZ', 'EA', 'EB', 'EC', 'ED', 'EE', 'EF', 'EG', 'EH', 'EI', 'EJ', 'EK', 'EL', 'EM', 'EN', 'EO', 'EP', 'EQ', 'ER', 'ES', 'ET', 'EU', 'EV', 'EW', 'EX', 'EY', 'EZ', 'FA', 'FB', 'FC', 'FD', 'FE', 'FF', 'FG', 'FH', 'FI', 'FJ', 'FK', 'FL', 'FM', 'FN', 'FO', 'FP', 'FQ', 'FR', 'FS', 'FT', 'FU', 'FV', 'FW', 'FX', 'FY', 'FZ', 'GA', 'GB', 'GC', 'GD', 'GE', 'GF', 'GG', 'GH', 'GI', 'GJ', 'GK', 'GL', 'GM', 'GN', 'GO', 'GP', 'GQ', 'GR', 'GS', 'GT', 'GU', 'GV', 'GW', 'GX', 'GY', 'GZ', 'HA', 'HB', 'HC', 'HD', 'HE', 'HF', 'HG', 'HH', 'HI', 'HJ', 'HK', 'HL', 'HM', 'HN', 'HO', 'HP', 'HQ', 'HR', 'HS', 'HT', 'HU', 'HV', 'HW', 'HX', 'HY', 'HZ', 'IA', 'IB', 'IC', 'ID', 'IE', 'IF', 'IG', 'IH', 'II', 'IJ', 'IK', 'IL', 'IM', 'IN', 'IO', 'IP', 'IQ', 'IR', 'IS', 'IT', 'IU', 'IV', 'IW', 'IX', 'IY', 'IZ', 'JA', 'JB', 'JC', 'JD', 'JE', 'JF', 'JG', 'JH', 'JI', 'JJ', 'JK', 'JL', 'JM', 'JN', 'JO', 'JP', 'JQ', 'JR', 'JS', 'JT', 'JU', 'JV', 'JW', 'JX', 'JY', 'JZ', 'KA', 'KB', 'KC', 'KD', 'KE', 'KF', 'KG', 'KH', 'KI', 'KJ', 'KK', 'KL', 'KM', 'KN', 'KO', 'KP', 'KQ', 'KR', 'KS', 'KT', 'KU', 'KV', 'KW', 'KX', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LD', 'LE', 'LF', 'LG', 'LH', 'LI', 'LJ', 'LK', 'LL', 'LM', 'LN', 'LO', 'LP', 'LQ', 'LR', 'LS', 'LT', 'LU', 'LV', 'LW', 'LX', 'LY', 'LZ', 'MA', 'MB', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MI', 'MJ', 'MK', 'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA', 'NB', 'NC', 'ND', 'NE', 'NF', 'NG', 'NH', 'NI', 'NJ', 'NK', 'NL', 'NM', 'NN', 'NO', 'NP', 'NQ', 'NR', 'NS', 'NT', 'NU', 'NV', 'NW', 'NX', 'NY', 'NZ', 'OA', 'OB', 'OC', 'OD', 'OE', 'OF', 'OG', 'OH', 'OI', 'OJ', 'OK', 'OL', 'OM', 'ON', 'OO', 'OP', 'OQ', 'OR', 'OS', 'OT', 'OU', 'OV', 'OW', 'OX', 'OY', 'OZ', 'PA', 'PB', 'PC', 'PD', 'PE', 'PF', 'PG', 'PH', 'PI', 'PJ', 'PK', 'PL', 'PM', 'PN', 'PO', 'PP', 'PQ', 'PR', 'PS', 'PT', 'PU', 'PV', 'PW', 'PX', 'PY', 'PZ', 'QA', 'QB', 'QC', 'QD', 'QE', 'QF', 'QG', 'QH', 'QI', 'QJ', 'QK', 'QL', 'QM', 'QN', 'QO', 'QP', 'QQ', 'QR', 'QS', 'QT', 'QU', 'QV', 'QW', 'QX', 'QY', 'QZ', 'RA', 'RB', 'RC', 'RD', 'RE', 'RF', 'RG', 'RH', 'RI', 'RJ', 'RK', 'RL', 'RM', 'RN', 'RO', 'RP', 'RQ', 'RR', 'RS', 'RT', 'RU', 'RV', 'RW', 'RX', 'RY', 'RZ', 'SA', 'SB', 'SC', 'SD', 'SE', 'SF', 'SG', 'SH', 'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SP', 'SQ', 'SR', 'SS', 'ST', 'SU', 'SV', 'SW', 'SX', 'SY', 'SZ', 'TA', 'TB', 'TC', 'TD', 'TE', 'TF', 'TG', 'TH', 'TI', 'TJ', 'TK', 'TL', 'TM', 'TN', 'TO', 'TP', 'TQ', 'TR', 'TS', 'TT', 'TU', 'TV', 'TW', 'TX', 'TY', 'TZ', 'UA', 'UB', 'UC', 'UD', 'UE', 'UF', 'UG', 'UH', 'UI', 'UJ', 'UK', 'UL', 'UM', 'UN', 'UO', 'UP', 'UQ', 'UR', 'US', 'UT', 'UU', 'UV', 'UW', 'UX', 'UY', 'UZ', 'VA', 'VB', 'VC', 'VD', 'VE', 'VF', 'VG', 'VH', 'VI', 'VJ', 'VK', 'VL', 'VM', 'VN', 'VO', 'VP', 'VQ', 'VR', 'VS', 'VT', 'VU', 'VV', 'VW', 'VX', 'VY', 'VZ', 'WA', 'WB', 'WC', 'WD', 'WE', 'WF', 'WG', 'WH', 'WI', 'WJ', 'WK', 'WL', 'WM', 'WN', 'WO', 'WP', 'WQ', 'WR', 'WS', 'WT', 'WU', 'WV', 'WW', 'WX', 'WY', 'WZ', 'XA', 'XB', 'XC', 'XD', 'XE', 'XF', 'XG', 'XH', 'XI', 'XJ', 'XK', 'XL', 'XM', 'XN', 'XO', 'XP', 'XQ', 'XR', 'XS', 'XT', 'XU', 'XV', 'XW', 'XX', 'XY', 'XZ', 'YA', 'YB', 'YC', 'YD', 'YE', 'YF', 'YG', 'YH', 'YI', 'YJ', 'YK', 'YL', 'YM', 'YN', 'YO', 'YP', 'YQ', 'YR', 'YS', 'YT', 'YU', 'YV', 'YW', 'YX', 'YY', 'YZ', 'ZA', 'ZB', 'ZC', 'ZD', 'ZE', 'ZF', 'ZG', 'ZH', 'ZI', 'ZJ', 'ZK', 'ZL', 'ZM', 'ZN', 'ZO', 'ZP', 'ZQ', 'ZR', 'ZS', 'ZT', 'ZU', 'ZV', 'ZW', 'ZX', 'ZY', 'ZZ']);
@@ -19,6 +19,6 @@ public function up(): void
 
     public function down(): void
     {
-        Schema::dropIfExists('ip_adress_metadata');
+        Schema::dropIfExists('ip_address_metadata');
     }
 };
-- 
GitLab


From 8aaf9c7de56c50b2460fdf21d51b355baf1fbb9f Mon Sep 17 00:00:00 2001
From: SofianeLasri <alasri250@gmail.com>
Date: Wed, 19 Feb 2025 17:17:43 +0100
Subject: [PATCH 3/9] feat: add IP address metadata resolver service and
 related tests

- Implemented `IpAddressMetadataResolverService` to resolve metadata for IP addresses, including rate limiting and error handling.
- Added console command `ProcessIpAdressesCommand` to process IP addresses and dispatch jobs.
- Created `ProcessIpAddressesJob` to handle the resolution of IP address metadata asynchronously.
- Added feature tests for the new service and commands.
- Updated environment configuration for IP address resolver settings.
---
 .env.local-example                            |  6 +-
 .env.production                               |  6 +-
 .env.testing                                  |  6 +-
 .../Commands/ProcessIpAdressesCommand.php     | 31 ++++++++
 app/Jobs/ProcessIpAddressesJob.php            | 51 +++++++++++++
 .../IpAddressMetadataResolverService.php      | 71 +++++++++++++++++++
 composer.json                                 |  2 +-
 composer.lock                                 | 21 +++---
 config/ip-address-resolver.php                |  7 ++
 .../Command/ProcessIpAdressesCommandTest.php  | 28 ++++++++
 .../Command/ProcessUserAgentsCommandTest.php  | 27 +++++++
 ...p => UpdateImageDimensionsCommandTest.php} |  3 +-
 .../Feature/Service/AiProviderServiceTest.php |  6 +-
 .../IpAddressMetadataResolverServiceTest.php  | 51 +++++++++++++
 14 files changed, 299 insertions(+), 17 deletions(-)
 create mode 100644 app/Console/Commands/ProcessIpAdressesCommand.php
 create mode 100644 app/Jobs/ProcessIpAddressesJob.php
 create mode 100644 app/Services/IpAddressMetadataResolverService.php
 create mode 100644 config/ip-address-resolver.php
 create mode 100644 tests/Feature/Console/Command/ProcessIpAdressesCommandTest.php
 create mode 100644 tests/Feature/Console/Command/ProcessUserAgentsCommandTest.php
 rename tests/Feature/Console/Command/{UpdateImageDimensionsTest.php => UpdateImageDimensionsCommandTest.php} (94%)
 create mode 100644 tests/Feature/Service/IpAddressMetadataResolverServiceTest.php

diff --git a/.env.local-example b/.env.local-example
index 789b5f1..004ebc7 100644
--- a/.env.local-example
+++ b/.env.local-example
@@ -82,4 +82,8 @@ CDN_FILESYSTEM_DISK=bunnycdn
 AI_PROVIDER=openai
 OPENAI_URL=https://api.openai.com/v1/chat/completions
 OPENAI_API_KEY=
-OPENAI_MODEL=gpt-4o-mini
\ No newline at end of file
+OPENAI_MODEL=gpt-4o-mini
+
+IP_ADDRESS_RESOLVER_URL=http://ip-api.com/batch
+IP_ADDRESS_RESOLVER_CALL_LIMIT_PER_MINUTE=15
+IP_ADDRESS_RESOLVER_MAX_IP_ADDRESSES_PER_CALL=100
\ No newline at end of file
diff --git a/.env.production b/.env.production
index 4306866..550e0c2 100644
--- a/.env.production
+++ b/.env.production
@@ -82,4 +82,8 @@ CDN_FILESYSTEM_DISK=bunnycdn
 AI_PROVIDER=openai
 OPENAI_URL=https://api.openai.com/v1/chat/completions
 OPENAI_API_KEY=
-OPENAI_MODEL=gpt-4o-mini
\ No newline at end of file
+OPENAI_MODEL=gpt-4o-mini
+
+IP_ADDRESS_RESOLVER_URL=http://ip-api.com/batch
+IP_ADDRESS_RESOLVER_CALL_LIMIT_PER_MINUTE=15
+IP_ADDRESS_RESOLVER_MAX_IP_ADDRESSES_PER_CALL=100
\ No newline at end of file
diff --git a/.env.testing b/.env.testing
index 27f3f59..28fca8c 100644
--- a/.env.testing
+++ b/.env.testing
@@ -78,4 +78,8 @@ BUNNYCDN_REGION=de
 AI_PROVIDER=openai
 OPENAI_URL=https://api.test-provider.com/v1/chat/completions
 OPENAI_API_KEY=fake-api-key
-OPENAI_MODEL=gpt-4o-mini
\ No newline at end of file
+OPENAI_MODEL=gpt-4o-mini
+
+IP_ADDRESS_RESOLVER_URL=http://api.test-provider.com/batch
+IP_ADDRESS_RESOLVER_CALL_LIMIT_PER_MINUTE=15
+IP_ADDRESS_RESOLVER_MAX_IP_ADDRESSES_PER_CALL=100
\ No newline at end of file
diff --git a/app/Console/Commands/ProcessIpAdressesCommand.php b/app/Console/Commands/ProcessIpAdressesCommand.php
new file mode 100644
index 0000000..c9f8b9e
--- /dev/null
+++ b/app/Console/Commands/ProcessIpAdressesCommand.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Jobs\ProcessIpAddressesJob;
+use Illuminate\Console\Command;
+use SlProjects\LaravelRequestLogger\app\Models\IpAddress;
+
+class ProcessIpAdressesCommand extends Command
+{
+    protected $signature = 'process:ip-adresses';
+
+    protected $description = 'Process ip adresses to resolve their location';
+
+    public function handle(): void
+    {
+        $ipAddresses = IpAddress::leftJoin('ip_address_metadata', 'ip_addresses.id', '=', 'ip_address_metadata.ip_address_id')
+            ->whereNull('ip_address_metadata.id')
+            ->select('ip_addresses.id', 'ip_addresses.ip')
+            ->get();
+
+        if ($ipAddresses->isEmpty()) {
+            $this->info('No ip adresses to process');
+
+            return;
+        }
+
+        $this->info("Processing {$ipAddresses->count()} ip adresses");
+        ProcessIpAddressesJob::dispatch($ipAddresses);
+    }
+}
diff --git a/app/Jobs/ProcessIpAddressesJob.php b/app/Jobs/ProcessIpAddressesJob.php
new file mode 100644
index 0000000..d02f8cd
--- /dev/null
+++ b/app/Jobs/ProcessIpAddressesJob.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace App\Jobs;
+
+use App\Models\IpAddressMetadata;
+use App\Services\IpAddressMetadataResolverService;
+use Exception;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\Log;
+
+class ProcessIpAddressesJob implements ShouldQueue
+{
+    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+    public function __construct(private readonly Collection $ipAddresses) {}
+
+    public function handle(IpAddressMetadataResolverService $ipAddressMetadataResolver): void
+    {
+        try {
+            $metadataObjects = $ipAddressMetadataResolver->resolve($this->ipAddresses);
+        } catch (Exception $exception) {
+            report($exception);
+            $this->fail($exception);
+
+            return;
+        }
+
+        foreach ($metadataObjects as $metadata) {
+            if ($metadata['status'] === 'fail') {
+                Log::warning('Failed to resolve IP address metadata.', [
+                    'query' => $metadata['query'],
+                    'message' => $metadata['message'],
+                ]);
+
+                continue;
+            }
+
+            IpAddressMetadata::create([
+                'ip_address_id' => $this->ipAddresses->where('ip', $metadata['query'])->first()->id,
+                'country_code' => $metadata['countryCode'],
+                'lat' => $metadata['lat'],
+                'lon' => $metadata['lon'],
+            ]);
+        }
+    }
+}
diff --git a/app/Services/IpAddressMetadataResolverService.php b/app/Services/IpAddressMetadataResolverService.php
new file mode 100644
index 0000000..644f34e
--- /dev/null
+++ b/app/Services/IpAddressMetadataResolverService.php
@@ -0,0 +1,71 @@
+<?php
+
+namespace App\Services;
+
+use Exception;
+use Illuminate\Http\Client\ConnectionException;
+use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\Cache;
+use Illuminate\Support\Facades\Http;
+use Illuminate\Support\Facades\Log;
+use SlProjects\LaravelRequestLogger\app\Models\IpAddress;
+
+class IpAddressMetadataResolverService
+{
+    /**
+     * Resolve metadata for the given IP addresses.
+     * This method has a fail tolerance. The only exception that is thrown is when the API server returns a 422 status code.
+     * Server errors are logged and the method returns without throwing an exception.
+     *
+     * @param  Collection  $ipAddresses  The IP addresses to resolve metadata for. Instances of IpAddress.
+     * @return array{array{status: 'success'|'fail', message?: string, countryCode?: string, lat?: float, lon?: float, query: string}} The resolved metadata for each IP address.
+     *
+     * @throws ConnectionException
+     */
+    public static function resolve(Collection $ipAddresses): array
+    {
+        $url = config('ip-address-resolver.url').'?fields=status,message,countryCode,lat,lon,query';
+        $maxIpPerCall = config('ip-address-resolver.max_ip_addresses_per_call');
+        $maxCallsPerMinute = config('ip-address-resolver.call_limit_per_minute');
+        $currentCallsCount = Cache::get('ip-address-resolver.calls_count', 0);
+
+        if ($currentCallsCount >= $maxCallsPerMinute) {
+            Log::info('Max calls per minute reached. Skipping metadata resolution.');
+
+            return [];
+        }
+
+        Cache::increment('ip-address-resolver.calls_count', 1, 60);
+
+        if ($ipAddresses->count() > $maxIpPerCall) {
+            $ipAddresses = $ipAddresses->take($maxIpPerCall);
+        }
+
+        $response = Http::post($url, [
+            'ip_addresses' => $ipAddresses->pluck('ip')->toArray(),
+        ]);
+
+        if ($response->failed()) {
+            $returnedError = [
+                'status' => $response->status(),
+                'message' => $response->body(),
+            ];
+
+            if ($response->unprocessableContent()) {
+                $apiResponse = $response->json();
+                Log::error('The API rejected the request with a 422 unprocessable entity status code. ', $returnedError);
+                throw new Exception('The API rejected the request with a 422 unprocessable entity status code. '.$apiResponse['message']);
+            }
+            if ($response->serverError()) {
+                Log::info('The API server encountered an error while processing the request. Skipping metadata resolution.', $returnedError);
+
+                return [];
+            }
+            Log::error('The API server returned an unexpected status code. Skipping metadata resolution.', $returnedError);
+
+            return [];
+        }
+
+        return $response->json();
+    }
+}
diff --git a/composer.json b/composer.json
index 2147a7f..5622546 100644
--- a/composer.json
+++ b/composer.json
@@ -22,7 +22,7 @@
     "laravel/tinker": "^2.9",
     "platformcommunity/flysystem-bunnycdn": "*",
     "sentry/sentry-laravel": "^4.10",
-    "sl-projects/laravel-request-logger": "^1.0",
+    "sl-projects/laravel-request-logger": "dev-feature/enhance_tests_and_try_fixing_user_agents",
     "spatie/emoji": "^4.1",
     "spatie/laravel-backup": "^9.2",
     "spatie/laravel-markdown": "^2.7"
diff --git a/composer.lock b/composer.lock
index 11c3658..73cb391 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "01fe61521ac3505612dd88366956b8b8",
+  "content-hash": "a338e6602428e2dfbe2d9c34eb5ad10e",
     "packages": [
         {
             "name": "bacon/bacon-qr-code",
@@ -4527,16 +4527,16 @@
         },
         {
             "name": "sl-projects/laravel-request-logger",
-          "version": "v1.0.4",
+          "version": "dev-feature/enhance_tests_and_try_fixing_user_agents",
             "source": {
                 "type": "git",
                 "url": "https://github.com/SofianeLasri/laravel-request-logger.git",
-              "reference": "d39cef07bf23ffdc175830a72152cf97b5344712"
+              "reference": "cab591750e43cc85dfcca186c6825f331307f4d0"
             },
             "dist": {
                 "type": "zip",
-              "url": "https://api.github.com/repos/SofianeLasri/laravel-request-logger/zipball/d39cef07bf23ffdc175830a72152cf97b5344712",
-              "reference": "d39cef07bf23ffdc175830a72152cf97b5344712",
+              "url": "https://api.github.com/repos/SofianeLasri/laravel-request-logger/zipball/cab591750e43cc85dfcca186c6825f331307f4d0",
+              "reference": "cab591750e43cc85dfcca186c6825f331307f4d0",
                 "shasum": ""
             },
             "require": {
@@ -4557,7 +4557,8 @@
             },
             "autoload": {
                 "psr-4": {
-                    "SlProjects\\LaravelRequestLogger\\": "src/"
+                  "SlProjects\\LaravelRequestLogger\\": "src/",
+                  "SlProjects\\LaravelRequestLogger\\Database\\Factories\\": "src/database/factories/"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -4575,9 +4576,9 @@
             "description": "A Laravel package to log all incoming HTTP requests",
             "support": {
                 "issues": "https://github.com/SofianeLasri/laravel-request-logger/issues",
-              "source": "https://github.com/SofianeLasri/laravel-request-logger/tree/v1.0.4"
+              "source": "https://github.com/SofianeLasri/laravel-request-logger/tree/feature/enhance_tests_and_try_fixing_user_agents"
             },
-          "time": "2025-02-18T13:54:49+00:00"
+          "time": "2025-02-19T15:35:38+00:00"
         },
         {
             "name": "spatie/commonmark-shiki-highlighter",
@@ -10435,7 +10436,9 @@
     ],
     "aliases": [],
     "minimum-stability": "stable",
-  "stability-flags": {},
+  "stability-flags": {
+    "sl-projects/laravel-request-logger": 20
+  },
     "prefer-stable": true,
     "prefer-lowest": false,
     "platform": {
diff --git a/config/ip-address-resolver.php b/config/ip-address-resolver.php
new file mode 100644
index 0000000..7dc71a8
--- /dev/null
+++ b/config/ip-address-resolver.php
@@ -0,0 +1,7 @@
+<?php
+
+return [
+    'url' => env('IP_ADDRESS_RESOLVER_URL', 'http://ip-api.com/batch'),
+    'call_limit_per_minute' => env('IP_ADDRESS_RESOLVER_CALL_LIMIT_PER_MINUTE', 15),
+    'max_ip_addresses_per_call' => env('IP_ADDRESS_RESOLVER_MAX_IP_ADDRESSES_PER_CALL', 100),
+];
diff --git a/tests/Feature/Console/Command/ProcessIpAdressesCommandTest.php b/tests/Feature/Console/Command/ProcessIpAdressesCommandTest.php
new file mode 100644
index 0000000..6234d51
--- /dev/null
+++ b/tests/Feature/Console/Command/ProcessIpAdressesCommandTest.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace Tests\Feature\Console\Command;
+
+use App\Console\Commands\ProcessIpAdressesCommand;
+use App\Jobs\ProcessIpAddressesJob;
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Illuminate\Support\Facades\Artisan;
+use Illuminate\Support\Facades\Queue;
+use PHPUnit\Framework\Attributes\CoversClass;
+use SlProjects\LaravelRequestLogger\app\Models\IpAddress;
+use Tests\TestCase;
+
+#[CoversClass(ProcessIpAdressesCommand::class)]
+class ProcessIpAdressesCommandTest extends TestCase
+{
+    use RefreshDatabase;
+
+    public function test_it_dispatches_job()
+    {
+        Queue::fake();
+        IpAddress::factory()->count(10)->create();
+
+        Artisan::call('process:ip-adresses');
+
+        Queue::assertPushed(ProcessIpAddressesJob::class);
+    }
+}
diff --git a/tests/Feature/Console/Command/ProcessUserAgentsCommandTest.php b/tests/Feature/Console/Command/ProcessUserAgentsCommandTest.php
new file mode 100644
index 0000000..7f01e94
--- /dev/null
+++ b/tests/Feature/Console/Command/ProcessUserAgentsCommandTest.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Tests\Feature\Console\Command;
+
+use App\Console\Commands\ProcessUserAgentsCommand;
+use App\Jobs\ProcessUserAgentJob;
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Illuminate\Support\Facades\Queue;
+use PHPUnit\Framework\Attributes\CoversClass;
+use SlProjects\LaravelRequestLogger\app\Models\UserAgent;
+use Tests\TestCase;
+
+#[CoversClass(ProcessUserAgentsCommand::class)]
+class ProcessUserAgentsCommandTest extends TestCase
+{
+    use RefreshDatabase;
+
+    public function test_it_dispatches_job()
+    {
+        Queue::fake();
+        UserAgent::factory()->count(10)->create();
+
+        $this->artisan('process:user-agents');
+
+        Queue::assertPushed(ProcessUserAgentJob::class, 10);
+    }
+}
diff --git a/tests/Feature/Console/Command/UpdateImageDimensionsTest.php b/tests/Feature/Console/Command/UpdateImageDimensionsCommandTest.php
similarity index 94%
rename from tests/Feature/Console/Command/UpdateImageDimensionsTest.php
rename to tests/Feature/Console/Command/UpdateImageDimensionsCommandTest.php
index df50701..34f4c12 100644
--- a/tests/Feature/Console/Command/UpdateImageDimensionsTest.php
+++ b/tests/Feature/Console/Command/UpdateImageDimensionsCommandTest.php
@@ -15,7 +15,8 @@
 /**
  * Tests de la commande de mise à jour des dimensions des images
  */
-#[CoversClass(UpdateImageDimensionsCommand::class)] class UpdateImageDimensionsTest extends TestCase
+#[CoversClass(UpdateImageDimensionsCommand::class)]
+class UpdateImageDimensionsCommandTest extends TestCase
 {
     use RefreshDatabase;
 
diff --git a/tests/Feature/Service/AiProviderServiceTest.php b/tests/Feature/Service/AiProviderServiceTest.php
index 4cd5d62..1de43af 100644
--- a/tests/Feature/Service/AiProviderServiceTest.php
+++ b/tests/Feature/Service/AiProviderServiceTest.php
@@ -60,7 +60,7 @@ public function test_prompt_with_pictures_sends_correct_request()
     {
         Storage::fake('public');
         Http::fake([
-            'https://api.test-provider.com' => Http::response(json_encode($this->sampleResponse)),
+            'https://api.test-provider.com' => Http::response($this->sampleResponse),
         ]);
 
         $mockTranscodingService = Mockery::mock(ImageTranscodingService::class);
@@ -91,7 +91,7 @@ public function test_prompt_with_pictures_sends_correct_request()
     public function test_prompt_sends_correct_request()
     {
         Http::fake([
-            'https://api.test-provider.com' => Http::response(json_encode($this->sampleResponse)),
+            'https://api.test-provider.com' => Http::response($this->sampleResponse),
         ]);
 
         Config::set('ai-provider.selected-provider', 'test-provider');
@@ -116,7 +116,7 @@ public function test_prompt_with_pictures_handles_transcoding_failure()
     {
         Storage::fake('public');
         Http::fake([
-            'https://api.test-provider.com' => Http::response(json_encode($this->sampleResponse)),
+            'https://api.test-provider.com' => Http::response($this->sampleResponse),
         ]);
 
         $mockTranscodingService = Mockery::mock(ImageTranscodingService::class);
diff --git a/tests/Feature/Service/IpAddressMetadataResolverServiceTest.php b/tests/Feature/Service/IpAddressMetadataResolverServiceTest.php
new file mode 100644
index 0000000..dcb6c86
--- /dev/null
+++ b/tests/Feature/Service/IpAddressMetadataResolverServiceTest.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace Tests\Feature\Service;
+
+use App\Services\IpAddressMetadataResolverService;
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Illuminate\Support\Facades\Exceptions;
+use Illuminate\Support\Facades\Http;
+use PHPUnit\Framework\Attributes\CoversClass;
+use SlProjects\LaravelRequestLogger\app\Models\IpAddress;
+use Tests\TestCase;
+
+#[CoversClass(IpAddressMetadataResolverService::class)]
+class IpAddressMetadataResolverServiceTest extends TestCase
+{
+    use RefreshDatabase;
+
+    public function test_resolves_ip_addresses_successfully()
+    {
+        Exceptions::fake();
+
+        Http::fake([
+            '*' => Http::response([
+                [
+                    'status' => 'success',
+                    'countryCode' => 'US',
+                    'lat' => 37.7892,
+                    'lon' => -122.402,
+                    'query' => '208.80.152.201',
+                ],
+                [
+                    'status' => 'success',
+                    'countryCode' => 'CA',
+                    'lat' => 45.6085,
+                    'lon' => -73.5493,
+                    'query' => '24.48.0.1',
+                ],
+            ]),
+        ]);
+
+        $service = new IpAddressMetadataResolverService;
+
+        $ipAddresses = IpAddress::factory()->count(2)->create();
+        $result = $service->resolve($ipAddresses);
+
+        Exceptions::assertNothingReported();
+        $this->assertCount(2, $result);
+        $this->assertEquals('US', $result[0]['countryCode']);
+        $this->assertEquals('CA', $result[1]['countryCode']);
+    }
+}
-- 
GitLab


From c94527bb44c9608f751c2ef6c1e688056c8b067c Mon Sep 17 00:00:00 2001
From: SofianeLasri <alasri250@gmail.com>
Date: Wed, 19 Feb 2025 17:25:10 +0100
Subject: [PATCH 4/9] refactor(tests): rename command test files and update
 namespaces

- Renamed test files in the `tests/Feature/Console/Command` directory to `tests/Feature/Console/Commands`.
- Updated namespaces in the renamed test files to reflect the new directory structure.
- Added a new test file `ProcessIpAddressesJobTest.php` to test the `ProcessIpAddressesJob` functionality.
---
 ...FlushUnusedUploadedPicturesCommandTest.php |  5 +-
 .../OptimizeUploadedPicturesCommandTest.php   |  5 +-
 .../ProcessIpAdressesCommandTest.php          |  2 +-
 .../ProcessUserAgentsCommandTest.php          |  2 +-
 .../UpdateImageDimensionsCommandTest.php      |  2 +-
 .../Jobs/ProcessIpAddressesJobTest.php        | 59 +++++++++++++++++++
 6 files changed, 68 insertions(+), 7 deletions(-)
 rename tests/Feature/Console/{Command => Commands}/FlushUnusedUploadedPicturesCommandTest.php (86%)
 rename tests/Feature/Console/{Command => Commands}/OptimizeUploadedPicturesCommandTest.php (89%)
 rename tests/Feature/Console/{Command => Commands}/ProcessIpAdressesCommandTest.php (94%)
 rename tests/Feature/Console/{Command => Commands}/ProcessUserAgentsCommandTest.php (94%)
 rename tests/Feature/Console/{Command => Commands}/UpdateImageDimensionsCommandTest.php (97%)
 create mode 100644 tests/Feature/Jobs/ProcessIpAddressesJobTest.php

diff --git a/tests/Feature/Console/Command/FlushUnusedUploadedPicturesCommandTest.php b/tests/Feature/Console/Commands/FlushUnusedUploadedPicturesCommandTest.php
similarity index 86%
rename from tests/Feature/Console/Command/FlushUnusedUploadedPicturesCommandTest.php
rename to tests/Feature/Console/Commands/FlushUnusedUploadedPicturesCommandTest.php
index 0d30022..c362a64 100644
--- a/tests/Feature/Console/Command/FlushUnusedUploadedPicturesCommandTest.php
+++ b/tests/Feature/Console/Commands/FlushUnusedUploadedPicturesCommandTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Tests\Feature\Console\Command;
+namespace Tests\Feature\Console\Commands;
 
 use App\Console\Commands\FlushUnusedUploadedPicturesCommand;
 use App\Models\UploadedPicture;
@@ -9,7 +9,8 @@
 use PHPUnit\Framework\Attributes\CoversClass;
 use Tests\TestCase;
 
-#[CoversClass(FlushUnusedUploadedPicturesCommand::class)] class FlushUnusedUploadedPicturesCommandTest extends TestCase
+#[CoversClass(FlushUnusedUploadedPicturesCommand::class)]
+class FlushUnusedUploadedPicturesCommandTest extends TestCase
 {
     use RefreshDatabase;
 
diff --git a/tests/Feature/Console/Command/OptimizeUploadedPicturesCommandTest.php b/tests/Feature/Console/Commands/OptimizeUploadedPicturesCommandTest.php
similarity index 89%
rename from tests/Feature/Console/Command/OptimizeUploadedPicturesCommandTest.php
rename to tests/Feature/Console/Commands/OptimizeUploadedPicturesCommandTest.php
index f9f09ee..8863523 100644
--- a/tests/Feature/Console/Command/OptimizeUploadedPicturesCommandTest.php
+++ b/tests/Feature/Console/Commands/OptimizeUploadedPicturesCommandTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Tests\Feature\Console\Command;
+namespace Tests\Feature\Console\Commands;
 
 use App\Console\Commands\OptimizeUploadedPicturesCommand;
 use App\Models\UploadedPicture;
@@ -12,7 +12,8 @@
 /**
  * Tests de la commande d'optimisation des images uploadées
  */
-#[CoversClass(OptimizeUploadedPicturesCommand::class)] class OptimizeUploadedPicturesCommandTest extends TestCase
+#[CoversClass(OptimizeUploadedPicturesCommand::class)]
+class OptimizeUploadedPicturesCommandTest extends TestCase
 {
     use RefreshDatabase;
 
diff --git a/tests/Feature/Console/Command/ProcessIpAdressesCommandTest.php b/tests/Feature/Console/Commands/ProcessIpAdressesCommandTest.php
similarity index 94%
rename from tests/Feature/Console/Command/ProcessIpAdressesCommandTest.php
rename to tests/Feature/Console/Commands/ProcessIpAdressesCommandTest.php
index 6234d51..87153e4 100644
--- a/tests/Feature/Console/Command/ProcessIpAdressesCommandTest.php
+++ b/tests/Feature/Console/Commands/ProcessIpAdressesCommandTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Tests\Feature\Console\Command;
+namespace Tests\Feature\Console\Commands;
 
 use App\Console\Commands\ProcessIpAdressesCommand;
 use App\Jobs\ProcessIpAddressesJob;
diff --git a/tests/Feature/Console/Command/ProcessUserAgentsCommandTest.php b/tests/Feature/Console/Commands/ProcessUserAgentsCommandTest.php
similarity index 94%
rename from tests/Feature/Console/Command/ProcessUserAgentsCommandTest.php
rename to tests/Feature/Console/Commands/ProcessUserAgentsCommandTest.php
index 7f01e94..c6390dc 100644
--- a/tests/Feature/Console/Command/ProcessUserAgentsCommandTest.php
+++ b/tests/Feature/Console/Commands/ProcessUserAgentsCommandTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Tests\Feature\Console\Command;
+namespace Tests\Feature\Console\Commands;
 
 use App\Console\Commands\ProcessUserAgentsCommand;
 use App\Jobs\ProcessUserAgentJob;
diff --git a/tests/Feature/Console/Command/UpdateImageDimensionsCommandTest.php b/tests/Feature/Console/Commands/UpdateImageDimensionsCommandTest.php
similarity index 97%
rename from tests/Feature/Console/Command/UpdateImageDimensionsCommandTest.php
rename to tests/Feature/Console/Commands/UpdateImageDimensionsCommandTest.php
index 34f4c12..99b4578 100644
--- a/tests/Feature/Console/Command/UpdateImageDimensionsCommandTest.php
+++ b/tests/Feature/Console/Commands/UpdateImageDimensionsCommandTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Tests\Feature\Console\Command;
+namespace Tests\Feature\Console\Commands;
 
 use App\Console\Commands\UpdateImageDimensionsCommand;
 use App\Models\UploadedPicture;
diff --git a/tests/Feature/Jobs/ProcessIpAddressesJobTest.php b/tests/Feature/Jobs/ProcessIpAddressesJobTest.php
new file mode 100644
index 0000000..0057137
--- /dev/null
+++ b/tests/Feature/Jobs/ProcessIpAddressesJobTest.php
@@ -0,0 +1,59 @@
+<?php
+
+namespace Tests\Feature\Jobs;
+
+use App\Jobs\ProcessIpAddressesJob;
+use App\Services\IpAddressMetadataResolverService;
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Illuminate\Support\Facades\Http;
+use PHPUnit\Framework\Attributes\CoversClass;
+use SlProjects\LaravelRequestLogger\app\Models\IpAddress;
+use Tests\TestCase;
+
+#[CoversClass(ProcessIpAddressesJob::class)]
+class ProcessIpAddressesJobTest extends TestCase
+{
+    use RefreshDatabase;
+
+    public function test_processes_ip_addresses_successfully()
+    {
+        $ip1 = IpAddress::factory()->create(['ip' => '208.80.152.201']);
+        $ip2 = IpAddress::factory()->create(['ip' => '24.48.0.1']);
+
+        Http::fake([
+            '*' => Http::response([
+                [
+                    'status' => 'success',
+                    'countryCode' => 'US',
+                    'lat' => 37.7892,
+                    'lon' => -122.402,
+                    'query' => '208.80.152.201',
+                ],
+                [
+                    'status' => 'success',
+                    'countryCode' => 'CA',
+                    'lat' => 45.6085,
+                    'lon' => -73.5493,
+                    'query' => '24.48.0.1',
+                ],
+            ]),
+        ]);
+
+        $job = new ProcessIpAddressesJob(collect([$ip1, $ip2]));
+        $job->handle(app(IpAddressMetadataResolverService::class));
+
+        $this->assertDatabaseHas('ip_address_metadata', [
+            'ip_address_id' => $ip1->id,
+            'country_code' => 'US',
+            'lat' => 37.7892,
+            'lon' => -122.402,
+        ]);
+
+        $this->assertDatabaseHas('ip_address_metadata', [
+            'ip_address_id' => $ip2->id,
+            'country_code' => 'CA',
+            'lat' => 45.6085,
+            'lon' => -73.5493,
+        ]);
+    }
+}
-- 
GitLab


From 6b1140b7bbc13db80e764523f537cd34b735f8f5 Mon Sep 17 00:00:00 2001
From: SofianeLasri <alasri250@gmail.com>
Date: Wed, 19 Feb 2025 17:26:09 +0100
Subject: [PATCH 5/9] feat: add scheduled command to process IP addresses
 hourly

---
 routes/console.php | 1 +
 1 file changed, 1 insertion(+)

diff --git a/routes/console.php b/routes/console.php
index 0ef4bc9..a2e9f05 100644
--- a/routes/console.php
+++ b/routes/console.php
@@ -9,6 +9,7 @@
 
 Schedule::command('save:requests')->everyMinute()->sentryMonitor();
 Schedule::command('process:user-agents')->hourly()->sentryMonitor();
+Schedule::command('process:ip-adresses')->hourly()->sentryMonitor();
 Schedule::command('flush:unused-uploaded-pictures')->daily()->sentryMonitor();
 
 Schedule::command('backup:clean --disable-notifications')->daily()->at('01:00');
-- 
GitLab


From 85da8689fa708cad6b66553a888d1e5f6eb11f4e Mon Sep 17 00:00:00 2001
From: SofianeLasri <alasri250@gmail.com>
Date: Wed, 19 Feb 2025 17:37:34 +0100
Subject: [PATCH 6/9] feat: optimize IP address processing and update scheduled
 command frequency

- Simplified the HTTP request in `IpAddressMetadataResolverService.php` by removing unnecessary array wrapping.
- Updated the join in `HomeController.php` to include `ip_address_metadata` for more accurate data retrieval.
- Changed the frequency of the `process:ip-adresses` command in `console.php` to run every five minutes instead of hourly.
---
 app/Http/Controllers/Admin/HomeController.php     | 3 ++-
 app/Services/IpAddressMetadataResolverService.php | 4 +---
 routes/console.php                                | 2 +-
 3 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/app/Http/Controllers/Admin/HomeController.php b/app/Http/Controllers/Admin/HomeController.php
index 2af9767..33e3cb1 100644
--- a/app/Http/Controllers/Admin/HomeController.php
+++ b/app/Http/Controllers/Admin/HomeController.php
@@ -25,13 +25,14 @@ public function index(): View
         $visits = LoggedRequest::selectRaw('
                 logged_requests.url_id,
                 logged_requests.ip_address_id,
-                logged_requests.country_code,
+                ip_address_metadata.country_code,
                 logged_requests.created_at,
                 urls.url
             ')
             ->distinct('logged_requests.url_id', 'logged_requests.ip_address_id')
             ->join('urls', 'logged_requests.url_id', '=', 'urls.id')
             ->join('user_agent_metadata', 'logged_requests.user_agent_id', '=', 'user_agent_metadata.user_agent_id')
+            ->join('ip_address_metadata', 'logged_requests.ip_address_id', '=', 'ip_address_metadata.ip_address_id')
             ->whereLike('urls.url', config('app.url').'%')
             ->whereNotIn('urls.url', $individualExcludedRoutes)
             ->where('user_agent_metadata.is_bot', false)
diff --git a/app/Services/IpAddressMetadataResolverService.php b/app/Services/IpAddressMetadataResolverService.php
index 644f34e..13f4eae 100644
--- a/app/Services/IpAddressMetadataResolverService.php
+++ b/app/Services/IpAddressMetadataResolverService.php
@@ -41,9 +41,7 @@ public static function resolve(Collection $ipAddresses): array
             $ipAddresses = $ipAddresses->take($maxIpPerCall);
         }
 
-        $response = Http::post($url, [
-            'ip_addresses' => $ipAddresses->pluck('ip')->toArray(),
-        ]);
+        $response = Http::post($url, $ipAddresses->pluck('ip')->toArray());
 
         if ($response->failed()) {
             $returnedError = [
diff --git a/routes/console.php b/routes/console.php
index a2e9f05..3719509 100644
--- a/routes/console.php
+++ b/routes/console.php
@@ -9,7 +9,7 @@
 
 Schedule::command('save:requests')->everyMinute()->sentryMonitor();
 Schedule::command('process:user-agents')->hourly()->sentryMonitor();
-Schedule::command('process:ip-adresses')->hourly()->sentryMonitor();
+Schedule::command('process:ip-adresses')->everyFiveMinutes()->sentryMonitor();
 Schedule::command('flush:unused-uploaded-pictures')->daily()->sentryMonitor();
 
 Schedule::command('backup:clean --disable-notifications')->daily()->at('01:00');
-- 
GitLab


From 5f7d0ebee9df9f821a93744c990ce3f336612cd5 Mon Sep 17 00:00:00 2001
From: SofianeLasri <alasri250@gmail.com>
Date: Wed, 19 Feb 2025 17:55:53 +0100
Subject: [PATCH 7/9] refactor(HomeController): simplify query structure for
 logged requests

---
 app/Http/Controllers/Admin/HomeController.php | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/app/Http/Controllers/Admin/HomeController.php b/app/Http/Controllers/Admin/HomeController.php
index 33e3cb1..a8afe81 100644
--- a/app/Http/Controllers/Admin/HomeController.php
+++ b/app/Http/Controllers/Admin/HomeController.php
@@ -22,13 +22,12 @@ public function index(): View
             }
         }
 
-        $visits = LoggedRequest::selectRaw('
-                logged_requests.url_id,
-                logged_requests.ip_address_id,
-                ip_address_metadata.country_code,
-                logged_requests.created_at,
-                urls.url
-            ')
+        $visits = LoggedRequest::select([
+            'logged_requests.url_id',
+            'logged_requests.ip_address_id',
+            'ip_address_metadata.country_code',
+            'logged_requests.created_at',
+            'urls.url'])
             ->distinct('logged_requests.url_id', 'logged_requests.ip_address_id')
             ->join('urls', 'logged_requests.url_id', '=', 'urls.id')
             ->join('user_agent_metadata', 'logged_requests.user_agent_id', '=', 'user_agent_metadata.user_agent_id')
-- 
GitLab


From 421bd98bbb23d66be51ab74a7230c0f8298010dc Mon Sep 17 00:00:00 2001
From: SofianeLasri <alasri250@gmail.com>
Date: Wed, 19 Feb 2025 18:02:30 +0100
Subject: [PATCH 8/9] chore: update laravel-request-logger version and clean up
 composer files

---
 composer.json |  2 +-
 composer.lock | 92 +++++++++++++++++++++++++--------------------------
 2 files changed, 46 insertions(+), 48 deletions(-)

diff --git a/composer.json b/composer.json
index 5622546..2147a7f 100644
--- a/composer.json
+++ b/composer.json
@@ -22,7 +22,7 @@
     "laravel/tinker": "^2.9",
     "platformcommunity/flysystem-bunnycdn": "*",
     "sentry/sentry-laravel": "^4.10",
-    "sl-projects/laravel-request-logger": "dev-feature/enhance_tests_and_try_fixing_user_agents",
+    "sl-projects/laravel-request-logger": "^1.0",
     "spatie/emoji": "^4.1",
     "spatie/laravel-backup": "^9.2",
     "spatie/laravel-markdown": "^2.7"
diff --git a/composer.lock b/composer.lock
index 73cb391..4dad8ba 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-  "content-hash": "a338e6602428e2dfbe2d9c34eb5ad10e",
+    "content-hash": "01fe61521ac3505612dd88366956b8b8",
     "packages": [
         {
             "name": "bacon/bacon-qr-code",
@@ -4438,20 +4438,20 @@
         },
         {
             "name": "sentry/sentry-laravel",
-          "version": "4.13.0",
+            "version": "4.13.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/getsentry/sentry-laravel.git",
-              "reference": "d232ac494258e0d50a77c575a5af5f1a426d3f87"
+                "reference": "d232ac494258e0d50a77c575a5af5f1a426d3f87"
             },
             "dist": {
                 "type": "zip",
-              "url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/d232ac494258e0d50a77c575a5af5f1a426d3f87",
-              "reference": "d232ac494258e0d50a77c575a5af5f1a426d3f87",
+                "url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/d232ac494258e0d50a77c575a5af5f1a426d3f87",
+                "reference": "d232ac494258e0d50a77c575a5af5f1a426d3f87",
                 "shasum": ""
             },
             "require": {
-              "illuminate/support": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0 | ^12.0",
+                "illuminate/support": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0 | ^12.0",
                 "nyholm/psr7": "^1.0",
                 "php": "^7.2 | ^8.0",
                 "sentry/sentry": "^4.10",
@@ -4461,12 +4461,12 @@
                 "friendsofphp/php-cs-fixer": "^3.11",
                 "guzzlehttp/guzzle": "^7.2",
                 "laravel/folio": "^1.1",
-              "laravel/framework": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0 | ^12.0",
+                "laravel/framework": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0 | ^12.0",
                 "livewire/livewire": "^2.0 | ^3.0",
                 "mockery/mockery": "^1.3",
-              "orchestra/testbench": "^4.7 | ^5.1 | ^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0",
+                "orchestra/testbench": "^4.7 | ^5.1 | ^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0",
                 "phpstan/phpstan": "^1.10",
-              "phpunit/phpunit": "^8.4 | ^9.3 | ^10.4 | ^11.5"
+                "phpunit/phpunit": "^8.4 | ^9.3 | ^10.4 | ^11.5"
             },
             "type": "library",
             "extra": {
@@ -4511,7 +4511,7 @@
             ],
             "support": {
                 "issues": "https://github.com/getsentry/sentry-laravel/issues",
-              "source": "https://github.com/getsentry/sentry-laravel/tree/4.13.0"
+                "source": "https://github.com/getsentry/sentry-laravel/tree/4.13.0"
             },
             "funding": [
                 {
@@ -4523,20 +4523,20 @@
                     "type": "custom"
                 }
             ],
-          "time": "2025-02-18T10:09:29+00:00"
+            "time": "2025-02-18T10:09:29+00:00"
         },
         {
             "name": "sl-projects/laravel-request-logger",
-          "version": "dev-feature/enhance_tests_and_try_fixing_user_agents",
+            "version": "v1.0.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/SofianeLasri/laravel-request-logger.git",
-              "reference": "cab591750e43cc85dfcca186c6825f331307f4d0"
+                "reference": "e42196f70e1c3b7b1ad2ea9a202b6d1e8c5a585f"
             },
             "dist": {
                 "type": "zip",
-              "url": "https://api.github.com/repos/SofianeLasri/laravel-request-logger/zipball/cab591750e43cc85dfcca186c6825f331307f4d0",
-              "reference": "cab591750e43cc85dfcca186c6825f331307f4d0",
+                "url": "https://api.github.com/repos/SofianeLasri/laravel-request-logger/zipball/e42196f70e1c3b7b1ad2ea9a202b6d1e8c5a585f",
+                "reference": "e42196f70e1c3b7b1ad2ea9a202b6d1e8c5a585f",
                 "shasum": ""
             },
             "require": {
@@ -4557,8 +4557,8 @@
             },
             "autoload": {
                 "psr-4": {
-                  "SlProjects\\LaravelRequestLogger\\": "src/",
-                  "SlProjects\\LaravelRequestLogger\\Database\\Factories\\": "src/database/factories/"
+                    "SlProjects\\LaravelRequestLogger\\": "src/",
+                    "SlProjects\\LaravelRequestLogger\\Database\\Factories\\": "src/database/factories/"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -4576,9 +4576,9 @@
             "description": "A Laravel package to log all incoming HTTP requests",
             "support": {
                 "issues": "https://github.com/SofianeLasri/laravel-request-logger/issues",
-              "source": "https://github.com/SofianeLasri/laravel-request-logger/tree/feature/enhance_tests_and_try_fixing_user_agents"
+                "source": "https://github.com/SofianeLasri/laravel-request-logger/tree/v1.0.6"
             },
-          "time": "2025-02-19T15:35:38+00:00"
+            "time": "2025-02-19T16:59:10+00:00"
         },
         {
             "name": "spatie/commonmark-shiki-highlighter",
@@ -5082,16 +5082,16 @@
         },
         {
             "name": "spatie/shiki-php",
-          "version": "2.3.1",
+            "version": "2.3.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/spatie/shiki-php.git",
-              "reference": "24b4dcc161f37144180edbef49557edb96c1dc2d"
+                "reference": "24b4dcc161f37144180edbef49557edb96c1dc2d"
             },
             "dist": {
                 "type": "zip",
-              "url": "https://api.github.com/repos/spatie/shiki-php/zipball/24b4dcc161f37144180edbef49557edb96c1dc2d",
-              "reference": "24b4dcc161f37144180edbef49557edb96c1dc2d",
+                "url": "https://api.github.com/repos/spatie/shiki-php/zipball/24b4dcc161f37144180edbef49557edb96c1dc2d",
+                "reference": "24b4dcc161f37144180edbef49557edb96c1dc2d",
                 "shasum": ""
             },
             "require": {
@@ -5135,7 +5135,7 @@
                 "spatie"
             ],
             "support": {
-              "source": "https://github.com/spatie/shiki-php/tree/2.3.1"
+                "source": "https://github.com/spatie/shiki-php/tree/2.3.1"
             },
             "funding": [
                 {
@@ -5143,7 +5143,7 @@
                     "type": "github"
                 }
             ],
-          "time": "2025-02-18T13:18:46+00:00"
+            "time": "2025-02-18T13:18:46+00:00"
         },
         {
             "name": "spatie/temporary-directory",
@@ -8278,16 +8278,16 @@
         },
         {
             "name": "laravel/pint",
-          "version": "v1.21.0",
+            "version": "v1.21.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/pint.git",
-              "reference": "531fa0871fbde719c51b12afa3a443b8f4e4b425"
+                "reference": "531fa0871fbde719c51b12afa3a443b8f4e4b425"
             },
             "dist": {
                 "type": "zip",
-              "url": "https://api.github.com/repos/laravel/pint/zipball/531fa0871fbde719c51b12afa3a443b8f4e4b425",
-              "reference": "531fa0871fbde719c51b12afa3a443b8f4e4b425",
+                "url": "https://api.github.com/repos/laravel/pint/zipball/531fa0871fbde719c51b12afa3a443b8f4e4b425",
+                "reference": "531fa0871fbde719c51b12afa3a443b8f4e4b425",
                 "shasum": ""
             },
             "require": {
@@ -8295,15 +8295,15 @@
                 "ext-mbstring": "*",
                 "ext-tokenizer": "*",
                 "ext-xml": "*",
-              "php": "^8.2.0"
+                "php": "^8.2.0"
             },
             "require-dev": {
-              "friendsofphp/php-cs-fixer": "^3.68.5",
-              "illuminate/view": "^11.42.0",
-              "larastan/larastan": "^3.0.4",
-              "laravel-zero/framework": "^11.36.1",
+                "friendsofphp/php-cs-fixer": "^3.68.5",
+                "illuminate/view": "^11.42.0",
+                "larastan/larastan": "^3.0.4",
+                "laravel-zero/framework": "^11.36.1",
                 "mockery/mockery": "^1.6.12",
-              "nunomaduro/termwind": "^2.3",
+                "nunomaduro/termwind": "^2.3",
                 "pestphp/pest": "^2.36.0"
             },
             "bin": [
@@ -8340,7 +8340,7 @@
                 "issues": "https://github.com/laravel/pint/issues",
                 "source": "https://github.com/laravel/pint"
             },
-          "time": "2025-02-18T03:18:57+00:00"
+            "time": "2025-02-18T03:18:57+00:00"
         },
         {
             "name": "laravel/sail",
@@ -9234,16 +9234,16 @@
         },
         {
             "name": "phpunit/phpunit",
-          "version": "11.5.8",
+            "version": "11.5.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
-              "reference": "c9bd61aab12f0fc5e82ecfe621ff518a1d1f1049"
+                "reference": "c9bd61aab12f0fc5e82ecfe621ff518a1d1f1049"
             },
             "dist": {
                 "type": "zip",
-              "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c9bd61aab12f0fc5e82ecfe621ff518a1d1f1049",
-              "reference": "c9bd61aab12f0fc5e82ecfe621ff518a1d1f1049",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c9bd61aab12f0fc5e82ecfe621ff518a1d1f1049",
+                "reference": "c9bd61aab12f0fc5e82ecfe621ff518a1d1f1049",
                 "shasum": ""
             },
             "require": {
@@ -9315,7 +9315,7 @@
             "support": {
                 "issues": "https://github.com/sebastianbergmann/phpunit/issues",
                 "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
-              "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.8"
+                "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.8"
             },
             "funding": [
                 {
@@ -9331,7 +9331,7 @@
                     "type": "tidelift"
                 }
             ],
-          "time": "2025-02-18T06:26:59+00:00"
+            "time": "2025-02-18T06:26:59+00:00"
         },
         {
             "name": "sebastian/cli-parser",
@@ -10436,9 +10436,7 @@
     ],
     "aliases": [],
     "minimum-stability": "stable",
-  "stability-flags": {
-    "sl-projects/laravel-request-logger": 20
-  },
+    "stability-flags": {},
     "prefer-stable": true,
     "prefer-lowest": false,
     "platform": {
@@ -10447,6 +10445,6 @@
         "ext-pdo": "*",
         "ext-zip": "*"
     },
-  "platform-dev": {},
-  "plugin-api-version": "2.6.0"
+    "platform-dev": {},
+    "plugin-api-version": "2.6.0"
 }
-- 
GitLab


From 3d447d34c3aa553f27882c83012c195e5deff19e Mon Sep 17 00:00:00 2001
From: SofianeLasri <alasri250@gmail.com>
Date: Wed, 19 Feb 2025 18:05:13 +0100
Subject: [PATCH 9/9] chore: update dependencies in composer.lock to latest
 versions

---
 composer.lock | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/composer.lock b/composer.lock
index 4dad8ba..31c0384 100644
--- a/composer.lock
+++ b/composer.lock
@@ -1680,16 +1680,16 @@
         },
         {
             "name": "laravel/framework",
-            "version": "v11.42.1",
+            "version": "v11.43.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/framework.git",
-                "reference": "ff392f42f6c55cc774ce75553a11c6b031da67f8"
+                "reference": "053f26afb699c845945e7380b407dd019a0a2c74"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/framework/zipball/ff392f42f6c55cc774ce75553a11c6b031da67f8",
-                "reference": "ff392f42f6c55cc774ce75553a11c6b031da67f8",
+                "url": "https://api.github.com/repos/laravel/framework/zipball/053f26afb699c845945e7380b407dd019a0a2c74",
+                "reference": "053f26afb699c845945e7380b407dd019a0a2c74",
                 "shasum": ""
             },
             "require": {
@@ -1891,7 +1891,7 @@
                 "issues": "https://github.com/laravel/framework/issues",
                 "source": "https://github.com/laravel/framework"
             },
-            "time": "2025-02-12T20:58:18+00:00"
+            "time": "2025-02-19T16:06:03+00:00"
         },
         {
             "name": "laravel/horizon",
@@ -1975,16 +1975,16 @@
         },
         {
             "name": "laravel/octane",
-            "version": "v2.7.0",
+            "version": "v2.8.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/octane.git",
-                "reference": "c9580d430fa8459823bd1dfbcb2bcfd591548cec"
+                "reference": "1c5190cc5ad67eb4aadbf1816dcbfedc692851e7"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/octane/zipball/c9580d430fa8459823bd1dfbcb2bcfd591548cec",
-                "reference": "c9580d430fa8459823bd1dfbcb2bcfd591548cec",
+                "url": "https://api.github.com/repos/laravel/octane/zipball/1c5190cc5ad67eb4aadbf1816dcbfedc692851e7",
+                "reference": "1c5190cc5ad67eb4aadbf1816dcbfedc692851e7",
                 "shasum": ""
             },
             "require": {
@@ -2061,7 +2061,7 @@
                 "issues": "https://github.com/laravel/octane/issues",
                 "source": "https://github.com/laravel/octane"
             },
-            "time": "2025-02-11T15:04:38+00:00"
+            "time": "2025-02-18T15:18:13+00:00"
         },
         {
             "name": "laravel/prompts",
@@ -8853,16 +8853,16 @@
         },
         {
             "name": "phpstan/phpstan",
-            "version": "2.1.5",
+            "version": "2.1.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpstan/phpstan.git",
-                "reference": "451b17f9665481ee502adc39be987cb71067ece2"
+                "reference": "6eaec7c6c9e90dcfe46ad1e1ffa5171e2dab641c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpstan/phpstan/zipball/451b17f9665481ee502adc39be987cb71067ece2",
-                "reference": "451b17f9665481ee502adc39be987cb71067ece2",
+                "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6eaec7c6c9e90dcfe46ad1e1ffa5171e2dab641c",
+                "reference": "6eaec7c6c9e90dcfe46ad1e1ffa5171e2dab641c",
                 "shasum": ""
             },
             "require": {
@@ -8907,7 +8907,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2025-02-13T12:49:56+00:00"
+            "time": "2025-02-19T15:46:42+00:00"
         },
         {
             "name": "phpunit/php-code-coverage",
-- 
GitLab