diff --git a/app/Console/Commands/CronCheckLocation.php b/app/Console/Commands/CronCheckLocation.php
new file mode 100644
index 00000000..58fd3fc3
--- /dev/null
+++ b/app/Console/Commands/CronCheckLocation.php
@@ -0,0 +1,47 @@
+where(function ($query) {
+ $query->whereNull('network_info')
+ ->orWhereNotNull('network_location');
+ })
+ ->where('nmea_distance', '<=', 50)
+ ->where('distance', '<=', 5000)
+ ->update(['flg_checked_location' => 1]);
+
+ Photo::
+ whereNull('flg_checked_location')
+ ->where(function ($query) {
+ $query->whereNull('network_info')
+ ->orWhereNotNull('network_location');
+ })
+ ->update(['flg_checked_location' => 0]);
+ }
+}
diff --git a/app/Console/Commands/PomLocateByNmea.php b/app/Console/Commands/PomLocateByNmea.php
new file mode 100644
index 00000000..10bb1d73
--- /dev/null
+++ b/app/Console/Commands/PomLocateByNmea.php
@@ -0,0 +1,64 @@
+whereNull('flg_checked_location')
+ ->where('device_platform', 'Android')
+ ->limit(2000)
+ ->get();
+
+ foreach ($photos as $photo) {
+ $photoId = $photo->id;
+ $nmeaMsg = $photo->nmea_msg;
+ $lat = $photo->lat;
+ $lng = $photo->lng;
+
+ $nmeaLocation = get_coordinates_from_nmea($nmeaMsg);
+
+ if ($nmeaLocation) {
+ $nmeaLocationJson = json_encode($nmeaLocation);
+ $distance = get_distance_from_coordinates($lat, $lng, $nmeaLocation['lat'], $nmeaLocation['lon']);
+ $checkLocation = $distance < 50 ? 1 : 0;
+
+ Photo::
+ where('id', $photoId)
+ ->update([
+ 'nmea_location' => $nmeaLocationJson,
+ 'nmea_distance' => $distance,
+ 'flg_checked_location' => $checkLocation,
+ ]);
+ } else {
+ Photo::
+ where('id', $photoId)
+ ->update(['flg_checked_location' => 0]);
+ }
+ }
+
+ }
+}
diff --git a/app/Http/Controllers/ApiController.php b/app/Http/Controllers/ApiController.php
index 11ba1299..135900a1 100644
--- a/app/Http/Controllers/ApiController.php
+++ b/app/Http/Controllers/ApiController.php
@@ -15,6 +15,7 @@
use App\Models\Attr\Codepoint;
use App\Models\Attr\BuildingPart;
use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Log;
use App\Http\Resources\UprnCollection;
use App\Http\Resources\ShapeCollection;
@@ -214,6 +215,8 @@ public function comm_photo(Request $request){
$photo = json_decode($photo_json, true);
if (json_last_error() === JSON_ERROR_NONE) {
$output = setPhoto($photo, $user_id, $task_id);
+ Artisan::queue('app:pom-locate-by-nmea');
+ Artisan::queue('app:cron-check-location');
} else {
$output['status'] = 'error';
$output['error_msg'] = 'photo json decode error';
diff --git a/app/helpers.php b/app/helpers.php
index 8cd57ffa..e60688dd 100644
--- a/app/helpers.php
+++ b/app/helpers.php
@@ -162,7 +162,11 @@ function setPhoto($photo, $user_id, $task_id)
'nmea_location' => null,
'nmea_distance' => null,
'digest' => $photo['digest'],
- 'timestamp' => Carbon::now()->format('Y-m-d H:i:s')
+ 'timestamp' => Carbon::now()->format('Y-m-d H:i:s'),
+ 'provider' => $photo['provider'] ?? null,
+ 'osnma_enabled' => $photo['osnmaEnabled'] ?? null,
+ 'osnma_validated' => $photo['osnmaValidated'] ?? null,
+ 'validated_sats' => $photo['validatedSats'] ?? null
]);
$status['photo_id'] = $newPhoto->id;
@@ -257,7 +261,12 @@ function getPhoto($photo_id, $wantsbase64Photo=false)
'path',
'file_name',
'digest',
- 'rotation_correction as angle'
+ 'rotation_correction as angle',
+ 'network_info',
+ 'provider',
+ 'osnma_enabled',
+ 'osnma_validated',
+ 'validated_sats'
])
->where('flg_deleted', 0)
->where('id', $photo_id)
@@ -307,7 +316,12 @@ function getPhoto($photo_id, $wantsbase64Photo=false)
'created' => $photo->created,
'digest' => $photo->digest,
'link' => $photo->link,
- 'angle' => $photo->angle
+ 'angle' => $photo->angle,
+ 'network_info' => $photo->network_info,
+ 'provider' => $photo->provider,
+ 'osnma_enabled' => $photo->osnma_enabled,
+ 'osnma_validated' => $photo->osnma_validated,
+ 'validated_sats' => $photo->validated_sats
];
if($wantsbase64Photo){
@@ -354,7 +368,7 @@ function get_distance_from_coordinates($a_lat, $a_lng, $b_lat, $b_lng)
$const_p = pi() / 180;
$const_r = 12742;
- $a = 0.5 - cos(($b_lat - $a_lat) * $const_p) / 2 + cos($a_lat * $const_p) * cos($b_lat * $const_p) * (1 - cos(($b_lng - $a_lng) * $const_p)) / 2;
+ $a = 0.5 - cos(($b_lat - $a_lat) * $const_p) / 2 + cos($a_lat * $const_p) * cos($b_lat * $const_p) * (1 - cos((null) * $const_p)) / 2;
$distance = $const_r * sin(sqrt($a));
@@ -424,6 +438,10 @@ function setPhotos($photos, $user_id, $task_id)
$efkLngGpsIf = $photo['efkLngGpsIf'] ?? null;
$efkAltGpsIf = $photo['efkAltGpsIf'] ?? null;
$efkTimeGpsIf = isset($photo['efkTimeGpsIf']) ? gmdate('Y-m-d H:i:s', strtotime($photo['efkTimeGpsIf'])) : null;
+ $provider = isset($photo['provider']) ? $photo['provider'] : null;
+ $osnmaEnabled = isset($photo['osnmaEnabled']) ? $photo['osnmaEnabled'] : null;
+ $osnmaValidated = isset($photo['osnmaValidated']) ? $photo['osnmaValidated'] : null;
+ $validatedSats = isset($photo['validatedSats']) ? $photo['validatedSats'] : null;
$existing_photo = DB::table('photo')->where('digest', $digest)->first();
@@ -472,6 +490,10 @@ function setPhotos($photos, $user_id, $task_id)
'efkLngGpsIf' => $efkLngGpsIf,
'efkAltGpsIf' => $efkAltGpsIf,
'efkTimeGpsIf' => $efkTimeGpsIf,
+ 'provider' => $provider,
+ 'osnma_enabled' => $osnmaEnabled,
+ 'osnma_validated' => $osnmaValidated,
+ 'validated_sats' => $validatedSats
]);
if (isset($photo['photo'])) {
$sql_path = DB::table('user')->select('pa_id')->where('id', $user_id)->first();
@@ -592,7 +614,14 @@ function getTaskPhotos($task_id = null, $user_id = null, $wantsBase64Photo=false
'file_name',
'digest',
'id',
- 'rotation_correction as angle'
+ 'rotation_correction as angle',
+ 'flg_checked_location',
+ 'flg_original',
+ 'network_info',
+ 'provider',
+ 'osnma_enabled',
+ 'osnma_validated',
+ 'validated_sats'
])
->where('flg_deleted', 0);
@@ -651,6 +680,11 @@ function getTaskPhotos($task_id = null, $user_id = null, $wantsBase64Photo=false
'id' => $photo->id,
'angle' => $photo->angle,
'link' => $photo->link,
+ 'network_info' => $photo->network_info,
+ 'provider' => $photo->provider,
+ 'osnma_enabled' => $photo->osnma_enabled,
+ 'osnma_validated' => $photo->osnma_validated,
+ 'validated_sats' => $photo->validated_sats
];
if($wantsBase64Photo){
$file = null;
@@ -662,11 +696,15 @@ function getTaskPhotos($task_id = null, $user_id = null, $wantsBase64Photo=false
}else{
$out['link'] = $photo->link;
}
-
+
+ $photoVerificationData = getPhotoVerifiedStatus($photo);
+ $out['return'] = $photoVerificationData['return'];
+ $out['verified'] = $photoVerificationData['verified'];
+
+
$output[] = $out;
}
-
return $output;
}
@@ -708,7 +746,7 @@ function deleteSelectedUnassignedPhoto(array $uids)
return $affectedRows;
}
-function getPhotosWithoutTask($user_id)
+function getPhotosWithoutTask($user_id, $paginate = false)
{
$photos = Photo
::select([
@@ -754,15 +792,22 @@ function getPhotosWithoutTask($user_id)
'file_name',
'digest',
'id',
- 'rotation_correction as angle'
+ 'rotation_correction as angle',
+ 'flg_checked_location',
+ 'flg_original',
+ 'network_info',
+ 'provider',
+ 'osnma_enabled',
+ 'osnma_validated',
+ 'validated_sats'
])
->where('user_id', $user_id)
->where('flg_deleted', 0)
- ->whereNull('task_id')
- ->get();
+ ->whereNull('task_id');
+ if($paginate) $photos = $photos->paginate(10);
+ else $photos = $photos->get();
$output = [];
-
foreach ($photos as $photo) {
$photoData = [
'altitude' => $photo->altitude,
@@ -806,7 +851,12 @@ function getPhotosWithoutTask($user_id)
'digest' => $photo->digest,
'id' => $photo->id,
'link' => $photo->link,
- 'angle' => $photo->angle
+ 'angle' => $photo->angle,
+ 'network_info' => $photo->network_info,
+ 'provider' => $photo->provider,
+ 'osnma_enabled' => $photo->osnma_enabled,
+ 'osnma_validated' => $photo->osnma_validated,
+ 'validated_sats' => $photo->validated_sats
];
$file = null;
@@ -815,10 +865,17 @@ function getPhotosWithoutTask($user_id)
$file = file_get_contents($filePath);
}
$photoData['photo'] = $file ? base64_encode($file) : null;
+
+ $photoVerificationData = getPhotoVerifiedStatus($photo);
+ $photoData['return'] = $photoVerificationData['return'];
+ $photoData['verified'] = $photoVerificationData['verified'];
+
+
+ $photo = $photoData;
$output[] = $photoData;
}
-
- return $output;
+
+ return $photos;
}
@@ -902,63 +959,106 @@ function getPhotoByIds(array $photoIds)
'created',
'path',
'file_name',
- 'digest'
+ 'digest',
+ 'network_info',
+ 'provider',
+ 'osnma_enabled',
+ 'osnma_validated',
+ 'validated_sats'
])
->where('flg_deleted', 0)
->whereIn('id', $photoIds)
->get();
-$output = [];
-
-foreach ($photos as $photo) {
- $currentPhoto = [
- 'altitude' => $photo->altitude,
- 'vertical_view_angle' => $photo->vertical_view_angle,
- 'accuracy' => $photo->accuracy,
- 'distance' => $photo->distance,
- 'nmea_distance' => $photo->nmea_distance,
- 'device_manufacture' => $photo->device_manufacture,
- 'device_model' => $photo->device_model,
- 'device_platform' => $photo->device_platform,
- 'device_version' => $photo->device_version,
- 'efkLatGpsL1' => $photo->efkLatGpsL1,
- 'efkLngGpsL1' => $photo->efkLngGpsL1,
- 'efkAltGpsL1' => $photo->efkAltGpsL1,
- 'efkTimeGpsL1' => $photo->efkTimeGpsL1,
- 'efkLatGpsL5' => $photo->efkLatGpsL5,
- 'efkLngGpsL5' => $photo->efkLngGpsL5,
- 'efkAltGpsL5' => $photo->efkAltGpsL5,
- 'efkTimeGpsL5' => $photo->efkTimeGpsL5,
- 'efkLatGpsIf' => $photo->efkLatGpsIf,
- 'efkLngGpsIf' => $photo->efkLngGpsIf,
- 'efkAltGpsIf' => $photo->efkAltGpsIf,
- 'efkTimeGpsIf' => $photo->efkTimeGpsIf,
- 'efkLatGalE1' => $photo->efkLatGalE1,
- 'efkLngGalE1' => $photo->efkLngGalE1,
- 'efkAltGalE1' => $photo->efkAltGalE1,
- 'efkTimeGalE1' => $photo->efkTimeGalE1,
- 'efkLatGalE5' => $photo->efkLatGalE5,
- 'efkLngGalE5' => $photo->efkLngGalE5,
- 'efkAltGalE5' => $photo->efkAltGalE5,
- 'efkTimeGalE5' => $photo->efkTimeGalE5,
- 'efkLatGalIf' => $photo->efkLatGalIf,
- 'efkLngGalIf' => $photo->efkLngGalIf,
- 'efkAltGalIf' => $photo->efkAltGalIf,
- 'efkTimeGalIf' => $photo->efkTimeGalIf,
- 'note' => $photo->note,
- 'lat' => $photo->lat,
- 'lng' => $photo->lng,
- 'photo_heading' => $photo->photo_heading,
- 'created' => $photo->created,
- 'digest' => $photo->digest,
- 'link' => $photo->link
- ];
-
+ $output = [];
+
+ foreach ($photos as $photo) {
+ $currentPhoto = [
+ 'altitude' => $photo->altitude,
+ 'vertical_view_angle' => $photo->vertical_view_angle,
+ 'accuracy' => $photo->accuracy,
+ 'distance' => $photo->distance,
+ 'nmea_distance' => $photo->nmea_distance,
+ 'device_manufacture' => $photo->device_manufacture,
+ 'device_model' => $photo->device_model,
+ 'device_platform' => $photo->device_platform,
+ 'device_version' => $photo->device_version,
+ 'efkLatGpsL1' => $photo->efkLatGpsL1,
+ 'efkLngGpsL1' => $photo->efkLngGpsL1,
+ 'efkAltGpsL1' => $photo->efkAltGpsL1,
+ 'efkTimeGpsL1' => $photo->efkTimeGpsL1,
+ 'efkLatGpsL5' => $photo->efkLatGpsL5,
+ 'efkLngGpsL5' => $photo->efkLngGpsL5,
+ 'efkAltGpsL5' => $photo->efkAltGpsL5,
+ 'efkTimeGpsL5' => $photo->efkTimeGpsL5,
+ 'efkLatGpsIf' => $photo->efkLatGpsIf,
+ 'efkLngGpsIf' => $photo->efkLngGpsIf,
+ 'efkAltGpsIf' => $photo->efkAltGpsIf,
+ 'efkTimeGpsIf' => $photo->efkTimeGpsIf,
+ 'efkLatGalE1' => $photo->efkLatGalE1,
+ 'efkLngGalE1' => $photo->efkLngGalE1,
+ 'efkAltGalE1' => $photo->efkAltGalE1,
+ 'efkTimeGalE1' => $photo->efkTimeGalE1,
+ 'efkLatGalE5' => $photo->efkLatGalE5,
+ 'efkLngGalE5' => $photo->efkLngGalE5,
+ 'efkAltGalE5' => $photo->efkAltGalE5,
+ 'efkTimeGalE5' => $photo->efkTimeGalE5,
+ 'efkLatGalIf' => $photo->efkLatGalIf,
+ 'efkLngGalIf' => $photo->efkLngGalIf,
+ 'efkAltGalIf' => $photo->efkAltGalIf,
+ 'efkTimeGalIf' => $photo->efkTimeGalIf,
+ 'note' => $photo->note,
+ 'lat' => $photo->lat,
+ 'lng' => $photo->lng,
+ 'photo_heading' => $photo->photo_heading,
+ 'created' => $photo->created,
+ 'digest' => $photo->digest,
+ 'link' => $photo->link,
+ 'network_info' => $photo->network_info,
+ 'provider' => $photo->provider,
+ 'osnma_enabled' => $photo->osnma_enabled,
+ 'osnma_validated' => $photo->osnma_validated,
+ 'validated_sats' => $photo->validated_sats
+ ];
+
- // Add the photo data to the output array
- $output[] = $currentPhoto;
+ // Add the photo data to the output array
+ $output[] = $currentPhoto;
+ }
+
+ return $output;
}
-return $output;
+function getPhotoVerifiedStatus($photo){
+ $photoData = [];
+ $return = 'incomplete';
+ $verified = true;
+ if ($photo->flg_checked_location === 0) {
+ $return = 'not_verified';
+ $verified = false;
+ } elseif (empty($photo->flg_checked_location)) {
+ if ($return !== 'not_verified') {
+ $return = 'incomplete';
+ }
+ $verified = false;
+ } elseif ($verified) {
+ $return = 'verified';
+ }
+
+ if ($photo->flg_original === 0) {
+ $return = 'not_verified';
+ $verified = false;
+ } elseif (empty($photo->flg_original)) {
+ if ($return !== 'not_verified') {
+ $return = 'incomplete';
+ }
+ $verified = false;
+ } elseif ($verified) {
+ $return = 'verified';
+ }
+ $photoData['return'] = $return;
+ $photoData['verified'] = $verified;
+
+ return $photoData;
}
diff --git a/database/migrations/2025_05_21_072049_add_osnma_to_photo_table.php b/database/migrations/2025_05_21_072049_add_osnma_to_photo_table.php
new file mode 100644
index 00000000..d1ebd714
--- /dev/null
+++ b/database/migrations/2025_05_21_072049_add_osnma_to_photo_table.php
@@ -0,0 +1,31 @@
+string('provider', 255)->nullable();
+ $table->string('osnma_enabled', 255)->nullable();
+ $table->string('osnma_validated', 255)->nullable();
+ $table->string('validated_sats', 255)->nullable();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('photo', function (Blueprint $table) {
+ $table->dropColumn(['provider', 'osnma_enabled', 'osnma_validated', 'validated_sats']);
+ });
+ }
+};
diff --git a/resources/js/Components/Pdf/ClientPdfRenderer.tsx b/resources/js/Components/Pdf/ClientPdfRenderer.tsx
index 3db1c1a0..9771f9fb 100644
--- a/resources/js/Components/Pdf/ClientPdfRenderer.tsx
+++ b/resources/js/Components/Pdf/ClientPdfRenderer.tsx
@@ -359,41 +359,34 @@ const PdfPage = ({
{photo?.created}
-