fix: enforce session auth and polish login page

This commit is contained in:
Sean McElwain 2026-04-26 21:35:15 -05:00
parent 7e347ad5c6
commit aecc7c5679
4 changed files with 283 additions and 9 deletions

View File

@ -2,6 +2,7 @@ from pathlib import Path
from decimal import Decimal from decimal import Decimal
from fastapi import FastAPI, Request from fastapi import FastAPI, Request
from fastapi.responses import RedirectResponse
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from sqlalchemy import create_engine, func from sqlalchemy import create_engine, func
@ -199,6 +200,29 @@ from starlette.middleware.sessions import SessionMiddleware
from app.routes.auth import router as auth_router from app.routes.auth import router as auth_router
@app.middleware("http")
async def auth_session_guard(request, call_next):
session = request.scope.get("session", {}) or {}
current_user = session.get("current_user")
request.state.current_user = current_user
path = request.url.path
allowed_prefixes = (
"/login",
"/logout",
"/static",
"/health",
)
if path == "/favicon.ico" or any(path.startswith(prefix) for prefix in allowed_prefixes):
return await call_next(request)
if not current_user:
login_url = f"/login?next={path}"
return RedirectResponse(url=login_url, status_code=303)
return await call_next(request)
app.add_middleware( app.add_middleware(
SessionMiddleware, SessionMiddleware,
secret_key="document-processor-change-this-secret", secret_key="document-processor-change-this-secret",
@ -208,10 +232,4 @@ app.add_middleware(
) )
@app.middleware("http")
async def load_current_user(request, call_next):
session = request.scope.get("session", {}) or {}
request.state.current_user = session.get("current_user")
return await call_next(request)
app.include_router(auth_router) app.include_router(auth_router)

View File

@ -948,3 +948,24 @@ body { background: var(--shell-bg); }
} }
} }
/* ===== end mobile spacing pass ===== */ /* ===== end mobile spacing pass ===== */
/* ===== desktop app width fill ===== */
@media (min-width: 901px) {
.main {
padding-right: 0.6rem !important;
}
.main-content {
max-width: none !important;
width: calc(100vw - 4.8rem) !important;
margin-right: 0 !important;
padding-right: 0.6rem !important;
}
.app-shell.nav-open .main-content {
width: calc(100vw - 14.6rem) !important;
}
}
/* ===== end desktop app width fill ===== */

View File

@ -5460,3 +5460,238 @@ table {
} }
} }
/* ===== end dashboard mobile polish ===== */ /* ===== end dashboard mobile polish ===== */
/* ===== desktop detail top card layout v2 ===== */
@media (min-width: 901px) {
.detail-doc-actions-row {
display: block !important;
margin-bottom: 0.3rem !important;
}
.detail-doc-actions-grid {
display: grid !important;
grid-template-columns: minmax(20rem, 24rem) auto auto !important;
align-items: end !important;
column-gap: 0.45rem !important;
row-gap: 0.18rem !important;
width: 100% !important;
}
.detail-doc-type-form {
display: grid !important;
grid-template-columns: minmax(16rem, 1fr) auto !important;
align-items: end !important;
gap: 0.45rem !important;
margin: 0 !important;
min-width: 0 !important;
}
.detail-type-input-wrap {
min-width: 0 !important;
}
.detail-type-input-wrap input {
width: 100% !important;
max-width: none !important;
}
.detail-update-button {
margin: 0 !important;
align-self: end !important;
justify-self: start !important;
}
.detail-flags-stack {
display: flex !important;
flex-direction: column !important;
justify-content: center !important;
gap: 0.12rem !important;
margin: 0 !important;
align-self: center !important;
}
.detail-check-inline {
display: inline-flex !important;
align-items: center !important;
gap: 0.25rem !important;
white-space: nowrap !important;
line-height: 1.05 !important;
margin: 0 !important;
}
.detail-review-flags-form {
margin: 0 !important;
align-self: center !important;
}
.detail-saveflags-button {
margin: 0 !important;
}
.detail-save-pdf-form {
display: block !important;
margin: 0 !important;
}
.detail-path-row {
display: grid !important;
grid-template-columns: minmax(0, 1fr) auto !important;
align-items: end !important;
gap: 0.45rem !important;
width: 100% !important;
}
.detail-path-row > div:first-child {
min-width: 0 !important;
}
.detail-save-pdf-form input[name="output_path"] {
width: 100% !important;
min-width: 0 !important;
}
.queue-nav-row {
display: flex !important;
flex-wrap: wrap !important;
align-items: center !important;
gap: 0.35rem !important;
margin-top: 0.35rem !important;
}
.queue-nav-row > * {
margin: 0 !important;
}
.detail-trash-inline,
.detail-trash-form {
order: 3 !important;
}
.detail-save-document-button {
order: 4 !important;
margin-left: auto !important;
}
/* right pane title rows should match mobile polish on desktop too */
.ocr-review-header-row,
.extracted-fields-header-row,
.line-items-header-row {
display: grid !important;
grid-template-columns: minmax(0, 1fr) auto !important;
align-items: center !important;
column-gap: 0.45rem !important;
}
}
/* ===== end desktop detail top card layout v2 ===== */
/* ===== polished login page ===== */
.login-page-shell {
max-width: 34rem;
margin: 3.5rem auto;
padding: 1.25rem 1rem;
}
.login-card {
padding: 1.1rem !important;
border-radius: 1.1rem !important;
}
.login-card .page-title {
margin: 0 0 0.18rem 0 !important;
}
.login-card .page-subtitle {
margin: 0 0 0.75rem 0 !important;
color: #6b7280 !important;
}
.login-card .form-grid {
gap: 0.72rem !important;
}
.login-card .form-field label {
font-size: 0.82rem !important;
margin-bottom: 0.2rem !important;
color: #6b7280 !important;
}
.login-card input[type="text"],
.login-card input[type="password"] {
min-height: 2.5rem !important;
height: 2.5rem !important;
padding: 0 0.8rem !important;
border-radius: 0.85rem !important;
font-size: 0.98rem !important;
}
.login-button-row {
margin-top: 0.85rem !important;
}
.login-button-row button,
.login-button-row .button-link {
min-height: 2.35rem !important;
height: 2.35rem !important;
padding: 0 0.95rem !important;
border-radius: 999px !important;
}
@media (max-width: 900px) {
.login-page-shell {
max-width: none;
margin: 2.25rem auto;
padding: 0.8rem 0.7rem;
}
.login-card {
padding: 0.85rem !important;
border-radius: 1rem !important;
}
.login-card .page-title {
font-size: 1rem !important;
line-height: 1.08 !important;
margin-bottom: 0.12rem !important;
}
.login-card .page-subtitle {
font-size: 0.72rem !important;
line-height: 1.15 !important;
margin-bottom: 0.55rem !important;
}
.login-card .form-grid {
gap: 0.5rem !important;
}
.login-card .form-field label {
font-size: 0.72rem !important;
line-height: 1.1 !important;
margin-bottom: 0.14rem !important;
}
.login-card input[type="text"],
.login-card input[type="password"] {
min-height: 2.1rem !important;
height: 2.1rem !important;
padding: 0 0.65rem !important;
border-radius: 0.8rem !important;
font-size: 0.88rem !important;
}
.login-button-row {
margin-top: 0.6rem !important;
}
.login-button-row button,
.login-button-row .button-link {
min-height: 1.95rem !important;
height: 1.95rem !important;
padding: 0 0.75rem !important;
font-size: 0.8rem !important;
}
}
/* ===== end polished login page ===== */

View File

@ -7,8 +7,8 @@
<link rel="stylesheet" href="/static/app-shell.css?v=21"> <link rel="stylesheet" href="/static/app-shell.css?v=21">
</head> </head>
<body> <body>
<main class="main" style="max-width:520px; margin:3rem auto; padding:2rem 1rem;"> <main class="main login-page-shell">
<div class="card"> <div class="card login-card">
<h1 class="page-title">Login</h1> <h1 class="page-title">Login</h1>
<p class="page-subtitle">Sign in to Document Processor.</p> <p class="page-subtitle">Sign in to Document Processor.</p>
@ -28,7 +28,7 @@
</div> </div>
</div> </div>
<div class="button-row" style="margin-top:1rem;"> <div class="button-row login-button-row">
<button class="primary" type="submit">Login</button> <button class="primary" type="submit">Login</button>
</div> </div>
</form> </form>