Пример #1
0
 def __init__(self):
     self.strava_resource = StravaResource()
     self.app_constants = AppConstants()
     self.app_variables = AppVariables()
     self.operations = Operations()
     self.database_resource = DatabaseResource()
     self.telegram_resource = TelegramResource()
     self.iron_cache_resource = IronCacheResource()
     self.athlete_resource = AthleteResource()
Пример #2
0
 def __init__(self):
     self.bot_constants = AppConstants()
     self.bot_variables = AppVariables()
     self.operations = Operations()
     self.aes_cipher = AESCipher(self.bot_variables.crypt_key_length,
                                 self.bot_variables.crypt_key)
     self.telegram_resource = TelegramResource()
     self.database_resource = DatabaseResource()
     self.strava_resource = StravaResource()
     self.athlete_resource = AthleteResource()
     self.iron_cache_resource = IronCacheResource()
     self.auto_update_indoor_ride = AutoUpdateIndoorRide()
     self.activity_summary = ActivitySummary()
Пример #3
0
from flask import Flask, request, jsonify
from scout_apm.flask import ScoutApm

from app.commands.challenges import CalculateChallengesStats, Challenges
from app.common.constants_and_variables import AppVariables, AppConstants
from app.common.execution_time import execution_time
from app.processor import update_stats, handle_webhook, telegram_send_message, challenges_api_hits, \
    telegram_send_approval_message
from app.resources.athlete import AthleteResource
from app.resources.database import DatabaseResource
from app.resources.iron_cache import IronCacheResource
from app.resources.strava import StravaResource

app_variables = AppVariables()
app_constants = AppConstants()
strava_resource = StravaResource()
athlete_resource = AthleteResource()
database_resource = DatabaseResource()
iron_cache_resource = IronCacheResource()
calculate_challenge_stats = CalculateChallengesStats()
challenges = Challenges()

app = Flask(__name__)
app.config.from_object(__name__)

ScoutApm(app)

app.config['SCOUT_MONITOR'] = app_variables.scout_monitor
app.config['SCOUT_KEY'] = app_variables.scout_key
app.config['SCOUT_NAME'] = app_variables.scout_name
Пример #4
0
class Process:
    def __init__(self):
        self.bot_constants = AppConstants()
        self.bot_variables = AppVariables()
        self.operations = Operations()
        self.aes_cipher = AESCipher(self.bot_variables.crypt_key_length,
                                    self.bot_variables.crypt_key)
        self.telegram_resource = TelegramResource()
        self.database_resource = DatabaseResource()
        self.strava_resource = StravaResource()
        self.athlete_resource = AthleteResource()
        self.iron_cache_resource = IronCacheResource()
        self.auto_update_indoor_ride = AutoUpdateIndoorRide()
        self.activity_summary = ActivitySummary()

    def calculate_stats(self, athlete_details):
        calculate_stats = CalculateStats(athlete_details['athlete_token'])
        calculated_stats = calculate_stats.calculate()
        name = calculated_stats['athlete_name']
        calculated_stats = ujson.dumps(calculated_stats)
        self.database_resource.write_operation(
            self.bot_constants.QUERY_UPDATE_STRAVA_DATA.format(
                name=name,
                strava_data=calculated_stats,
                athlete_id=athlete_details['athlete_id']))
        self.iron_cache_resource.put_cache(
            "stats", athlete_details['telegram_username'], calculated_stats)
        self.telegram_resource.send_message(
            self.bot_constants.MESSAGE_UPDATED_STATS.format(athlete_name=name))
        logging.info("Updated stats for https://www.strava.com/athletes/%s",
                     athlete_details['athlete_id'])

    def process_update_stats(self, athlete_id):
        athlete_details = self.athlete_resource.get_athlete_details(athlete_id)
        if athlete_details:
            self.calculate_stats(athlete_details)
            self.telegram_resource.send_message(
                chat_id=athlete_details['chat_id'],
                message="Updated stats. Click /stats to check.",
                shadow=False)
        else:
            message = "Old athlete [Athlete](https://www.strava.com/athletes/{athlete_id}). Not registered anymore.".format(
                athlete_id=athlete_id)
            logging.info(message)
            self.telegram_resource.send_message(message)

    def process_update_all_stats(self):
        athlete_ids = self.database_resource.read_all_operation(
            self.bot_constants.QUERY_FETCH_ALL_ATHLETE_IDS)
        for athlete_id in athlete_ids:
            athlete_details = self.athlete_resource.get_athlete_details(
                athlete_id[0])
            if athlete_details:
                logging.info("Updating stats for %s", athlete_id[0])
                self.calculate_stats(athlete_details)
        logging.info("Updated stats for all the athletes.")

    def alert_webhook_event_of_athlete(self, event, athlete_details):
        event_type = "New Activity"
        if event['aspect_type'] == "delete":
            event_type = "Activity Deleted"
        message = self.bot_constants.MESSAGE_ACTIVITY_ALERT.format(
            callback_type=event_type,
            activity_id=event['object_id'],
            athlete_name=athlete_details['name'])
        self.telegram_resource.send_message(message)

    def handle_aspect_type_update(self, event, athlete_details):
        athlete_id = event['owner_id']
        if 'authorized' in event['updates'] and event['updates'][
                'authorized'] == "false":
            if athlete_details:
                if self.database_resource.write_operation(
                        self.bot_constants.QUERY_DEACTIVATE_ATHLETE.format(
                            athlete_id=athlete_id)):
                    message = self.bot_constants.MESSAGE_DEAUTHORIZE_SUCCESS.format(
                        name=athlete_details['name'], athlete_id=athlete_id)
                else:
                    message = self.bot_constants.MESSAGE_DEAUTHORIZE_FAILURE.format(
                        name=athlete_details['name'], athlete_id=athlete_id)
                self.telegram_resource.send_message(message)

    def handle_aspect_type_create(self, event, athlete_details):
        activity_id = event['object_id']
        object_type = event['object_type']
        activity = self.strava_resource.get_strava_activity(
            athlete_details['athlete_token'], activity_id)
        if activity:
            if self.operations.supported_activities(activity):
                self.calculate_stats(athlete_details)
                if object_type == "activity":
                    self.auto_update_indoor_ride.main(activity,
                                                      athlete_details)
                    self.activity_summary.main(activity, athlete_details)
            else:
                message = self.bot_constants.MESSAGE_UNSUPPORTED_ACTIVITY.format(
                    activity_type=activity.type)
                logging.info(message)
                self.telegram_resource.send_message(message)
        else:
            message = "Triggering update stats as something went wrong. Exception: {exception}".format(
                exception=traceback.format_exc())
            logging.error(message)
            self.telegram_resource.send_message(message)
            self.calculate_stats(athlete_details)

    def process_webhook(self, event):
        aspect_type = event['aspect_type']
        athlete_id = event['owner_id']
        activity_id = event['object_id']
        athlete_details = self.athlete_resource.get_athlete_details(athlete_id)

        if aspect_type == "update":
            self.handle_aspect_type_update(event, athlete_details)
        else:
            if athlete_details:
                self.alert_webhook_event_of_athlete(event, athlete_details)
                if aspect_type == "create":
                    self.handle_aspect_type_create(event, athlete_details)
                elif aspect_type == "delete":
                    self.calculate_stats(athlete_details)
            else:
                logging.info(
                    "Old Athlete: [Athlete](https://www.strava.com/athletes/%s) | [Activity](https://www.strava.com/activities/%s)",
                    athlete_id, activity_id)
Пример #5
0
 def __init__(self):
     self.app_constants = AppConstants()
     self.operations = Operations()
     self.strava_resource = StravaResource()
     self.telegram_resource = TelegramResource()
 def __init__(self, athlete_token):
     self.athlete_token = athlete_token
     self.operations = Operations()
     self.strava_resource = StravaResource()
class CalculateStats:
    def __init__(self, athlete_token):
        self.athlete_token = athlete_token
        self.operations = Operations()
        self.strava_resource = StravaResource()

    @staticmethod
    def get_rider_stats():
        return {
            "updated": "",
            "athlete_name": "",
            "athlete_strava_joined_date": "",
            "athlete_followers": 0,
            "athlete_following": 0,
            "ride_at_total": 0,
            "ride_at_indoor_total": 0,
            "ride_at_distance": 0,
            "ride_at_indoor_distance": 0,
            "ride_at_moving_time": 0,
            "ride_at_indoor_moving_time": 0,
            "ride_at_elevation_gain": 0,
            "ride_at_fifty": 0,
            "ride_at_hundred": 0,
            "ride_at_biggest_ride": 0,
            "ride_at_max_elevation_gain": 0,
            "ride_at_achievements": 0,
            "ride_at_commutes": 0,
            "ride_at_pr": 0,
            "ride_at_calories": 0,
            "ride_ytd_total": 0,
            "ride_ytd_indoor_total": 0,
            "ride_ytd_distance": 0,
            "ride_ytd_indoor_distance": 0,
            "ride_ytd_moving_time": 0,
            "ride_ytd_indoor_moving_time": 0,
            "ride_ytd_elevation_gain": 0,
            "ride_ytd_fifty": 0,
            "ride_ytd_hundred": 0,
            "ride_ytd_biggest_ride": 0,
            "ride_ytd_max_elevation_gain": 0,
            "ride_ytd_achievements": 0,
            "ride_ytd_commutes": 0,
            "ride_ytd_pr": 0,
            "ride_ytd_calories": 0,
            "ride_py_total": 0,
            "ride_py_indoor_total": 0,
            "ride_py_distance": 0,
            "ride_py_indoor_distance": 0,
            "ride_py_moving_time": 0,
            "ride_py_indoor_moving_time": 0,
            "ride_py_elevation_gain": 0,
            "ride_py_fifty": 0,
            "ride_py_hundred": 0,
            "ride_py_biggest_ride": 0,
            "ride_py_max_elevation_gain": 0,
            "ride_py_achievements": 0,
            "ride_py_commutes": 0,
            "ride_py_pr": 0,
            "ride_py_calories": 0,
            "ride_cm_total": 0,
            "ride_cm_indoor_total": 0,
            "ride_cm_distance": 0,
            "ride_cm_indoor_distance": 0,
            "ride_cm_moving_time": 0,
            "ride_cm_indoor_moving_time": 0,
            "ride_cm_elevation_gain": 0,
            "ride_cm_fifty": 0,
            "ride_cm_hundred": 0,
            "ride_cm_biggest_ride": 0,
            "ride_cm_max_elevation_gain": 0,
            "ride_cm_achievements": 0,
            "ride_cm_commutes": 0,
            "ride_cm_pr": 0,
            "ride_cm_calories": 0,
            "ride_pm_total": 0,
            "ride_pm_indoor_total": 0,
            "ride_pm_distance": 0,
            "ride_pm_indoor_distance": 0,
            "ride_pm_moving_time": 0,
            "ride_pm_indoor_moving_time": 0,
            "ride_pm_elevation_gain": 0,
            "ride_pm_fifty": 0,
            "ride_pm_hundred": 0,
            "ride_pm_biggest_ride": 0,
            "ride_pm_max_elevation_gain": 0,
            "ride_pm_achievements": 0,
            "ride_pm_commutes": 0,
            "ride_pm_pr": 0,
            "ride_pm_calories": 0,
            "run_at_total": 0,
            "run_at_indoor_total": 0,
            "run_at_distance": 0,
            "run_at_indoor_distance": 0,
            "run_at_moving_time": 0,
            "run_at_indoor_moving_time": 0,
            "run_at_elevation_gain": 0,
            "run_at_five": 0,
            "run_at_ten": 0,
            "run_at_hm": 0,
            "run_at_fm": 0,
            "run_at_ultra": 0,
            "run_at_biggest_run": 0,
            "run_at_max_elevation_gain": 0,
            "run_at_achievements": 0,
            "run_at_commutes": 0,
            "run_at_pr": 0,
            "run_at_calories": 0,
            "run_ytd_total": 0,
            "run_ytd_indoor_total": 0,
            "run_ytd_distance": 0,
            "run_ytd_indoor_distance": 0,
            "run_ytd_moving_time": 0,
            "run_ytd_indoor_moving_time": 0,
            "run_ytd_elevation_gain": 0,
            "run_ytd_five": 0,
            "run_ytd_ten": 0,
            "run_ytd_hm": 0,
            "run_ytd_fm": 0,
            "run_ytd_ultra": 0,
            "run_ytd_biggest_run": 0,
            "run_ytd_max_elevation_gain": 0,
            "run_ytd_achievements": 0,
            "run_ytd_commutes": 0,
            "run_ytd_pr": 0,
            "run_ytd_calories": 0,
            "run_py_total": 0,
            "run_py_indoor_total": 0,
            "run_py_distance": 0,
            "run_py_indoor_distance": 0,
            "run_py_moving_time": 0,
            "run_py_indoor_moving_time": 0,
            "run_py_elevation_gain": 0,
            "run_py_five": 0,
            "run_py_ten": 0,
            "run_py_hm": 0,
            "run_py_fm": 0,
            "run_py_ultra": 0,
            "run_py_biggest_run": 0,
            "run_py_max_elevation_gain": 0,
            "run_py_achievements": 0,
            "run_py_commutes": 0,
            "run_py_pr": 0,
            "run_py_calories": 0,
            "run_cm_total": 0,
            "run_cm_indoor_total": 0,
            "run_cm_distance": 0,
            "run_cm_indoor_distance": 0,
            "run_cm_moving_time": 0,
            "run_cm_indoor_moving_time": 0,
            "run_cm_elevation_gain": 0,
            "run_cm_five": 0,
            "run_cm_ten": 0,
            "run_cm_hm": 0,
            "run_cm_fm": 0,
            "run_cm_ultra": 0,
            "run_cm_biggest_run": 0,
            "run_cm_max_elevation_gain": 0,
            "run_cm_achievements": 0,
            "run_cm_commutes": 0,
            "run_cm_pr": 0,
            "run_cm_calories": 0,
            "run_pm_total": 0,
            "run_pm_indoor_total": 0,
            "run_pm_distance": 0,
            "run_pm_indoor_distance": 0,
            "run_pm_moving_time": 0,
            "run_pm_indoor_moving_time": 0,
            "run_pm_elevation_gain": 0,
            "run_pm_five": 0,
            "run_pm_ten": 0,
            "run_pm_hm": 0,
            "run_pm_fm": 0,
            "run_pm_ultra": 0,
            "run_pm_biggest_run": 0,
            "run_pm_max_elevation_gain": 0,
            "run_pm_achievements": 0,
            "run_pm_commutes": 0,
            "run_pm_pr": 0,
            "run_pm_calories": 0,
            "swim_at_total": 0,
            "swim_at_distance": 0,
            "swim_at_moving_time": 0,
            "swim_at_50": 0,
            "swim_at_100": 0,
            "swim_at_200": 0,
            "swim_at_400": 0,
            "swim_at_800": 0,
            "swim_at_1500": 0,
            "swim_at_biggest_swim": 0,
            "swim_at_achievements": 0,
            "swim_at_pr": 0,
            "swim_at_calories": 0,
            "swim_ytd_total": 0,
            "swim_ytd_distance": 0,
            "swim_ytd_moving_time": 0,
            "swim_ytd_50": 0,
            "swim_ytd_100": 0,
            "swim_ytd_200": 0,
            "swim_ytd_400": 0,
            "swim_ytd_800": 0,
            "swim_ytd_1500": 0,
            "swim_ytd_biggest_swim": 0,
            "swim_ytd_achievements": 0,
            "swim_ytd_pr": 0,
            "swim_ytd_calories": 0,
            "swim_py_total": 0,
            "swim_py_distance": 0,
            "swim_py_moving_time": 0,
            "swim_py_50": 0,
            "swim_py_100": 0,
            "swim_py_200": 0,
            "swim_py_400": 0,
            "swim_py_800": 0,
            "swim_py_1500": 0,
            "swim_py_biggest_swim": 0,
            "swim_py_achievements": 0,
            "swim_py_pr": 0,
            "swim_py_calories": 0,
            "swim_cm_total": 0,
            "swim_cm_distance": 0,
            "swim_cm_moving_time": 0,
            "swim_cm_50": 0,
            "swim_cm_100": 0,
            "swim_cm_200": 0,
            "swim_cm_400": 0,
            "swim_cm_800": 0,
            "swim_cm_1500": 0,
            "swim_cm_biggest_swim": 0,
            "swim_cm_achievements": 0,
            "swim_cm_pr": 0,
            "swim_cm_calories": 0,
            "swim_pm_total": 0,
            "swim_pm_distance": 0,
            "swim_pm_moving_time": 0,
            "swim_pm_50": 0,
            "swim_pm_100": 0,
            "swim_pm_200": 0,
            "swim_pm_400": 0,
            "swim_pm_800": 0,
            "swim_pm_1500": 0,
            "swim_pm_biggest_swim": 0,
            "swim_pm_achievements": 0,
            "swim_pm_pr": 0,
            "swim_pm_calories": 0,
        }

    def calculate(self):
        logging.info("Calculating stats..")
        athlete_info = self.strava_resource.get_athlete_info(
            self.athlete_token)
        activities = self.strava_resource.get_strava_activities_after_date(
            self.athlete_token, "1970-01-01T00:00:00Z")
        today_date = date.today()
        current_month = today_date.month
        previous_month = (current_month - 1) if (current_month > 1) else 12
        current_year = date.today().year
        previous_year = today_date.year - 1
        rider_stats = self.get_rider_stats()

        rider_stats["updated"] = datetime.now().strftime("%d-%m-%Y %H:%M:%S")
        rider_stats["athlete_name"] = "{first_name} {last_name}".format(
            first_name=athlete_info.firstname, last_name=athlete_info.lastname)
        rider_stats[
            "athlete_strava_joined_date"] = athlete_info.created_at.date(
            ).strftime('%Y-%m-%d')
        rider_stats["athlete_followers"] = athlete_info.follower_count
        rider_stats["athlete_following"] = athlete_info.friend_count

        for activity in activities:
            if not self.operations.is_flagged(activity):
                distance = float(activity.distance)
                moving_time = unithelper.timedelta_to_seconds(
                    activity.moving_time)
                total_elevation_gain = float(activity.total_elevation_gain)
                activity_year = activity.start_date_local.year
                activity_month = activity.start_date_local.month
                if self.operations.is_activity_a_ride(activity):
                    rider_stats["ride_at_total"] += 1
                    rider_stats["ride_at_distance"] += distance
                    rider_stats["ride_at_moving_time"] += moving_time
                    rider_stats[
                        "ride_at_elevation_gain"] += total_elevation_gain
                    rider_stats[
                        "ride_at_achievements"] += activity.achievement_count
                    rider_stats["ride_at_pr"] += activity.pr_count
                    if activity.kilojoules:
                        rider_stats["ride_at_calories"] += activity.kilojoules
                    if self.operations.is_indoor(activity):
                        rider_stats["ride_at_indoor_total"] += 1
                        rider_stats["ride_at_indoor_distance"] += distance
                        rider_stats[
                            "ride_at_indoor_moving_time"] += moving_time
                    if activity.commute:
                        rider_stats["ride_at_commutes"] += 1
                    if distance > rider_stats["ride_at_biggest_ride"]:
                        rider_stats["ride_at_biggest_ride"] = distance
                    if total_elevation_gain > rider_stats[
                            "ride_at_max_elevation_gain"]:
                        rider_stats[
                            "ride_at_max_elevation_gain"] = total_elevation_gain
                    if 50000.0 <= distance < 100000.0:
                        rider_stats["ride_at_fifty"] += 1
                    elif distance > 100000.0:
                        rider_stats["ride_at_hundred"] += 1
                elif self.operations.is_activity_a_run(activity):
                    rider_stats["run_at_total"] += 1
                    rider_stats["run_at_distance"] += distance
                    rider_stats["run_at_moving_time"] += moving_time
                    rider_stats[
                        "run_at_elevation_gain"] += total_elevation_gain
                    rider_stats[
                        "run_at_achievements"] += activity.achievement_count
                    rider_stats["run_at_pr"] += activity.pr_count
                    if activity.kilojoules:
                        rider_stats["run_at_calories"] += activity.kilojoules
                    if self.operations.is_indoor(activity):
                        rider_stats["run_at_indoor_total"] += 1
                        rider_stats["run_at_indoor_distance"] += distance
                        rider_stats["run_at_indoor_moving_time"] += moving_time
                    if activity.commute:
                        rider_stats["run_at_commutes"] += 1
                    if distance > rider_stats["run_at_biggest_run"]:
                        rider_stats["run_at_biggest_run"] = distance
                    if total_elevation_gain > rider_stats[
                            "run_at_max_elevation_gain"]:
                        rider_stats[
                            "run_at_max_elevation_gain"] = total_elevation_gain
                    if 5000.0 <= distance < 10000.0:
                        rider_stats["run_at_five"] += 1
                    elif 10000.0 <= distance < 21000.0:
                        rider_stats["run_at_ten"] += 1
                    elif 21000.0 <= distance < 42000.0:
                        rider_stats["run_at_hm"] += 1
                    elif 42000.0 <= distance < 44000.0:
                        rider_stats["run_at_fm"] += 1
                    elif distance > 44000.0:
                        rider_stats["run_at_ultra"] += 1
                elif self.operations.is_activity_a_swim(activity):
                    rider_stats["swim_at_total"] += 1
                    rider_stats["swim_at_distance"] += distance
                    rider_stats["swim_at_moving_time"] += moving_time
                    rider_stats[
                        "swim_at_achievements"] += activity.achievement_count
                    rider_stats["swim_at_pr"] += activity.pr_count
                    if activity.kilojoules:
                        rider_stats["swim_at_calories"] += activity.kilojoules
                    if distance > rider_stats["swim_at_biggest_swim"]:
                        rider_stats["swim_at_biggest_swim"] = distance
                    if 50.0 <= distance < 100.0:
                        rider_stats["swim_at_50"] += 1
                    elif 100.0 <= distance < 200.0:
                        rider_stats["swim_at_100"] += 1
                    elif 200.0 <= distance < 400.0:
                        rider_stats["swim_at_200"] += 1
                    elif 400.0 <= distance < 800.0:
                        rider_stats["swim_at_400"] += 1
                    elif 800.0 <= distance < 1500.0:
                        rider_stats["swim_at_800"] += 1
                    elif distance > 1500.0:
                        rider_stats["swim_at_1500"] += 1

                if activity_year == current_year:
                    if self.operations.is_activity_a_ride(activity):
                        rider_stats["ride_ytd_total"] += 1
                        rider_stats["ride_ytd_distance"] += distance
                        rider_stats["ride_ytd_moving_time"] += moving_time
                        rider_stats[
                            "ride_ytd_elevation_gain"] += total_elevation_gain
                        rider_stats[
                            "ride_ytd_achievements"] += activity.achievement_count
                        rider_stats["ride_ytd_pr"] += activity.pr_count
                        if activity.kilojoules:
                            rider_stats[
                                "ride_ytd_calories"] += activity.kilojoules
                        if self.operations.is_indoor(activity):
                            rider_stats["ride_ytd_indoor_total"] += 1
                            rider_stats["ride_ytd_indoor_distance"] += distance
                            rider_stats[
                                "ride_ytd_indoor_moving_time"] += moving_time
                        if activity.commute:
                            rider_stats["ride_ytd_commutes"] += 1
                        if distance > rider_stats["ride_ytd_biggest_ride"]:
                            rider_stats["ride_ytd_biggest_ride"] = distance
                        if total_elevation_gain > rider_stats[
                                "ride_ytd_max_elevation_gain"]:
                            rider_stats[
                                "ride_ytd_max_elevation_gain"] = total_elevation_gain
                        if 50000.0 <= distance < 100000.0:
                            rider_stats["ride_ytd_fifty"] += 1
                        elif distance > 100000.0:
                            rider_stats["ride_ytd_hundred"] += 1
                    elif self.operations.is_activity_a_run(activity):
                        rider_stats["run_ytd_total"] += 1
                        rider_stats["run_ytd_distance"] += distance
                        rider_stats["run_ytd_moving_time"] += moving_time
                        rider_stats[
                            "run_ytd_elevation_gain"] += total_elevation_gain
                        rider_stats[
                            "run_ytd_achievements"] += activity.achievement_count
                        rider_stats["run_ytd_pr"] += activity.pr_count
                        if activity.kilojoules:
                            rider_stats[
                                "run_ytd_calories"] += activity.kilojoules
                        if self.operations.is_indoor(activity):
                            rider_stats["run_ytd_indoor_total"] += 1
                            rider_stats["run_ytd_indoor_distance"] += distance
                            rider_stats[
                                "run_ytd_indoor_moving_time"] += moving_time
                        if activity.commute:
                            rider_stats["run_ytd_commutes"] += 1
                        if distance > rider_stats["run_ytd_biggest_run"]:
                            rider_stats["run_ytd_biggest_run"] = distance
                        if total_elevation_gain > rider_stats[
                                "run_ytd_max_elevation_gain"]:
                            rider_stats[
                                "run_ytd_max_elevation_gain"] = total_elevation_gain
                        if 5000.0 <= distance < 10000.0:
                            rider_stats["run_ytd_five"] += 1
                        elif 10000.0 <= distance < 21000.0:
                            rider_stats["run_ytd_ten"] += 1
                        elif 21000.0 <= distance < 42000.0:
                            rider_stats["run_ytd_hm"] += 1
                        elif 42000.0 <= distance < 44000.0:
                            rider_stats["run_ytd_fm"] += 1
                        elif distance > 44000.0:
                            rider_stats["run_ytd_ultra"] += 1
                    elif self.operations.is_activity_a_swim(activity):
                        rider_stats["swim_ytd_total"] += 1
                        rider_stats["swim_ytd_distance"] += distance
                        rider_stats["swim_ytd_moving_time"] += moving_time
                        rider_stats[
                            "swim_ytd_achievements"] += activity.achievement_count
                        rider_stats["swim_ytd_pr"] += activity.pr_count
                        if activity.kilojoules:
                            rider_stats[
                                "swim_ytd_calories"] += activity.kilojoules
                        if distance > rider_stats["swim_ytd_biggest_swim"]:
                            rider_stats["swim_ytd_biggest_swim"] = distance
                        if 50.0 <= distance < 100.0:
                            rider_stats["swim_ytd_50"] += 1
                        elif 100.0 <= distance < 200.0:
                            rider_stats["swim_ytd_100"] += 1
                        elif 200.0 <= distance < 400.0:
                            rider_stats["swim_ytd_200"] += 1
                        elif 400.0 <= distance < 800.0:
                            rider_stats["swim_ytd_400"] += 1
                        elif 800.0 <= distance < 1500.0:
                            rider_stats["swim_ytd_800"] += 1
                        elif distance > 1500.0:
                            rider_stats["swim_ytd_1500"] += 1

                if activity_year == previous_year:
                    if self.operations.is_activity_a_ride(activity):
                        rider_stats["ride_py_total"] += 1
                        rider_stats["ride_py_distance"] += distance
                        rider_stats["ride_py_moving_time"] += moving_time
                        rider_stats[
                            "ride_py_elevation_gain"] += total_elevation_gain
                        rider_stats[
                            "ride_py_achievements"] += activity.achievement_count
                        rider_stats["ride_py_pr"] += activity.pr_count
                        if activity.kilojoules:
                            rider_stats[
                                "ride_py_calories"] += activity.kilojoules
                        if self.operations.is_indoor(activity):
                            rider_stats["ride_py_indoor_total"] += 1
                            rider_stats["ride_py_indoor_distance"] += distance
                            rider_stats[
                                "ride_py_indoor_moving_time"] += moving_time
                        if activity.commute:
                            rider_stats["ride_py_commutes"] += 1
                        if distance > rider_stats["ride_py_biggest_ride"]:
                            rider_stats["ride_py_biggest_ride"] = distance
                        if total_elevation_gain > rider_stats[
                                "ride_py_max_elevation_gain"]:
                            rider_stats[
                                "ride_py_max_elevation_gain"] = total_elevation_gain
                        if 50000.0 <= distance < 100000.0:
                            rider_stats["ride_py_fifty"] += 1
                        elif distance > 100000.0:
                            rider_stats["ride_py_hundred"] += 1
                    elif self.operations.is_activity_a_run(activity):
                        rider_stats["run_py_total"] += 1
                        rider_stats["run_py_distance"] += distance
                        rider_stats["run_py_moving_time"] += moving_time
                        rider_stats[
                            "run_py_elevation_gain"] += total_elevation_gain
                        rider_stats[
                            "run_py_achievements"] += activity.achievement_count
                        rider_stats["run_py_pr"] += activity.pr_count
                        if activity.kilojoules:
                            rider_stats[
                                "run_py_calories"] += activity.kilojoules
                        if self.operations.is_indoor(activity):
                            rider_stats["run_py_indoor_total"] += 1
                            rider_stats["run_py_indoor_distance"] += distance
                            rider_stats[
                                "run_py_indoor_moving_time"] += moving_time
                        if activity.commute:
                            rider_stats["run_py_commutes"] += 1
                        if distance > rider_stats["run_py_biggest_run"]:
                            rider_stats["run_py_biggest_run"] = distance
                        if total_elevation_gain > rider_stats[
                                "run_py_max_elevation_gain"]:
                            rider_stats[
                                "run_py_max_elevation_gain"] = total_elevation_gain
                        if 5000.0 <= distance < 10000.0:
                            rider_stats["run_py_five"] += 1
                        elif 10000.0 <= distance < 21000.0:
                            rider_stats["run_py_ten"] += 1
                        elif 21000.0 <= distance < 42000.0:
                            rider_stats["run_py_hm"] += 1
                        elif 42000.0 <= distance < 44000.0:
                            rider_stats["run_py_fm"] += 1
                        elif distance > 44000.0:
                            rider_stats["run_py_ultra"] += 1
                    elif self.operations.is_activity_a_swim(activity):
                        rider_stats["swim_py_total"] += 1
                        rider_stats["swim_py_distance"] += distance
                        rider_stats["swim_py_moving_time"] += moving_time
                        rider_stats[
                            "swim_py_achievements"] += activity.achievement_count
                        rider_stats["swim_py_pr"] += activity.pr_count
                        if activity.kilojoules:
                            rider_stats[
                                "swim_py_calories"] += activity.kilojoules
                        if distance > rider_stats["swim_py_biggest_swim"]:
                            rider_stats["swim_py_biggest_swim"] = distance
                        if 50.0 <= distance < 100.0:
                            rider_stats["swim_py_50"] += 1
                        elif 100.0 <= distance < 200.0:
                            rider_stats["swim_py_100"] += 1
                        elif 200.0 <= distance < 400.0:
                            rider_stats["swim_py_200"] += 1
                        elif 400.0 <= distance < 800.0:
                            rider_stats["swim_py_400"] += 1
                        elif 800.0 <= distance < 1500.0:
                            rider_stats["swim_py_800"] += 1
                        elif distance > 1500.0:
                            rider_stats["swim_py_1500"] += 1

                if activity_month == current_month and activity_year == current_year:
                    if self.operations.is_activity_a_ride(activity):
                        rider_stats["ride_cm_total"] += 1
                        rider_stats["ride_cm_distance"] += distance
                        rider_stats["ride_cm_moving_time"] += moving_time
                        rider_stats[
                            "ride_cm_elevation_gain"] += total_elevation_gain
                        rider_stats[
                            "ride_cm_achievements"] += activity.achievement_count
                        rider_stats["ride_cm_pr"] += activity.pr_count
                        if activity.kilojoules:
                            rider_stats[
                                "ride_cm_calories"] += activity.kilojoules
                        if self.operations.is_indoor(activity):
                            rider_stats["ride_cm_indoor_total"] += 1
                            rider_stats["ride_cm_indoor_distance"] += distance
                            rider_stats[
                                "ride_cm_indoor_moving_time"] += moving_time
                        if activity.commute:
                            rider_stats["ride_cm_commutes"] += 1
                        if distance > rider_stats["ride_cm_biggest_ride"]:
                            rider_stats["ride_cm_biggest_ride"] = distance
                        if total_elevation_gain > rider_stats[
                                "ride_cm_max_elevation_gain"]:
                            rider_stats[
                                "ride_cm_max_elevation_gain"] = total_elevation_gain
                        if 50000.0 <= distance < 100000.0:
                            rider_stats["ride_cm_fifty"] += 1
                        elif distance > 100000.0:
                            rider_stats["ride_cm_hundred"] += 1
                    elif self.operations.is_activity_a_run(activity):
                        rider_stats["run_cm_total"] += 1
                        rider_stats["run_cm_distance"] += distance
                        rider_stats["run_cm_moving_time"] += moving_time
                        rider_stats[
                            "run_cm_elevation_gain"] += total_elevation_gain
                        rider_stats[
                            "run_cm_achievements"] += activity.achievement_count
                        rider_stats["run_cm_pr"] += activity.pr_count
                        if activity.kilojoules:
                            rider_stats[
                                "run_cm_calories"] += activity.kilojoules
                        if self.operations.is_indoor(activity):
                            rider_stats["run_cm_indoor_total"] += 1
                            rider_stats["run_cm_indoor_distance"] += distance
                            rider_stats[
                                "run_cm_indoor_moving_time"] += moving_time
                        if activity.commute:
                            rider_stats["run_cm_commutes"] += 1
                        if distance > rider_stats["run_cm_biggest_run"]:
                            rider_stats["run_cm_biggest_run"] = distance
                        if total_elevation_gain > rider_stats[
                                "run_cm_max_elevation_gain"]:
                            rider_stats[
                                "run_cm_max_elevation_gain"] = total_elevation_gain
                        if 5000.0 <= distance < 10000.0:
                            rider_stats["run_cm_five"] += 1
                        elif 10000.0 <= distance < 21000.0:
                            rider_stats["run_cm_ten"] += 1
                        elif 21000.0 <= distance < 42000.0:
                            rider_stats["run_cm_hm"] += 1
                        elif 42000.0 <= distance < 44000.0:
                            rider_stats["run_cm_fm"] += 1
                        elif distance > 44000.0:
                            rider_stats["run_cm_ultra"] += 1
                    elif self.operations.is_activity_a_swim(activity):
                        rider_stats["swim_cm_total"] += 1
                        rider_stats["swim_cm_distance"] += distance
                        rider_stats["swim_cm_moving_time"] += moving_time
                        rider_stats[
                            "swim_cm_achievements"] += activity.achievement_count
                        rider_stats["swim_cm_pr"] += activity.pr_count
                        if activity.kilojoules:
                            rider_stats[
                                "swim_cm_calories"] += activity.kilojoules
                        if distance > rider_stats["swim_cm_biggest_swim"]:
                            rider_stats["swim_cm_biggest_swim"] = distance
                        if 50.0 <= distance < 100.0:
                            rider_stats["swim_cm_50"] += 1
                        elif 100.0 <= distance < 200.0:
                            rider_stats["swim_cm_100"] += 1
                        elif 200.0 <= distance < 400.0:
                            rider_stats["swim_cm_200"] += 1
                        elif 400.0 <= distance < 800.0:
                            rider_stats["swim_cm_400"] += 1
                        elif 800.0 <= distance < 1500.0:
                            rider_stats["swim_cm_800"] += 1
                        elif distance > 1500.0:
                            rider_stats["swim_cm_1500"] += 1

                # TODO This condition fails for January. Fix it.
                if activity_month == previous_month and activity_year == current_year:
                    if self.operations.is_activity_a_ride(activity):
                        rider_stats["ride_pm_total"] += 1
                        rider_stats["ride_pm_distance"] += distance
                        rider_stats["ride_pm_moving_time"] += moving_time
                        rider_stats[
                            "ride_pm_elevation_gain"] += total_elevation_gain
                        rider_stats[
                            "ride_pm_achievements"] += activity.achievement_count
                        rider_stats["ride_pm_pr"] += activity.pr_count
                        if activity.kilojoules:
                            rider_stats[
                                "ride_pm_calories"] += activity.kilojoules
                        if self.operations.is_indoor(activity):
                            rider_stats["ride_pm_indoor_total"] += 1
                            rider_stats["ride_pm_indoor_distance"] += distance
                            rider_stats[
                                "ride_pm_indoor_moving_time"] += moving_time
                        if activity.commute:
                            rider_stats["ride_pm_commutes"] += 1
                        if distance > rider_stats["ride_pm_biggest_ride"]:
                            rider_stats["ride_pm_biggest_ride"] = distance
                        if total_elevation_gain > rider_stats[
                                "ride_pm_max_elevation_gain"]:
                            rider_stats[
                                "ride_pm_max_elevation_gain"] = total_elevation_gain
                        if 50000.0 <= distance < 100000.0:
                            rider_stats["ride_pm_fifty"] += 1
                        elif distance > 100000.0:
                            rider_stats["ride_pm_hundred"] += 1
                    elif self.operations.is_activity_a_run(activity):
                        rider_stats["run_pm_total"] += 1
                        rider_stats["run_pm_distance"] += distance
                        rider_stats["run_pm_moving_time"] += moving_time
                        rider_stats[
                            "run_pm_elevation_gain"] += total_elevation_gain
                        rider_stats[
                            "run_pm_achievements"] += activity.achievement_count
                        rider_stats["run_pm_pr"] += activity.pr_count
                        if activity.kilojoules:
                            rider_stats[
                                "run_pm_calories"] += activity.kilojoules
                        if self.operations.is_indoor(activity):
                            rider_stats["run_pm_indoor_total"] += 1
                            rider_stats["run_pm_indoor_distance"] += distance
                            rider_stats[
                                "run_pm_indoor_moving_time"] += moving_time
                        if activity.commute:
                            rider_stats["run_pm_commutes"] += 1
                        if distance > rider_stats["run_pm_biggest_run"]:
                            rider_stats["run_pm_biggest_run"] = distance
                        if total_elevation_gain > rider_stats[
                                "run_pm_max_elevation_gain"]:
                            rider_stats[
                                "run_pm_max_elevation_gain"] = total_elevation_gain
                        if 5000.0 <= distance < 10000.0:
                            rider_stats["run_pm_five"] += 1
                        elif 10000.0 <= distance < 21000.0:
                            rider_stats["run_pm_ten"] += 1
                        elif 21000.0 <= distance < 42000.0:
                            rider_stats["run_pm_hm"] += 1
                        elif 42000.0 <= distance < 44000.0:
                            rider_stats["run_pm_fm"] += 1
                        elif distance > 44000.0:
                            rider_stats["run_pm_ultra"] += 1
                    elif self.operations.is_activity_a_swim(activity):
                        rider_stats["swim_pm_total"] += 1
                        rider_stats["swim_pm_distance"] += distance
                        rider_stats["swim_pm_moving_time"] += moving_time
                        rider_stats[
                            "swim_pm_achievements"] += activity.achievement_count
                        rider_stats["swim_pm_pr"] += activity.pr_count
                        if activity.kilojoules:
                            rider_stats[
                                "swim_pm_calories"] += activity.kilojoules
                        if distance > rider_stats["swim_pm_biggest_swim"]:
                            rider_stats["swim_pm_biggest_swim"] = distance
                        if 50.0 <= distance < 100.0:
                            rider_stats["swim_pm_50"] += 1
                        elif 100.0 <= distance < 200.0:
                            rider_stats["swim_pm_100"] += 1
                        elif 200.0 <= distance < 400.0:
                            rider_stats["swim_pm_200"] += 1
                        elif 400.0 <= distance < 800.0:
                            rider_stats["swim_pm_400"] += 1
                        elif 800.0 <= distance < 1500.0:
                            rider_stats["swim_pm_800"] += 1
                        elif distance > 1500.0:
                            rider_stats["swim_pm_1500"] += 1

        return rider_stats
Пример #8
0
class AutoUpdateIndoorRide:
    def __init__(self):
        self.app_constants = AppConstants()
        self.operations = Operations()
        self.strava_resource = StravaResource()
        self.telegram_resource = TelegramResource()

    @staticmethod
    def get_indoor_activity_name(athlete_details, activity):
        if athlete_details['update_indoor_ride_data']['name'] == 'Automatic':
            activity_hour = activity.start_date_local.hour
            if 3 <= activity_hour <= 11:
                athlete_details['update_indoor_ride_data'][
                    'name'] = "Morning Ride"
            elif 12 <= activity_hour <= 15:
                athlete_details['update_indoor_ride_data'][
                    'name'] = "Afternoon Ride"
            elif 16 <= activity_hour <= 18:
                athlete_details['update_indoor_ride_data'][
                    'name'] = "Evening Ride"
            elif (19 <= activity_hour <= 23) or (0 <= activity_hour <= 2):
                athlete_details['update_indoor_ride_data'][
                    'name'] = "Night Ride"

        return athlete_details

    def get_configured_update_indoor_ride_data(self, athlete_details):
        configured_data = self.app_constants.MESSAGE_UPDATED_INDOOR_RIDE
        if athlete_details['update_indoor_ride_data']['name']:
            configured_data += "\nActivity Name: {activity_name}".format(
                activity_name=athlete_details['update_indoor_ride_data']
                ['name'])
        if athlete_details['update_indoor_ride_data']['gear_id']:
            bike_name = self.strava_resource.get_gear_name(
                athlete_details['athlete_token'],
                athlete_details['update_indoor_ride_data']['gear_id'])
            configured_data += "\nBike: {bike_name}".format(
                bike_name=bike_name)

        return configured_data

    def main(self, activity, athlete_details):
        if self.operations.is_activity_a_ride(activity):
            if self.operations.is_indoor(activity):
                if athlete_details['update_indoor_ride']:
                    athlete_details = self.get_indoor_activity_name(
                        athlete_details, activity)
                    result = self.strava_resource.update_strava_activity(
                        athlete_details['athlete_token'], activity.id,
                        athlete_details['update_indoor_ride_data']['name'],
                        athlete_details['update_indoor_ride_data']['gear_id'])
                    if result:
                        message = self.get_configured_update_indoor_ride_data(
                            athlete_details)
                    else:
                        message = "Error auto updating indoor ride."

                    self.telegram_resource.send_message(
                        chat_id=athlete_details['chat_id'], message=message)
                else:
                    logging.info("Auto update indoor ride is not enabled.")
            else:
                logging.info("Activity is not an indoor ride.")
        else:
            logging.info("Activity Type is not Ride.")
Пример #9
0
class ToKOddMonth:
    def __init__(self):
        self.strava_resource = StravaResource()
        self.app_constants = AppConstants()
        self.app_variables = AppVariables()
        self.operations = Operations()
        self.database_resource = DatabaseResource()
        self.telegram_resource = TelegramResource()
        self.iron_cache_resource = IronCacheResource()
        self.athlete_resource = AthleteResource()

    @staticmethod
    def get_activity_type(activity):
        activity_type = None
        if activity.type == 'VirtualRide' or activity.type == 'Ride':
            activity_type = "Ride"
        elif activity.type == 'Run' or activity.type == 'VirtualRun':
            activity_type = "Run"
        elif activity.type == 'Swim':
            activity_type = "Swim"

        return activity_type

    def get_activities_calendar(self, athlete_details):
        activities_calendar = {
            "calendar": {
                "2019916": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019917": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019918": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019919": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019920": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019921": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019922": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019923": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019924": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019925": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019926": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019927": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019928": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019929": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019930": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019101": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019102": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019103": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019104": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019105": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019106": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019107": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019108": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019109": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191010": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191011": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191012": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191013": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191014": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191015": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191016": {
                    "result": False,
                    "activities": []
                },
                "20191017": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191018": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191019": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191020": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191021": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191022": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191023": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191024": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191025": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191026": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191027": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191028": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191029": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191030": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191031": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019111": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019112": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019113": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019114": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019115": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019116": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019117": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019118": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "2019119": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191110": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191111": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191112": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191113": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191114": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191115": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191116": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191117": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191118": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191119": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191120": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191121": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191122": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191123": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                },
                "20191124": {
                    "result": False,
                    "data": {
                        "activities": []
                    }
                }
            }
        }
        try:
            for activity in self.strava_resource.get_strava_activities_after_date_before_date(
                    athlete_details['athlete_token'],
                    self.app_variables.tok_odd_challenges_from_date,
                    self.app_variables.tok_odd_challenges_to_date):
                activity_type = activity.type
                activity_year = activity.start_date_local.year
                activity_month = activity.start_date_local.month
                activity_day = activity.start_date_local.day
                activity_distance = float(activity.distance)
                activity_elevation = float(
                    activity.total_elevation_gain
                ) if not self.operations.is_indoor(activity) else 0.0
                activity_time = unithelper.timedelta_to_seconds(
                    activity.moving_time)
                calendar_key = "{activity_year}{activity_month}{activity_day}".format(
                    activity_year=activity_year,
                    activity_month=activity_month,
                    activity_day=activity_day)
                logging.info(
                    "Type: %s | Year: %s | Month: %s | Day: %s | Distance: %s | Time: %s | Elevation: %s, Calendar Key: %s",
                    activity_type, activity_year, activity_month, activity_day,
                    activity_distance, activity_time, activity_elevation,
                    calendar_key)
                if self.operations.supported_activities_for_tok_challenges(
                        activity
                ) and activity_month in self.app_variables.tok_odd_challenges_month and activity_year in self.app_variables.tok_odd_challenges_year:
                    logging.info("Activity considered.")
                    activities_calendar["calendar"][calendar_key][
                        "result"] = True
                    activities_calendar["calendar"][calendar_key]["data"][
                        "activities"].append({
                            "type":
                            self.get_activity_type(activity),
                            "distance":
                            activity_distance,
                            "elevation":
                            activity_elevation
                        })

        except ValueError as exception_message:
            if str(exception_message) == "day is out of range for month":
                logging.info("Future date")
            else:
                logging.info(exception_message)
        except Exception:
            logging.info(traceback.format_exc())
        finally:
            return ujson.dumps(activities_calendar)

    @staticmethod
    def cap_ride_distance_and_elevation(activities_calendar):
        for activity_day in activities_calendar["calendar"]:
            if activities_calendar["calendar"][activity_day]["result"]:
                for activity in activities_calendar["calendar"][activity_day][
                        "data"]["activities"]:
                    if activity["type"] == "Ride":
                        activity[
                            "distance"] = activity["distance"] if activity[
                                "distance"] < 150000.0 else 150000.0
                        activity[
                            "elevation"] = activity["elevation"] if activity[
                                "elevation"] < 2000.0 else 2000.0
        return activities_calendar

    @staticmethod
    def calculate_activity_points(activities_calendar):
        for activity_day in activities_calendar["calendar"]:
            if activities_calendar["calendar"][activity_day]["result"]:
                for activity in activities_calendar["calendar"][activity_day][
                        "data"]["activities"]:
                    if activity["type"] == "Ride":
                        activity["activity_points"] = 1 if activity[
                            "distance"] >= 10000.0 else 0
                    elif activity["type"] == "Run":
                        activity["activity_points"] = 0
                    elif activity["type"] == "Swim":
                        activity["activity_points"] = 0
        return activities_calendar

    @staticmethod
    def calculate_distance_bonus(activities_calendar):
        for activity_day in activities_calendar["calendar"]:
            if activities_calendar["calendar"][activity_day]["result"]:
                for activity in activities_calendar["calendar"][activity_day][
                        "data"]["activities"]:
                    if activity["type"] == "Ride":
                        if activity["distance"] >= 100000.0:
                            activity["distance_bonus_points"] = 35
                        elif activity["distance"] >= 50000.0:
                            activity["distance_bonus_points"] = 15
                        elif activity["distance"] >= 25000.0:
                            activity["distance_bonus_points"] = 5
                        else:
                            activity["distance_bonus_points"] = 0
                    elif activity["type"] == "Run":
                        if activity["distance"] >= 40000.0:
                            activity["distance_bonus_points"] = 35
                        elif activity["distance"] >= 20000.0:
                            activity["distance_bonus_points"] = 16
                        elif activity["distance"] >= 15000.0:
                            activity["distance_bonus_points"] = 12
                        elif activity["distance"] >= 10000.0:
                            activity["distance_bonus_points"] = 7
                        elif activity["distance"] >= 5000.0:
                            activity["distance_bonus_points"] = 3
                        else:
                            activity["distance_bonus_points"] = 0
                    elif activity["type"] == "Swim":
                        if activity["distance"] >= 2000.0:
                            activity["distance_bonus_points"] = 10
                        elif activity["distance"] >= 1500.0:
                            activity["distance_bonus_points"] = 5
                        elif activity["distance"] >= 1000.0:
                            activity["distance_bonus_points"] = 3
                        else:
                            activity["distance_bonus_points"] = 0
        return activities_calendar

    @staticmethod
    def calculate_elevation_bonus(activities_calendar):
        for activity_day in activities_calendar["calendar"]:
            if activities_calendar["calendar"][activity_day]["result"]:
                for activity in activities_calendar["calendar"][activity_day][
                        "data"]["activities"]:
                    if activity["type"] == "Ride":
                        if activity["elevation"] >= 2000.0:
                            activity["elevation_bonus_points"] = 60
                        elif activity["elevation"] >= 1500.0:
                            activity["elevation_bonus_points"] = 40
                        elif activity["elevation"] >= 1000.0:
                            activity["elevation_bonus_points"] = 25
                        elif activity["elevation"] >= 500.0:
                            activity["elevation_bonus_points"] = 10
                        else:
                            activity["elevation_bonus_points"] = 0
                    elif activity["type"] == "Run":
                        activity["elevation_bonus_points"] = 0
                    elif activity["type"] == "Swim":
                        activity["elevation_bonus_points"] = 0
        return activities_calendar

    @staticmethod
    def calculate_total_distance_and_elevation_for_the_day(
            activities_calendar):
        for activity_day in activities_calendar["calendar"]:
            if activities_calendar["calendar"][activity_day]["result"]:
                activities_calendar["calendar"][activity_day]["data"].update(
                    {"distance": {
                        "Ride": 0.0,
                        "Run": 0.0,
                        "Swim": 0.0
                    }})
                activities_calendar["calendar"][activity_day]["data"].update(
                    {"elevation": {
                        "Ride": 0.0,
                        "Run": 0.0,
                        "Swim": 0.0
                    }})
                for activity in activities_calendar["calendar"][activity_day][
                        "data"]["activities"]:
                    if activity["type"] == "Ride":
                        activities_calendar["calendar"][activity_day]["data"][
                            "distance"]["Ride"] += activity["distance"]
                        activities_calendar["calendar"][activity_day]["data"][
                            "elevation"]["Ride"] += activity["elevation"]
                    elif activity["type"] == "Run":
                        activities_calendar["calendar"][activity_day]["data"][
                            "distance"]["Run"] += activity["distance"]
                        activities_calendar["calendar"][activity_day]["data"][
                            "elevation"]["Run"] += activity["elevation"]
                    elif activity["type"] == "Swim":
                        activities_calendar["calendar"][activity_day]["data"][
                            "distance"]["Swim"] += activity["distance"]
                        activities_calendar["calendar"][activity_day]["data"][
                            "elevation"]["Swim"] += activity["elevation"]

        return activities_calendar

    @staticmethod
    def calculate_max_distance_and_elevation_for_the_day(activities_calendar):
        for activity_day in activities_calendar["calendar"]:
            if activities_calendar["calendar"][activity_day]["result"]:
                activities_calendar["calendar"][activity_day]["data"].update(
                    {"max_distance": {
                        "Ride": 0.0,
                        "Run": 0.0,
                        "Swim": 0.0
                    }})
                activities_calendar["calendar"][activity_day]["data"].update(
                    {"max_elevation": {
                        "Ride": 0.0,
                        "Run": 0.0,
                        "Swim": 0.0
                    }})
                list_max_distance_ride = list()
                list_max_distance_run = list()
                list_max_distance_swim = list()
                list_max_elevation_ride = list()
                list_max_elevation_run = list()
                list_max_elevation_swim = list()
                for activity in activities_calendar["calendar"][activity_day][
                        "data"]["activities"]:
                    if activity["type"] == "Ride":
                        list_max_distance_ride.append(activity["distance"])
                        list_max_elevation_ride.append(activity["elevation"])
                    elif activity["type"] == "Run":
                        list_max_distance_run.append(activity["distance"])
                        list_max_elevation_run.append(activity["elevation"])
                    elif activity["type"] == "Swim":
                        list_max_distance_swim.append(activity["distance"])
                        list_max_elevation_swim.append(activity["elevation"])

                activities_calendar["calendar"][activity_day]["data"][
                    "max_distance"]["Ride"] = max(
                        list_max_distance_ride
                    ) if len(list_max_distance_ride) > 0 else 0
                activities_calendar["calendar"][activity_day]["data"][
                    "max_distance"]["Run"] = max(list_max_distance_run) if len(
                        list_max_distance_run) > 0 else 0
                activities_calendar["calendar"][activity_day]["data"][
                    "max_distance"]["Swim"] = max(
                        list_max_distance_swim
                    ) if len(list_max_distance_swim) > 0 else 0
                activities_calendar["calendar"][activity_day]["data"][
                    "max_elevation"]["Ride"] = max(
                        list_max_elevation_ride
                    ) if len(list_max_elevation_ride) > 0 else 0
                activities_calendar["calendar"][activity_day]["data"][
                    "max_elevation"]["Run"] = max(
                        list_max_elevation_run
                    ) if len(list_max_elevation_run) > 0 else 0
                activities_calendar["calendar"][activity_day]["data"][
                    "max_elevation"]["Swim"] = max(
                        list_max_elevation_swim
                    ) if len(list_max_elevation_swim) > 0 else 0

        return activities_calendar

    @staticmethod
    def calculate_total_distance_and_elevation(activities_calendar):
        activities_calendar.update(
            {"total_distance": {
                "Ride": 0.0,
                "Run": 0.0,
                "Swim": 0.0
            }})
        activities_calendar.update(
            {"total_elevation": {
                "Ride": 0.0,
                "Run": 0.0,
                "Swim": 0.0
            }})
        for activity_day in activities_calendar["calendar"]:
            if activities_calendar["calendar"][activity_day]["result"]:
                activities_calendar["total_distance"]["Ride"] += \
                activities_calendar["calendar"][activity_day]["data"]["distance"]["Ride"]
                activities_calendar["total_distance"]["Run"] += \
                activities_calendar["calendar"][activity_day]["data"]["distance"]["Run"]
                activities_calendar["total_distance"]["Swim"] += \
                activities_calendar["calendar"][activity_day]["data"]["distance"]["Swim"]
                activities_calendar["total_elevation"]["Ride"] += \
                activities_calendar["calendar"][activity_day]["data"]["elevation"]["Ride"]
                activities_calendar["total_elevation"]["Run"] += \
                activities_calendar["calendar"][activity_day]["data"]["elevation"]["Run"]
                activities_calendar["total_elevation"]["Swim"] += \
                activities_calendar["calendar"][activity_day]["data"]["elevation"]["Swim"]

        return activities_calendar

    @staticmethod
    def calculate_consecutive_fifties_and_hundreds(activities_calendar):
        activities_calendar.update({
            "consecutives": {
                "hundreds": {
                    "three": 0,
                    "two": 0
                },
                "fifties": {
                    "five": 0,
                    "three": 0
                }
            }
        })

        hundreds_streak = 0
        fifties_streak = 0
        for activity_day in activities_calendar["calendar"]:
            if activities_calendar["calendar"][activity_day]["result"]:
                max_distance = activities_calendar["calendar"][activity_day][
                    "data"]["max_distance"]["Ride"]
                if max_distance >= 100000.0:
                    hundreds_streak += 1
                    fifties_streak += 1
                else:
                    hundreds_streak = 0
                    if max_distance >= 50000.0:
                        fifties_streak += 1
                    else:
                        fifties_streak = 0

                if hundreds_streak == 2:
                    activities_calendar["consecutives"]["hundreds"]["two"] += 1
                elif hundreds_streak == 3:
                    activities_calendar["consecutives"]["hundreds"][
                        "three"] += 1
                    activities_calendar["consecutives"]["hundreds"]["two"] -= 1
                    hundreds_streak = 0
                elif fifties_streak == 3:
                    activities_calendar["consecutives"]["fifties"][
                        "three"] += 1
                elif fifties_streak == 5:
                    activities_calendar["consecutives"]["fifties"]["five"] += 1
                    activities_calendar["consecutives"]["fifties"][
                        "three"] -= 1
                    fifties_streak = 0
            else:
                hundreds_streak = 0
                fifties_streak = 0

        return activities_calendar

    def calculate_base_points(self, points, activities_calendar):
        points["base"]["Ride"]["distance"] = int(
            self.operations.meters_to_kilometers(
                activities_calendar["total_distance"]["Ride"] / 10)) * 2
        points["base"]["Run"]["distance"] = int(
            self.operations.meters_to_kilometers(
                activities_calendar["total_distance"]["Run"]))
        points["base"]["Swim"]["distance"] = int(
            activities_calendar["total_distance"]["Swim"] / 500)
        points["base"]["Ride"]["elevation"] = int(
            activities_calendar["total_elevation"]["Ride"] / 100)
        for activity_day in activities_calendar["calendar"]:
            if activities_calendar["calendar"][activity_day]["result"]:
                for activity in activities_calendar["calendar"][activity_day][
                        "data"]["activities"]:
                    points["base"]["Ride"]["activities"] += activity[
                        "activity_points"]
        return points

    @staticmethod
    def calculate_bonus_points(points, activities_calendar):
        if activities_calendar["total_distance"]["Ride"] >= 3000000.0:
            points["bonus"]["Ride"]["total_distance"] = 500
        if activities_calendar["total_elevation"]["Ride"] >= 35000.0:
            points["bonus"]["Ride"]["total_elevation"] = 500
        for activity_day in activities_calendar["calendar"]:
            if activities_calendar["calendar"][activity_day]["result"]:
                for activity in activities_calendar["calendar"][activity_day][
                        "data"]["activities"]:
                    if activity["type"] == "Ride":
                        points["bonus"]["Ride"]["distance"] += activity[
                            "distance_bonus_points"]
                        points["bonus"]["Ride"]["elevation"] += activity[
                            "elevation_bonus_points"]
                    # elif activity["type"] == "Run":
                    #     points["bonus"]["Run"]["distance"] += activity["distance_bonus_points"]
                    # elif activity["type"] == "Swim":
                    #     points["bonus"]["Swim"]["distance"] += activity["distance_bonus_points"]
        points["bonus"]["Ride"][
            "three_consecutive_hundreds"] = 100 * activities_calendar[
                "consecutives"]["hundreds"]["three"]
        points["bonus"]["Ride"][
            "two_consecutive_hundreds"] = 50 * activities_calendar[
                "consecutives"]["hundreds"]["two"]
        points["bonus"]["Ride"][
            "five_consecutive_fifties"] = 50 * activities_calendar[
                "consecutives"]["fifties"]["five"]
        points["bonus"]["Ride"][
            "three_consecutive_fifties"] = 25 * activities_calendar[
                "consecutives"]["fifties"]["three"]

        return points

    @staticmethod
    def calculate_total_points(points):
        total_points = list()
        total_points.append(sum(list(points["base"]["Ride"].values())))
        total_points.append(sum(list(points["base"]["Run"].values())))
        total_points.append(sum(list(points["base"]["Swim"].values())))
        total_points.append(sum(list(points["bonus"]["Ride"].values())))
        total_points.append(sum(list(points["bonus"]["Run"].values())))
        total_points.append(sum(list(points["bonus"]["Swim"].values())))
        return sum(total_points)

    @staticmethod
    def prepare_challenge_summary(points, total_points, athlete_details):
        challenge_summary = "*ToK Challenge Summary*:\n\n"
        challenge_summary += "Athlete Name: {}\n".format(
            athlete_details["name"])
        challenge_summary += "Total Points: {}\n\n".format(total_points)
        # if points["base"]["Ride"]["distance"] > 0:
        challenge_summary += "*Ride*:\n\n"
        challenge_summary += "_Base Points_:\n\n"
        challenge_summary += "Distance: {}\n".format(
            points["base"]["Ride"]["distance"])
        challenge_summary += "Elevation: {}\n".format(
            points["base"]["Ride"]["elevation"])
        challenge_summary += "Activities: {}\n\n".format(
            points["base"]["Ride"]["activities"])
        challenge_summary += "_Bonus Points_:\n\n"
        challenge_summary += "Distance slots: {}\n".format(
            points["bonus"]["Ride"]["distance"])
        challenge_summary += "Elevation slots: {}\n".format(
            points["bonus"]["Ride"]["elevation"])
        challenge_summary += "3 consecutive 50s: {}\n".format(
            points["bonus"]["Ride"]["three_consecutive_fifties"])
        challenge_summary += "5 consecutive 50s: {}\n".format(
            points["bonus"]["Ride"]["five_consecutive_fifties"])
        challenge_summary += "2 consecutive 100s: {}\n".format(
            points["bonus"]["Ride"]["two_consecutive_hundreds"])
        challenge_summary += "3 consecutive 100s: {}\n".format(
            points["bonus"]["Ride"]["three_consecutive_hundreds"])
        challenge_summary += "3000 km total: {}\n".format(
            points["bonus"]["Ride"]["total_distance"])
        challenge_summary += "35000 meters total: {}\n\n".format(
            points["bonus"]["Ride"]["total_elevation"])
        # if points["base"]["Run"]["distance"] > 0:
        challenge_summary += "*Run*:\n\n"
        challenge_summary += "Base Points: {}\n\n".format(
            points["base"]["Run"]["distance"])
        # challenge_summary += "Bonus Points: {}\n\n".format(points["bonus"]["Run"]["distance"])
        # if points["base"]["Swim"]["distance"] > 0:
        challenge_summary += "*Swim*:\n\n"
        challenge_summary += "Base Points: {}\n".format(
            points["base"]["Swim"]["distance"])
        # challenge_summary += "Bonus Points: {}".format(points["bonus"]["Swim"]["distance"])

        return challenge_summary

    def send_challenges_summary(self,
                                athlete_details,
                                challenges_summary,
                                notify=False):
        if notify and athlete_details['enable_activity_summary']:
            self.telegram_resource.send_message(
                chat_id=athlete_details['chat_id'], message=challenges_summary)
            logging.info("Sent challenge summary.")

    def tok_odd_challenges(self, athlete_details):
        logging.info("Calculating ToK odd challenges..")
        activities_calendar = ujson.loads(
            self.get_activities_calendar(athlete_details))
        # logging.info("Activities Calendar: %s", activities_calendar)
        activities_calendar = self.cap_ride_distance_and_elevation(
            activities_calendar)
        # logging.info("Activities Calendar with capped distance and elevation for Rides: %s", activities_calendar)
        activities_calendar = self.calculate_activity_points(
            activities_calendar)
        # logging.info("Activities Calendar with activity points: %s", activities_calendar)
        activities_calendar = self.calculate_distance_bonus(
            activities_calendar)
        # logging.info("Activities Calendar with distance bonus: %s", activities_calendar)
        activities_calendar = self.calculate_elevation_bonus(
            activities_calendar)
        # logging.info("Activities Calendar with elevation bonus: %s", activities_calendar)
        activities_calendar = self.calculate_total_distance_and_elevation_for_the_day(
            activities_calendar)
        # logging.info("Activities Calendar with total distance and elevation for the day: %s", activities_calendar)
        activities_calendar = self.calculate_max_distance_and_elevation_for_the_day(
            activities_calendar)
        # logging.info("Activities Calendar with max distance slot for the day: %s", activities_calendar)
        activities_calendar = self.calculate_total_distance_and_elevation(
            activities_calendar)
        # logging.info("Activities Calendar with total distance and elevation: %s", activities_calendar)
        activities_calendar = self.calculate_consecutive_fifties_and_hundreds(
            activities_calendar)
        logging.info("Activities Calendar: %s", activities_calendar)

        points = {
            "base": {
                "Ride": {
                    "distance": 0,
                    "elevation": 0,
                    "activities": 0
                },
                "Run": {
                    "distance": 0
                },
                "Swim": {
                    "distance": 0
                }
            },
            "bonus": {
                "Ride": {
                    "distance": 0,
                    "elevation": 0,
                    "total_distance": 0,
                    "total_elevation": 0,
                    "three_consecutive_hundreds": 0,
                    "two_consecutive_hundreds": 0,
                    "five_consecutive_fifties": 0,
                    "three_consecutive_fifties": 0
                },
                "Run": {
                    "distance": 0
                },
                "Swim": {
                    "distance": 0
                }
            }
        }
        points = self.calculate_base_points(points, activities_calendar)
        points = self.calculate_bonus_points(points, activities_calendar)
        logging.info("Points with bonus: %s", points)

        total_points = self.calculate_total_points(points)
        logging.info("Total points: %s", total_points)

        if self.database_resource.write_operation(
                self.app_constants.QUERY_UPDATE_TOK_ODD_CHALLENGES_DATA.format(
                    challenges_data=ujson.dumps({
                        'athlete_id':
                        athlete_details['athlete_id'],
                        'points':
                        total_points
                    }),
                    athlete_id=athlete_details['athlete_id'])):
            self.telegram_resource.send_message(
                "Updated ToK odd challenges data for {name}.".format(
                    name=athlete_details['name']))
        else:
            self.telegram_resource.send_message(
                "Failed to update ToK odd challenges data for {name}".format(
                    name=athlete_details['name']))

        athlete_details_from_bot = self.athlete_resource.get_athlete_details(
            athlete_details['athlete_id'])
        if athlete_details_from_bot:
            challenge_summary = self.prepare_challenge_summary(
                points, total_points, athlete_details_from_bot)
            self.send_challenges_summary(athlete_details_from_bot,
                                         challenge_summary, True)

    def consolidate_tok_odd_challenges_result(self):
        odd_challenge = list()

        results = self.database_resource.read_all_operation(
            self.app_constants.QUERY_GET_TOK_ODD_CHALLENGES_DATA)
        for result in results:
            name = result[0]
            challenges = result[1]
            challenges_data = result[2]

            if challenges:
                odd_challenge.append({
                    'name': name,
                    'value': challenges_data['points']
                })

        odd_challenge_temp = sorted(odd_challenge,
                                    key=operator.itemgetter('value'),
                                    reverse=True)

        odd_challenge_sorted = list()
        rank = 1
        for athlete in odd_challenge_temp:
            odd_challenge_sorted.append({
                'rank': rank,
                'name': athlete['name'],
                'value': athlete['value']
            })
            rank += 1

        if len(odd_challenge_sorted) == 0:
            odd_challenge_sorted.append({'rank': '', 'name': '', 'value': ''})

        self.iron_cache_resource.put_cache("tok_odd_challenges_result",
                                           "leaderboard",
                                           ujson.dumps(odd_challenge_sorted))
        self.telegram_resource.send_message(
            "Updated cache for ToK odd month challenge.")