Improvement
This commit is contained in:
147
app.py
147
app.py
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user