04/27 Fixed some issues
This commit is contained in:
+5
-5
@@ -5,7 +5,8 @@ from app.utils.time_utils import now_eastern
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(user_id):
|
||||
return User.query.get(int(user_id))
|
||||
from app import db
|
||||
return db.session.get(User, int(user_id))
|
||||
|
||||
class User(UserMixin, db.Model):
|
||||
__tablename__ = 'users'
|
||||
@@ -16,10 +17,9 @@ class User(UserMixin, db.Model):
|
||||
email = db.Column(db.String(255), unique=True, nullable=False, index=True)
|
||||
password_hash = db.Column(db.String(255), nullable=False)
|
||||
role = db.Column(
|
||||
# 'supervisor' retained temporarily so the Enum is valid before the
|
||||
# migration UPDATE runs. The migration removes it after all rows are
|
||||
# updated to 'director'.
|
||||
db.Enum('admin', 'supervisor', 'director', 'inspector', 'project_manager', 'customer'),
|
||||
# Phase 11 migration complete — 'supervisor' removed from both the DB
|
||||
# ENUM and this Python-side declaration. Director is the canonical role.
|
||||
db.Enum('admin', 'director', 'inspector', 'project_manager', 'customer'),
|
||||
nullable=False
|
||||
)
|
||||
created_at = db.Column(db.DateTime, default=now_eastern)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import logging
|
||||
from flask import Blueprint, render_template
|
||||
from flask_login import login_required, current_user
|
||||
from app import db
|
||||
@@ -13,6 +14,8 @@ from app.utils.time_utils import now_eastern
|
||||
|
||||
bp = Blueprint('dashboard', __name__)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@bp.route('/')
|
||||
@bp.route('/dashboard')
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import logging
|
||||
from flask import Blueprint, render_template, redirect, url_for, flash, request, abort
|
||||
from flask_login import login_required, current_user
|
||||
from app import db
|
||||
@@ -10,6 +11,8 @@ from app.utils.scope import get_customer_scope
|
||||
|
||||
bp = Blueprint('facilities', __name__, url_prefix='/facilities')
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@bp.route('/')
|
||||
@login_required
|
||||
def list_facilities():
|
||||
@@ -43,6 +46,8 @@ def create_facility():
|
||||
|
||||
db.session.add(facility)
|
||||
db.session.commit()
|
||||
logger.info('FACILITIES | create | user=%s | facility_id=%s name=%r',
|
||||
current_user.username, facility.id, facility.name)
|
||||
log_action(ACTION_CREATE, 'Facility', facility.id, facility.name,
|
||||
f'contact={facility.contact_person or ""}; project_id={facility.project_id}; active={facility.active}')
|
||||
flash(f'Facility "{facility.name}" created successfully.', 'success')
|
||||
@@ -85,6 +90,8 @@ def edit_facility(facility_id):
|
||||
facility.active = form.active.data
|
||||
|
||||
db.session.commit()
|
||||
logger.info('FACILITIES | edit | user=%s | facility_id=%s name=%r',
|
||||
current_user.username, facility.id, facility.name)
|
||||
log_action(ACTION_UPDATE, 'Facility', facility.id, facility.name,
|
||||
f'project_id={facility.project_id}; active={facility.active}')
|
||||
flash(f'Facility "{facility.name}" updated successfully.', 'success')
|
||||
@@ -108,6 +115,8 @@ def delete_facility(facility_id):
|
||||
facility_id_snap = facility.id
|
||||
db.session.delete(facility)
|
||||
db.session.commit()
|
||||
logger.info('FACILITIES | delete | user=%s | facility_id=%s name=%r',
|
||||
current_user.username, facility_id_snap, facility_name)
|
||||
log_action(ACTION_DELETE, 'Facility', facility_id_snap, facility_name)
|
||||
flash(f'Facility "{facility_name}" has been permanently deleted.', 'success')
|
||||
return redirect(url_for('facilities.list_facilities'))
|
||||
@@ -134,6 +143,8 @@ def create_area(facility_id):
|
||||
|
||||
db.session.add(area)
|
||||
db.session.commit()
|
||||
logger.info('FACILITIES | create_area | user=%s | area_id=%s name=%r facility=%r',
|
||||
current_user.username, area.id, area.name, facility.name)
|
||||
log_action(ACTION_CREATE, 'Area', area.id, area.name,
|
||||
f'facility={facility.name}; type={area.area_type or ""}')
|
||||
flash(f'Area "{area.name}" created successfully.', 'success')
|
||||
@@ -159,6 +170,8 @@ def edit_area(area_id):
|
||||
area.facility_id = form.facility_id.data
|
||||
|
||||
db.session.commit()
|
||||
logger.info('FACILITIES | edit_area | user=%s | area_id=%s name=%r',
|
||||
current_user.username, area.id, area.name)
|
||||
log_action(ACTION_UPDATE, 'Area', area.id, area.name,
|
||||
f'facility_id={area.facility_id}; type={area.area_type or ""}')
|
||||
flash(f'Area "{area.name}" updated successfully.', 'success')
|
||||
@@ -192,6 +205,8 @@ def delete_area(area_id):
|
||||
area_id_snap = area.id
|
||||
db.session.delete(area)
|
||||
db.session.commit()
|
||||
logger.info('FACILITIES | delete_area | user=%s | area_id=%s name=%r',
|
||||
current_user.username, area_id_snap, area_name)
|
||||
log_action(ACTION_DELETE, 'Area', area_id_snap, area_name)
|
||||
flash(f'Area "{area_name}" deleted successfully.', 'success')
|
||||
return redirect(url_for('facilities.view_facility', facility_id=facility_id))
|
||||
@@ -142,7 +142,7 @@ def view(issue_id):
|
||||
return redirect(url_for('issues.index'))
|
||||
|
||||
form = IssueUpdateForm(obj=issue)
|
||||
staff = User.query.filter(User.role.in_(['director','inspector'])).order_by(User.username).all()
|
||||
staff = User.query.filter(User.role.in_(['admin', 'director', 'inspector'])).order_by(User.username).all()
|
||||
form.assigned_to.choices = [(0, '— Unassigned —')] + [(u.id, u.username) for u in staff]
|
||||
form.status.data = form.status.data or issue.status
|
||||
|
||||
@@ -385,7 +385,7 @@ def unfollow(issue_id):
|
||||
def create():
|
||||
form = IssueForm()
|
||||
areas = Area.query.join(Facility).filter(Facility.active == True).order_by(Facility.name, Area.name).all()
|
||||
staff = User.query.filter(User.role.in_(['director','inspector'])).order_by(User.username).all()
|
||||
staff = User.query.filter(User.role.in_(['admin', 'director', 'inspector'])).order_by(User.username).all()
|
||||
|
||||
form.area_id.choices = [(a.id, f"{a.facility.name} — {a.name}") for a in areas]
|
||||
form.assigned_to.choices = [(0, '— Unassigned —')] + [(u.id, u.username) for u in staff]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import csv
|
||||
import io
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from app.utils.time_utils import now_eastern
|
||||
from flask import (Blueprint, render_template, request,
|
||||
@@ -13,9 +14,12 @@ from app.models.issue import Issue
|
||||
from app.models.user import User
|
||||
from app.utils.decorators import supervisor_required
|
||||
from app.utils.scope import get_customer_scope
|
||||
from app.utils.audit import log_action, ACTION_EXPORT
|
||||
|
||||
bp = Blueprint('reports', __name__, url_prefix='/reports')
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _date_range():
|
||||
"""Parse ?start= and ?end= query params; default to last 30 days."""
|
||||
@@ -360,6 +364,17 @@ def facility_scorecard(facility_id):
|
||||
def export_inspections():
|
||||
start, end = _date_range()
|
||||
|
||||
logger.info(
|
||||
'REPORTS | export_inspections | user=%s | range=%s to %s',
|
||||
current_user.username,
|
||||
start.strftime('%Y-%m-%d'),
|
||||
end.strftime('%Y-%m-%d'),
|
||||
)
|
||||
log_action(
|
||||
ACTION_EXPORT, 'Inspection', None, 'CSV Export',
|
||||
f'range={start.strftime("%Y-%m-%d")} to {end.strftime("%Y-%m-%d")}',
|
||||
)
|
||||
|
||||
rows = db.session.query(
|
||||
Inspection.id,
|
||||
Inspection.inspection_date,
|
||||
@@ -414,6 +429,17 @@ def export_inspections():
|
||||
def export_issues():
|
||||
start, end = _date_range()
|
||||
|
||||
logger.info(
|
||||
'REPORTS | export_issues | user=%s | range=%s to %s',
|
||||
current_user.username,
|
||||
start.strftime('%Y-%m-%d'),
|
||||
end.strftime('%Y-%m-%d'),
|
||||
)
|
||||
log_action(
|
||||
ACTION_EXPORT, 'Issue', None, 'CSV Export',
|
||||
f'range={start.strftime("%Y-%m-%d")} to {end.strftime("%Y-%m-%d")}',
|
||||
)
|
||||
|
||||
rows = db.session.query(
|
||||
Issue.id,
|
||||
Issue.reported_at,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import logging
|
||||
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify, abort
|
||||
from flask_login import login_required, current_user
|
||||
from app import db
|
||||
@@ -9,6 +10,8 @@ from app.utils.audit import log_action, ACTION_CREATE, ACTION_UPDATE, ACTION_DEL
|
||||
|
||||
bp = Blueprint('templates', __name__, url_prefix='/templates')
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Template CRUD
|
||||
@@ -36,6 +39,8 @@ def create_template():
|
||||
)
|
||||
db.session.add(template)
|
||||
db.session.commit()
|
||||
logger.info('TEMPLATES | create | user=%s | template_id=%s name=%r',
|
||||
current_user.username, template.id, template.name)
|
||||
log_action(ACTION_CREATE, 'Template', template.id, template.name,
|
||||
f'frequency={template.frequency}')
|
||||
|
||||
@@ -73,6 +78,8 @@ def edit_template(template_id):
|
||||
template.description = form.description.data
|
||||
template.frequency = form.frequency.data
|
||||
db.session.commit()
|
||||
logger.info('TEMPLATES | edit | user=%s | template_id=%s name=%r',
|
||||
current_user.username, template.id, template.name)
|
||||
log_action(ACTION_UPDATE, 'Template', template.id, template.name,
|
||||
f'frequency={template.frequency}')
|
||||
flash(f'Template "{template.name}" updated successfully.', 'success')
|
||||
@@ -114,6 +121,8 @@ def rename_template(template_id):
|
||||
template.frequency = new_frequency
|
||||
|
||||
db.session.commit()
|
||||
logger.info('TEMPLATES | rename | user=%s | template_id=%s name=%r',
|
||||
current_user.username, template.id, template.name)
|
||||
log_action(ACTION_UPDATE, 'Template', template.id, template.name,
|
||||
f'frequency={template.frequency}; via=rename')
|
||||
flash(f'Template "{template.name}" updated successfully.', 'success')
|
||||
@@ -136,6 +145,8 @@ def delete_template(template_id):
|
||||
template_id_snap = template.id
|
||||
db.session.delete(template)
|
||||
db.session.commit()
|
||||
logger.info('TEMPLATES | delete | user=%s | template_id=%s name=%r',
|
||||
current_user.username, template_id_snap, template_name)
|
||||
log_action(ACTION_DELETE, 'Template', template_id_snap, template_name)
|
||||
|
||||
flash(f'Template "{template_name}" deleted successfully.', 'success')
|
||||
@@ -178,6 +189,8 @@ def duplicate_template(template_id):
|
||||
new_tpl.form_schema = src.form_schema
|
||||
|
||||
db.session.commit()
|
||||
logger.info('TEMPLATES | duplicate | user=%s | new_template_id=%s source_id=%s',
|
||||
current_user.username, new_tpl.id, src.id)
|
||||
log_action(ACTION_CREATE, 'Template', new_tpl.id, new_tpl.name,
|
||||
f'duplicated_from={src.id}; frequency={new_tpl.frequency}')
|
||||
|
||||
@@ -274,6 +287,8 @@ def save_form_schema(template_id):
|
||||
|
||||
template.form_schema = sanitised
|
||||
db.session.commit()
|
||||
logger.info('TEMPLATES | save_form_schema | user=%s | template_id=%s fields=%s',
|
||||
current_user.username, template.id, len(sanitised))
|
||||
log_action(ACTION_UPDATE, 'Template', template.id, template.name,
|
||||
f'form_schema saved; field_count={len(sanitised)}')
|
||||
|
||||
@@ -323,6 +338,8 @@ def create_checklist_item(template_id):
|
||||
)
|
||||
db.session.add(item)
|
||||
db.session.commit()
|
||||
logger.info('TEMPLATES | create_checklist_item | user=%s | item_id=%s template_id=%s',
|
||||
current_user.username, item.id, template.id)
|
||||
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}')
|
||||
@@ -354,6 +371,8 @@ def edit_checklist_item(item_id):
|
||||
item.weight = form.weight.data
|
||||
item.requires_photo = form.requires_photo.data
|
||||
db.session.commit()
|
||||
logger.info('TEMPLATES | edit_checklist_item | user=%s | item_id=%s template_id=%s',
|
||||
current_user.username, item.id, item.template_id)
|
||||
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}')
|
||||
@@ -381,6 +400,8 @@ def delete_checklist_item(item_id):
|
||||
item_id_snap = item.id
|
||||
db.session.delete(item)
|
||||
db.session.commit()
|
||||
logger.info('TEMPLATES | delete_checklist_item | user=%s | item_id=%s template_id=%s',
|
||||
current_user.username, item_id_snap, template_id)
|
||||
log_action(ACTION_DELETE, 'ChecklistItem', item_id_snap, item_desc,
|
||||
f'template_id={template_id}')
|
||||
flash('Checklist item deleted successfully.', 'success')
|
||||
|
||||
@@ -310,7 +310,7 @@ def notify_customers_for_facility(
|
||||
from app.models.facility import Facility
|
||||
from app.models.user import User
|
||||
|
||||
facility = Facility.query.get(facility_id)
|
||||
facility = db.session.get(Facility, facility_id)
|
||||
if not facility:
|
||||
logger.warning(
|
||||
'notify_customers_for_facility | facility_id=%s not found', facility_id
|
||||
@@ -342,7 +342,7 @@ def notify_customers_for_facility(
|
||||
return
|
||||
|
||||
for user_id in notified_user_ids:
|
||||
user = User.query.get(user_id)
|
||||
user = db.session.get(User, user_id)
|
||||
if not user or not user.active or user.role != 'customer':
|
||||
continue
|
||||
try:
|
||||
@@ -397,7 +397,7 @@ def send_pending_digests(frequency: str = 'daily'):
|
||||
|
||||
sent_count = 0
|
||||
for user_id in pending_user_ids:
|
||||
user = User.query.get(user_id)
|
||||
user = db.session.get(User, user_id)
|
||||
if not user or not user.email:
|
||||
continue
|
||||
|
||||
|
||||
Reference in New Issue
Block a user