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} - + + + Network status - Photo location has not been{" "} + {photo?.network_info ? 'Online' : '-'} - - - verified yet{" "} - + + + OSNMA validation + {photo?.osnma_enabled == "1" ? Enabled : Disabled} + + {photo.osnma_enabled == "1" && + + Validated satellites + {photo.validated_sats} + } + - - Photo is original{" "} - + {photo?.osnma_validated == "1" ? Photo location is OSNMA validated : Photo location is not validated} + diff --git a/resources/js/Components/TaskGallery/Modal_.tsx b/resources/js/Components/TaskGallery/Modal_.tsx index 9ceec435..290718f1 100644 --- a/resources/js/Components/TaskGallery/Modal_.tsx +++ b/resources/js/Components/TaskGallery/Modal_.tsx @@ -604,11 +604,28 @@ const Modal_ = ({
Parcel Ref
{landData?.properties?.description || ''}
-
OSNMA Validated
-
{(photo as any)?.['OSNMA Validated'] || 'False'}
-
Note
{photo?.note}
+ +
Network status
+
{photo.network_info ? 'Online': '-'}
+ +
OSNMA validation
+ {photo.osnma_enabled == "1" ? +
Enabled
: +
Photo has not been verified yet
+ } + + {photo.osnma_enabled == "1" && <> +
Validated satellites
+
{photo.validated_sats}
+ } + +
+ {photo.osnma_validated == "1" ? +
Photo location is OSNMA validated
: +
Photo location is not validated
+ } diff --git a/resources/js/Components/TaskGallery/TaskGallery.tsx b/resources/js/Components/TaskGallery/TaskGallery.tsx index b97da48d..1e2b69c9 100644 --- a/resources/js/Components/TaskGallery/TaskGallery.tsx +++ b/resources/js/Components/TaskGallery/TaskGallery.tsx @@ -278,4 +278,4 @@ const TaskGallery = ({ ); }; -export default TaskGallery; +export default TaskGallery; \ No newline at end of file diff --git a/resources/js/Pages/Farmers/PdfPreview.tsx b/resources/js/Pages/Farmers/PdfPreview.tsx index 6ba56d4a..61eb5275 100644 --- a/resources/js/Pages/Farmers/PdfPreview.tsx +++ b/resources/js/Pages/Farmers/PdfPreview.tsx @@ -50,7 +50,6 @@ export function PdfPreview({ tasks, photos, auth, total }: PageProps) { @@ -58,7 +57,6 @@ export function PdfPreview({ tasks, photos, auth, total }: PageProps) { @@ -68,7 +66,6 @@ export function PdfPreview({ tasks, photos, auth, total }: PageProps) { @@ -76,7 +73,6 @@ export function PdfPreview({ tasks, photos, auth, total }: PageProps) { @@ -86,7 +82,6 @@ export function PdfPreview({ tasks, photos, auth, total }: PageProps) { @@ -94,7 +89,6 @@ export function PdfPreview({ tasks, photos, auth, total }: PageProps) { @@ -104,7 +98,6 @@ export function PdfPreview({ tasks, photos, auth, total }: PageProps) { @@ -112,7 +105,6 @@ export function PdfPreview({ tasks, photos, auth, total }: PageProps) { @@ -122,7 +114,6 @@ export function PdfPreview({ tasks, photos, auth, total }: PageProps) { @@ -130,7 +121,6 @@ export function PdfPreview({ tasks, photos, auth, total }: PageProps) { @@ -140,7 +130,6 @@ export function PdfPreview({ tasks, photos, auth, total }: PageProps) { @@ -148,7 +137,6 @@ export function PdfPreview({ tasks, photos, auth, total }: PageProps) { @@ -158,7 +146,6 @@ export function PdfPreview({ tasks, photos, auth, total }: PageProps) { @@ -166,7 +153,6 @@ export function PdfPreview({ tasks, photos, auth, total }: PageProps) {