Add functionality to import/export readings in csv format

This commit is contained in:
Peter Stockings
2024-12-24 20:32:58 +11:00
parent cd8f9453c5
commit 10ee97794e
3 changed files with 98 additions and 4 deletions

View File

@@ -1,9 +1,12 @@
from flask import Blueprint, render_template, redirect, request, url_for, flash import csv
from io import StringIO
from flask import Blueprint, render_template, redirect, request, send_file, url_for, flash
from werkzeug.security import generate_password_hash, check_password_hash from werkzeug.security import generate_password_hash, check_password_hash
from app.models import Profile, Reading, db, User from app.models import Profile, Reading, db, User
from app.forms import DeleteForm, LoginForm, ProfileForm, ReadingForm, SignupForm from app.forms import DeleteForm, LoginForm, ProfileForm, ReadingForm, SignupForm
from flask_login import login_user, login_required, current_user, logout_user from flask_login import login_user, login_required, current_user, logout_user
import base64 import base64
from datetime import datetime, timedelta
main = Blueprint('main', __name__) main = Blueprint('main', __name__)
auth = Blueprint('auth', __name__) auth = Blueprint('auth', __name__)
@@ -45,8 +48,6 @@ def logout():
@main.route('/', methods=['GET', 'POST']) @main.route('/', methods=['GET', 'POST'])
@login_required @login_required
def dashboard(): def dashboard():
from datetime import datetime, timedelta
# Default values # Default values
start_date = None start_date = None
end_date = None end_date = None
@@ -197,3 +198,66 @@ def profile():
return redirect(url_for('user.profile')) return redirect(url_for('user.profile'))
return render_template('profile.html', form=form, profile=profile) return render_template('profile.html', form=form, profile=profile)
@main.route('/data', methods=['GET', 'POST'])
@login_required
def manage_data():
if request.method == 'POST':
# Handle CSV file upload
file = request.files.get('file')
if file and file.filename.endswith('.csv'):
try:
csv_data = csv.reader(StringIO(file.read().decode('utf-8')))
next(csv_data) # Skip the header row
for row in csv_data:
timestamp, systolic, diastolic, heart_rate = row
reading = Reading(
user_id=current_user.id,
timestamp=datetime.strptime(timestamp, '%Y-%m-%d %H:%M:%S'),
systolic=int(systolic),
diastolic=int(diastolic),
heart_rate=int(heart_rate),
)
db.session.add(reading)
db.session.commit()
flash('Data imported successfully!', 'success')
except Exception as e:
flash(f'Error importing data: {str(e)}', 'danger')
else:
flash('Please upload a valid CSV file.', 'danger')
return redirect(url_for('main.manage_data'))
return render_template('data.html')
@main.route('/data/export', methods=['GET'])
@login_required
def export_data():
import io
output = io.StringIO()
writer = csv.writer(output)
# Write CSV header
writer.writerow(['Timestamp', 'Systolic', 'Diastolic', 'Heart Rate'])
# Write user readings to the CSV
readings = Reading.query.filter_by(user_id=current_user.id).all()
for reading in readings:
writer.writerow([
reading.timestamp.strftime('%Y-%m-%d %H:%M:%S'),
reading.systolic,
reading.diastolic,
reading.heart_rate,
])
# Convert text to bytes for `send_file`
output.seek(0)
response = io.BytesIO(output.getvalue().encode('utf-8'))
output.close()
return send_file(
response,
mimetype='text/csv',
as_attachment=True,
download_name='readings.csv'
)

View File

@@ -20,7 +20,7 @@
<div class="flex items-center space-x-4"> <div class="flex items-center space-x-4">
{% if current_user.is_authenticated %} {% if current_user.is_authenticated %}
<a rel="prefetch" href="{{ url_for('main.dashboard') }}" class="px-4 py-2 hover:underline">Dashboard</a> <a rel="prefetch" href="{{ url_for('main.dashboard') }}" class="px-4 py-2 hover:underline">Dashboard</a>
<a href="{{ url_for('main.manage_data') }}" class="px-4 py-2 hover:underline">Data</a>
<!-- Profile with Photo or Default Icon --> <!-- Profile with Photo or Default Icon -->
<a rel="prefetch" href="{{ url_for('user.profile') }}" <a rel="prefetch" href="{{ url_for('user.profile') }}"
class="relative flex items-center space-x-2 group"> class="relative flex items-center space-x-2 group">

30
app/templates/data.html Normal file
View File

@@ -0,0 +1,30 @@
{% extends "_layout.html" %}
{% block content %}
<div class="max-w-4xl mx-auto p-4">
<h1 class="text-2xl font-bold mb-4">Import/Export Data</h1>
<!-- Import Data Section -->
<div class="bg-white p-6 rounded-lg shadow-md mb-6">
<h2 class="text-lg font-semibold mb-4">Import Data</h2>
<form method="POST" action="{{ url_for('main.manage_data') }}" enctype="multipart/form-data">
<label for="file" class="block text-sm font-medium text-gray-700 mb-2">Upload CSV File</label>
<input type="file" name="file" id="file"
class="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<button type="submit"
class="mt-4 bg-blue-600 text-white px-6 py-2 rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500">
Import Data
</button>
</form>
</div>
<!-- Export Data Section -->
<div class="bg-white p-6 rounded-lg shadow-md">
<h2 class="text-lg font-semibold mb-4">Export Data</h2>
<a href="{{ url_for('main.export_data') }}"
class="bg-green-600 text-white px-6 py-2 rounded-lg shadow-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500">
Download CSV
</a>
</div>
</div>
{% endblock %}