fix addresses, paths, and lake

This commit is contained in:
zyphlar
2026-04-03 22:27:44 -07:00
parent 3e114b05ac
commit 1bb092d6da
2 changed files with 140 additions and 29 deletions
+41 -9
View File
@@ -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
View File
@@ -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>