Add functionality to import/export readings in csv format
This commit is contained in:
@@ -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'
|
||||||
|
)
|
||||||
@@ -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
30
app/templates/data.html
Normal 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 %}
|
||||||
Reference in New Issue
Block a user