fix addresses, paths, and lake
This commit is contained in:
+41
-9
@@ -27,8 +27,8 @@ def index():
|
|||||||
# Organize scripts by category
|
# Organize scripts by category
|
||||||
scripts_by_category = {
|
scripts_by_category = {
|
||||||
'Download County Data': ['download-county-addresses', 'download-county-roads', 'download-county-paths'],
|
'Download County Data': ['download-county-addresses', 'download-county-roads', 'download-county-paths'],
|
||||||
'Download OSM Data': ['download-osm-roads', 'download-osm-paths'],
|
'Download OSM Data': ['download-osm-roads', 'download-osm-addresses', 'download-osm-paths'],
|
||||||
'Convert Data': ['convert-roads', 'convert-paths'],
|
'Convert Data': ['convert-roads', 'convert-addresses', 'convert-paths'],
|
||||||
'Diff Data': ['diff-roads', 'diff-paths', 'diff-addresses'],
|
'Diff Data': ['diff-roads', 'diff-paths', 'diff-addresses'],
|
||||||
'Utilities': ['ls', 'make-new-latest']
|
'Utilities': ['ls', 'make-new-latest']
|
||||||
}
|
}
|
||||||
@@ -58,26 +58,29 @@ def get_script_map():
|
|||||||
'ls': 'ls -al /data',
|
'ls': 'ls -al /data',
|
||||||
'make-new-latest': 'cd /data && NEWDIR=$(date +%y%m%d) && mkdir -p $NEWDIR/lake $NEWDIR/sumter && ln -sfn $NEWDIR latest',
|
'make-new-latest': 'cd /data && NEWDIR=$(date +%y%m%d) && mkdir -p $NEWDIR/lake $NEWDIR/sumter && ln -sfn $NEWDIR latest',
|
||||||
# todo: make a clean-old-data script
|
# todo: make a clean-old-data script
|
||||||
|
'download-county-paths': {
|
||||||
|
'sumter': {'type': 'upload', 'dest': '/data/latest/sumter/paths.shp.zip'},
|
||||||
|
# lake: not available
|
||||||
|
},
|
||||||
'download-county-addresses': {
|
'download-county-addresses': {
|
||||||
# deliver files with standardized names
|
# deliver files with standardized names
|
||||||
'sumter': 'mkdir -p /data/latest/sumter && wget https://www.arcgis.com/sharing/rest/content/items/c75c5aac13a648968c5596b0665be28b/data -O /data/latest/sumter/addresses.shp.zip',
|
'sumter': 'mkdir -p /data/latest/sumter && wget https://www.arcgis.com/sharing/rest/content/items/c75c5aac13a648968c5596b0665be28b/data -O /data/latest/sumter/addresses.shp.zip',
|
||||||
'lake': 'mkdir -p /data/latest/lake && wget [LAKE_URL_HERE] -O /data/latest/lake/addresses.shp.zip'
|
'lake': 'mkdir -p /data/latest/lake && wget https://c.lakecountyfl.gov/ftp/GIS/GisDownloads/Shapefiles/Addresspoints.zip -O /data/latest/lake/addresses.shp.zip'
|
||||||
},
|
},
|
||||||
'download-county-roads': {
|
'download-county-roads': {
|
||||||
# deliver files with standardized names
|
# deliver files with standardized names
|
||||||
'sumter': 'mkdir -p /data/latest/sumter && wget https://www.arcgis.com/sharing/rest/content/items/9177e17c72d3433aa79630c7eda84add/data -O /data/latest/sumter/roads.shp.zip',
|
'sumter': 'mkdir -p /data/latest/sumter && wget https://www.arcgis.com/sharing/rest/content/items/9177e17c72d3433aa79630c7eda84add/data -O /data/latest/sumter/roads.shp.zip',
|
||||||
'lake': 'mkdir -p /data/latest/lake && wget [LAKE_URL_HERE] -O /data/latest/lake/roads.shp.zip'
|
'lake': 'mkdir -p /data/latest/lake && wget https://c.lakecountyfl.gov/ftp/GIS/GisDownloads/Shapefiles/Streets.zip -O /data/latest/lake/roads.shp.zip'
|
||||||
},
|
|
||||||
'download-county-paths': {
|
|
||||||
# deliver files with standardized names
|
|
||||||
#'sumter': ['/data/latest/sumter/paths.shp.zip'],
|
|
||||||
#'lake': ['/data/latest/lake/paths.shp.zip']
|
|
||||||
},
|
},
|
||||||
# todo: integrate osm downloading and shapefile converting into diff-roads like addresses
|
# todo: integrate osm downloading and shapefile converting into diff-roads like addresses
|
||||||
'download-osm-roads': {
|
'download-osm-roads': {
|
||||||
'lake': ['python', 'download-overpass.py', '--type', 'highways', 'Lake County', 'Florida', '/data/latest/lake/osm-roads.geojson'],
|
'lake': ['python', 'download-overpass.py', '--type', 'highways', 'Lake County', 'Florida', '/data/latest/lake/osm-roads.geojson'],
|
||||||
'sumter': ['python', 'download-overpass.py', '--type', 'highways', 'Sumter County', 'Florida', '/data/latest/sumter/osm-roads.geojson']
|
'sumter': ['python', 'download-overpass.py', '--type', 'highways', 'Sumter County', 'Florida', '/data/latest/sumter/osm-roads.geojson']
|
||||||
},
|
},
|
||||||
|
'download-osm-addresses': {
|
||||||
|
'lake': ['python', 'download-overpass.py', '--type', 'addresses', 'Lake County', 'Florida', '/data/latest/lake/osm-addresses.geojson'],
|
||||||
|
'sumter': ['python', 'download-overpass.py', '--type', 'addresses', 'Sumter County', 'Florida', '/data/latest/sumter/osm-addresses.geojson']
|
||||||
|
},
|
||||||
'download-osm-paths': {
|
'download-osm-paths': {
|
||||||
# todo: no lake county paths
|
# todo: no lake county paths
|
||||||
#'lake': ['python', 'download-overpass.py', '--type', 'highways', 'Lake County', 'Florida', '/data/latest/lake/osm-roads.geojson'],
|
#'lake': ['python', 'download-overpass.py', '--type', 'highways', 'Lake County', 'Florida', '/data/latest/lake/osm-roads.geojson'],
|
||||||
@@ -88,6 +91,10 @@ def get_script_map():
|
|||||||
'sumter': ['python', 'shp-to-geojson.py', '/data/latest/sumter/roads.shp.zip', '/data/latest/sumter/county-roads.geojson'],
|
'sumter': ['python', 'shp-to-geojson.py', '/data/latest/sumter/roads.shp.zip', '/data/latest/sumter/county-roads.geojson'],
|
||||||
'lake': ['python', 'shp-to-geojson.py', '/data/latest/lake/roads.shp.zip', '/data/latest/lake/county-roads.geojson']
|
'lake': ['python', 'shp-to-geojson.py', '/data/latest/lake/roads.shp.zip', '/data/latest/lake/county-roads.geojson']
|
||||||
},
|
},
|
||||||
|
'convert-addresses': {
|
||||||
|
'sumter': ['python', 'shp-to-geojson.py', '/data/latest/sumter/addresses.shp.zip', '/data/latest/sumter/county-addresses.geojson'],
|
||||||
|
'lake': ['python', 'shp-to-geojson.py', '/data/latest/lake/addresses.shp.zip', '/data/latest/lake/county-addresses.geojson']
|
||||||
|
},
|
||||||
'convert-paths': {
|
'convert-paths': {
|
||||||
#todo: delete sumter-multi-modal-convert.py ?
|
#todo: delete sumter-multi-modal-convert.py ?
|
||||||
'sumter': ['python', 'shp-to-geojson.py', '/data/latest/sumter/paths.shp.zip', '/data/latest/sumter/county-paths.geojson'],
|
'sumter': ['python', 'shp-to-geojson.py', '/data/latest/sumter/paths.shp.zip', '/data/latest/sumter/county-paths.geojson'],
|
||||||
@@ -231,6 +238,31 @@ def cancel_job():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({'error': str(e)}), 500
|
return jsonify({'error': str(e)}), 500
|
||||||
|
|
||||||
|
@app.route('/api/upload-file', methods=['POST'])
|
||||||
|
def upload_file():
|
||||||
|
"""Upload a shapefile ZIP to a path under /data/latest"""
|
||||||
|
dest = request.form.get('dest')
|
||||||
|
if not dest or not dest.startswith('/data/latest/'):
|
||||||
|
return jsonify({'error': 'Invalid destination path'}), 400
|
||||||
|
|
||||||
|
latest = '/data/latest'
|
||||||
|
if os.path.exists(latest) or os.path.islink(latest):
|
||||||
|
if os.path.isdir(latest) and not os.path.islink(latest):
|
||||||
|
return jsonify({'error': '/data/latest is a directory, not a symlink. Please run "Make New Latest" first.'}), 400
|
||||||
|
else:
|
||||||
|
return jsonify({'error': '/data/latest does not exist. Please run "Make New Latest" first.'}), 400
|
||||||
|
|
||||||
|
if 'file' not in request.files:
|
||||||
|
return jsonify({'error': 'No file provided'}), 400
|
||||||
|
|
||||||
|
f = request.files['file']
|
||||||
|
if not f.filename.lower().endswith('.zip'):
|
||||||
|
return jsonify({'error': 'File must be a ZIP archive (.zip)'}), 400
|
||||||
|
|
||||||
|
os.makedirs(os.path.dirname(dest), exist_ok=True)
|
||||||
|
f.save(dest)
|
||||||
|
return jsonify({'success': True, 'path': dest})
|
||||||
|
|
||||||
@app.route('/api/list-files')
|
@app.route('/api/list-files')
|
||||||
def list_files():
|
def list_files():
|
||||||
"""List available GeoJSON files"""
|
"""List available GeoJSON files"""
|
||||||
|
|||||||
+99
-20
@@ -205,6 +205,23 @@
|
|||||||
.cancel-button.active {
|
.cancel-button.active {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.upload-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-row span.unavailable {
|
||||||
|
color: #999;
|
||||||
|
font-size: 13px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-row input[type="file"] {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -239,30 +256,56 @@
|
|||||||
{# County-specific commands #}
|
{# County-specific commands #}
|
||||||
<div class="button-grid">
|
<div class="button-grid">
|
||||||
{% if 'lake' in script_config %}
|
{% if 'lake' in script_config %}
|
||||||
<div class="button-with-checkbox">
|
{% set lake_config = script_config['lake'] %}
|
||||||
<button class="script-button lake" onclick="runScript('{{ script_name }}', 'lake')">
|
{% if lake_config is mapping and lake_config.get('type') == 'upload' %}
|
||||||
{{ script_name|replace('-', ' ')|title }} (Lake)
|
<div class="upload-row">
|
||||||
</button>
|
<input type="file" id="upload-lake-{{ script_name }}" accept=".zip">
|
||||||
{% if script_name == 'diff-addresses' %}
|
<button class="script-button lake" onclick="uploadFile('upload-lake-{{ script_name }}', '{{ lake_config['dest'] }}')">
|
||||||
<label>
|
{{ script_name|replace('-', ' ')|title }} (Lake)
|
||||||
<input type="checkbox" id="force-redownload-lake">
|
</button>
|
||||||
Force OSM Redownload
|
</div>
|
||||||
</label>
|
{% else %}
|
||||||
|
<div class="button-with-checkbox">
|
||||||
|
<button class="script-button lake" onclick="runScript('{{ script_name }}', 'lake')">
|
||||||
|
{{ script_name|replace('-', ' ')|title }} (Lake)
|
||||||
|
</button>
|
||||||
|
{% if script_name == 'diff-addresses' %}
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="force-redownload-lake">
|
||||||
|
Force OSM Redownload
|
||||||
|
</label>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if 'sumter' in script_config %}
|
{% if 'sumter' in script_config %}
|
||||||
<div class="button-with-checkbox">
|
{% set sumter_config = script_config['sumter'] %}
|
||||||
<button class="script-button sumter" onclick="runScript('{{ script_name }}', 'sumter')">
|
{% if sumter_config is mapping and sumter_config.get('type') == 'upload' %}
|
||||||
{{ script_name|replace('-', ' ')|title }} (Sumter)
|
<div class="upload-row">
|
||||||
</button>
|
<input type="file" id="upload-sumter-{{ script_name }}" accept=".zip">
|
||||||
{% if script_name == 'diff-addresses' %}
|
<button class="script-button sumter" onclick="uploadFile('upload-sumter-{{ script_name }}', '{{ sumter_config['dest'] }}')">
|
||||||
<label>
|
{{ script_name|replace('-', ' ')|title }} (Sumter)
|
||||||
<input type="checkbox" id="force-redownload-sumter">
|
</button>
|
||||||
Force OSM Redownload
|
</div>
|
||||||
</label>
|
{% else %}
|
||||||
|
<div class="button-with-checkbox">
|
||||||
|
<button class="script-button sumter" onclick="runScript('{{ script_name }}', 'sumter')">
|
||||||
|
{{ script_name|replace('-', ' ')|title }} (Sumter)
|
||||||
|
</button>
|
||||||
|
{% if script_name == 'diff-addresses' %}
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="force-redownload-sumter">
|
||||||
|
Force OSM Redownload
|
||||||
|
</label>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% if script_name == 'download-county-paths' %}
|
||||||
|
<div class="upload-row">
|
||||||
|
<span class="unavailable">Download County Paths (Lake): not available</span>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -440,6 +483,42 @@
|
|||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function uploadFile(inputId, dest) {
|
||||||
|
const input = document.getElementById(inputId);
|
||||||
|
if (!input || !input.files.length) {
|
||||||
|
showStatus('Please select a file first.', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = input.files[0];
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
formData.append('dest', dest);
|
||||||
|
|
||||||
|
showStatus(`Uploading ${file.name}...`, 'info');
|
||||||
|
document.querySelectorAll('.script-button').forEach(btn => btn.disabled = true);
|
||||||
|
|
||||||
|
fetch('/api/upload-file', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.error) {
|
||||||
|
showStatus(`Error: ${data.error}`, 'error');
|
||||||
|
} else {
|
||||||
|
showStatus(`Uploaded to ${data.path}`, 'success');
|
||||||
|
input.value = '';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
showStatus(`Error: ${error.message}`, 'error');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
enableButtons();
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user