From 3db39eac71039a5037c5a0ed59edaf8a7ef9ac3c Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Thu, 24 Jul 2025 23:13:01 -0300 Subject: [PATCH 1/4] Fix to add a photo list to the constructor of the entry model --- src/pilgrim/models/entry.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pilgrim/models/entry.py b/src/pilgrim/models/entry.py index 7835067..6dac3e4 100644 --- a/src/pilgrim/models/entry.py +++ b/src/pilgrim/models/entry.py @@ -1,5 +1,6 @@ -from typing import Any +from typing import Any, List +from pilgrim.models.photo import Photo from pilgrim.models.photo_in_entry import photo_entry_association from sqlalchemy import Column, Integer, String, ForeignKey, DateTime from sqlalchemy.orm import relationship @@ -21,9 +22,12 @@ class Entry(Base): fk_travel_diary_id = Column(Integer, ForeignKey("travel_diaries.id"), nullable=False) travel_diary = relationship("TravelDiary", back_populates="entries") - def __init__(self, title: str, text: str, date: str, travel_diary_id: int, **kw: Any): + def __init__(self, title: str, text: str, date: Any, travel_diary_id: int, photos: List[Photo] = None, **kw: Any): super().__init__(**kw) self.title = title self.text = text self.date = date self.fk_travel_diary_id = travel_diary_id + if photos: + self.photos = photos + From 8d45b4361edb797aa627a5ffbc95ebde3f17cd2f Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Miranda Date: Thu, 24 Jul 2025 23:18:34 -0300 Subject: [PATCH 2/4] Update src/pilgrim/models/entry.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/pilgrim/models/entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pilgrim/models/entry.py b/src/pilgrim/models/entry.py index 6dac3e4..7ae7abd 100644 --- a/src/pilgrim/models/entry.py +++ b/src/pilgrim/models/entry.py @@ -28,6 +28,6 @@ class Entry(Base): self.text = text self.date = date self.fk_travel_diary_id = travel_diary_id - if photos: + if photos is not None: self.photos = photos From 819a2c7b6b1c266508d5f222d4b1e6c48a35814c Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Thu, 24 Jul 2025 23:36:02 -0300 Subject: [PATCH 3/4] Add the tests for the new methods of deleting --- tests/conftest.py | 25 ++++++++++++++++- tests/service/test_entry_service.py | 43 +++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 59d0e26..bb57cca 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,10 @@ +from datetime import datetime + import pytest from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker +from pilgrim.models.entry import Entry from pilgrim.database import Base from pilgrim.models.travel_diary import TravelDiary from pilgrim.models.photo import Photo @@ -61,4 +64,24 @@ def session_with_photos(session_with_one_diary): session.add_all([photo1, photo2]) session.commit() - return session, [photo1, photo2] \ No newline at end of file + return session, [photo1, photo2] + +@pytest.fixture +def entry_with_photo_references(session_with_one_diary): + session, diary = session_with_one_diary + photo1 = Photo(filepath="p1.jpg", name="P1", photo_hash="aaaaaaaa", fk_travel_diary_id=diary.id) + photo2 = Photo(filepath="p2.jpg", name="P2", photo_hash="bbbbbbbb", fk_travel_diary_id=diary.id) + session.add_all([photo1, photo2]) + session.flush() + entry = Entry( + title="Entrada com Fotos", + text="Texto com a foto A [[photo::aaaaaaaa]] e também a foto B [[photo::bbbbbbbb]].", + date=datetime.now(), + travel_diary_id=diary.id, + photos=[photo1, photo2] + ) + session.add(entry) + session.commit() + session.refresh(entry) + + return session, entry diff --git a/tests/service/test_entry_service.py b/tests/service/test_entry_service.py index cdad48f..5cab040 100644 --- a/tests/service/test_entry_service.py +++ b/tests/service/test_entry_service.py @@ -261,3 +261,46 @@ def test_delete_returns_none_if_entry_does_not_exist(db_session): non_existent_entry.id = 999 result = service.delete(non_existent_entry) assert result is None + +def test_delete_references_for_specific_photo(entry_with_photo_references): + session, entry = entry_with_photo_references + service = EntryService(session) + updated_entry = service.delete_references_for_specific_photo(entry, "aaaaaaaa") + assert "[[photo::aaaaaaaa]]" not in updated_entry.text + assert "[[photo::bbbbbbbb]]" in updated_entry.text + +def test_delete_specific_photo_reference_does_nothing_if_no_match(entry_with_photo_references): + session, entry = entry_with_photo_references + service = EntryService(session) + + original_text = entry.text + updated_entry = service.delete_references_for_specific_photo(entry, "cccccccc") + assert updated_entry.text == original_text + +def test_delete_all_photo_references_removes_all_refs(entry_with_photo_references): + session, entry = entry_with_photo_references + service = EntryService(session) + updated_entry = service.delete_all_photo_references(entry) + assert "[[photo::aaaaaaaa]]" not in updated_entry.text + assert "[[photo::bbbbbbbb]]" not in updated_entry.text + +def test_delete_all_photo_references_uses_truncated_hash(session_with_one_diary): + session, diary = session_with_one_diary + service = EntryService(session) + long_hash_photo = Photo( + filepath="long.jpg", name="Long", + photo_hash="1234567890abcdef", # Hash com 16 caracteres + fk_travel_diary_id=diary.id + ) + entry = Entry( + title="Teste de Hash Curto", + text="Referência com hash truncado [[photo::12345678]].", # Texto usa só os 8 primeiros + date=datetime.now(), + travel_diary_id=diary.id + ) + entry.photos.append(long_hash_photo) + session.add_all([long_hash_photo, entry]) + session.commit() + updated_entry = service.delete_all_photo_references(entry) + expected_text = "Referência com hash truncado ." + assert "[[photo::12345678]]" not in updated_entry.text From 3d926993e8f124ba572f8b5b01baa1b34283d1c4 Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Fri, 25 Jul 2025 00:13:08 -0300 Subject: [PATCH 4/4] Add the tests for the new methods of deleting --- tests/conftest.py | 17 ++++++++-- tests/service/test_travel_diary_service.py | 39 ++++++++++++++++++++-- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index bb57cca..91dff2a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,12 +1,12 @@ -from datetime import datetime - import pytest from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker +from datetime import datetime from pilgrim.models.entry import Entry from pilgrim.database import Base from pilgrim.models.travel_diary import TravelDiary +from pilgrim.models.entry import Entry from pilgrim.models.photo import Photo # Todos os imports necessários para as fixtures devem estar aqui @@ -85,3 +85,16 @@ def entry_with_photo_references(session_with_one_diary): session.refresh(entry) return session, entry + + +@pytest.fixture +def session_with_multiple_entries(session_with_one_diary): + session, diary = session_with_one_diary + session.query(Entry).delete() + entry1 = Entry(title="Entrada 1", text="Texto 1", date=datetime.now(), travel_diary_id=diary.id) + entry2 = Entry(title="Entrada 2", text="Texto 2", date=datetime.now(), travel_diary_id=diary.id) + + session.add_all([entry1, entry2]) + session.commit() + + return session, diary \ No newline at end of file diff --git a/tests/service/test_travel_diary_service.py b/tests/service/test_travel_diary_service.py index efab0f9..9a1e890 100644 --- a/tests/service/test_travel_diary_service.py +++ b/tests/service/test_travel_diary_service.py @@ -1,9 +1,12 @@ -from unittest.mock import patch, MagicMock from pathlib import Path +from unittest.mock import patch, MagicMock + import pytest -from pilgrim import TravelDiary +from pilgrim.models.photo import Photo +from pilgrim.models.travel_diary import TravelDiary +from pilgrim.models.entry import Entry from pilgrim.service.travel_diary_service import TravelDiaryService @patch.object(TravelDiaryService, '_ensure_diary_directory') @@ -140,4 +143,34 @@ def test_sanitize_directory_name_handles_uniqueness(db_session): db_session.commit() third_sanitized_name = service._sanitize_directory_name("Viagem para a Praia") - assert third_sanitized_name == "viagem_para_a_praia_2" \ No newline at end of file + assert third_sanitized_name == "viagem_para_a_praia_2" + +def test_delete_all_entries_successfully(session_with_multiple_entries): + session, diary = session_with_multiple_entries + service = TravelDiaryService(session) + diary_id = 1 + assert session.query(Entry).filter_by(fk_travel_diary_id=diary_id).count() == 2 + result = service.delete_all_entries(diary) + assert result is True + assert session.query(Entry).filter_by(fk_travel_diary_id=diary_id).count() == 0 + +@patch.object(TravelDiaryService, '_ensure_diary_directory') +@patch('pathlib.Path.unlink') +@patch('pathlib.Path.exists', return_value=True) +@patch('pilgrim.utils.DirectoryManager.get_diaries_root', return_value=Path("/fake/diaries_root")) +def test_delete_all_photos_orchestration( + mock_ensure_dir, mock_unlink, mock_exists, mock_get_root, entry_with_photo_references +): + session, entry = entry_with_photo_references + diary_id = entry.fk_travel_diary_id + service = TravelDiaryService(session) + assert session.query(Photo).filter_by(fk_travel_diary_id=diary_id).count() == 2 + assert "[[photo::" in entry.text + diary = session.get(TravelDiary, diary_id) + result = service.delete_all_photos(diary) + assert result is True + photos_after_delete = session.query(Photo).filter_by(fk_travel_diary_id=diary_id).all() + assert len(photos_after_delete) == 0 + session.refresh(entry) + assert "[[photo::" not in entry.text + assert mock_unlink.call_count == 2