fix: enforce session auth and polish login page
This commit is contained in:
parent
7e347ad5c6
commit
aecc7c5679
30
app/main.py
30
app/main.py
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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 ===== */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 ===== */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue