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 view(*args, **kwargs)
|
||||||
return wrapped
|
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
|
@app.context_processor
|
||||||
@@ -127,73 +191,36 @@ def dashboard(page=1):
|
|||||||
return redirect(url_for("welcome"))
|
return redirect(url_for("welcome"))
|
||||||
|
|
||||||
is_admin = profile.get("is_admin")
|
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
|
# Pagination settings
|
||||||
per_page = int(request.args.get('per_page', 25))
|
per_page = int(request.args.get('per_page', 25))
|
||||||
offset = (page - 1) * per_page
|
offset = (page - 1) * per_page
|
||||||
query = None
|
case_email_match = None
|
||||||
|
if is_admin and request.args.get('case_email'):
|
||||||
# Get total count efficiently using a count aggregation query
|
case_email_match = request.args.get('case_email')
|
||||||
try:
|
if not is_admin and not profile.get('case_email'):
|
||||||
# Firestore doesn't have a direct count() method, so we need to count documents
|
return redirect(url_for("welcome"))
|
||||||
import time
|
paginated_rows, total_projects = projects_for(profile, case_email_match, per_page, offset)
|
||||||
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
|
|
||||||
|
|
||||||
# Calculate pagination
|
# Calculate pagination
|
||||||
total_pages = (total_projects + per_page - 1) // per_page # Ceiling division
|
total_pages = (total_projects + per_page - 1) // per_page # Ceiling division
|
||||||
|
|
||||||
# Read only the current page from Firestore using limit() and offset()
|
# Read only the current page from Firestore using limit() and offset()
|
||||||
import time
|
import time
|
||||||
start_time = time.time()
|
print(f"Retrieved {len(paginated_rows)} projects from Firestore")
|
||||||
# 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")
|
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
pprint([p['property_contacts'] for p in paginated_rows if p['property_contacts'].get('propertyManager1', None)])
|
pprint([p['property_contacts'] for p in paginated_rows if p['property_contacts'].get('propertyManager1', None)])
|
||||||
pprint([p['ProjectId'] for p in paginated_rows ])
|
pprint([p['ProjectId'] for p in paginated_rows ])
|
||||||
# Render table with pagination data
|
# Render table with pagination data
|
||||||
return render_template("dashboard.html",
|
return render_template("dashboard.html",
|
||||||
rows=paginated_rows,
|
rows=paginated_rows,
|
||||||
case_email=case_email,
|
case_email=case_email_match,
|
||||||
current_page=page,
|
current_page=page,
|
||||||
total_pages=total_pages,
|
total_pages=total_pages,
|
||||||
total_projects=total_projects,
|
total_projects=total_projects,
|
||||||
per_page=per_page)
|
per_page=per_page)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/dashboard/export_xls")
|
@app.route("/dashboard/export_xls")
|
||||||
@login_required
|
@login_required
|
||||||
@@ -206,33 +233,15 @@ def dashboard_export_xls():
|
|||||||
|
|
||||||
is_admin = profile.get("is_admin")
|
is_admin = profile.get("is_admin")
|
||||||
case_email = None
|
case_email = None
|
||||||
if not is_admin:
|
if not is_admin and not profile.get('case_email'):
|
||||||
case_email = profile.get("case_email")
|
return redirect(url_for("welcome"))
|
||||||
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")
|
|
||||||
|
|
||||||
# Get all projects without pagination
|
# Get all projects without pagination
|
||||||
try:
|
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
|
# 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
|
# Order by matter_description to maintain consistent ordering
|
||||||
projects_ref = projects_ref.order_by("matter_description")
|
print(f"Retrieved {cnt} projects from Firestore for XLS export")
|
||||||
|
|
||||||
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")
|
|
||||||
|
|
||||||
# Create workbook and worksheet
|
# Create workbook and worksheet
|
||||||
wb = Workbook()
|
wb = Workbook()
|
||||||
|
|||||||
Reference in New Issue
Block a user