Apr 1 2026: clean up code
This commit is contained in:
+1
-1
@@ -170,7 +170,7 @@ def refresh():
|
||||
request.remote_addr)
|
||||
return api_error('Refresh token is invalid or expired', 401)
|
||||
|
||||
user = User.query.get(rt_row.user_id)
|
||||
user = db.session.get(User, rt_row.user_id)
|
||||
if user is None or not user.active:
|
||||
rt_row.revoke()
|
||||
db.session.commit()
|
||||
|
||||
@@ -34,6 +34,7 @@ from flask import request, g, abort
|
||||
|
||||
from app.api.jwt_utils import decode_access_token
|
||||
from app.api.errors import api_error
|
||||
from app import db
|
||||
from app.models.user import User
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -62,7 +63,7 @@ def jwt_required(f):
|
||||
return api_error('Access token is invalid or expired', 401)
|
||||
|
||||
user_id = int(payload.get('sub', 0))
|
||||
user = User.query.get(user_id)
|
||||
user = db.session.get(User, user_id)
|
||||
|
||||
if user is None:
|
||||
return api_error('User not found', 401)
|
||||
|
||||
+4
-7
@@ -2,6 +2,7 @@ import logging
|
||||
from datetime import datetime, timedelta
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, flash
|
||||
from flask_login import login_required
|
||||
from app import db
|
||||
from app.models.audit import AuditLog
|
||||
from app.models.user import User
|
||||
from app.utils.decorators import admin_required
|
||||
@@ -55,13 +56,13 @@ def index():
|
||||
|
||||
# Distinct action and entity_type values for the filter dropdowns
|
||||
distinct_actions = (
|
||||
db.session.query(AuditLog.action)
|
||||
AuditLog.query.with_entities(AuditLog.action)
|
||||
.distinct()
|
||||
.order_by(AuditLog.action)
|
||||
.all()
|
||||
)
|
||||
distinct_entity_types = (
|
||||
db.session.query(AuditLog.entity_type)
|
||||
AuditLog.query.with_entities(AuditLog.entity_type)
|
||||
.distinct()
|
||||
.order_by(AuditLog.entity_type)
|
||||
.all()
|
||||
@@ -144,8 +145,4 @@ def purge():
|
||||
f'older than {label} have been permanently deleted.',
|
||||
'success' if deleted else 'info',
|
||||
)
|
||||
return redirect(url_for('audit.index'))
|
||||
|
||||
|
||||
# Avoid circular import — imported after function definitions
|
||||
from app import db # noqa: E402
|
||||
return redirect(url_for('audit.index'))
|
||||
@@ -249,8 +249,8 @@ def add_assignment(customer_id):
|
||||
def remove_assignment(assignment_id):
|
||||
assignment = CustomerAssignment.query.get_or_404(assignment_id)
|
||||
customer_id = assignment.user_id
|
||||
customer = User.query.get(customer_id)
|
||||
project = Project.query.get(assignment.project_id)
|
||||
customer = db.session.get(User, customer_id)
|
||||
project = db.session.get(Project, assignment.project_id)
|
||||
|
||||
username = customer.username if customer else f'user_id={customer_id}'
|
||||
project_name = project.name if project else f'project_id={assignment.project_id}'
|
||||
|
||||
@@ -241,7 +241,7 @@ def facility_trend():
|
||||
if facility_id not in cids:
|
||||
return jsonify({'labels': [], 'data': [], 'facility': ''}), 403
|
||||
|
||||
facility = Facility.query.get(facility_id)
|
||||
facility = db.session.get(Facility, facility_id)
|
||||
if not facility:
|
||||
return jsonify({'labels': [], 'data': [], 'facility': ''})
|
||||
|
||||
|
||||
@@ -318,7 +318,7 @@ def execute(inspection_id):
|
||||
# fields (rating, pass_fail) so the inspector doesn't re-enter static
|
||||
# data but must re-evaluate every scoreable item fresh.
|
||||
if not saved_responses and inspection.parent_inspection_id:
|
||||
parent = Inspection.query.get(inspection.parent_inspection_id)
|
||||
parent = db.session.get(Inspection, inspection.parent_inspection_id)
|
||||
if parent and parent.notes:
|
||||
try:
|
||||
parent_parsed = json.loads(parent.notes)
|
||||
@@ -717,7 +717,7 @@ def flag_issue(inspection_id):
|
||||
)
|
||||
|
||||
if issue.assigned_to:
|
||||
assignee = User.query.get(issue.assigned_to)
|
||||
assignee = db.session.get(User, issue.assigned_to)
|
||||
if assignee and assignee.id != current_user.id:
|
||||
notify(
|
||||
recipient = assignee,
|
||||
|
||||
@@ -107,7 +107,7 @@ def view(issue_id):
|
||||
if current_user.role == 'customer':
|
||||
from app.models.facility import Area
|
||||
cids = get_customer_scope(current_user) or []
|
||||
area = Area.query.get(issue.area_id)
|
||||
area = db.session.get(Area, issue.area_id)
|
||||
if not area or area.facility_id not in cids:
|
||||
flash('Access denied.', 'danger')
|
||||
return redirect(url_for('issues.index'))
|
||||
@@ -167,7 +167,7 @@ def view(issue_id):
|
||||
|
||||
# 1. Status changed — notify assignee
|
||||
if old_status != issue.status and new_assigned_to:
|
||||
assignee = User.query.get(new_assigned_to)
|
||||
assignee = db.session.get(User, new_assigned_to)
|
||||
if assignee and assignee.id != actor_id:
|
||||
notify(
|
||||
recipient = assignee,
|
||||
@@ -186,7 +186,7 @@ def view(issue_id):
|
||||
|
||||
# 2. Reassigned — notify new assignee
|
||||
if (old_assigned_to != new_assigned_to) and new_assigned_to:
|
||||
new_assignee = User.query.get(new_assigned_to)
|
||||
new_assignee = db.session.get(User, new_assigned_to)
|
||||
if new_assignee and new_assignee.id != actor_id:
|
||||
notify(
|
||||
recipient = new_assignee,
|
||||
@@ -204,7 +204,7 @@ def view(issue_id):
|
||||
|
||||
# 3. Unassigned — notify previous assignee
|
||||
if old_assigned_to and old_assigned_to != new_assigned_to:
|
||||
old_assignee = User.query.get(old_assigned_to)
|
||||
old_assignee = db.session.get(User, old_assigned_to)
|
||||
if old_assignee and old_assignee.id != actor_id:
|
||||
notify(
|
||||
recipient = old_assignee,
|
||||
@@ -221,7 +221,7 @@ def view(issue_id):
|
||||
|
||||
# 4. Comment added — notify assignee
|
||||
if comment_body and new_assigned_to:
|
||||
commentee = User.query.get(new_assigned_to)
|
||||
commentee = db.session.get(User, new_assigned_to)
|
||||
if commentee and commentee.id != actor_id:
|
||||
notify(
|
||||
recipient = commentee,
|
||||
@@ -250,7 +250,8 @@ def view(issue_id):
|
||||
f'to "{issue.status.replace("_"," ").title()}"'
|
||||
)
|
||||
if old_assigned_to != new_assigned_to:
|
||||
new_name = User.query.get(new_assigned_to).username if new_assigned_to else 'Unassigned'
|
||||
_new_assignee_obj = db.session.get(User, new_assigned_to) if new_assigned_to else None
|
||||
new_name = _new_assignee_obj.username if _new_assignee_obj else 'Unassigned'
|
||||
changes.append(f'reassigned to {new_name}')
|
||||
if comment_body:
|
||||
changes.append(f'new comment added by {current_user.username}')
|
||||
@@ -378,7 +379,7 @@ def create():
|
||||
f'severity={issue.severity}; assigned_to={issue.assigned_to}')
|
||||
|
||||
if issue.assigned_to:
|
||||
assignee = User.query.get(issue.assigned_to)
|
||||
assignee = db.session.get(User, issue.assigned_to)
|
||||
if assignee and assignee.id != current_user.id:
|
||||
notify(
|
||||
recipient = assignee,
|
||||
@@ -397,7 +398,7 @@ def create():
|
||||
db.session.commit()
|
||||
|
||||
# ── Notify customer portal users for this facility ──────────
|
||||
area = Area.query.get(issue.area_id)
|
||||
area = db.session.get(Area, issue.area_id)
|
||||
if area:
|
||||
notify_customers_for_facility(
|
||||
facility_id = area.facility_id,
|
||||
|
||||
@@ -3,7 +3,7 @@ import logging
|
||||
from flask import (Blueprint, jsonify, request, abort,
|
||||
render_template, redirect, url_for, flash, current_app)
|
||||
from flask_login import login_required, current_user
|
||||
from app import db
|
||||
from app import db, csrf
|
||||
from app.models.notification import (
|
||||
Notification, NotificationPreference, ALL_EVENT_TYPES
|
||||
)
|
||||
@@ -166,6 +166,7 @@ def preferences():
|
||||
# ── Digest trigger (called by cron) ───────────────────────────────────────────
|
||||
|
||||
@bp.route('/send-digest', methods=['POST'])
|
||||
@csrf.exempt
|
||||
def send_digest():
|
||||
"""Trigger digest email delivery. Protected by a shared secret token.
|
||||
|
||||
@@ -198,6 +199,7 @@ def send_digest():
|
||||
# ── SLA alert trigger (called by cron) ────────────────────────────────────────
|
||||
|
||||
@bp.route('/check-sla', methods=['POST'])
|
||||
@csrf.exempt
|
||||
def check_sla():
|
||||
"""Scan all open issues for SLA breaches and dispatch alerts.
|
||||
|
||||
@@ -219,4 +221,4 @@ def check_sla():
|
||||
sent = send_sla_alerts()
|
||||
|
||||
logger.info('SLA CHECK TRIGGERED | notifications_sent=%s', sent)
|
||||
return jsonify({'ok': True, 'notifications_sent': sent})
|
||||
return jsonify({'ok': True, 'notifications_sent': sent})
|
||||
@@ -181,7 +181,7 @@ def add_assignment(project_id):
|
||||
db.session.add(assignment)
|
||||
db.session.commit()
|
||||
|
||||
user = User.query.get(form.user_id.data)
|
||||
user = db.session.get(User, form.user_id.data)
|
||||
scope_label = f'facility_id={facility_id}' if facility_id else 'all facilities'
|
||||
logger.info('PROJECTS | assignment_add | admin=%s customer=%s project_id=%s scope=%s',
|
||||
current_user.username, user.username, project_id, scope_label)
|
||||
@@ -208,7 +208,7 @@ def remove_assignment(assignment_id):
|
||||
assignment = CustomerAssignment.query.get_or_404(assignment_id)
|
||||
project_id = assignment.project_id
|
||||
project = Project.query.get_or_404(project_id)
|
||||
user = User.query.get(assignment.user_id)
|
||||
user = db.session.get(User, assignment.user_id)
|
||||
|
||||
username = user.username if user else f'user_id={assignment.user_id}'
|
||||
assignment_id_snap = assignment.id
|
||||
|
||||
@@ -32,7 +32,7 @@ from flask_login import login_required, current_user
|
||||
from flask_mail import Message
|
||||
from sqlalchemy import func
|
||||
|
||||
from app import db, mail
|
||||
from app import db, mail, csrf
|
||||
from app.models.scheduled_report import ScheduledReport
|
||||
from app.models.inspection import Inspection, InspectionTemplate
|
||||
from app.models.facility import Facility, Area
|
||||
@@ -419,6 +419,9 @@ def send_now(report_id):
|
||||
if ok:
|
||||
report.last_sent_at = now_eastern()
|
||||
db.session.commit()
|
||||
log_action(ACTION_UPDATE, 'ScheduledReport', report.id, report.name,
|
||||
f'manual send_now by {current_user.username}; '
|
||||
f'frequency={report.frequency}; recipients={len(report.recipient_list())}')
|
||||
flash(f'Report "{report.name}" sent successfully.', 'success')
|
||||
else:
|
||||
flash(f'Failed to send report "{report.name}". Check application logs.', 'danger')
|
||||
@@ -428,6 +431,7 @@ def send_now(report_id):
|
||||
# ── Cron endpoint ─────────────────────────────────────────────────────────────
|
||||
|
||||
@bp.route('/send', methods=['POST'])
|
||||
@csrf.exempt
|
||||
def send():
|
||||
"""Token-protected endpoint called by cron to dispatch due reports.
|
||||
|
||||
@@ -452,12 +456,20 @@ def send():
|
||||
sent, failed = 0, 0
|
||||
for report in due:
|
||||
ok = _send_report(report)
|
||||
# Always advance next_send_at so a failed report does not get
|
||||
# retried on every subsequent cron run. last_sent_at is only
|
||||
# updated on a successful delivery so the UI accurately reflects
|
||||
# when the last good email was dispatched.
|
||||
report.next_send_at = _compute_next_send(frequency, now)
|
||||
if ok:
|
||||
report.last_sent_at = now
|
||||
report.next_send_at = _compute_next_send(frequency, now)
|
||||
sent += 1
|
||||
else:
|
||||
failed += 1
|
||||
logger.error(
|
||||
'SCHEDULED REPORT FAILED | id=%s | name=%r | frequency=%s',
|
||||
report.id, report.name, frequency,
|
||||
)
|
||||
db.session.commit()
|
||||
|
||||
logger.info('SCHEDULED REPORTS CRON | frequency=%s | due=%s | sent=%s | failed=%s',
|
||||
|
||||
+11
-1
@@ -305,6 +305,9 @@ def create_checklist_item(template_id):
|
||||
)
|
||||
db.session.add(item)
|
||||
db.session.commit()
|
||||
log_action(ACTION_CREATE, 'ChecklistItem', item.id, item.item_description[:80],
|
||||
f'template_id={template.id}; category={item.category or ""}; '
|
||||
f'scoring_type={item.scoring_type}')
|
||||
|
||||
flash('Checklist item added successfully.', 'success')
|
||||
return redirect(url_for('templates.edit_template', template_id=template.id))
|
||||
@@ -331,6 +334,9 @@ def edit_checklist_item(item_id):
|
||||
item.weight = form.weight.data
|
||||
item.requires_photo = form.requires_photo.data
|
||||
db.session.commit()
|
||||
log_action(ACTION_UPDATE, 'ChecklistItem', item.id, item.item_description[:80],
|
||||
f'template_id={item.template_id}; category={item.category or ""}; '
|
||||
f'scoring_type={item.scoring_type}')
|
||||
flash('Checklist item updated successfully.', 'success')
|
||||
return redirect(url_for('templates.edit_template', template_id=item.template_id))
|
||||
|
||||
@@ -349,8 +355,12 @@ def edit_checklist_item(item_id):
|
||||
def delete_checklist_item(item_id):
|
||||
item = ChecklistItem.query.get_or_404(item_id)
|
||||
template_id = item.template_id
|
||||
item_desc = item.item_description[:80]
|
||||
item_id_snap = item.id
|
||||
db.session.delete(item)
|
||||
db.session.commit()
|
||||
log_action(ACTION_DELETE, 'ChecklistItem', item_id_snap, item_desc,
|
||||
f'template_id={template_id}')
|
||||
flash('Checklist item deleted successfully.', 'success')
|
||||
return redirect(url_for('templates.edit_template', template_id=template_id))
|
||||
|
||||
@@ -363,7 +373,7 @@ def reorder_items(template_id):
|
||||
item_order = request.json.get('item_order', [])
|
||||
|
||||
for index, item_id in enumerate(item_order):
|
||||
item = ChecklistItem.query.get(item_id)
|
||||
item = db.session.get(ChecklistItem, item_id)
|
||||
if item and item.template_id == template.id:
|
||||
item.display_order = index
|
||||
|
||||
|
||||
Reference in New Issue
Block a user