fix(pej): use SessionLocal instead of db_session
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions

The codebase uses SessionLocal() with try/finally pattern,
not db_session. Import error broke all blueprint registration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-03-16 18:30:24 +01:00
parent f0358024e8
commit 39965f68ee
3 changed files with 189 additions and 165 deletions

View File

@ -8,7 +8,7 @@ from flask import Response
from flask_login import login_required, current_user from flask_login import login_required, current_user
from . import bp from . import bp
from database import db_session, ZOPKCompanyLink, Company from database import SessionLocal, ZOPKCompanyLink, Company
from blueprints.pej_constants import get_nuclear_project_ids, LINK_TYPE_LABELS from blueprints.pej_constants import get_nuclear_project_ids, LINK_TYPE_LABELS
@ -19,44 +19,48 @@ def pej_export_csv():
if not current_user.can_access_admin_panel(): if not current_user.can_access_admin_panel():
return "Brak uprawnień", 403 return "Brak uprawnień", 403
nuclear_ids = get_nuclear_project_ids() db = SessionLocal()
try:
nuclear_ids = get_nuclear_project_ids(db)
results = db_session.query(ZOPKCompanyLink, Company).join( results = db.query(ZOPKCompanyLink, Company).join(
Company, ZOPKCompanyLink.company_id == Company.id Company, ZOPKCompanyLink.company_id == Company.id
).filter( ).filter(
ZOPKCompanyLink.project_id.in_(nuclear_ids), ZOPKCompanyLink.project_id.in_(nuclear_ids),
ZOPKCompanyLink.relevance_score >= 25, ZOPKCompanyLink.relevance_score >= 25,
Company.status == 'active' Company.status == 'active'
).order_by(ZOPKCompanyLink.relevance_score.desc()).all() ).order_by(ZOPKCompanyLink.relevance_score.desc()).all()
output = io.StringIO() output = io.StringIO()
# UTF-8 BOM for Excel # UTF-8 BOM for Excel
output.write('\ufeff') output.write('\ufeff')
writer = csv.writer(output, delimiter=';', quoting=csv.QUOTE_ALL) writer = csv.writer(output, delimiter=';', quoting=csv.QUOTE_ALL)
writer.writerow([
'Nazwa firmy', 'Email', 'Telefon', 'Branża', 'PKD (główny)',
'Usługi', 'Typ współpracy PEJ', 'Opis współpracy', 'Score', 'Miasto'
])
for link, company in results:
writer.writerow([ writer.writerow([
company.name or '', 'Nazwa firmy', 'Email', 'Telefon', 'Branża', 'PKD (główny)',
company.email or '', 'Usługi', 'Typ współpracy PEJ', 'Opis współpracy', 'Score', 'Miasto'
company.phone or '',
company.category.name if company.category else '',
company.pkd_code or '',
company.services_offered or '',
LINK_TYPE_LABELS.get(link.link_type, link.link_type or ''),
link.collaboration_description or '',
link.relevance_score or 0,
company.address_city or ''
]) ])
filename = f'pej-local-content-{date.today().isoformat()}.csv' for link, company in results:
writer.writerow([
company.name or '',
company.email or '',
company.phone or '',
company.category.name if company.category else '',
company.pkd_code or '',
company.services_offered or '',
LINK_TYPE_LABELS.get(link.link_type, link.link_type or ''),
link.collaboration_description or '',
link.relevance_score or 0,
company.address_city or ''
])
return Response( filename = f'pej-local-content-{date.today().isoformat()}.csv'
output.getvalue(),
mimetype='text/csv; charset=utf-8', return Response(
headers={'Content-Disposition': f'attachment; filename="{filename}"'} output.getvalue(),
) mimetype='text/csv; charset=utf-8',
headers={'Content-Disposition': f'attachment; filename="{filename}"'}
)
finally:
db.close()

View File

@ -1,6 +1,6 @@
"""Shared constants and helpers for PEJ section.""" """Shared constants and helpers for PEJ section."""
from database import db_session, ZOPKProject from database import SessionLocal, ZOPKProject
# Explicit slug list — easy to extend with SMR projects later # Explicit slug list — easy to extend with SMR projects later
NUCLEAR_PROJECT_SLUGS = ['nuclear-plant'] NUCLEAR_PROJECT_SLUGS = ['nuclear-plant']
@ -13,10 +13,18 @@ LINK_TYPE_LABELS = {
} }
def get_nuclear_project_ids(): def get_nuclear_project_ids(db=None):
"""Return IDs of nuclear projects from ZOPK.""" """Return IDs of nuclear projects from ZOPK."""
projects = db_session.query(ZOPKProject.id).filter( close = False
ZOPKProject.slug.in_(NUCLEAR_PROJECT_SLUGS), if db is None:
ZOPKProject.project_type == 'energy' db = SessionLocal()
).all() close = True
return [p.id for p in projects] try:
projects = db.query(ZOPKProject.id).filter(
ZOPKProject.slug.in_(NUCLEAR_PROJECT_SLUGS),
ZOPKProject.project_type == 'energy'
).all()
return [p.id for p in projects]
finally:
if close:
db.close()

View File

@ -8,7 +8,7 @@ from sqlalchemy import func
from . import bp from . import bp
from database import ( from database import (
db_session, ZOPKNews, ZOPKMilestone, SessionLocal, ZOPKNews, ZOPKMilestone,
ZOPKCompanyLink, Company, Announcement, Category ZOPKCompanyLink, Company, Announcement, Category
) )
from blueprints.pej_constants import get_nuclear_project_ids, LINK_TYPE_LABELS from blueprints.pej_constants import get_nuclear_project_ids, LINK_TYPE_LABELS
@ -18,158 +18,170 @@ from blueprints.pej_constants import get_nuclear_project_ids, LINK_TYPE_LABELS
@login_required @login_required
def pej_index(): def pej_index():
"""PEJ landing page — hero, stats, news, timeline, top companies, announcements.""" """PEJ landing page — hero, stats, news, timeline, top companies, announcements."""
nuclear_ids = get_nuclear_project_ids() db = SessionLocal()
if not nuclear_ids: try:
abort(404) nuclear_ids = get_nuclear_project_ids(db)
if not nuclear_ids:
abort(404)
# Stats # Stats
companies_count = db_session.query(func.count(ZOPKCompanyLink.id)).filter( companies_count = db.query(func.count(ZOPKCompanyLink.id)).filter(
ZOPKCompanyLink.project_id.in_(nuclear_ids), ZOPKCompanyLink.project_id.in_(nuclear_ids),
ZOPKCompanyLink.relevance_score >= 25 ZOPKCompanyLink.relevance_score >= 25
).scalar() or 0 ).scalar() or 0
news_count = db_session.query(func.count(ZOPKNews.id)).filter( news_count = db.query(func.count(ZOPKNews.id)).filter(
ZOPKNews.project_id.in_(nuclear_ids), ZOPKNews.project_id.in_(nuclear_ids),
ZOPKNews.status.in_(['approved', 'auto_approved']) ZOPKNews.status.in_(['approved', 'auto_approved'])
).scalar() or 0 ).scalar() or 0
milestones_count = db_session.query(func.count(ZOPKMilestone.id)).filter( milestones_count = db.query(func.count(ZOPKMilestone.id)).filter(
ZOPKMilestone.category == 'nuclear' ZOPKMilestone.category == 'nuclear'
).scalar() or 0 ).scalar() or 0
# Latest news (4) # Latest news (4)
news = db_session.query(ZOPKNews).filter( news = db.query(ZOPKNews).filter(
ZOPKNews.project_id.in_(nuclear_ids), ZOPKNews.project_id.in_(nuclear_ids),
ZOPKNews.status.in_(['approved', 'auto_approved']) ZOPKNews.status.in_(['approved', 'auto_approved'])
).order_by(ZOPKNews.published_at.desc()).limit(4).all() ).order_by(ZOPKNews.published_at.desc()).limit(4).all()
# Nuclear milestones # Nuclear milestones
milestones = db_session.query(ZOPKMilestone).filter( milestones = db.query(ZOPKMilestone).filter(
ZOPKMilestone.category == 'nuclear' ZOPKMilestone.category == 'nuclear'
).order_by(ZOPKMilestone.target_date.asc()).all() ).order_by(ZOPKMilestone.target_date.asc()).all()
# Top 6 companies by relevance # Top 6 companies by relevance
top_companies = db_session.query(ZOPKCompanyLink, Company).join( top_companies = db.query(ZOPKCompanyLink, Company).join(
Company, ZOPKCompanyLink.company_id == Company.id Company, ZOPKCompanyLink.company_id == Company.id
).filter( ).filter(
ZOPKCompanyLink.project_id.in_(nuclear_ids), ZOPKCompanyLink.project_id.in_(nuclear_ids),
ZOPKCompanyLink.relevance_score >= 25, ZOPKCompanyLink.relevance_score >= 25,
Company.status == 'active' Company.status == 'active'
).order_by(ZOPKCompanyLink.relevance_score.desc()).limit(6).all() ).order_by(ZOPKCompanyLink.relevance_score.desc()).limit(6).all()
# PEJ announcements (status='published' in Announcement model) # PEJ announcements (status='published' in Announcement model)
announcements = db_session.query(Announcement).filter( announcements = db.query(Announcement).filter(
Announcement.categories.contains(['pej']), Announcement.categories.contains(['pej']),
Announcement.status == 'published' Announcement.status == 'published'
).order_by(Announcement.created_at.desc()).limit(3).all() ).order_by(Announcement.created_at.desc()).limit(3).all()
return render_template('pej/index.html', return render_template('pej/index.html',
companies_count=companies_count, companies_count=companies_count,
news_count=news_count, news_count=news_count,
milestones_count=milestones_count, milestones_count=milestones_count,
news=news, news=news,
milestones=milestones, milestones=milestones,
top_companies=top_companies, top_companies=top_companies,
announcements=announcements, announcements=announcements,
link_type_labels=LINK_TYPE_LABELS link_type_labels=LINK_TYPE_LABELS
) )
finally:
db.close()
@bp.route('/pej/local-content') @bp.route('/pej/local-content')
@login_required @login_required
def pej_local_content(): def pej_local_content():
"""Full list of Norda companies matched to nuclear projects.""" """Full list of Norda companies matched to nuclear projects."""
nuclear_ids = get_nuclear_project_ids() db = SessionLocal()
if not nuclear_ids: try:
abort(404) nuclear_ids = get_nuclear_project_ids(db)
if not nuclear_ids:
abort(404)
page = request.args.get('page', 1, type=int) page = request.args.get('page', 1, type=int)
per_page = 20 per_page = 20
category_filter = request.args.get('category', 0, type=int) category_filter = request.args.get('category', 0, type=int)
link_type_filter = request.args.get('link_type', '') link_type_filter = request.args.get('link_type', '')
search_query = request.args.get('q', '') search_query = request.args.get('q', '')
query = db_session.query(ZOPKCompanyLink, Company).join( query = db.query(ZOPKCompanyLink, Company).join(
Company, ZOPKCompanyLink.company_id == Company.id Company, ZOPKCompanyLink.company_id == Company.id
).filter( ).filter(
ZOPKCompanyLink.project_id.in_(nuclear_ids), ZOPKCompanyLink.project_id.in_(nuclear_ids),
ZOPKCompanyLink.relevance_score >= 25, ZOPKCompanyLink.relevance_score >= 25,
Company.status == 'active' Company.status == 'active'
) )
if category_filter: if category_filter:
query = query.filter(Company.category_id == category_filter) query = query.filter(Company.category_id == category_filter)
if link_type_filter: if link_type_filter:
query = query.filter(ZOPKCompanyLink.link_type == link_type_filter) query = query.filter(ZOPKCompanyLink.link_type == link_type_filter)
if search_query: if search_query:
query = query.filter(Company.name.ilike(f'%{search_query}%')) query = query.filter(Company.name.ilike(f'%{search_query}%'))
total = query.count() total = query.count()
results = query.order_by( results = query.order_by(
ZOPKCompanyLink.relevance_score.desc() ZOPKCompanyLink.relevance_score.desc()
).offset((page - 1) * per_page).limit(per_page).all() ).offset((page - 1) * per_page).limit(per_page).all()
# Get distinct categories for filter dropdown # Get distinct categories for filter dropdown
category_ids = db_session.query(Company.category_id).join( category_ids = db.query(Company.category_id).join(
ZOPKCompanyLink, Company.id == ZOPKCompanyLink.company_id ZOPKCompanyLink, Company.id == ZOPKCompanyLink.company_id
).filter( ).filter(
ZOPKCompanyLink.project_id.in_(nuclear_ids), ZOPKCompanyLink.project_id.in_(nuclear_ids),
ZOPKCompanyLink.relevance_score >= 25, ZOPKCompanyLink.relevance_score >= 25,
Company.status == 'active', Company.status == 'active',
Company.category_id.isnot(None) Company.category_id.isnot(None)
).distinct().all() ).distinct().all()
category_ids = [c[0] for c in category_ids if c[0]] category_ids = [c[0] for c in category_ids if c[0]]
categories = db_session.query(Category).filter( categories = db.query(Category).filter(
Category.id.in_(category_ids) Category.id.in_(category_ids)
).order_by(Category.name).all() if category_ids else [] ).order_by(Category.name).all() if category_ids else []
link_types = db_session.query(ZOPKCompanyLink.link_type).filter( link_types = db.query(ZOPKCompanyLink.link_type).filter(
ZOPKCompanyLink.project_id.in_(nuclear_ids), ZOPKCompanyLink.project_id.in_(nuclear_ids),
ZOPKCompanyLink.relevance_score >= 25 ZOPKCompanyLink.relevance_score >= 25
).distinct().all() ).distinct().all()
link_types = sorted([lt[0] for lt in link_types if lt[0]]) link_types = sorted([lt[0] for lt in link_types if lt[0]])
total_pages = math.ceil(total / per_page) if total > 0 else 1 total_pages = math.ceil(total / per_page) if total > 0 else 1
return render_template('pej/local_content.html', return render_template('pej/local_content.html',
results=results, results=results,
total=total, total=total,
page=page, page=page,
per_page=per_page, per_page=per_page,
total_pages=total_pages, total_pages=total_pages,
categories=categories, categories=categories,
link_types=link_types, link_types=link_types,
link_type_labels=LINK_TYPE_LABELS, link_type_labels=LINK_TYPE_LABELS,
category_filter=category_filter, category_filter=category_filter,
link_type_filter=link_type_filter, link_type_filter=link_type_filter,
search_query=search_query search_query=search_query
) )
finally:
db.close()
@bp.route('/pej/aktualnosci') @bp.route('/pej/aktualnosci')
@login_required @login_required
def pej_news(): def pej_news():
"""Nuclear news list with pagination.""" """Nuclear news list with pagination."""
nuclear_ids = get_nuclear_project_ids() db = SessionLocal()
if not nuclear_ids: try:
abort(404) nuclear_ids = get_nuclear_project_ids(db)
if not nuclear_ids:
abort(404)
page = request.args.get('page', 1, type=int) page = request.args.get('page', 1, type=int)
per_page = 20 per_page = 20
query = db_session.query(ZOPKNews).filter( query = db.query(ZOPKNews).filter(
ZOPKNews.project_id.in_(nuclear_ids), ZOPKNews.project_id.in_(nuclear_ids),
ZOPKNews.status.in_(['approved', 'auto_approved']) ZOPKNews.status.in_(['approved', 'auto_approved'])
).order_by(ZOPKNews.published_at.desc()) ).order_by(ZOPKNews.published_at.desc())
total = query.count() total = query.count()
news = query.offset((page - 1) * per_page).limit(per_page).all() news = query.offset((page - 1) * per_page).limit(per_page).all()
total_pages = math.ceil(total / per_page) if total > 0 else 1 total_pages = math.ceil(total / per_page) if total > 0 else 1
return render_template('pej/news.html', return render_template('pej/news.html',
news=news, news=news,
page=page, page=page,
total=total, total=total,
total_pages=total_pages total_pages=total_pages
) )
finally:
db.close()