<commit_before>class SentencesApi {
    @Decorators.publish
    static subscribeToSentences(lessonId): Mongo.Cursor<Sentence> {
        var user = ACL.getUserOrThrow(this);
        return Sentences.find({ lessonId: lessonId });
    }

    @Decorators.method
    static addSentence(text: string, lessonId: string, callback?) {
        var user = ACL.getUserOrThrow(this);
        
        Sentences.insert({
            text: text,
            testType: SentenceTestType.Default,
            translations: [],
            backTranslations: [],
            lessonId: lessonId,
            order: Sentences.find({ lessonId: lessonId }).count(),
            wordHints: SentencesApi.generateWordHints(lessonId, text)
        });
    }

    @Decorators.method
    static updateSentence(sentenceModel: Sentence, callback?) {
        var user = ACL.getUserOrThrow(this);
        Sentences.update(
            { _id: sentenceModel._id }, 
            { $set: { 
                text: sentenceModel.text,
                testType: sentenceModel.testType,
                translations: sentenceModel.translations,
                backTranslations: sentenceModel.backTranslations,
                order: sentenceModel.order,
                wordHints: SentencesApi.generateWordHints(sentenceModel.lessonId, sentenceModel.text)
            } }
        );
    }

    static generateWordHints(lessonId: string, text: string) {
        let lessonIds = [];
        Courses.findOne({ "tree.lessons.id": lessonId }).tree.forEach(r => r.lessons.forEach(l => lessonIds.push(l.id)));
        let wordHints = {}; 
        for (let word of Utilities.sentenceToWords(text)) {
            let wordObj = Words.findOne({ lessonId: { $in: lessonIds }, $or: [{ text: word }, { "inflections.text": word }]});
            let html = '';
            if (wordObj) {
                let inflection = wordObj.inflections.filter(i => i.text == word)[0];
                wordHints[word] = { wordId: wordObj._id, translations: inflection ? [ inflection.remarks ] : wordObj.translations.map(t => t.text) };
            }
        }
        return wordHints;
    }

    // this is a very heavy operation
    // probably need to rewrite later
    static refreshWordHints(word) {
        var sentences = Sentences.find({ text: new RegExp(word.replace(/[^a-zäö]/g,''), 'i') }, { fields: { text: 1 } }).fetch();
        for (var sentence of sentences) {
            Sentences.update(
                { _id: sentence._id }, 
                { $set: { 
                    wordHints: SentencesApi.generateWordHints(sentence.lessonId, sentence.text)
                } }
            );
        }
    }

    @Decorators.method
    static removeSentence(sentence, callback?) {<commit_msg>Fixed wordHints refresh when a word is changed.<commit_after>class SentencesApi {
    @Decorators.publish
    static subscribeToSentences(lessonId): Mongo.Cursor<Sentence> {
        var user = ACL.getUserOrThrow(this);
        return Sentences.find({ lessonId: lessonId });
    }

    @Decorators.method
    static addSentence(text: string, lessonId: string, callback?) {
        var user = ACL.getUserOrThrow(this);
        
        Sentences.insert({
            text: text,
            testType: SentenceTestType.Default,
            translations: [],
            backTranslations: [],
            lessonId: lessonId,
            order: Sentences.find({ lessonId: lessonId }).count(),
            wordHints: SentencesApi.generateWordHints(lessonId, text)
        });
    }

    @Decorators.method
    static updateSentence(sentenceModel: Sentence, callback?) {
        var user = ACL.getUserOrThrow(this);
        Sentences.update(
            { _id: sentenceModel._id }, 
            { $set: { 
                text: sentenceModel.text,
                testType: sentenceModel.testType,
                translations: sentenceModel.translations,
                backTranslations: sentenceModel.backTranslations,
                order: sentenceModel.order,
                wordHints: SentencesApi.generateWordHints(sentenceModel.lessonId, sentenceModel.text)
            } }
        );
    }

    static generateWordHints(lessonId: string, text: string) {
        let lessonIds = [];
        Courses.findOne({ "tree.lessons.id": lessonId }).tree.forEach(r => r.lessons.forEach(l => lessonIds.push(l.id)));
        let wordHints = {}; 
        for (let word of Utilities.sentenceToWords(text)) {
            let wordObj = Words.findOne({ lessonId: { $in: lessonIds }, $or: [{ text: word }, { "inflections.text": word }]});
            let html = '';
            if (wordObj) {
                let inflection = wordObj.inflections.filter(i => i.text == word)[0];
                wordHints[word] = { wordId: wordObj._id, translations: inflection ? [ inflection.remarks ] : wordObj.translations.map(t => t.text) };
            }
        }
        return wordHints;
    }

    // this is a very heavy operation
    // probably need to rewrite later
    static refreshWordHints(word) {
        var sentences = Sentences.find({ text: { $regex: word.replace(/[^a-zäö]/g,''), $options: 'i' } }, { fields: { text: 1, lessonId: 1 } }).fetch();
        for (var sentence of sentences) {
            Sentences.update(
                { _id: sentence._id }, 
                { $set: { 
                    wordHints: SentencesApi.generateWordHints(sentence.lessonId, sentence.text)
                } }
            );
        }
    }

    @Decorators.method
    static removeSentence(sentence, callback?) {
{'fraction_non_alphanumeric': 0.11918972689455598, 'fraction_numerical': 0.0009043226623259179, 'mean_word_length': 2.062015503875969, 'pattern_counts': {'":': 4, '<': 5, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7311239', 'n_tokens_mistral': 1638, 'n_tokens_neox': 1540, 'n_words': 320}