-
Notifications
You must be signed in to change notification settings - Fork 9
Add project and organization foreign keys to async Job model #578
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| """Add project_id and organization_id to job table | ||
|
|
||
| Revision ID: 043 | ||
| Revises: 042 | ||
| Create Date: 2026-02-04 14:39:00.000000 | ||
|
|
||
| """ | ||
| from alembic import op | ||
| import sqlalchemy as sa | ||
|
|
||
|
|
||
| # revision identifiers, used by Alembic. | ||
| revision = "043" | ||
| down_revision = "042" | ||
| branch_labels = None | ||
| depends_on = None | ||
|
|
||
|
|
||
| def upgrade(): | ||
| # ### commands auto generated by Alembic - please adjust! ### | ||
| # Add organization_id column | ||
| op.add_column( | ||
| "job", | ||
| sa.Column( | ||
| "organization_id", | ||
| sa.Integer(), | ||
| nullable=False, | ||
| comment="Reference to the organization", | ||
| ), | ||
| ) | ||
|
|
||
| # Add project_id column | ||
| op.add_column( | ||
| "job", | ||
| sa.Column( | ||
| "project_id", | ||
| sa.Integer(), | ||
| nullable=False, | ||
| comment="Reference to the project", | ||
| ), | ||
| ) | ||
|
Comment on lines
+22
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: find . -name "043_add_project_org_to_job_table.py" -type fRepository: ProjectTech4DevAI/kaapi-backend Length of output: 141 🏁 Script executed: cat -n ./backend/app/alembic/versions/043_add_project_org_to_job_table.pyRepository: ProjectTech4DevAI/kaapi-backend Length of output: 2822 🏁 Script executed: # Check if there are other migrations or code that shows if job table has existing data
# Search for job table references and existing data loading
rg "job" ./backend/app/alembic/versions --type py -B2 -A2 | head -50Repository: ProjectTech4DevAI/kaapi-backend Length of output: 4884 🏁 Script executed: # Find the Job model definition
find ./backend -name "*.py" -type f | xargs grep -l "class Job" | head -5Repository: ProjectTech4DevAI/kaapi-backend Length of output: 129 🏁 Script executed: cat -n ./backend/app/models/job.pyRepository: ProjectTech4DevAI/kaapi-backend Length of output: 3679 🏁 Script executed: # Check if there are any existing jobs or test data setups
find ./backend -name "*.py" -type f | xargs grep -l "Job(" | head -5Repository: ProjectTech4DevAI/kaapi-backend Length of output: 276 🏁 Script executed: # Check previous migrations to see when job table was created
ls -la ./backend/app/alembic/versions/ | grep -E "^\-.*\.py$" | tail -20Repository: ProjectTech4DevAI/kaapi-backend Length of output: 1878 🏁 Script executed: cat -n ./backend/app/alembic/versions/029_create_job_table.pyRepository: ProjectTech4DevAI/kaapi-backend Length of output: 1698 🏁 Script executed: # Check if there are any jobs created in the codebase or seeded
rg "Job(" ./backend/app/crud/jobs.py -A 3 | head -30Repository: ProjectTech4DevAI/kaapi-backend Length of output: 133 🏁 Script executed: # Check for actual job creation logic to see if jobs are created during normal operation
rg "status.*PENDING\|PROCESSING" ./backend/app/crud/jobs.py | head -20Repository: ProjectTech4DevAI/kaapi-backend Length of output: 57 🏁 Script executed: # Check the jobs CRUD file to see how jobs are created/used
head -100 ./backend/app/crud/jobs.pyRepository: ProjectTech4DevAI/kaapi-backend Length of output: 1415 Backfill organization_id and project_id before enforcing NOT NULL constraints. This migration adds NOT NULL columns to an existing def upgrade():
op.add_column(
"job",
sa.Column("organization_id", sa.Integer(), nullable=True, comment="Reference to the organization"),
)
op.add_column(
"job",
sa.Column("project_id", sa.Integer(), nullable=True, comment="Reference to the project"),
)
# Backfill existing rows here
# op.execute(...)
op.alter_column("job", "organization_id", nullable=False)
op.alter_column("job", "project_id", nullable=False)
# Then add FK constraints and indexesAlso add type hints to 🤖 Prompt for AI Agents |
||
|
|
||
| # Create foreign key constraints | ||
| op.create_foreign_key( | ||
| "fk_job_organization_id", | ||
| "job", | ||
| "organization", | ||
| ["organization_id"], | ||
| ["id"], | ||
| ondelete="CASCADE", | ||
| ) | ||
|
|
||
| op.create_foreign_key( | ||
| "fk_job_project_id", | ||
| "job", | ||
| "project", | ||
| ["project_id"], | ||
| ["id"], | ||
| ondelete="CASCADE", | ||
| ) | ||
|
|
||
| # Create indexes | ||
| op.create_index( | ||
| "ix_job_organization_id", | ||
| "job", | ||
| ["organization_id"], | ||
| unique=False, | ||
| ) | ||
|
|
||
| op.create_index( | ||
| "ix_job_project_id", | ||
| "job", | ||
| ["project_id"], | ||
| unique=False, | ||
| ) | ||
| # ### end Alembic commands ### | ||
|
|
||
|
|
||
| def downgrade(): | ||
| # ### commands auto generated by Alembic - please adjust! ### | ||
| # Drop indexes | ||
| op.drop_index("ix_job_project_id", table_name="job") | ||
| op.drop_index("ix_job_organization_id", table_name="job") | ||
|
|
||
| # Drop foreign key constraints | ||
| op.drop_constraint("fk_job_project_id", "job", type_="foreignkey") | ||
| op.drop_constraint("fk_job_organization_id", "job", type_="foreignkey") | ||
|
|
||
| # Drop columns | ||
| op.drop_column("job", "project_id") | ||
| op.drop_column("job", "organization_id") | ||
| # ### end Alembic commands ### | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,7 +20,7 @@ class PrivateUserCreate(BaseModel): | |
| is_verified: bool = False | ||
|
|
||
|
|
||
| @router.post("/users/", response_model=UserPublic, include_in_schema=False) | ||
| @router.post("/users", response_model=UserPublic, include_in_schema=False) | ||
| def create_user(user_in: PrivateUserCreate, session: SessionDep) -> Any: | ||
|
Comment on lines
+23
to
24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check for remaining trailing slashes in route definitions across the codebase
rg -n '@router\.(get|post|put|patch|delete)\("[^"]+/"' backend/app/api/routes/Repository: ProjectTech4DevAI/kaapi-backend Length of output: 57 🏁 Script executed: # Also check the specific file mentioned to see the current state
cat -n backend/app/api/routes/private.py | head -40Repository: ProjectTech4DevAI/kaapi-backend Length of output: 1141 🏁 Script executed: # Check utils.py for the /test-email/ route mentioned in the comment
rg -n 'test-email' backend/app/api/routes/Repository: ProjectTech4DevAI/kaapi-backend Length of output: 129 🏁 Script executed: # Get context around the /test-email/ line in utils.py
rg -B 2 -A 2 'test-email' backend/app/api/routes/utils.pyRepository: ProjectTech4DevAI/kaapi-backend Length of output: 200 🏁 Script executed: # Check all routes in utils.py to see their structure
cat -n backend/app/api/routes/utils.pyRepository: ProjectTech4DevAI/kaapi-backend Length of output: 1149 🏁 Script executed: # Check for /reset-password route mentioned in the review comment
rg -n 'reset-password' backend/app/api/routes/Repository: ProjectTech4DevAI/kaapi-backend Length of output: 166 🏁 Script executed: # Get a comprehensive list of all routes to verify the standardization claim
rg -n '@router\.(get|post|put|patch|delete)\(' backend/app/api/routes/ -A 1Repository: ProjectTech4DevAI/kaapi-backend Length of output: 11662 Fix return type annotation: use The route path standardization ( 🤖 Prompt for AI Agents |
||
| """ | ||
| Create a new user. | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,54 @@ | ||||||||||||
| """Validation utilities for document uploads.""" | ||||||||||||
|
|
||||||||||||
| import logging | ||||||||||||
| from pathlib import Path | ||||||||||||
|
|
||||||||||||
| from fastapi import HTTPException, UploadFile | ||||||||||||
|
|
||||||||||||
| from app.core.config import settings | ||||||||||||
|
|
||||||||||||
| logger = logging.getLogger(__name__) | ||||||||||||
|
|
||||||||||||
| # Maximum file size for document uploads (in bytes) | ||||||||||||
| # Default: 50 MB, configurable via settings | ||||||||||||
| MAX_DOCUMENT_SIZE = settings.MAX_DOCUMENT_UPLOAD_SIZE_MB * 1024 * 1024 | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| async def validate_document_file(file: UploadFile) -> int: | ||||||||||||
| """ | ||||||||||||
| Validate document file size. | ||||||||||||
|
|
||||||||||||
| Args: | ||||||||||||
| file: The uploaded file | ||||||||||||
|
|
||||||||||||
| Returns: | ||||||||||||
| File size in bytes if valid | ||||||||||||
|
|
||||||||||||
| Raises: | ||||||||||||
| HTTPException: If validation fails | ||||||||||||
| """ | ||||||||||||
| if not file.filename: | ||||||||||||
| raise HTTPException( | ||||||||||||
| status_code=422, | ||||||||||||
| detail="File must have a filename", | ||||||||||||
| ) | ||||||||||||
|
|
||||||||||||
| # Get file size by seeking to end | ||||||||||||
| file.file.seek(0, 2) | ||||||||||||
| file_size = file.file.tell() | ||||||||||||
| file.file.seek(0) | ||||||||||||
|
|
||||||||||||
| if file_size > MAX_DOCUMENT_SIZE: | ||||||||||||
| raise HTTPException( | ||||||||||||
| status_code=413, | ||||||||||||
| detail=f"File too large. Maximum size: {MAX_DOCUMENT_SIZE / (1024 * 1024):.0f}MB", | ||||||||||||
| ) | ||||||||||||
|
|
||||||||||||
| if file_size == 0: | ||||||||||||
| raise HTTPException( | ||||||||||||
| status_code=422, | ||||||||||||
| detail="Empty file uploaded" | ||||||||||||
| ) | ||||||||||||
|
|
||||||||||||
| logger.info(f"Document file validated: {file.filename} ({file_size} bytes)") | ||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefix and mask the validation log message. The info log should include the function prefix and mask the filename before logging. 🛠️ Suggested fix- logger.info(f"Document file validated: {file.filename} ({file_size} bytes)")
+ logger.info(
+ f"[validate_document_file] Document file validated: "
+ f"{mask_string(file.filename)} ({file_size} bytes)"
+ )As per coding guidelines: Prefix all log messages with the function name in square brackets: 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||
| return file_size | ||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add explicit return types to Alembic hooks.
upgradeanddowngradeshould explicitly returnNone.🛠️ Suggested fix
As per coding guidelines: **/*.py: Always add type hints to all function parameters and return values in Python code
Also applies to: 79-79
🤖 Prompt for AI Agents