diff --git a/tools/migrations/26-02-16--add_translation_search.sql b/tools/migrations/26-02-16--add_translation_search.sql deleted file mode 100644 index 48428935..00000000 --- a/tools/migrations/26-02-16--add_translation_search.sql +++ /dev/null @@ -1,14 +0,0 @@ --- Translation search history table --- Tracks successful searches made in the Translation Tab for history view --- Only logs when a translation was found (meaning exists) -CREATE TABLE translation_search ( - id INT AUTO_INCREMENT PRIMARY KEY, - user_id INT NOT NULL, - meaning_id INT NOT NULL, - search_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - - FOREIGN KEY (user_id) REFERENCES user(id), - FOREIGN KEY (meaning_id) REFERENCES meaning(id), - - INDEX idx_user_time (user_id, search_time DESC) -); diff --git a/tools/migrations/26-02-17--simplify_translation_search.sql b/tools/migrations/26-02-17--simplify_translation_search.sql new file mode 100644 index 00000000..ba349a3c --- /dev/null +++ b/tools/migrations/26-02-17--simplify_translation_search.sql @@ -0,0 +1,18 @@ +-- Drop old translation_search table (had meaning_id, now we just store search_word) +DROP TABLE IF EXISTS translation_search; + +-- New simplified translation search history table +-- Stores the search word and learned language (active during search) +-- Filtered by current learned language when displayed +CREATE TABLE translation_search ( + id INT AUTO_INCREMENT PRIMARY KEY, + user_id INT NOT NULL, + search_word VARCHAR(255) NOT NULL, + learned_language_id INT NOT NULL, + search_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + + FOREIGN KEY (user_id) REFERENCES user(id), + FOREIGN KEY (learned_language_id) REFERENCES language(id), + + INDEX idx_user_lang_time (user_id, learned_language_id, search_time DESC) +); diff --git a/zeeguu/api/endpoints/translation.py b/zeeguu/api/endpoints/translation.py index fb3c453e..5e1b6c12 100644 --- a/zeeguu/api/endpoints/translation.py +++ b/zeeguu/api/endpoints/translation.py @@ -189,7 +189,6 @@ def get_multiple_translations(from_lang_code, to_lang_code): translations = get_all_translations(word_str, context, from_lang_code, to_lang_code, is_separated_mwe, full_sentence_context) # Save meanings for each translation - first_meaning = None for t in translations: translation_text = t.get("translation", "") if translation_text: @@ -201,18 +200,6 @@ def get_multiple_translations(from_lang_code, to_lang_code): to_lang_code, ) t["meaning_id"] = meaning.id - if first_meaning is None: - first_meaning = meaning - - # Log search to history only if we found a translation - if first_meaning: - try: - user = User.find_by_id(flask.g.user_id) - TranslationSearch.log_search(db_session, user, first_meaning) - db_session.commit() - except Exception as e: - db_session.rollback() - zeeguu_log(f"[TRANSLATION] Failed to log search history: {e}") return json_result(dict(translations=translations)) @@ -222,7 +209,7 @@ def get_multiple_translations(from_lang_code, to_lang_code): @requires_session def get_translation_history(): """ - Returns recent translation searches for the current user. + Returns recent translation searches for the current user's learned language. Used by the Translation Tab's history view. :return: json array with recent searches @@ -230,10 +217,36 @@ def get_translation_history(): user = User.find_by_id(flask.g.user_id) limit = request.args.get("limit", 50, type=int) - searches = TranslationSearch.get_history(user, limit=limit) + searches = TranslationSearch.get_history(user, user.learned_language, limit=limit) return json_result([s.as_dict() for s in searches]) +@api.route("/log_translation_search", methods=["POST"]) +@cross_domain +@requires_session +def log_translation_search(): + """ + Log a translation search to history. + Called by frontend when user searches for a word. + + :param search_word: The word that was searched + :return: success status + """ + search_word = request.form.get("search_word", "").strip() + if not search_word: + return "search_word required", 400 + + try: + user = User.find_by_id(flask.g.user_id) + TranslationSearch.log_search(db_session, user, search_word, user.learned_language) + db_session.commit() + return "OK" + except Exception as e: + db_session.rollback() + zeeguu_log(f"[TRANSLATION] Failed to log search history: {e}") + return "OK" # Don't fail the request for logging errors + + @api.route( "/get_translations_stream//", methods=["POST"] ) diff --git a/zeeguu/core/model/translation_search.py b/zeeguu/core/model/translation_search.py index 4ed36de9..9134426d 100644 --- a/zeeguu/core/model/translation_search.py +++ b/zeeguu/core/model/translation_search.py @@ -2,14 +2,14 @@ from sqlalchemy import desc from zeeguu.core.model.db import db -from zeeguu.core.model.meaning import Meaning +from zeeguu.core.model.language import Language from zeeguu.core.model.user import User class TranslationSearch(db.Model): """ - Tracks successful translation searches made in the Translation Tab. - Only logs searches where a translation was found (meaning exists). + Tracks translation searches made in the Translation Tab. + Stores the search word and learned language (active during search). """ __tablename__ = "translation_search" @@ -19,38 +19,46 @@ class TranslationSearch(db.Model): user_id = db.Column(db.Integer, db.ForeignKey(User.id), nullable=False) user = db.relationship(User) - meaning_id = db.Column(db.Integer, db.ForeignKey(Meaning.id), nullable=False) - meaning = db.relationship(Meaning) + search_word = db.Column(db.String(255), nullable=False) + + learned_language_id = db.Column( + db.Integer, db.ForeignKey(Language.id), nullable=False + ) + learned_language = db.relationship(Language) search_time = db.Column(db.DateTime, nullable=False, default=datetime.now) - def __init__(self, user: User, meaning: Meaning): + def __init__(self, user: User, search_word: str, learned_language: Language): self.user = user - self.meaning = meaning + self.search_word = search_word + self.learned_language = learned_language self.search_time = datetime.now() def __repr__(self): - return f"TranslationSearch({self.meaning.origin.content})" + return f"TranslationSearch({self.search_word}, {self.learned_language.code})" @classmethod - def log_search(cls, session, user: User, meaning: Meaning): + def log_search(cls, session, user: User, search_word: str, learned_language: Language): """ Log a translation search to history. Note: Does not commit - caller is responsible for committing. """ - search = cls(user=user, meaning=meaning) + search = cls(user=user, search_word=search_word, learned_language=learned_language) session.add(search) return search @classmethod - def get_history(cls, user: User, limit: int = 50): + def get_history(cls, user: User, learned_language: Language, limit: int = 50): """ - Get recent translation searches for a user. + Get recent translation searches for a user in a specific language. Returns most recent searches first. """ return ( - cls.query.filter(cls.user_id == user.id) + cls.query.filter( + cls.user_id == user.id, + cls.learned_language_id == learned_language.id + ) .order_by(desc(cls.search_time)) .limit(limit) .all() @@ -60,10 +68,7 @@ def as_dict(self): """Return dictionary representation for API response.""" return { "id": self.id, - "search_word": self.meaning.origin.content, - "translation": self.meaning.translation.content, - "from_language": self.meaning.origin.language.code, - "to_language": self.meaning.translation.language.code, - "meaning_id": self.meaning.id, + "search_word": self.search_word, + "language": self.learned_language.code, "search_time": self.search_time.isoformat(), }