From a9f0b32eea6c93c635c5f9f353f6a1c408834ec1 Mon Sep 17 00:00:00 2001 From: "ahmed.mujtaba" Date: Mon, 3 Aug 2026 19:55:01 +0500 Subject: [PATCH] pdf product converted --- backend/alembic_setup.py | 1 + backend/db_setup.py | 8 + backend/inbox/decoded_attachments/Farman.pdf | Bin 0 -> 132136 bytes backend/inbox/file_decoder.py | 15 +- backend/inbox/models.py | 154 +++++++++++------- backend/migrations/script.py.mako | 1 + ...-817ded7e4f55_initial_roles_users_inbox.py | 104 ++++++++++++ ...ea9c09868aff_remove_message_attachments.py | 32 ++++ backend/role/models.py | 36 ++-- backend/users/app.py | 4 +- backend/users/models.py | 39 ++--- 11 files changed, 282 insertions(+), 112 deletions(-) create mode 100644 backend/inbox/decoded_attachments/Farman.pdf create mode 100644 backend/migrations/versions/20260803_1416-817ded7e4f55_initial_roles_users_inbox.py create mode 100644 backend/migrations/versions/20260803_1452-ea9c09868aff_remove_message_attachments.py diff --git a/backend/alembic_setup.py b/backend/alembic_setup.py index f2ea2cf..fd4c52c 100644 --- a/backend/alembic_setup.py +++ b/backend/alembic_setup.py @@ -103,6 +103,7 @@ from typing import Sequence, Union from alembic import op import sqlalchemy as sa +import sqlmodel # SQLModel renders AutoString() into migrations but adds no import ${imports if imports else ""} revision: str = ${repr(up_revision)} diff --git a/backend/db_setup.py b/backend/db_setup.py index 2b79826..5ce0337 100644 --- a/backend/db_setup.py +++ b/backend/db_setup.py @@ -31,6 +31,7 @@ from sqlalchemy.ext.asyncio import ( create_async_engine, ) from sqlalchemy.orm import DeclarativeBase +from sqlmodel import SQLModel from dotenv import load_dotenv load_dotenv() @@ -124,6 +125,13 @@ class Base(DeclarativeBase): ) +# SQLModel keeps its own registry, so `SQLModel` tables would be invisible to the +# Alembic autogenerate in alembic_setup.py, which diffs `Base.metadata` alone. +# Pointing SQLModel at the same MetaData gives both styles one registry, and lets +# SQLModel tables inherit the naming convention and the default schema above. +SQLModel.metadata = Base.metadata + + _engine: AsyncEngine | None = None _sessionmaker: async_sessionmaker[AsyncSession] | None = None diff --git a/backend/inbox/decoded_attachments/Farman.pdf b/backend/inbox/decoded_attachments/Farman.pdf new file mode 100644 index 0000000000000000000000000000000000000000..839269d21cbd576f37495e4d6863c1a4f52414ea GIT binary patch literal 132136 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 WQ2Vux%euYw2;|aq#cr2Qx%dFy|1`}2 literal 0 HcmV?d00001 diff --git a/backend/inbox/file_decoder.py b/backend/inbox/file_decoder.py index b642b98..39f1c84 100644 --- a/backend/inbox/file_decoder.py +++ b/backend/inbox/file_decoder.py @@ -19,25 +19,22 @@ _DEFAULT_OUT_DIR = Path(__file__).resolve().parent / "decoded_attachments" def _decode_bytes(attachment: dict) -> bytes: - """base64 -> raw bytes, with an integrity check against declared size.""" + """base64 -> raw bytes. + + Graph's ``size`` often includes MIME/encoding overhead and may not equal + ``len(contentBytes)`` after decode, so it is not treated as a hard check. + """ b64 = attachment.get("contentBytes") if not b64: raise AttachmentDecodeError(f"{attachment.get('name')!r}: no contentBytes") try: - raw = base64.b64decode(b64, validate=True) + return base64.b64decode(b64, validate=True) except binascii.Error as exc: raise AttachmentDecodeError( f"{attachment.get('name')!r}: bad base64: {exc}" ) from exc - declared = attachment.get("size") - if declared is not None and len(raw) != declared: - raise AttachmentDecodeError( - f"{attachment.get('name')!r}: declared {declared} B, decoded {len(raw)} B" - ) - return raw - def _write(out_dir: Path, name: str, raw: bytes) -> Path: out_dir = Path(out_dir) diff --git a/backend/inbox/models.py b/backend/inbox/models.py index 85ab894..09b583a 100644 --- a/backend/inbox/models.py +++ b/backend/inbox/models.py @@ -1,73 +1,103 @@ -from sqlalchemy import Column, Integer, String, ForeignKey, DateTime, Boolean, UUID -from sqlalchemy.dialects.postgresql import JSONB -from sqlalchemy.orm import relationship -from sqlmodel import SQLModel -from datetime import datetime -from users.models import Users -from sqlalchemy.ext.asyncio import AsyncSession import uuid +from datetime import datetime +from typing import Any, Optional -class Inbox(SQLModel,table=True): - id=Column(Integer,primary_key=True,autoincrement=True) - user_id = Column(UUID,ForeignKey("users.id")) +from sqlalchemy import Column +from sqlalchemy.dialects.postgresql import JSONB +from sqlalchemy.ext.asyncio import AsyncSession +from sqlmodel import Field, Relationship, SQLModel - alert_id=Column(UUID,ForeignKey("inbox_alerts.id")) - - alerts=relationship("Inbox_Alerts",back_populates="inbox",foreign_keys=[alert_id]) - - message_id=Column(UUID,ForeignKey("inbox_messages.id")) - - messages=relationship("Inbox_Messages",back_populates="inbox",foreign_keys=[message_id]) - - created_at=Column(DateTime,default=datetime.now) - updated_at=Column(DateTime,default=datetime.now) - # is_active=Column(Boolean,default=True) - # is_deleted=Column(Boolean,default=False) - # user=relationship("Users",back_populates="inbox",foreign_keys=[user_id]) +from users.models import Users -class Inbox_Alerts(SQLModel,table=True): - id=Column(UUID,primary_key=True,default=uuid.uuid4) - alert_sender_name=Column(String,nullable=False) - alert_sender_email=Column(String,nullable=False) - is_read=Column(Boolean,default=False) - recieve_time=Column(DateTime,default=datetime.now) -class Inbox_Messages(SQLModel,table=True): - id=Column(UUID,primary_key=True,default=uuid.uuid4) - full_email_response=Column(JSONB,nullable=True) - message_subject=Column(String,nullable=False) - message_body=Column(String,nullable=False) - message_sent_time=Column(String,nullable=False) - # message_status=Column(String,nullable=False) - message_received_time=Column(String,nullable=False) - message_from=Column(String,nullable=False) - message_to=Column(String,nullable=False) - message_cc=Column(String,nullable=True) - message_bcc=Column(String,nullable=True) - message_attachments=Column(JSONB,nullable=True) - message_read=Column(Boolean,default=False) - attachment=Column(Boolean,default=False) - message_reply=Column(String,nullable=True) - file_path=Column(String,nullable=True) +class Inbox(SQLModel, table=True): + __tablename__ = "inbox" + + id: int | None = Field(default=None, primary_key=True) + user_id: uuid.UUID | None = Field(default=None, foreign_key="users.id") + + alert_id: uuid.UUID | None = Field(default=None, foreign_key="inbox_alerts.id") + alerts: Optional["Inbox_Alerts"] = Relationship(back_populates="inbox") + + message_id: uuid.UUID | None = Field(default=None, foreign_key="inbox_messages.id") + messages: Optional["Inbox_Messages"] = Relationship(back_populates="inbox") + + created_at: datetime = Field(default_factory=datetime.now) + updated_at: datetime = Field(default_factory=datetime.now) + # is_active: bool = Field(default=True) + # is_deleted: bool = Field(default=False) + # user: Users | None = Relationship(back_populates="inbox") + + +class Inbox_Alerts(SQLModel, table=True): + __tablename__ = "inbox_alerts" + + id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) + alert_sender_name: str + alert_sender_email: str + is_read: bool = Field(default=False) + recieve_time: datetime = Field(default_factory=datetime.now) + + inbox: list[Inbox] = Relationship(back_populates="alerts") + + +class Inbox_Messages(SQLModel, table=True): + __tablename__ = "inbox_messages" + + id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) + full_email_response: dict[str, Any] | None = Field( + default=None, sa_column=Column(JSONB) + ) + message_subject: str + message_body: str + message_sent_time: str + message_received_time: str + message_from: str + message_to: str + message_cc: str | None = Field(default=None) + message_bcc: str | None = Field(default=None) + message_read: bool = Field(default=False) + attachment: bool = Field(default=False) + message_reply: str | None = Field(default=None) + file_path: str | None = Field(default=None) + + inbox: list[Inbox] = Relationship(back_populates="messages") + + @staticmethod + def _body_text(email_data: dict) -> str: + body = email_data.get("body") + if isinstance(body, dict): + return body.get("content") or "" + if isinstance(body, str): + return body + return email_data.get("bodyPreview") or "" @classmethod - async def insert_email(cls,session:AsyncSession,email_data:dict): - email=cls( - message_subject=email_data.get("subject"), - message_body=email_data.get("body"), - # message_type=email_data.get("type"), - message_sent_time=email_data.get("sentDateTime"), - message_read=email_data.get("isRead"), - message_received_time=email_data.get("receivedDateTime"), - message_from=email_data.get("from").get("emailAddress").get("address"), - message_to=",".join([r["emailAddress"]["address"] for r in email_data.get("toRecipients", [])]), - message_cc=",".join([r["emailAddress"]["address"] for r in email_data.get("ccRecipients", [])]), - message_bcc=",".join([r["emailAddress"]["address"] for r in email_data.get("bccRecipients", [])]), - message_attachments=email_data.get("attachments"), - attachment=email_data.get("hasAttachments"), - message_reply=",".join([r["emailAddress"]["address"] for r in email_data.get("replyTo", [])]), + async def insert_email(cls, session: AsyncSession, email_data: dict): + email = cls( + message_subject=email_data.get("subject") or "", + message_body=cls._body_text(email_data), + message_sent_time=email_data.get("sentDateTime") or "", + message_read=bool(email_data.get("isRead")), + message_received_time=email_data.get("receivedDateTime") or "", + message_from=email_data.get("from", {}) + .get("emailAddress", {}) + .get("address", ""), + message_to=",".join( + [r["emailAddress"]["address"] for r in email_data.get("toRecipients", [])] + ), + message_cc=",".join( + [r["emailAddress"]["address"] for r in email_data.get("ccRecipients", [])] + ), + message_bcc=",".join( + [r["emailAddress"]["address"] for r in email_data.get("bccRecipients", [])] + ), + attachment=bool(email_data.get("hasAttachments")), + message_reply=",".join( + [r["emailAddress"]["address"] for r in email_data.get("replyTo", [])] + ), full_email_response=email_data, ) session.add(email) await session.commit() - return email \ No newline at end of file + return email diff --git a/backend/migrations/script.py.mako b/backend/migrations/script.py.mako index e2c743f..76f46f7 100644 --- a/backend/migrations/script.py.mako +++ b/backend/migrations/script.py.mako @@ -11,6 +11,7 @@ from typing import Sequence, Union from alembic import op import sqlalchemy as sa +import sqlmodel # SQLModel renders AutoString() into migrations but adds no import ${imports if imports else ""} revision: str = ${repr(up_revision)} diff --git a/backend/migrations/versions/20260803_1416-817ded7e4f55_initial_roles_users_inbox.py b/backend/migrations/versions/20260803_1416-817ded7e4f55_initial_roles_users_inbox.py new file mode 100644 index 0000000..696e860 --- /dev/null +++ b/backend/migrations/versions/20260803_1416-817ded7e4f55_initial_roles_users_inbox.py @@ -0,0 +1,104 @@ +"""initial roles users inbox + +Revision ID: 817ded7e4f55 +Revises: +Create Date: 2026-08-03 14:16:25.739300+00:00 +""" + +from __future__ import annotations + +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +import sqlmodel +from sqlalchemy.dialects import postgresql + +revision: str = '817ded7e4f55' +down_revision: Union[str, None] = None +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('inbox_alerts', + sa.Column('id', sa.Uuid(), nullable=False), + sa.Column('alert_sender_name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column('alert_sender_email', sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column('is_read', sa.Boolean(), nullable=False), + sa.Column('recieve_time', sa.DateTime(), nullable=False), + sa.PrimaryKeyConstraint('id', name=op.f('pk_inbox_alerts')), + schema='app' + ) + op.create_table('inbox_messages', + sa.Column('id', sa.Uuid(), nullable=False), + sa.Column('full_email_response', postgresql.JSONB(astext_type=sa.Text()), nullable=True), + sa.Column('message_subject', sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column('message_body', sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column('message_sent_time', sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column('message_received_time', sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column('message_from', sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column('message_to', sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column('message_cc', sqlmodel.sql.sqltypes.AutoString(), nullable=True), + sa.Column('message_bcc', sqlmodel.sql.sqltypes.AutoString(), nullable=True), + sa.Column('message_attachments', postgresql.JSONB(astext_type=sa.Text()), nullable=True), + sa.Column('message_read', sa.Boolean(), nullable=False), + sa.Column('attachment', sa.Boolean(), nullable=False), + sa.Column('message_reply', sqlmodel.sql.sqltypes.AutoString(), nullable=True), + sa.Column('file_path', sqlmodel.sql.sqltypes.AutoString(), nullable=True), + sa.PrimaryKeyConstraint('id', name=op.f('pk_inbox_messages')), + schema='app' + ) + op.create_table('roles', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('role_name', sa.Enum('SYSTEM_ADMINISTRATOR', 'HR_ADMINISTRATOR', 'RECRUITER', 'HIRING_MANAGER', 'DEPARTMENT_HEAD', 'INTERVIEWER', 'CEO', 'CANDIDATE', name='enumroles'), nullable=False), + sa.Column('description', sqlmodel.sql.sqltypes.AutoString(), nullable=True), + sa.Column('permissions', postgresql.JSONB(astext_type=sa.Text()), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=False), + sa.Column('updated_at', sa.DateTime(), nullable=False), + sa.Column('is_active', sa.Boolean(), nullable=False), + sa.Column('is_deleted', sa.Boolean(), nullable=False), + sa.PrimaryKeyConstraint('id', name=op.f('pk_roles')), + sa.UniqueConstraint('role_name', name=op.f('uq_roles_role_name')), + schema='app' + ) + op.create_table('users', + sa.Column('id', sa.Uuid(), nullable=False), + sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column('email', sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column('role_id', sa.Integer(), nullable=True), + sa.Column('password', sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=False), + sa.Column('updated_at', sa.DateTime(), nullable=False), + sa.Column('is_active', sa.Boolean(), nullable=False), + sa.Column('is_deleted', sa.Boolean(), nullable=False), + sa.ForeignKeyConstraint(['role_id'], ['app.roles.id'], name=op.f('fk_users_role_id_roles')), + sa.PrimaryKeyConstraint('id', name=op.f('pk_users')), + sa.UniqueConstraint('email', name=op.f('uq_users_email')), + schema='app' + ) + op.create_table('inbox', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('user_id', sa.Uuid(), nullable=True), + sa.Column('alert_id', sa.Uuid(), nullable=True), + sa.Column('message_id', sa.Uuid(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=False), + sa.Column('updated_at', sa.DateTime(), nullable=False), + sa.ForeignKeyConstraint(['alert_id'], ['app.inbox_alerts.id'], name=op.f('fk_inbox_alert_id_inbox_alerts')), + sa.ForeignKeyConstraint(['message_id'], ['app.inbox_messages.id'], name=op.f('fk_inbox_message_id_inbox_messages')), + sa.ForeignKeyConstraint(['user_id'], ['app.users.id'], name=op.f('fk_inbox_user_id_users')), + sa.PrimaryKeyConstraint('id', name=op.f('pk_inbox')), + schema='app' + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('inbox', schema='app') + op.drop_table('users', schema='app') + op.drop_table('roles', schema='app') + op.drop_table('inbox_messages', schema='app') + op.drop_table('inbox_alerts', schema='app') + # ### end Alembic commands ### diff --git a/backend/migrations/versions/20260803_1452-ea9c09868aff_remove_message_attachments.py b/backend/migrations/versions/20260803_1452-ea9c09868aff_remove_message_attachments.py new file mode 100644 index 0000000..534fa38 --- /dev/null +++ b/backend/migrations/versions/20260803_1452-ea9c09868aff_remove_message_attachments.py @@ -0,0 +1,32 @@ +"""remove_message_attachments + +Revision ID: ea9c09868aff +Revises: 817ded7e4f55 +Create Date: 2026-08-03 14:52:42.420029+00:00 +""" + +from __future__ import annotations + +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +import sqlmodel # SQLModel renders AutoString() into migrations but adds no import +from sqlalchemy.dialects import postgresql + +revision: str = 'ea9c09868aff' +down_revision: Union[str, None] = '817ded7e4f55' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('inbox_messages', 'message_attachments', schema='app') + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('inbox_messages', sa.Column('message_attachments', postgresql.JSONB(astext_type=sa.Text()), autoincrement=False, nullable=True), schema='app') + # ### end Alembic commands ### diff --git a/backend/role/models.py b/backend/role/models.py index 337cc3d..bad6c01 100644 --- a/backend/role/models.py +++ b/backend/role/models.py @@ -1,12 +1,13 @@ -from sqlalchemy import Column, Integer, String, DateTime, Boolean, Enum as SAEnum -from sqlalchemy.dialects.postgresql import JSONB -from sqlalchemy.orm import relationship -from sqlmodel import SQLModel from datetime import datetime from enum import Enum +from typing import Any + +from sqlalchemy import Column, Enum as SAEnum +from sqlalchemy.dialects.postgresql import JSONB +from sqlmodel import Field, Relationship, SQLModel -class EnumRoles(Enum): +class EnumRoles(str, Enum): SYSTEM_ADMINISTRATOR = "system_administrator" HR_ADMINISTRATOR = "hr_administrator" RECRUITER = "recruiter" @@ -17,14 +18,19 @@ class EnumRoles(Enum): CANDIDATE = "candidate" -class Roles(SQLModel,table=True): +class Roles(SQLModel, table=True): __tablename__ = "roles" - id = Column(Integer, primary_key=True,autoincrement=True) - role_name = Column(SAEnum(EnumRoles),nullable=False,unique=True,default=EnumRoles.SYSTEM_ADMINISTRATOR) - description = Column(String,nullable=True,default="System Administrator") - permissions = Column(JSONB,nullable=True) - created_at = Column(DateTime,default=datetime.now) - updated_at = Column(DateTime,default=datetime.now) - is_active = Column(Boolean,default=True) - is_deleted = Column(Boolean,default=False) - users = relationship("Users", back_populates="role") \ No newline at end of file + + id: int | None = Field(default=None, primary_key=True) + role_name: EnumRoles = Field( + default=EnumRoles.SYSTEM_ADMINISTRATOR, + sa_column=Column(SAEnum(EnumRoles), nullable=False, unique=True), + ) + description: str | None = Field(default="System Administrator") + permissions: dict[str, Any] | None = Field(default=None, sa_column=Column(JSONB)) + created_at: datetime = Field(default_factory=datetime.now) + updated_at: datetime = Field(default_factory=datetime.now) + is_active: bool = Field(default=True) + is_deleted: bool = Field(default=False) + + users: list["Users"] = Relationship(back_populates="role") diff --git a/backend/users/app.py b/backend/users/app.py index b7813c2..aafb0ce 100644 --- a/backend/users/app.py +++ b/backend/users/app.py @@ -3,12 +3,12 @@ from fastapi.responses import JSONResponse from fastapi import HTTPException from db_setup import get_session from sqlalchemy.ext.asyncio import AsyncSession -from inbox.views import Email +from users.models import Users from dotenv import load_dotenv load_dotenv() router = APIRouter() @router.post("/users/create") -async def create_user(user: User, session: AsyncSession = Depends(get_session)): +async def create_user(user: Users, session: AsyncSession = Depends(get_session)): pass \ No newline at end of file diff --git a/backend/users/models.py b/backend/users/models.py index 5ac610a..b201aeb 100644 --- a/backend/users/models.py +++ b/backend/users/models.py @@ -1,30 +1,21 @@ -from sqlalchemy import Column, Integer, String, ForeignKey, DateTime, Boolean, UUID -from sqlalchemy.orm import relationship import uuid from datetime import datetime -from sqlmodel import SQLModel + +from sqlmodel import Field, Relationship, SQLModel + from role.models import Roles -class Users(SQLModel,table=True): + +class Users(SQLModel, table=True): __tablename__ = "users" - id = Column(UUID, primary_key=True,default=uuid.uuid4) - name = Column(String,nullable=False) - email = Column(String,nullable=False,unique=True) - role_id = Column(Integer,ForeignKey("roles.id")) - role = relationship("Roles",back_populates="users",foreign_keys=[role_id]) - password = Column(String,nullable=False) - created_at = Column(DateTime,default=datetime.now) - updated_at = Column(DateTime,default=datetime.now) - is_active = Column(Boolean,default=True) - is_deleted = Column(Boolean,default=False) - - # role = Column(String,nullable=False) - # company_id = Column(UUID,ForeignKey("companies.id")) - # company = relationship("Companies",back_populates="users") - # created_by = Column(UUID,ForeignKey("users.id")) - # created_by_user = relationship("Users",back_populates="users") - # updated_by = Column(UUID,ForeignKey("users.id")) - # updated_by_user = relationship("Users",back_populates="users") - # deleted_by = Column(UUID,ForeignKey("users.id")) - # deleted_by_user = relationship("Users",back_populates="users") \ No newline at end of file + id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) + name: str + email: str = Field(unique=True) + role_id: int | None = Field(default=None, foreign_key="roles.id") + role: Roles | None = Relationship(back_populates="users") + password: str + created_at: datetime = Field(default_factory=datetime.now) + updated_at: datetime = Field(default_factory=datetime.now) + is_active: bool = Field(default=True) + is_deleted: bool = Field(default=False)