diff --git a/alembic/versions/20240604_1215_8ec02f1af257_add_proof_source_field.py b/alembic/versions/20240604_1215_8ec02f1af257_add_proof_source_field.py new file mode 100644 index 00000000..9680ba67 --- /dev/null +++ b/alembic/versions/20240604_1215_8ec02f1af257_add_proof_source_field.py @@ -0,0 +1,30 @@ +"""Add Proof source field + +Revision ID: 8ec02f1af257 +Revises: 8a6892a20b5d +Create Date: 2024-06-04 12:15:04.418674 + +""" +from typing import Sequence, Union + +import sqlalchemy as sa + +from alembic import op + +# revision identifiers, used by Alembic. +revision: str = "8ec02f1af257" +down_revision: Union[str, None] = "8a6892a20b5d" +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.add_column("proofs", sa.Column("source", sa.String(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("proofs", "source") + # ### end Alembic commands ### diff --git a/app/crud.py b/app/crud.py index e8210479..9a29bf3a 100644 --- a/app/crud.py +++ b/app/crud.py @@ -383,7 +383,7 @@ def create_proof( mimetype: str, type: ProofTypeEnum, user: UserCreate, - price_count: int = 0, + source: str = None, ) -> Proof: """Create a proof in the database. @@ -398,7 +398,7 @@ def create_proof( mimetype=mimetype, type=type, owner=user.user_id, - price_count=price_count, + source=source, ) db.add(db_proof) db.commit() diff --git a/app/models.py b/app/models.py index 38995f40..5d4666cc 100644 --- a/app/models.py +++ b/app/models.py @@ -126,6 +126,8 @@ class Proof(Base): owner = mapped_column(String, index=True) + source = mapped_column(String, nullable=True) + created = mapped_column( DateTime(timezone=True), server_default=func.now(), index=True ) diff --git a/app/routers/proofs.py b/app/routers/proofs.py index a2165bfd..0f0fc42a 100644 --- a/app/routers/proofs.py +++ b/app/routers/proofs.py @@ -40,6 +40,7 @@ def upload_proof( file: UploadFile, type: Annotated[ProofTypeEnum, Form(description="The type of the proof")], current_user: schemas.UserCreate = Depends(get_current_user), + app_name: str | None = None, db: Session = Depends(get_db), ) -> Proof: """ @@ -51,7 +52,9 @@ def upload_proof( This endpoint requires authentication. """ file_path, mimetype = crud.create_proof_file(file) - db_proof = crud.create_proof(db, file_path, mimetype, type=type, user=current_user) + db_proof = crud.create_proof( + db, file_path, mimetype, type=type, user=current_user, source=app_name + ) return db_proof diff --git a/app/schemas.py b/app/schemas.py index a9e8deb2..52a9fec3 100644 --- a/app/schemas.py +++ b/app/schemas.py @@ -182,10 +182,15 @@ class ProofFull(BaseModel): file_path: str | None mimetype: str type: ProofTypeEnum | None = None - owner: str price_count: int = Field( description="number of prices for this proof.", examples=[15], default=0 ) + owner: str + # source: str | None = Field( + # description="Source (App name)", + # examples=["web app", "mobile app"], + # default=None, + # ) created: datetime.datetime diff --git a/tests/integration/test_api.py b/tests/integration/test_api.py index 1e618680..a98c12e0 100644 --- a/tests/integration/test_api.py +++ b/tests/integration/test_api.py @@ -818,7 +818,7 @@ def test_delete_price_moderator( # Test proofs # ------------------------------------------------------------------------------ -def test_create_proof(user_session: SessionModel, clean_proofs): +def test_create_proof(db_session, user_session: SessionModel, clean_proofs): # This test depends on the previous test_create_price # without authentication response = client.post( @@ -854,6 +854,7 @@ def test_create_proof(user_session: SessionModel, clean_proofs): headers={"Authorization": f"Bearer {user_session.token}"}, ) assert response.status_code == 201 + assert len(crud.get_proofs(db_session)) == 1 response = client.post( "/api/v1/proofs/upload", @@ -862,9 +863,24 @@ def test_create_proof(user_session: SessionModel, clean_proofs): headers={"Authorization": f"Bearer {user_session.token}"}, ) assert response.status_code == 201 + assert len(crud.get_proofs(db_session)) == 1 + 1 + # with app_name + response = client.post( + "/api/v1/proofs/upload?app_name=test", + files={"file": ("filename", (io.BytesIO(b"test")), "image/webp")}, + data={"type": "RECEIPT"}, + headers={"Authorization": f"Bearer {user_session.token}"}, + ) + assert response.status_code == 201 + assert len(crud.get_proofs(db_session)) == 2 + 1 + assert crud.get_proofs(db_session)[-1][0].source == "test" + + +def test_get_proofs(db_session, user_session: SessionModel, clean_proofs): + crud.create_proof(db_session, "/", "test.webp", "PRICE_TAG", user_session.user) + crud.create_proof(db_session, "/", "test.webp", "RECEIPT", user_session.user) -def test_get_proofs(user_session: SessionModel): # without authentication response = client.get("/api/v1/proofs") assert response.status_code == 401 @@ -895,8 +911,8 @@ def test_get_proofs(user_session: SessionModel): for i, item in enumerate(data): assert isinstance(item["id"], int) - assert item["file_path"].startswith("0001/") - assert item["file_path"].endswith(".webp") + # assert item["file_path"].startswith("0001/") + # assert item["file_path"].endswith(".webp") assert item["type"] == ("PRICE_TAG" if i == 0 else "RECEIPT") assert item["owner"] == "user" assert item["price_count"] == 0