瀏覽代碼

add comment to Benevole and template

clovis 1 年之前
父節點
當前提交
bbd6b68712

+ 30 - 0
alembic/versions/2024081845_implmement_comment_at_benevole_and__f058df5a266c.py

@@ -0,0 +1,30 @@
+"""implmement comment at benevole and template
+
+Revision ID: f058df5a266c
+Revises: 8fee990845df
+Create Date: 2024-08-18 17:45:45.047712
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = 'f058df5a266c'
+down_revision = '8fee990845df'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.add_column('slot_templates', sa.Column('comment', sa.String(), nullable=False))
+    op.add_column('volunteers', sa.Column('comment', sa.String(), nullable=False))
+    # ### end Alembic commands ###
+
+
+def downgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.drop_column('volunteers', 'comment')
+    op.drop_column('slot_templates', 'comment')
+    # ### end Alembic commands ###

+ 4 - 9
app/api/endpoints/templates.py

@@ -81,15 +81,7 @@ async def update_template(
     if (template is None) or (template.project_id != str(project_id)):
         raise HTTPException(status_code=404, detail="Template not found")
 
-    if payload.title is not None:
-        template.title = payload.title
-    if payload.description is not None:
-        template.description = payload.description
-    if payload.responsible_contact is not None:
-        template.responsible_contact = payload.responsible_contact
-    if payload.place is not None:
-        template.place = payload.place
-
+    input_dict = payload.model_dump(exclude_unset=True)
     if payload.tags is not None:
         # Remove previous keys in association table
         session.execute(
@@ -106,6 +98,9 @@ async def update_template(
                     [(template.id, t_id) for t_id in payload.tags]
                 )
             )
+        del input_dict["tags"]
+
+    update_object_from_payload(template, input_dict)
 
     session.commit()
     session.refresh(template)

+ 3 - 0
app/models.py

@@ -109,6 +109,7 @@ class Volunteer(Base):
     slots: Mapped[list["Slot"]] = relationship(
         secondary=association_table_volunteer_slot, back_populates="volunteers"
     )
+    comment: Mapped[str] = mapped_column(String(), default="")
 
     @hybrid_property
     def slots_id(self) -> list[str]:
@@ -215,6 +216,8 @@ class SlotTemplate(Base):
         secondary=association_table_template_tags, back_populates="templates"
     )
 
+    comment: Mapped[str] = mapped_column(String(), default="")
+
     @hybrid_property
     def slots_id(self) -> list[str]:
         return [s.id for s in self.slots]

+ 4 - 0
app/schemas/requests.py

@@ -79,6 +79,7 @@ class VolunteerCreateRequest(BaseRequest):
     phone_number: str
     automatic_sms: bool = Field(default=True)
     slots: Optional[list[UUID4]] = None
+    comment: Optional[str] = None
 
 
 class VolunteerUpdateRequest(BaseRequest):
@@ -88,6 +89,7 @@ class VolunteerUpdateRequest(BaseRequest):
     phone_number: Optional[str] = None
     automatic_sms: Optional[bool] = None
     slots: Optional[list[UUID4]] = None
+    comment: Optional[str] = None
 
 
 class SlotCreateRequest(BaseRequest):
@@ -114,6 +116,7 @@ class TemplateCreateRequest(BaseRequest):
     place: Optional[str] = None
     responsible_contact: Optional[str] = None
     tags: Optional[list[UUID4]] = None
+    comment: Optional[str] = None
 
 
 class TemplateUpdateRequest(BaseRequest):
@@ -123,6 +126,7 @@ class TemplateUpdateRequest(BaseRequest):
     responsible_contact: Optional[str] = None
     # slots: Optional[list[UUID4]] = None
     tags: Optional[list[UUID4]] = None
+    comment: Optional[str] = None
 
 
 class TagCreateRequest(BaseRequest):

+ 2 - 0
app/schemas/responses.py

@@ -36,6 +36,7 @@ class VolunteerResponse(BaseObjectResponse):
     phone_number: str
     automatic_sms: bool
     slots_id: list[str] = []
+    comment: str
 
 
 class SlotResponse(BaseObjectResponse):
@@ -61,6 +62,7 @@ class TemplateResponse(BaseObjectResponse):
     place: str
     responsible_contact: str
     tags_id: list[str] = []
+    comment: str
 
 
 class TagResponse(BaseObjectResponse):

+ 4 - 1
app/tests/test_template.py

@@ -36,6 +36,7 @@ async def test_create_template_fail(
         {"title": "1st template", "responsible_contact": "echo"},
         {"title": "1st template", "description": "&é'(-è_çecho"},
         {"title": "1st template", "place": "3", "description": "&é'(-è_çecho"},
+        {"title": "1st template", "comment": "55"},
     ],
 )
 async def test_create_template(
@@ -97,6 +98,7 @@ async def test_update_template_fail(
         (422, {"tags": ["1", "2"]}),
         # (422, {"slots": "1"}),
         (400, {"tags": [default_slot_id]}),
+        (422, {"comment": 1235}),
     ],
 )
 async def test_update_template_fail_payload_validation(
@@ -129,6 +131,7 @@ async def test_update_template_fail_payload_validation(
             "description": "&é'(-è_çecho",
         },
         {"title": "1st template", "place": "3", "description": "&é'(-è_çecho"},
+        {"title": "1st template", "comment": "&é'(-è_çecho"},
     ],
 )
 async def test_update_template(
@@ -147,7 +150,7 @@ async def test_update_template(
     assert response.status_code == 200
     template = session.get(SlotTemplate, default_template_id)
     assert template is not None
-    for k in ["title", "description", "place", "responsible_contact"]:
+    for k in ["title", "description", "place", "responsible_contact", "comment"]:
         val = template.__getattribute__(k)
         if k in payload:
             assert val == payload[k]

+ 33 - 1
app/tests/test_volunteer.py

@@ -76,6 +76,7 @@ async def test_create_volunteer(
     assert response.status_code == 200
     assert response.json()["id"] != default_project_id
     assert response.json()["name"] == "Lancelot"
+    assert response.json()["comment"] == ""
     result = session.execute(
         select(Volunteer).where(Volunteer.project_id == default_project_id)
     )
@@ -92,6 +93,35 @@ async def test_create_volunteer(
     assert response.status_code == 422
 
 
+async def test_create_volunteer_comment(
+    client: AsyncClient,
+    default_public_project: Project,
+    default_user_headers: dict,
+    session: Session,
+):
+    payload = {
+        "name": "Lancelot",
+        "email": "lancelot@dulac.fr",
+        "phone_number": "03 14 15 92 65",
+        "comment": "it's a knight",
+    }
+    # Test normal payload
+    response = await client.post(
+        app.url_path_for("create_volunteer", project_id=default_project_id),
+        json=payload,
+        headers=default_user_headers,
+    )
+    assert response.status_code == 200
+    assert response.json()["id"] != default_project_id
+    assert response.json()["name"] == "Lancelot"
+    assert response.json()["comment"] != ""
+    new_id = response.json()["id"]
+    result = session.execute(select(Volunteer).where(Volunteer.id == new_id))
+    volunteer = result.scalar_one_or_none()
+    assert volunteer is not None
+    assert volunteer.comment == "it's a knight"
+
+
 async def test_update_volunteer(
     client: AsyncClient,
     default_public_project: Project,
@@ -113,6 +143,7 @@ async def test_update_volunteer(
         "email": "lancelot@dulac.fr",
         "phone_number": "03 14 15 92 65",
         "automatic_sms": False,
+        "comment": "new comment",
     }
 
     # test invalid project_id
@@ -259,7 +290,8 @@ async def test_delete_volunteer(
 
     # check deletion is cascaded to slots
     result = session.execute(select(Slot).where(Slot.id == default_slot_id))
-    slot: Slot | None = result.scalars().first()
+    slot: Slot | None = result.scalar_one_or_none()
+    assert slot is not None
     assert default_volunteer_id not in slot.volunteers_id
 
     # Idempotence test