mirror of
https://github.com/sstent/foodplanner.git
synced 2026-01-25 03:01:35 +00:00
fixing imports
This commit is contained in:
9
.github/workflows/build-and-push.yml
vendored
9
.github/workflows/build-and-push.yml
vendored
@@ -35,6 +35,15 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /tmp/.buildx-cache # Or a custom path for your cache
|
||||
key: ${{ runner.os }}-docker-${{ hashFiles('Dockerfile') }}-${{ hashFiles('src/**') }} # Example key
|
||||
restore-keys: |
|
||||
${{ runner.os }}-docker-${{ hashFiles('Dockerfile') }}-
|
||||
${{ runner.os }}-docker-
|
||||
|
||||
- name: Extract metadata for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
|
||||
77
main.py
77
main.py
@@ -1938,7 +1938,6 @@ async def tracker_save_template(request: Request, db: Session = Depends(get_db))
|
||||
meal_time=tracked_meal.meal_time
|
||||
)
|
||||
db.add(template_meal)
|
||||
|
||||
db.commit()
|
||||
|
||||
logging.info(f"DEBUG: Successfully saved template with {len(tracked_meals)} meals")
|
||||
@@ -2060,4 +2059,78 @@ async def tracker_reset_to_plan(request: Request, db: Session = Depends(get_db))
|
||||
@app.get("/test")
|
||||
async def test_route():
|
||||
logging.info("DEBUG: Test route called")
|
||||
return {"status": "success", "message": "Test route is working"}
|
||||
return {"status": "success", "message": "Test route is working"}
|
||||
|
||||
@app.post("/templates/upload")
|
||||
async def bulk_upload_templates(file: UploadFile = File(...), db: Session = Depends(get_db)):
|
||||
"""Handle bulk template upload from CSV"""
|
||||
try:
|
||||
contents = await file.read()
|
||||
decoded = contents.decode('utf-8').splitlines()
|
||||
reader = csv.DictReader(decoded)
|
||||
|
||||
stats = {'created': 0, 'updated': 0, 'errors': []}
|
||||
|
||||
for row_num, row in enumerate(reader, 2): # Row numbers start at 2 (1-based + header)
|
||||
try:
|
||||
user = row.get('User', '').strip()
|
||||
template_id = row.get('ID', '').strip()
|
||||
|
||||
if not user or not template_id:
|
||||
stats['errors'].append(f"Row {row_num}: Missing User or ID")
|
||||
continue
|
||||
|
||||
# Create template name in format <User>-<ID>
|
||||
template_name = f"{user}-{template_id}"
|
||||
|
||||
# Check if template already exists
|
||||
existing_template = db.query(Template).filter(Template.name == template_name).first()
|
||||
if existing_template:
|
||||
# Update existing template - remove existing meals
|
||||
db.query(TemplateMeal).filter(TemplateMeal.template_id == existing_template.id).delete()
|
||||
template = existing_template
|
||||
stats['updated'] += 1
|
||||
else:
|
||||
# Create new template
|
||||
template = Template(name=template_name)
|
||||
db.add(template)
|
||||
stats['created'] += 1
|
||||
|
||||
db.flush() # Get template ID
|
||||
|
||||
# Meal time mappings from CSV columns
|
||||
meal_columns = {
|
||||
'Beverage 1': 'Beverage 1',
|
||||
'Breakfast': 'Breakfast',
|
||||
'Lunch': 'Lunch',
|
||||
'Dinner': 'Dinner',
|
||||
'Snack 1': 'Snack 1',
|
||||
'Snack 2': 'Snack 2'
|
||||
}
|
||||
|
||||
# Process each meal column
|
||||
for csv_column, meal_time in meal_columns.items():
|
||||
meal_name = row.get(csv_column, '').strip()
|
||||
if meal_name:
|
||||
# Find meal by name
|
||||
meal = db.query(Meal).filter(Meal.name.ilike(meal_name)).first()
|
||||
if meal:
|
||||
# Create template meal
|
||||
template_meal = TemplateMeal(
|
||||
template_id=template.id,
|
||||
meal_id=meal.id,
|
||||
meal_time=meal_time
|
||||
)
|
||||
db.add(template_meal)
|
||||
else:
|
||||
stats['errors'].append(f"Row {row_num}: Meal '{meal_name}' not found for {meal_time}")
|
||||
|
||||
except (KeyError, ValueError) as e:
|
||||
stats['errors'].append(f"Row {row_num}: {str(e)}")
|
||||
|
||||
db.commit()
|
||||
return stats
|
||||
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
return {"status": "error", "message": str(e)}
|
||||
@@ -32,4 +32,120 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Food Import</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="/foods/upload" method="post" enctype="multipart/form-data" class="csv-upload-form">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">CSV File</label>
|
||||
<input type="file" class="form-control" name="file" accept=".csv" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-secondary">Upload Foods CSV</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Meal Import</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="/meals/upload" method="post" enctype="multipart/form-data" class="csv-upload-form">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">CSV File</label>
|
||||
<input type="file" class="form-control" name="file" accept=".csv" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-secondary">Upload Meals CSV</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Template Import</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="/templates/upload" method="post" enctype="multipart/form-data" class="csv-upload-form">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">CSV File</label>
|
||||
<input type="file" class="form-control" name="file" accept=".csv" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-secondary">Upload Templates CSV</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4" id="upload-results" style="display: none;">
|
||||
<div class="alert">
|
||||
<strong>Upload Results:</strong>
|
||||
<p>Created: <span id="created-count"></span></p>
|
||||
<p>Updated: <span id="updated-count"></span></p>
|
||||
<div id="error-list" class="mt-2 text-danger"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.querySelectorAll('.csv-upload-form').forEach(form => {
|
||||
form.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const submitBtn = form.querySelector('button[type="submit"]');
|
||||
const resultsDiv = document.getElementById('upload-results');
|
||||
const alertDiv = resultsDiv.querySelector('.alert');
|
||||
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status"></span> Uploading...';
|
||||
|
||||
try {
|
||||
const formData = new FormData(form);
|
||||
const response = await fetch(form.action, {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
||||
|
||||
const results = await response.json();
|
||||
resultsDiv.style.display = 'block';
|
||||
|
||||
if (results.status === 'error') {
|
||||
alertDiv.className = 'alert alert-danger';
|
||||
document.getElementById('created-count').textContent = 'N/A';
|
||||
document.getElementById('updated-count').textContent = 'N/A';
|
||||
document.getElementById('error-list').innerHTML = `<strong>Error:</strong> ${results.message}`;
|
||||
} else {
|
||||
alertDiv.className = 'alert alert-success';
|
||||
document.getElementById('created-count').textContent = results.created || 0;
|
||||
document.getElementById('updated-count').textContent = results.updated || 0;
|
||||
|
||||
if (results.errors?.length > 0) {
|
||||
document.getElementById('error-list').innerHTML =
|
||||
`<strong>Errors (${results.errors.length}):</strong><br>` + results.errors.join('<br>');
|
||||
} else {
|
||||
document.getElementById('error-list').innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
resultsDiv.style.display = 'block';
|
||||
alertDiv.className = 'alert alert-danger';
|
||||
document.getElementById('created-count').textContent = 'N/A';
|
||||
document.getElementById('updated-count').textContent = 'N/A';
|
||||
document.getElementById('error-list').innerHTML =
|
||||
`<strong>Upload Failed:</strong> ${error.message}`;
|
||||
} finally {
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = 'Upload CSV';
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user