Commit ·
9e57130
1
Parent(s): dbfc012
fix: layout refinements + update deps
Browse files- Section labels: zero top-margin on first-child in section-block
- Bullets: remove duplicate disc via list-style:none!important, remove inline bullet char in school_profile
- Page numbers: light-blue (#1C75BC) footer color
- Remove 'Summary info' heading from university templates
- Bump all dependency floors to current stable versions
- Dockerfile base image python:3.11-slim -> 3.12-slim
- Dockerfile +1 -1
- app/core/database.py +48 -0
- app/services/pdf_renderer.py +1 -1
- app/static/css/print.css +5 -1
- app/templates/partials/blocks/school_profile.html +1 -2
- app/templates/partials/university.html +0 -1
- requirements.txt +10 -10
Dockerfile
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
FROM python:3.
|
| 2 |
|
| 3 |
# Playwright/Chromium system dependencies
|
| 4 |
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
|
|
| 1 |
+
FROM python:3.12-slim
|
| 2 |
|
| 3 |
# Playwright/Chromium system dependencies
|
| 4 |
RUN apt-get update && apt-get install -y --no-install-recommends \
|
app/core/database.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Database engine and session factory (SQLAlchemy).
|
| 2 |
+
|
| 3 |
+
Engine is created lazily to avoid crash on startup when no DB is available
|
| 4 |
+
(e.g. Hugging Face Spaces without MySQL).
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import logging
|
| 8 |
+
from sqlalchemy import create_engine
|
| 9 |
+
from sqlalchemy.orm import sessionmaker, DeclarativeBase
|
| 10 |
+
|
| 11 |
+
from app.core.config import get_settings
|
| 12 |
+
|
| 13 |
+
logger = logging.getLogger(__name__)
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class Base(DeclarativeBase):
|
| 17 |
+
pass
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
_engine = None
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def _get_engine():
|
| 24 |
+
global _engine
|
| 25 |
+
if _engine is None:
|
| 26 |
+
_settings = get_settings()
|
| 27 |
+
try:
|
| 28 |
+
_engine = create_engine(
|
| 29 |
+
_settings.database_url,
|
| 30 |
+
pool_pre_ping=True,
|
| 31 |
+
pool_recycle=3600,
|
| 32 |
+
echo=_settings.debug,
|
| 33 |
+
)
|
| 34 |
+
except Exception as exc:
|
| 35 |
+
logger.warning("Database engine creation failed: %s", exc)
|
| 36 |
+
raise
|
| 37 |
+
return _engine
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def get_db():
|
| 41 |
+
"""FastAPI dependency: yields a DB session, closes on exit."""
|
| 42 |
+
engine = _get_engine()
|
| 43 |
+
Session = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
| 44 |
+
db = Session()
|
| 45 |
+
try:
|
| 46 |
+
yield db
|
| 47 |
+
finally:
|
| 48 |
+
db.close()
|
app/services/pdf_renderer.py
CHANGED
|
@@ -168,7 +168,7 @@ async def render_pdf_from_html(
|
|
| 168 |
header_template='<span></span>',
|
| 169 |
footer_template=(
|
| 170 |
'<div style="width:100%;text-align:center;font-size:10px;'
|
| 171 |
-
'font-family:Century Gothic,Segoe UI,sans-serif;color:#
|
| 172 |
'padding:0 0 4px 0;">'
|
| 173 |
'<span class="pageNumber"></span></div>'
|
| 174 |
),
|
|
|
|
| 168 |
header_template='<span></span>',
|
| 169 |
footer_template=(
|
| 170 |
'<div style="width:100%;text-align:center;font-size:10px;'
|
| 171 |
+
'font-family:Century Gothic,Segoe UI,sans-serif;color:#1C75BC;'
|
| 172 |
'padding:0 0 4px 0;">'
|
| 173 |
'<span class="pageNumber"></span></div>'
|
| 174 |
),
|
app/static/css/print.css
CHANGED
|
@@ -182,7 +182,7 @@ a:visited {
|
|
| 182 |
.hb-bullet-list,
|
| 183 |
.ul,
|
| 184 |
ul.hb-bullet-list {
|
| 185 |
-
list-style: none;
|
| 186 |
margin: 0 0 8pt 16pt;
|
| 187 |
padding: 0;
|
| 188 |
font-size: 10pt;
|
|
@@ -640,6 +640,10 @@ table.programs td:nth-child(5) {
|
|
| 640 |
border: none;
|
| 641 |
}
|
| 642 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 643 |
.summary-section {
|
| 644 |
display: block;
|
| 645 |
}
|
|
|
|
| 182 |
.hb-bullet-list,
|
| 183 |
.ul,
|
| 184 |
ul.hb-bullet-list {
|
| 185 |
+
list-style: none !important;
|
| 186 |
margin: 0 0 8pt 16pt;
|
| 187 |
padding: 0;
|
| 188 |
font-size: 10pt;
|
|
|
|
| 640 |
border: none;
|
| 641 |
}
|
| 642 |
|
| 643 |
+
.section-block> :first-child {
|
| 644 |
+
margin-top: 0;
|
| 645 |
+
}
|
| 646 |
+
|
| 647 |
.summary-section {
|
| 648 |
display: block;
|
| 649 |
}
|
app/templates/partials/blocks/school_profile.html
CHANGED
|
@@ -18,7 +18,6 @@
|
|
| 18 |
<tr>
|
| 19 |
<td class="hb-school-top-summary">
|
| 20 |
{% if block.data.overview %}
|
| 21 |
-
<div class="hb-summary-title">Summary info</div>
|
| 22 |
<ul class="hb-summary-ul">
|
| 23 |
{% if block.data.overview.founded %}<li><span class="hb-lbl">Founded:</span> {{
|
| 24 |
block.data.overview.founded | e }}</li>{% endif %}
|
|
@@ -70,7 +69,7 @@
|
|
| 70 |
<ul class="hb-benefits-ul">
|
| 71 |
{% for b in block.data.benefits %}
|
| 72 |
{% if b %}
|
| 73 |
-
<li class="hb-benefit-item">
|
| 74 |
{% endif %}
|
| 75 |
{% endfor %}
|
| 76 |
</ul>
|
|
|
|
| 18 |
<tr>
|
| 19 |
<td class="hb-school-top-summary">
|
| 20 |
{% if block.data.overview %}
|
|
|
|
| 21 |
<ul class="hb-summary-ul">
|
| 22 |
{% if block.data.overview.founded %}<li><span class="hb-lbl">Founded:</span> {{
|
| 23 |
block.data.overview.founded | e }}</li>{% endif %}
|
|
|
|
| 69 |
<ul class="hb-benefits-ul">
|
| 70 |
{% for b in block.data.benefits %}
|
| 71 |
{% if b %}
|
| 72 |
+
<li class="hb-benefit-item"><span class="hb-benefit-text">{{ b | e }}</span></li>
|
| 73 |
{% endif %}
|
| 74 |
{% endfor %}
|
| 75 |
</ul>
|
app/templates/partials/university.html
CHANGED
|
@@ -18,7 +18,6 @@
|
|
| 18 |
<tr>
|
| 19 |
<td class="school-top-summary">
|
| 20 |
{% if uni.overview %}
|
| 21 |
-
<div class="summary-title">Summary info</div>
|
| 22 |
<ul class="summary-ul">
|
| 23 |
{% if uni.overview.founded %}<li><span class="lbl">Founded:</span> {{ uni.overview.founded | e }}
|
| 24 |
</li>{% endif %}
|
|
|
|
| 18 |
<tr>
|
| 19 |
<td class="school-top-summary">
|
| 20 |
{% if uni.overview %}
|
|
|
|
| 21 |
<ul class="summary-ul">
|
| 22 |
{% if uni.overview.founded %}<li><span class="lbl">Founded:</span> {{ uni.overview.founded | e }}
|
| 23 |
</li>{% endif %}
|
requirements.txt
CHANGED
|
@@ -1,10 +1,10 @@
|
|
| 1 |
-
fastapi>=0.
|
| 2 |
-
uvicorn[standard]>=0.
|
| 3 |
-
pydantic>=2.
|
| 4 |
-
pydantic-settings>=2.
|
| 5 |
-
httpx>=0.
|
| 6 |
-
jinja2>=3.1.
|
| 7 |
-
markupsafe>=
|
| 8 |
-
playwright>=1.
|
| 9 |
-
pypdf>=
|
| 10 |
-
python-dotenv>=1.0.
|
|
|
|
| 1 |
+
fastapi>=0.135.0
|
| 2 |
+
uvicorn[standard]>=0.34.0
|
| 3 |
+
pydantic>=2.10.0
|
| 4 |
+
pydantic-settings>=2.7.0
|
| 5 |
+
httpx>=0.28.0
|
| 6 |
+
jinja2>=3.1.4
|
| 7 |
+
markupsafe>=3.0.0
|
| 8 |
+
playwright>=1.50.0
|
| 9 |
+
pypdf>=5.0.0
|
| 10 |
+
python-dotenv>=1.0.1
|