wip
This commit is contained in:
parent
026e2601c4
commit
e511cae64d
|
|
@ -3,6 +3,7 @@
|
||||||
namespace App\Jobs;
|
namespace App\Jobs;
|
||||||
|
|
||||||
use App\Enums\Status;
|
use App\Enums\Status;
|
||||||
|
use App\Livewire\Projects\Tabs\Mosaic;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\ProjectDownload;
|
use App\Models\ProjectDownload;
|
||||||
use App\Models\ProjectMosaic;
|
use App\Models\ProjectMosaic;
|
||||||
|
|
@ -88,8 +89,11 @@ public static function handleFor(Project $project, $year, $startWeekNumber)
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => sprintf('Week %d, %d', $startWeekNumber, $year),
|
'name' => sprintf('Week %d, %d', $startWeekNumber, $year),
|
||||||
'path' => sprintf('%s/%s/%s', $project->download_path, 'mosaics',
|
'path' => sprintf('%s/%s/%s',
|
||||||
sprintf('week_%d_%d.tif', $startWeekNumber, $year)),
|
$project->download_path,
|
||||||
|
'mosaics',
|
||||||
|
ProjectMosaic::getFilenameForYearAndWeek($year, $startWeekNumber)
|
||||||
|
),
|
||||||
'year' => $year,
|
'year' => $year,
|
||||||
'week' => $startWeekNumber,
|
'week' => $startWeekNumber,
|
||||||
]);
|
]);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,11 @@ class ProjectMosaic extends Model
|
||||||
'status'
|
'status'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public static function getFilenameForYearAndWeek($year, $startWeekNumber)
|
||||||
|
{
|
||||||
|
return sprintf('week_%02d_%d.tif', $startWeekNumber, $year);
|
||||||
|
}
|
||||||
|
|
||||||
public function project()
|
public function project()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Project::class);
|
return $this->belongsTo(Project::class);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
"laravel/sanctum": "^4.0",
|
"laravel/sanctum": "^4.0",
|
||||||
"laravel/telescope": "^5.0",
|
"laravel/telescope": "^5.0",
|
||||||
"laravel/tinker": "^2.9",
|
"laravel/tinker": "^2.9",
|
||||||
|
"leaflet/leaflet": "*",
|
||||||
"livewire/livewire": "^3.0",
|
"livewire/livewire": "^3.0",
|
||||||
"maatwebsite/excel": "^3.1",
|
"maatwebsite/excel": "^3.1",
|
||||||
"plesk/ext-laravel-integration": "^7.0"
|
"plesk/ext-laravel-integration": "^7.0"
|
||||||
|
|
|
||||||
28
laravel_app/composer.lock
generated
28
laravel_app/composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "42be2af1c7ce17f827e0b68db75435e9",
|
"content-hash": "02a769bc324ca6d387d9e85c61229c6b",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "bacon/bacon-qr-code",
|
"name": "bacon/bacon-qr-code",
|
||||||
|
|
@ -2264,6 +2264,32 @@
|
||||||
},
|
},
|
||||||
"time": "2024-01-04T16:10:04+00:00"
|
"time": "2024-01-04T16:10:04+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "leaflet/leaflet",
|
||||||
|
"version": "v1.4.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/aissasell/leaflet.git",
|
||||||
|
"reference": "7eadefcbd4d8bbb9af36a2b78186e6d068afa177"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/aissasell/leaflet/zipball/7eadefcbd4d8bbb9af36a2b78186e6d068afa177",
|
||||||
|
"reference": "7eadefcbd4d8bbb9af36a2b78186e6d068afa177",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-2-Clause"
|
||||||
|
],
|
||||||
|
"description": "an open-source JavaScript library for mobile-friendly interactive maps",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/aissasell/leaflet/issues",
|
||||||
|
"source": "https://github.com/aissasell/leaflet/tree/v1.4.0"
|
||||||
|
},
|
||||||
|
"time": "2019-03-23T14:27:52+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "league/commonmark",
|
"name": "league/commonmark",
|
||||||
"version": "2.4.2",
|
"version": "2.4.2",
|
||||||
|
|
|
||||||
6
laravel_app/package-lock.json
generated
6
laravel_app/package-lock.json
generated
|
|
@ -15,6 +15,7 @@
|
||||||
"@tailwindcss/aspect-ratio": "^0.4.2",
|
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||||
"alpinejs": "^3.13.3",
|
"alpinejs": "^3.13.3",
|
||||||
"flatpickr": "^4.6.13",
|
"flatpickr": "^4.6.13",
|
||||||
|
"leaflet": "^1.9.4",
|
||||||
"tailwindcss": "^3.3.3"
|
"tailwindcss": "^3.3.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
@ -1150,6 +1151,11 @@
|
||||||
"vite": "^3.0.0 || ^4.0.0"
|
"vite": "^3.0.0 || ^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/leaflet": {
|
||||||
|
"version": "1.9.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
|
||||||
|
"integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA=="
|
||||||
|
},
|
||||||
"node_modules/lilconfig": {
|
"node_modules/lilconfig": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
"@tailwindcss/aspect-ratio": "^0.4.2",
|
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||||
"alpinejs": "^3.13.3",
|
"alpinejs": "^3.13.3",
|
||||||
"flatpickr": "^4.6.13",
|
"flatpickr": "^4.6.13",
|
||||||
|
"leaflet": "^1.9.4",
|
||||||
"tailwindcss": "^3.3.3"
|
"tailwindcss": "^3.3.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,12 +32,12 @@
|
||||||
"src": "node_modules/@fortawesome/fontawesome-free/webfonts/fa-v4compatibility.woff2"
|
"src": "node_modules/@fortawesome/fontawesome-free/webfonts/fa-v4compatibility.woff2"
|
||||||
},
|
},
|
||||||
"resources/css/app.css": {
|
"resources/css/app.css": {
|
||||||
"file": "assets/app-93dd061f.css",
|
"file": "assets/app-df56bbfb.css",
|
||||||
"isEntry": true,
|
"isEntry": true,
|
||||||
"src": "resources/css/app.css"
|
"src": "resources/css/app.css"
|
||||||
},
|
},
|
||||||
"resources/js/alpine.js": {
|
"resources/js/alpine.js": {
|
||||||
"file": "assets/alpine-e0ba2549.js",
|
"file": "assets/alpine-d6afa966.js",
|
||||||
"isDynamicEntry": true,
|
"isDynamicEntry": true,
|
||||||
"src": "resources/js/alpine.js"
|
"src": "resources/js/alpine.js"
|
||||||
},
|
},
|
||||||
|
|
@ -45,7 +45,7 @@
|
||||||
"dynamicImports": [
|
"dynamicImports": [
|
||||||
"resources/js/alpine.js"
|
"resources/js/alpine.js"
|
||||||
],
|
],
|
||||||
"file": "assets/app-eb81fffd.js",
|
"file": "assets/app-f5ffacbb.js",
|
||||||
"isEntry": true,
|
"isEntry": true,
|
||||||
"src": "resources/js/app.js"
|
"src": "resources/js/app.js"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
@import url('https://rsms.me/inter/inter.css');
|
@import url('https://rsms.me/inter/inter.css');
|
||||||
@import '@fortawesome/fontawesome-free/css/all.css';
|
@import '@fortawesome/fontawesome-free/css/all.css';
|
||||||
@import "@dasundev/livewire-dropzone-styles";
|
@import "@dasundev/livewire-dropzone-styles";
|
||||||
|
@import "leaflet/dist/leaflet.css";
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import './bootstrap';
|
import './bootstrap';
|
||||||
import('./alpine');
|
import('./alpine');
|
||||||
import flatpckr from 'flatpickr';
|
import flatpckr from 'flatpickr';
|
||||||
|
import leaflet from 'leaflet';
|
||||||
window.flatpckr = flatpckr;
|
window.flatpckr = flatpckr;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
<x-notification />
|
<x-notification />
|
||||||
|
|
||||||
@stack('modals')
|
@stack('modals')
|
||||||
|
@stack('map')
|
||||||
|
|
||||||
@livewireScriptConfig
|
@livewireScriptConfig
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,44 @@
|
||||||
<div class="flex flex-col divide-y space-y-4 m-2">
|
@push('map')
|
||||||
|
@endpush
|
||||||
|
|
||||||
|
<div class="flex flex-col divide-y space-y-4 m-2"
|
||||||
|
x-data="{
|
||||||
|
processFile(file) {
|
||||||
|
let filetype = ['json','geojson'];
|
||||||
|
if(!filetype.includes(file.name.split('.').pop())) return;
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (event) => {
|
||||||
|
const data = event.target.result;
|
||||||
|
try {
|
||||||
|
this.showMap(JSON.parse(data));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error parsing GeoJSON:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
},
|
||||||
|
showMap(d){
|
||||||
|
try{
|
||||||
|
let map = document.getElementById('map');
|
||||||
|
map.style.height = '300px';
|
||||||
|
window.map = L.map('map').setView([51.505, -0.09], 13);
|
||||||
|
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
maxZoom: 19,
|
||||||
|
attribution: '© <a href=`http://www.openstreetmap.org/copyright`>OpenStreetMap</a>'
|
||||||
|
}).addTo(window.map);
|
||||||
|
window.geoJsonLayer = L.geoJSON();
|
||||||
|
window.geoJsonLayer.addTo(window.map);
|
||||||
|
}catch(err){
|
||||||
|
console.log('Map already loaded');
|
||||||
|
}
|
||||||
|
window.geoJsonLayer.addData(d);
|
||||||
|
window.map.fitBounds(geoJsonLayer.getBounds());
|
||||||
|
map.focus();
|
||||||
|
console.log('added geojson.');
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
x-on:livewire-upload-finish.document="processFile($event.target.files[0]);"
|
||||||
|
>
|
||||||
<div id="edit" class="flex flex-col md:flex-row gap-2">
|
<div id="edit" class="flex flex-col md:flex-row gap-2">
|
||||||
<div class="flex flex-col md:w-1/3">
|
<div class="flex flex-col md:w-1/3">
|
||||||
<div class="text-xl font-bold ">
|
<div class="text-xl font-bold ">
|
||||||
|
|
@ -10,6 +50,9 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="md:w-2/3">
|
<div class="md:w-2/3">
|
||||||
<form>
|
<form>
|
||||||
|
<div id="map">
|
||||||
|
|
||||||
|
</div>
|
||||||
<!-- Token Name -->
|
<!-- Token Name -->
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<x-label for="name" value="{{ __('Name') }}"/>
|
<x-label for="name" value="{{ __('Name') }}"/>
|
||||||
|
|
@ -23,6 +66,7 @@
|
||||||
wire:model="pivotFiles"
|
wire:model="pivotFiles"
|
||||||
:rules="['extensions:json,geojson','mimes:json,geojson']"
|
:rules="['extensions:json,geojson','mimes:json,geojson']"
|
||||||
:key="'pivotFiles'"
|
:key="'pivotFiles'"
|
||||||
|
wire:key="'pivotFiles'"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@error('pivotFiles')
|
@error('pivotFiles')
|
||||||
|
|
@ -36,6 +80,7 @@
|
||||||
wire:model="spanFiles"
|
wire:model="spanFiles"
|
||||||
:rules="['extensions:json,geojson','mimes:json,geojson']"
|
:rules="['extensions:json,geojson','mimes:json,geojson']"
|
||||||
:key="'spanFiles'"
|
:key="'spanFiles'"
|
||||||
|
wire:key="'spanFiles'"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@error('spanFiles')
|
@error('spanFiles')
|
||||||
|
|
@ -49,6 +94,7 @@
|
||||||
wire:model="harvestDataFiles"
|
wire:model="harvestDataFiles"
|
||||||
:rules="['extensions:xls,xlsx,ods','mimes:xls,xlsx,ods','required']"
|
:rules="['extensions:xls,xlsx,ods','mimes:xls,xlsx,ods','required']"
|
||||||
:key="'harvest_file'"
|
:key="'harvest_file'"
|
||||||
|
wire:key="'harvest_file'"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@error('harvest_file')
|
@error('harvest_file')
|
||||||
|
|
@ -67,20 +113,22 @@ class="flex flex-col md:flex-row">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="mail"
|
<div id="mail"
|
||||||
class="flex flex-col md:w-2/3"
|
class="flex flex-col md:w-2/3"
|
||||||
x-data="{showMail: null}"
|
x-data="{showMail: null}"
|
||||||
x-init="showMail = $wire.formData['mail_scheduled']"
|
x-init="showMail = $wire.formData['mail_scheduled']"
|
||||||
> {{-- flex col--}}
|
> {{-- flex col--}}
|
||||||
<div class="flex justify-between my-4">
|
<div class="flex justify-between my-4">
|
||||||
<div class="inline-flex items-center gap-2">
|
<div class="inline-flex items-center gap-2">
|
||||||
{{-- <span class="text-lg font-semibold dark:text-gray-300">{{__('Mail')}}</span>---}}
|
{{-- <span class="text-lg font-semibold dark:text-gray-300">{{__('Mail')}}</span>---}}
|
||||||
<div class=" text-md font-bold">
|
<div class=" text-md font-bold">
|
||||||
{{ __('Send a mail to recipients periodically') }}
|
{{ __('Send a mail to recipients periodically') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<label class="inline-flex items-center cursor-pointer gap-4">
|
<label class="inline-flex items-center cursor-pointer gap-4">
|
||||||
<input type="checkbox" class="sr-only peer" wire:model.live="formData.mail_scheduled" @click="showMail = $el.checked">
|
<input type="checkbox" class="sr-only peer" wire:model.live="formData.mail_scheduled"
|
||||||
<div class="relative w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-indigo-300 dark:peer-focus:ring-indigo-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-indigo-600"></div>
|
@click="showMail = $el.checked">
|
||||||
|
<div
|
||||||
|
class="relative w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-indigo-300 dark:peer-focus:ring-indigo-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-indigo-600"></div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex w-full ">
|
<div class="flex w-full ">
|
||||||
|
|
|
||||||
|
|
@ -131,20 +131,20 @@ class="hidden"
|
||||||
@script
|
@script
|
||||||
<script>
|
<script>
|
||||||
Alpine.data('dropzone', ({ _this, uuid, multiple }) => {
|
Alpine.data('dropzone', ({ _this, uuid, multiple }) => {
|
||||||
return ({
|
const process = {
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
isDropped: false,
|
isDropped: false,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
|
|
||||||
onDrop(e) {
|
onDrop(e) {
|
||||||
this.isDropped = true
|
this.isDropped = true;
|
||||||
this.isDragging = false
|
this.isDragging = false;
|
||||||
|
|
||||||
const file = multiple ? e.dataTransfer.files : e.dataTransfer.files[0]
|
|
||||||
|
|
||||||
|
const file = multiple ? e.dataTransfer.files : e.dataTransfer.files[0];
|
||||||
const args = ['upload', file, () => {
|
const args = ['upload', file, () => {
|
||||||
// Upload completed
|
// Upload completed
|
||||||
this.isLoading = false
|
this.isLoading = false;
|
||||||
|
this.processFile(file);
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
// An error occurred while uploading
|
// An error occurred while uploading
|
||||||
console.log('livewire-dropzone upload error', error);
|
console.log('livewire-dropzone upload error', error);
|
||||||
|
|
@ -154,7 +154,7 @@ class="hidden"
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// Upload file(s)
|
// Upload file(s)
|
||||||
multiple ? _this.uploadMultiple(...args) : _this.upload(...args)
|
multiple ? _this.uploadMultiple(...args) : _this.upload(...args);
|
||||||
},
|
},
|
||||||
onDragenter() {
|
onDragenter() {
|
||||||
if(!this.isDragging){
|
if(!this.isDragging){
|
||||||
|
|
@ -174,8 +174,9 @@ class="hidden"
|
||||||
removeUpload(tmpFilename) {
|
removeUpload(tmpFilename) {
|
||||||
// Dispatch an event to remove the temporarily uploaded file
|
// Dispatch an event to remove the temporarily uploaded file
|
||||||
_this.dispatch(uuid + ':fileRemoved', { tmpFilename })
|
_this.dispatch(uuid + ':fileRemoved', { tmpFilename })
|
||||||
},
|
}
|
||||||
});
|
};
|
||||||
|
return (process);
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@endscript
|
@endscript
|
||||||
|
|
|
||||||
43
laravel_app/tests/Unit/Models/ProjectMosaicTest.php
Normal file
43
laravel_app/tests/Unit/Models/ProjectMosaicTest.php
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit\Models;
|
||||||
|
|
||||||
|
use App\Jobs\ProjectDownloadTiffJob;
|
||||||
|
use App\Jobs\ProjectMosiacGeneratorJob;
|
||||||
|
use App\Jobs\ProjectReportGeneratorJob;
|
||||||
|
use App\Models\Project;
|
||||||
|
|
||||||
|
use App\Models\ProjectMosaic;
|
||||||
|
use Illuminate\Bus\PendingBatch;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Bus;
|
||||||
|
use Mockery;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class ProjectMosaicTest extends TestCase
|
||||||
|
{
|
||||||
|
use RefreshDatabase;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @dataProvider filenameProvider
|
||||||
|
* */
|
||||||
|
public function it_should_return_the_correct_attachment_path($year,$week, $expected)
|
||||||
|
{
|
||||||
|
$this->assertEquals(
|
||||||
|
$expected,
|
||||||
|
ProjectMosaic::getFilenameForYearAndWeek($year, $week)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function filenameProvider(){
|
||||||
|
return [
|
||||||
|
[2022, 1, 'week_01_2022.tif'],
|
||||||
|
[2022, 10, 'week_10_2022.tif'],
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue