Initial commit: Essential Oil Formula Cost Calculator

This commit is contained in:
2026-04-06 13:46:32 +00:00
commit 0368e85abe
25 changed files with 20897 additions and 0 deletions

53
scripts/backup.sh Executable file
View File

@@ -0,0 +1,53 @@
#!/bin/bash
# Weekly backup script - run locally or via cron
# Backs up: database from server + local code
# Keeps last 5 backups
BACKUP_BASE="$HOME/Hera DOCS/Projects/Essential Oil Formula Cost Calculator/backups"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="$BACKUP_BASE/$DATE"
mkdir -p "$BACKUP_DIR"
echo "📦 Backing up to: $BACKUP_DIR"
# 1. Download database from server
echo " Downloading database..."
ssh fam@oci.euphon.net "kubectl exec -n oil-calculator deploy/oil-calculator -- cat /data/oil_calculator.db" > "$BACKUP_DIR/oil_calculator.db" 2>/dev/null
if [ $? -eq 0 ] && [ -s "$BACKUP_DIR/oil_calculator.db" ]; then
echo " ✅ Database: $(du -h "$BACKUP_DIR/oil_calculator.db" | cut -f1)"
else
echo " ❌ Database download failed"
fi
# 2. Copy local code
echo " Copying code..."
PROJECT="$HOME/Hera DOCS/Projects/Essential Oil Formula Cost Calculator"
cp -r "$PROJECT/backend" "$BACKUP_DIR/"
cp -r "$PROJECT/frontend" "$BACKUP_DIR/"
cp "$PROJECT/Dockerfile" "$BACKUP_DIR/"
echo " ✅ Code copied"
# 3. Export all data as JSON (recipes, oils, users)
echo " Exporting data..."
ADMIN_TOKEN=$(cat /tmp/oil_admin_token.txt 2>/dev/null)
if [ -n "$ADMIN_TOKEN" ]; then
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" https://oil.oci.euphon.net/api/recipes > "$BACKUP_DIR/recipes.json" 2>/dev/null
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" https://oil.oci.euphon.net/api/oils > "$BACKUP_DIR/oils.json" 2>/dev/null
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" https://oil.oci.euphon.net/api/tags > "$BACKUP_DIR/tags.json" 2>/dev/null
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" https://oil.oci.euphon.net/api/users > "$BACKUP_DIR/users.json" 2>/dev/null
echo " ✅ Data exported"
else
echo " ⚠️ No admin token, skipping data export"
fi
# 4. Keep only last 5 backups
echo " Cleaning old backups..."
ls -dt "$BACKUP_BASE"/*/ 2>/dev/null | tail -n +31 | xargs rm -rf 2>/dev/null
REMAINING=$(ls -d "$BACKUP_BASE"/*/ 2>/dev/null | wc -l)
echo "$REMAINING backups retained"
echo ""
echo "✅ Backup complete: $BACKUP_DIR"
ls -la "$BACKUP_DIR/"

19
scripts/remote-backup.sh Executable file
View File

@@ -0,0 +1,19 @@
#!/bin/bash
# Remote backup: download database from server to local Mac
# Run via cron: crontab -e → 0 * * * * /path/to/remote-backup.sh
BACKUP_DIR="$HOME/Hera DOCS/Projects/Essential Oil Formula Cost Calculator/backups/remote"
mkdir -p "$BACKUP_DIR"
DATE=$(date +%Y%m%d_%H%M%S)
# Download database
ssh fam@oci.euphon.net "kubectl exec -n oil-calculator deploy/oil-calculator -- cat /data/oil_calculator.db" > "$BACKUP_DIR/oil_calculator_${DATE}.db" 2>/dev/null
if [ $? -eq 0 ] && [ -s "$BACKUP_DIR/oil_calculator_${DATE}.db" ]; then
echo "✅ Backup: $BACKUP_DIR/oil_calculator_${DATE}.db ($(du -h "$BACKUP_DIR/oil_calculator_${DATE}.db" | cut -f1))"
# Keep last 168 backups (7 days hourly)
ls -t "$BACKUP_DIR"/oil_calculator_*.db 2>/dev/null | tail -n +169 | xargs rm -f 2>/dev/null
else
echo "❌ Backup failed"
rm -f "$BACKUP_DIR/oil_calculator_${DATE}.db"
fi

View File

@@ -0,0 +1,46 @@
#!/usr/bin/env python3
"""
Scan the local recipe folder for new Excel files and extract recipes.
Run periodically (e.g., weekly) to find new content to add to the calculator.
Usage:
python3 scripts/scan-recipes-folder.py
It will:
1. Read all .xlsx files in the recipe folder
2. Compare with existing recipes in the API
3. Report any new recipes found
4. Optionally upload them (with --upload flag)
"""
import os
import sys
import json
import argparse
RECIPE_FOLDER = os.path.expanduser("~/Hera DOCS/Essential Oil/商业和公司/成本和配方")
API_BASE = "https://oil.oci.euphon.net"
def main():
parser = argparse.ArgumentParser(description="Scan recipe folder for new content")
parser.add_argument("--upload", action="store_true", help="Upload new recipes to API")
parser.add_argument("--token", help="Admin API token")
args = parser.parse_args()
print(f"📁 Scanning: {RECIPE_FOLDER}")
if not os.path.isdir(RECIPE_FOLDER):
print(f" Folder not found!")
return
files = [f for f in os.listdir(RECIPE_FOLDER) if f.endswith('.xlsx') and not f.startswith('~$')]
print(f" Found {len(files)} Excel files:")
for f in files:
mtime = os.path.getmtime(os.path.join(RECIPE_FOLDER, f))
from datetime import datetime
print(f" - {f} (modified: {datetime.fromtimestamp(mtime).strftime('%Y-%m-%d %H:%M')})")
print(f"\n💡 To add recipes from these files, use the web UI's '智能粘贴' feature")
print(f" or manually add them via the API.")
print(f"\n🔗 Admin URL: {API_BASE}/?token=<your-token>")
if __name__ == "__main__":
main()