<commit_before># coding=utf-8
from collections import Iterator
from datetime import datetime
from decimal import Decimal

from bson import ObjectId

from vulyk.models.stats import WorkSession
from vulyk.models.tasks import AbstractAnswer, Batch
from vulyk.signals import on_batch_done, on_task_done

from .core.events import Event
from .core.queries import MongoRuleExecutor
from .core.state import UserState
from .models.events import EventModel
from .models.rules import RuleModel, ProjectAndFreeRules
from .models.state import UserStateModel
from .models.task_types import (
    AbstractGamifiedTaskType, COINS_PER_TASK_KEY, POINTS_PER_TASK_KEY)

__all__ = [
    'track_events',
    'get_actual_rules'
]


@on_task_done.connect
def track_events(sender: object, answer: AbstractAnswer) -> None:
    """
    The most important gear of the gamification module.

    :param sender: Sender
    :type sender: object
    :param answer: Current finished task's answer instance
    :type answer: AbstractAnswer

    :rtype: None
    """
    from vulyk.app import TASKS_TYPES
    from vulyk.blueprints.gamification import gamification

    user = answer.created_by
    batch = answer.task.batch

    if not batch or batch.task_type not in TASKS_TYPES:
        return

    if isinstance(TASKS_TYPES[batch.task_type], AbstractGamifiedTaskType):
        dt = datetime.now()  # TODO: TZ Aware?
        # I. Get current/new state
        state = UserStateModel.get_or_create_by_user(user)

        # II. gather earned goods
        badges = list(filter(
            lambda rule: MongoRuleExecutor.achieved(
                user_id=user.id,
                rule=rule,
                collection=WorkSession.objects),
            get_actual_rules(
                state=state,
                task_type_name=batch.task_type,
                now=dt)))  # type: list[Rule]
        points = batch.batch_meta[POINTS_PER_TASK_KEY]
        coins = batch.batch_meta[COINS_PER_TASK_KEY]

        current_level = gamification.get_level(state.points)
        updated_level = gamification.get_level(state.points + Decimal(points))

        # III. Alter the state and create event
        UserStateModel.update_state(
            diff=UserState(
                user=user,
                level=updated_level,
                points=Decimal(points),
                actual_coins=Decimal(),
                potential_coins=Decimal(coins),
                achievements=badges,
                last_changed=dt))
        EventModel.from_event(<commit_msg>Oups, we've forgot to add bonuses for badges<commit_after># coding=utf-8
from collections import Iterator
from datetime import datetime
from decimal import Decimal

from bson import ObjectId

from vulyk.models.stats import WorkSession
from vulyk.models.tasks import AbstractAnswer, Batch
from vulyk.signals import on_batch_done, on_task_done

from .core.events import Event
from .core.queries import MongoRuleExecutor
from .core.state import UserState
from .models.events import EventModel
from .models.rules import RuleModel, ProjectAndFreeRules
from .models.state import UserStateModel
from .models.task_types import (
    AbstractGamifiedTaskType, COINS_PER_TASK_KEY, POINTS_PER_TASK_KEY)

__all__ = [
    'track_events',
    'get_actual_rules'
]


@on_task_done.connect
def track_events(sender: object, answer: AbstractAnswer) -> None:
    """
    The most important gear of the gamification module.

    :param sender: Sender
    :type sender: object
    :param answer: Current finished task's answer instance
    :type answer: AbstractAnswer

    :rtype: None
    """
    from vulyk.app import TASKS_TYPES
    from vulyk.blueprints.gamification import gamification

    user = answer.created_by
    batch = answer.task.batch

    if not batch or batch.task_type not in TASKS_TYPES:
        return

    if isinstance(TASKS_TYPES[batch.task_type], AbstractGamifiedTaskType):
        dt = datetime.now()  # TODO: TZ Aware?
        # I. Get current/new state
        state = UserStateModel.get_or_create_by_user(user)

        # II. gather earned goods
        badges = list(filter(
            lambda rule: MongoRuleExecutor.achieved(
                user_id=user.id,
                rule=rule,
                collection=WorkSession.objects),
            get_actual_rules(
                state=state,
                task_type_name=batch.task_type,
                now=dt)))  # type: list[Rule]
        points = batch.batch_meta[POINTS_PER_TASK_KEY]

        for b in badges:
            if b.bonus:
                points += b.bonus

        coins = batch.batch_meta[COINS_PER_TASK_KEY]

        current_level = gamification.get_level(state.points)
        updated_level = gamification.get_level(state.points + Decimal(points))

        # III. Alter the state and create event
        UserStateModel.update_state(
            diff=UserState(
                user=user,
                level=updated_level,
                points=Decimal(points),
                actual_coins=Decimal(),
                potential_coins=Decimal(coins),
                achievements=badges,
                last_changed=dt))
        EventModel.from_event(
{'fraction_non_alphanumeric': 0.07123499806426636, 'fraction_numerical': 0.00038714672861014324, 'mean_word_length': 2.6464361326746646, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '358643', 'n_tokens_mistral': 1533, 'n_tokens_neox': 1476, 'n_words': 370}