fix addresses, paths, and lake
This commit is contained in:
+41
-9
@@ -27,8 +27,8 @@ def index():
|
||||
# Organize scripts by category
|
||||
scripts_by_category = {
|
||||
'Download County Data': ['download-county-addresses', 'download-county-roads', 'download-county-paths'],
|
||||
'Download OSM Data': ['download-osm-roads', 'download-osm-paths'],
|
||||
'Convert Data': ['convert-roads', 'convert-paths'],
|
||||
'Download OSM Data': ['download-osm-roads', 'download-osm-addresses', 'download-osm-paths'],
|
||||
'Convert Data': ['convert-roads', 'convert-addresses', 'convert-paths'],
|
||||
'Diff Data': ['diff-roads', 'diff-paths', 'diff-addresses'],
|
||||
'Utilities': ['ls', 'make-new-latest']
|
||||
}
|
||||
@@ -58,26 +58,29 @@ def get_script_map():
|
||||
'ls': 'ls -al /data',
|
||||
'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
|
||||
'download-county-paths': {
|
||||
'sumter': {'type': 'upload', 'dest': '/data/latest/sumter/paths.shp.zip'},
|
||||
# lake: not available
|
||||
},
|
||||
'download-county-addresses': {
|
||||
# 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',
|
||||
'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': {
|
||||
# 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',
|
||||
'lake': 'mkdir -p /data/latest/lake && wget [LAKE_URL_HERE] -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']
|
||||
'lake': 'mkdir -p /data/latest/lake && wget https://c.lakecountyfl.gov/ftp/GIS/GisDownloads/Shapefiles/Streets.zip -O /data/latest/lake/roads.shp.zip'
|
||||
},
|
||||
# todo: integrate osm downloading and shapefile converting into diff-roads like addresses
|
||||
'download-osm-roads': {
|
||||
'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']
|
||||
},
|
||||
'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': {
|
||||
# todo: no lake county paths
|
||||
#'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'],
|
||||
'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': {
|
||||
#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'],
|
||||
@@ -231,6 +238,31 @@ def cancel_job():
|
||||
except Exception as e:
|
||||
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')
|
||||
def list_files():
|
||||
"""List available GeoJSON files"""
|
||||
|
||||
+99
-20
@@ -205,6 +205,23 @@
|
||||
.cancel-button.active {
|
||||
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>
|
||||
</head>
|
||||
<body>
|
||||
@@ -239,30 +256,56 @@
|
||||
{# County-specific commands #}
|
||||
<div class="button-grid">
|
||||
{% if 'lake' in script_config %}
|
||||
<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>
|
||||
{% set lake_config = script_config['lake'] %}
|
||||
{% if lake_config is mapping and lake_config.get('type') == 'upload' %}
|
||||
<div class="upload-row">
|
||||
<input type="file" id="upload-lake-{{ script_name }}" accept=".zip">
|
||||
<button class="script-button lake" onclick="uploadFile('upload-lake-{{ script_name }}', '{{ lake_config['dest'] }}')">
|
||||
{{ script_name|replace('-', ' ')|title }} (Lake)
|
||||
</button>
|
||||
</div>
|
||||
{% 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 %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if 'sumter' in script_config %}
|
||||
<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>
|
||||
{% set sumter_config = script_config['sumter'] %}
|
||||
{% if sumter_config is mapping and sumter_config.get('type') == 'upload' %}
|
||||
<div class="upload-row">
|
||||
<input type="file" id="upload-sumter-{{ script_name }}" accept=".zip">
|
||||
<button class="script-button sumter" onclick="uploadFile('upload-sumter-{{ script_name }}', '{{ sumter_config['dest'] }}')">
|
||||
{{ script_name|replace('-', ' ')|title }} (Sumter)
|
||||
</button>
|
||||
</div>
|
||||
{% 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 %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -440,6 +483,42 @@
|
||||
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>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user