Compare commits

...

2 Commits

Author SHA1 Message Date
Gustavo Henrique Santos Souza de Miranda 394f813f6f Added few checks to the reference to avoid malformed or invalid reference from being saved. 2025-07-05 07:26:47 -03:00
Gustavo Henrique Santos Souza de Miranda a9756b058e Changed some texts to be in english and also removed some debug messages. 2025-07-05 06:48:24 -03:00
1 changed files with 90 additions and 28 deletions

View File

@ -637,28 +637,90 @@ class EditEntryScreen(Screen):
def _get_linked_photos_from_text(self) -> Optional[List[Photo]]:
"""
Valida as referências de hash curto no texto contra o cache em memória.
- Retorna uma lista de objetos Photo se todas as referências forem válidas.
- Retorna None se UMA ÚNICA referência for inválida ou ambígua.
Validates photo references in the text against the memory cache.
Checks for:
- Malformed references
- Incorrect hash length
- Invalid or ambiguous hashes
Returns a list of unique photos (no duplicates even if referenced multiple times).
"""
text = self.text_entry.text
pattern = r"\[\[photo::(\w{8})\]\]"
short_hashes_in_text = set(re.findall(pattern, text))
# First check for malformed references
malformed_pattern = r"\[\[photo::([^\]]*)\](?!\])" # Missing ] at the end
malformed_matches = re.findall(malformed_pattern, text)
if malformed_matches:
for match in malformed_matches:
self.notify(f"❌ Malformed reference: '\\[\\[photo::{match}\\]' - Missing closing '\\]'", severity="error", timeout=10)
return None
# Look for incorrect format references
invalid_format = r"\[\[photo:[^:\]]+\]\]" # [[photo:something]] without ::
invalid_matches = re.findall(invalid_format, text)
if invalid_matches:
for match in invalid_matches:
escaped_match = match.replace("[", "\\[").replace("]", "\\]")
self.notify(f"❌ Invalid format: '{escaped_match}' - Use '\\[\\[photo::hash\\]\\]'", severity="error", timeout=10)
return None
# Now look for all references to validate
pattern = r"\[\[photo::([^\]]+)\]\]"
# Use set to get unique references only
all_refs = set(re.findall(pattern, text))
if not all_refs:
return [] # No references, valid operation
self._load_photos_for_diary(self.diary_id)
if not short_hashes_in_text:
return [] # Nenhuma referência, operação válida.
linked_photos: List[Photo] = []
for short_hash in short_hashes_in_text:
found_photos = [p for p in self.cached_photos if p.photo_hash.startswith(short_hash)]
processed_hashes = set() # Keep track of processed hashes to avoid duplicates
if len(found_photos) == 1:
linked_photos.append(found_photos[0])
for ref in all_refs:
# Skip if we already processed this hash
if ref in processed_hashes:
continue
# Validate hash length
if len(ref) != 8:
self.notify(
f"❌ Invalid hash: '{ref}' - Must be exactly 8 characters long",
severity="error",
timeout=10
)
return None
# Validate if contains only valid hexadecimal characters
if not re.match(r"^[0-9A-Fa-f]{8}$", ref):
self.notify(
f"❌ Invalid hash: '{ref}' - Use only hexadecimal characters (0-9, A-F)",
severity="error",
timeout=10
)
return None
# Search for photos matching the hash
found_photos = [p for p in self.cached_photos if p.photo_hash.startswith(ref)]
if len(found_photos) == 0:
self.notify(
f"❌ Hash not found: '{ref}' - No photo matches this hash",
severity="error",
timeout=10
)
return None
elif len(found_photos) > 1:
self.notify(
f"❌ Ambiguous hash: '{ref}' - Matches multiple photos",
severity="error",
timeout=10
)
return None
else:
self.notify(f"❌ Erro: Referência '\[{short_hash}\\]' é inválida ou ambígua!", severity="error", timeout=10)
return None # Aborta a operação
linked_photos.append(found_photos[0])
processed_hashes.add(ref) # Mark this hash as processed
return linked_photos
# Convert list to set and back to list to ensure uniqueness of photos
return list(set(linked_photos))
def on_option_list_option_selected(self, event: OptionList.OptionSelected) -> None:
"""Handles photo selection in the sidebar"""
@ -836,7 +898,7 @@ class EditEntryScreen(Screen):
photos_to_link = self._get_linked_photos_from_text()
if photos_to_link is None:
self.notify("⚠️ Salvamento cancelado. Corrija as referências de fotos.", severity="error")
self.notify("⚠️ Saving was canceled ", severity="error")
return
content = self.text_entry.text.strip()
@ -883,12 +945,12 @@ class EditEntryScreen(Screen):
self.next_entry_id = max(entry.id for entry in self.entries) + 1
self._update_entry_display()
self.notify(f"✅ Nova entrada '{new_entry.title}' salva com sucesso!")
self.notify(f"✅ New Entry: '{new_entry.title}' Successfully saved")
else:
self.notify("❌ Erro ao criar entrada")
self.notify("❌ Error creating the Entry")
except Exception as e:
self.notify(f"❌ Erro ao criar entrada: {str(e)}")
self.notify(f"❌ Error creating the entry: {str(e)}")
async def _async_update_entry(self, updated_content: str, photos_to_link: List[Photo]):
"""Atualiza uma entrada existente e sua associação de fotos."""
@ -896,7 +958,7 @@ class EditEntryScreen(Screen):
try:
if not self.entries:
self.notify("Nenhuma entrada para atualizar")
self.notify("No Entry to update")
return
entry_service = service_manager.get_entry_service()
current_entry = self.entries[self.current_entry_index]
@ -914,31 +976,31 @@ class EditEntryScreen(Screen):
self.has_unsaved_changes = False
self._original_content = updated_content # Pode ser o texto com hashes curtos
self._update_sub_header()
self.notify(f"✅ Entrada '{current_entry.title}' salva com sucesso!")
self.notify(f"✅ Entry: '{current_entry.title}' sucesfully saved")
except Exception as e:
# Desfaz as mudanças em caso de erro
self.notify(f"❌ Erro ao atualizar entrada: {str(e)}")
self.notify(f"❌ Error on updating the entry:: {str(e)}")
def on_key(self, event):
print("DEBUG: on_key called with", event.key, "sidebar_focused:", self.sidebar_focused, "sidebar_visible:", self.sidebar_visible)
# Sidebar contextual shortcuts
if self.sidebar_focused and self.sidebar_visible:
print("DEBUG: Processing sidebar shortcut for key:", event.key)
if event.key == "i":
print("DEBUG: Calling action_insert_photo")
self.action_insert_photo()
event.stop()
elif event.key == "n":
print("DEBUG: Calling action_ingest_new_photo")
self.action_ingest_new_photo()
event.stop()
elif event.key == "d":
print("DEBUG: Calling action_delete_photo")
self.action_delete_photo()
event.stop()
elif event.key == "e":
print("DEBUG: Calling action_edit_photo")
self.action_edit_photo()
event.stop()
# Shift+Tab: remove indent