Improvement

This commit is contained in:
2025-12-05 00:10:08 -08:00
parent c3e943f135
commit c3108ff68c

147
app.py
View File

@@ -29,6 +29,70 @@ def login_required(view):
return view(*args, **kwargs)
return wrapped
def projects_for(profile, case_email_match, per_page, offset):
"""
Filter projects based on user profile and case_email query string argument.
Args:
profile (dict): User profile containing 'enabled', 'is_admin', and 'case_email' fields
case_email_match (str): Case email from query string argument, or None
Returns:
list: List of project dictionaries that match the filtering criteria
"""
is_admin = profile.get("is_admin", False)
if not profile.get("enabled"):
return ([], 0)
# Query Firestore for projects where case_email is in viewing_emails array
try:
cnt = 0
if is_admin:
if case_email_match:
projects_ref = db.collection("projects").where("viewing_emails", "array_contains", case_email_match.lower())
# Get filtered document IDs using client-side filtering with partial match
z = db.collection("projects").select(["viewing_emails", "matter_description", "id"])
# Get all matching documents with their IDs and descriptions
matching_docs = [(x.id, x.to_dict().get('matter_description', '')) for x in z.stream()
if any(case_email_match.lower() in email.lower() for email in x.to_dict().get('viewing_emails', []))]
count = len(matching_docs)
# Sort by matter_description
matching_docs.sort(key=lambda x: x[1].lower())
# Extract just the IDs after sorting
filtered_ids = [doc_id for doc_id, _ in matching_docs]
# Apply client-side pagination
filtered_ids = filtered_ids[offset:offset + per_page]
print(f"Filtered document IDs (partial match, sorted, paginated): {filtered_ids}")
projects_ref = db.collection("projects")
projects = []
for doc_id in filtered_ids:
doc = projects_ref.document(doc_id).get()
if doc.exists:
projects.append(doc.to_dict())
return (projects, count)
else:
projects_ref = db.collection("projects")
else:
if not profile.get("case_email"):
return ([], 0)
projects_ref = db.collection("projects").where("viewing_emails", "array_contains", profile.get("case_email").to_lower())
cnt = int(projects_ref.count().get()[0][0].value)
projects = []
for doc in projects_ref.order_by("matter_description").limit(per_page).offset(offset).stream():
projects.append(doc.to_dict())
return (projects, cnt)
except Exception as e:
print(f"[ERROR] Failed to query projects: {e}")
return ([], 0)
@app.context_processor
@@ -127,73 +191,36 @@ def dashboard(page=1):
return redirect(url_for("welcome"))
is_admin = profile.get("is_admin")
case_email = None
if not is_admin:
case_email = profile.get("case_email")
if not case_email:
return redirect(url_for("welcome"))
if is_admin and request.args.get('case_email'):
case_email = request.args.get('case_email').lower()
# Validate email format
if '@' not in case_email:
return abort(400, "Invalid email format")
# Pagination settings
per_page = int(request.args.get('per_page', 25))
offset = (page - 1) * per_page
query = None
# Get total count efficiently using a count aggregation query
try:
# Firestore doesn't have a direct count() method, so we need to count documents
import time
start_time = time.time()
projects_ref = db.collection("projects")
# Filter projects where case_email is in viewing_emails array
if case_email:
query = projects_ref.where("viewing_emails", "array_contains", case_email.lower())
else:
query = projects_ref
total_projects = int(query.count().get()[0][0].value)
end_time = time.time()
print(f"Filtered projects count: {total_projects} (took {end_time - start_time:.2f}s)")
except Exception as e:
print(f"[WARN] Failed to get filtered count: {e}")
total_projects = 0
case_email_match = None
if is_admin and request.args.get('case_email'):
case_email_match = request.args.get('case_email')
if not is_admin and not profile.get('case_email'):
return redirect(url_for("welcome"))
paginated_rows, total_projects = projects_for(profile, case_email_match, per_page, offset)
# Calculate pagination
total_pages = (total_projects + per_page - 1) // per_page # Ceiling division
# Read only the current page from Firestore using limit() and offset()
import time
start_time = time.time()
# Filter projects where case_email is in viewing_emails array
if case_email:
projects_ref = db.collection("projects").where("viewing_emails", "array_contains", case_email.lower()).order_by("matter_description").limit(per_page).offset(offset)
else:
projects_ref = db.collection("projects").order_by("matter_description").limit(per_page).offset(offset)
docs = projects_ref.stream()
paginated_rows = []
for doc in docs:
paginated_rows.append(doc.to_dict())
end_time = time.time()
print(f"Retrieved {len(paginated_rows)} projects from Firestore (page {page} of {total_pages}) in {end_time - start_time:.2f}s")
print(f"Retrieved {len(paginated_rows)} projects from Firestore")
from pprint import pprint
pprint([p['property_contacts'] for p in paginated_rows if p['property_contacts'].get('propertyManager1', None)])
pprint([p['ProjectId'] for p in paginated_rows ])
# Render table with pagination data
return render_template("dashboard.html",
rows=paginated_rows,
case_email=case_email,
case_email=case_email_match,
current_page=page,
total_pages=total_pages,
total_projects=total_projects,
per_page=per_page)
@app.route("/dashboard/export_xls")
@login_required
@@ -206,33 +233,15 @@ def dashboard_export_xls():
is_admin = profile.get("is_admin")
case_email = None
if not is_admin:
case_email = profile.get("case_email")
if not case_email:
return redirect(url_for("welcome"))
if is_admin and request.args.get('case_email'):
case_email = request.args.get('case_email').lower()
# Validate email format
if '@' not in case_email:
return abort(400, "Invalid email format")
if not is_admin and not profile.get('case_email'):
return redirect(url_for("welcome"))
# Get all projects without pagination
try:
projects_ref = db.collection("projects")
all_rows, cnt = projects_for(profile, case_email, 10000, 0)
# Filter projects where case_email is in viewing_emails array
if case_email:
projects_ref = projects_ref.where("viewing_emails", "array_contains", case_email.lower())
# Order by matter_description to maintain consistent ordering
projects_ref = projects_ref.order_by("matter_description")
docs = projects_ref.stream()
all_rows = []
for doc in docs:
all_rows.append(doc.to_dict())
print(f"Retrieved {len(all_rows)} projects from Firestore for XLS export")
print(f"Retrieved {cnt} projects from Firestore for XLS export")
# Create workbook and worksheet
wb = Workbook()