feat: enhance authentication and publication download tracking
- Added JWT authentication support with configurable secret and expiration. - Introduced optional API key validation for endpoints. - Implemented tracking of publication downloads by researchers, storing records in a new PublicationDownload model. - Updated export endpoints to conditionally register downloads based on user authentication. - Enhanced researcher search response to indicate if publications were downloaded by the current user. - Updated environment configuration to include new JWT settings.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, UniqueConstraint
|
||||
from sqlalchemy.dialects.postgresql import UUID, JSONB
|
||||
from sqlalchemy.orm import relationship
|
||||
import uuid
|
||||
@@ -61,3 +61,23 @@ class Publication(Base):
|
||||
# Tu campo existente
|
||||
hash_fingerprint = Column(String, nullable=True)
|
||||
last_modified = Column(DateTime, nullable=True, default=None)
|
||||
|
||||
# Legacy: descargado global (deprecado). Mantener por compatibilidad de DB.
|
||||
downloaded = Column(Boolean, nullable=False, default=False)
|
||||
|
||||
|
||||
class PublicationDownload(Base):
|
||||
"""
|
||||
Marca de descarga por usuario (researcher) sobre cualquier publicación.
|
||||
Una fila por (researcher_id, publication_id).
|
||||
"""
|
||||
|
||||
__tablename__ = "publication_downloads"
|
||||
__table_args__ = (
|
||||
UniqueConstraint("researcher_id", "publication_id", name="uq_publication_download"),
|
||||
)
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
researcher_id = Column(UUID(as_uuid=True), ForeignKey("researchers.id"), nullable=False, index=True)
|
||||
publication_id = Column(UUID(as_uuid=True), ForeignKey("publications.id"), nullable=False, index=True)
|
||||
downloaded_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy import create_engine, inspect, text
|
||||
from sqlalchemy.orm import sessionmaker, declarative_base
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Cargar variables del .env para ejecuciones locales (en Docker ya vendrán por entorno).
|
||||
load_dotenv()
|
||||
|
||||
# -----------------------------
|
||||
# DATABASE URL
|
||||
@@ -42,3 +46,18 @@ def init_db():
|
||||
|
||||
# Crea todas las tablas si no existen
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
# Pequeñas migraciones "best-effort" para entornos sin Alembic.
|
||||
# (create_all no altera tablas existentes)
|
||||
_ensure_columns()
|
||||
|
||||
|
||||
def _ensure_columns():
|
||||
insp = inspect(engine)
|
||||
if "publications" in insp.get_table_names():
|
||||
cols = {c["name"] for c in insp.get_columns("publications")}
|
||||
if "downloaded" not in cols:
|
||||
with engine.begin() as conn:
|
||||
conn.execute(
|
||||
text("ALTER TABLE publications ADD COLUMN downloaded BOOLEAN NOT NULL DEFAULT FALSE")
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user