Ejemplo n.º 1
0
def dashboard(request):
    """Main dashboard view."""
    ctx = {
        "configurations": [],
        "windows": {
            "filtered": [],
            "all": []
        },
        "queueable": []
    }

    # Grab all configurations present to send to the dashboard.
    for config in Configuration.objects.all():
        ctx["configurations"].append({"id": config.pk, "name": config.name})

    wh = WindowHandler()
    wh.enum()
    for window in wh.filter().values():
        ctx["windows"]["filtered"].append(window.json())
    for window in wh.filter(filter_titles=False,
                            ignore_smaller=False).values():
        ctx["windows"]["all"].append(window.json())

    # Grab all queueable functions.
    for prop in BotProperty.all():
        ctx["queueable"].append({
            "name":
            title(prop["name"]),
            "func":
            prop["name"],
            "tooltip":
            prop["tooltip"] if prop["tooltip"] else None
        })

    return render(request, "dashboard.html", context=ctx)
Ejemplo n.º 2
0
def generate_queued(request):
    """Generate a queued function representing the function specified by the user."""
    func = request.GET.get("function")
    inst = BotInstance.objects.get(pk=request.GET.get("instance"))
    Queue.objects.add(function=func, instance=inst)

    return JsonResponse(data={"status": "success", "function": title(func)})
Ejemplo n.º 3
0
def shortcuts(request):
    """View all shortcuts available for use with the bot."""
    ctx = {
        "shortcuts":
        {title(k): v.split("+")
         for k, v in SHORTCUT_FUNCTIONS.items()}
    }
    return render(request, "shortcuts.html", context=ctx)
Ejemplo n.º 4
0
def shortcuts(request):
    """View all shortcuts available for use with the bot."""
    ctx = {
        "shortcuts": {
            title(prop["name"]): prop["shortcut"].split("+")
            for prop in BotProperty.shortcuts()
        }
    }
    return render(request, "shortcuts.html", context=ctx)
Ejemplo n.º 5
0
def statistics(request):
    if request.GET.get("instance"):
        stats = Statistics.objects.grab(instance=BotInstance.objects.get(
            pk=request.GET.get("instance")))
    else:
        stats = Statistics.objects.grab(instance=BotInstance.objects.grab())

    ctx = {
        "game_statistics": {
            title(key): value
            for key, value in stats.game_statistics.json().items()
        },
        "bot_statistics": {
            title(key): value
            for key, value in stats.bot_statistics.json().items()
        },
        "progress":
        stats.game_statistics.progress,
        "played":
        stats.game_statistics.played,
        "STATISTICS_JSON":
        json.dumps({
            "game_statistics": stats.game_statistics.json(),
            "bot_statistics": stats.bot_statistics.json()
        })
    }

    if request.GET.get("context"):
        return JsonResponse(
            data={
                "allStatistics":
                render(request, "statistics/statisticsTable.html",
                       context=ctx).content.decode(),
                "progress":
                render(request,
                       "statistics/statisticsProgress.html",
                       context=ctx).content.decode(),
                "played":
                render(request,
                       "statistics/statisticsPlayed.html",
                       context=ctx).content.decode()
            })

    return render(request, "statistics/allStatistics.html", context=ctx)
Ejemplo n.º 6
0
 def json(self):
     """
     Convert the QueuedFunction into a JSON compliant dictionary.
     """
     from titandash.utils import title
     return {
         "id": self.pk,
         "function": self.function,
         "title": title(self.function),
         "created": self.created.strftime(DATETIME_FMT)
     }
Ejemplo n.º 7
0
 def json(self):
     """
     Return Artifact as a JSON Compliant Object.
     """
     from titandash.utils import title
     return {
         "name": self.name,
         "title": title(self.name),
         "key": self.key,
         "image": self.image,
         "path": "{dir}{path}".format(dir=settings.STATIC_URL,
                                      path=self.image)
     }
Ejemplo n.º 8
0
def dashboard(request):
    """Main dashboard view."""
    ctx = {"configurations": [], "windows": [], "queueable": []}

    # Grab all configurations present to send to the dashboard.
    for config in Configuration.objects.all():
        ctx["configurations"].append({"id": config.pk, "name": config.name})

    wh = WindowHandler()
    wh.enum()
    for hwnd, window in wh.filter(contains=WINDOW_FILTER).items():
        ctx["windows"].append(window.json())

    ctx["windows"].reverse()

    # Grab all queueable functions.
    for queue in QUEUEABLE_FUNCTIONS:
        ctx["queueable"].append({
            "name": title(queue),
            "func": queue,
            "tooltip": QUEUEABLE_TOOLTIPS[queue]
        })

    return render(request, "dashboard.html", context=ctx)
Ejemplo n.º 9
0
 def __str__(self):
     from titandash.utils import title
     return "{name} ({key}) - [{tier}]".format(name=title(self.name),
                                               key=self.key,
                                               tier=self.tier)
Ejemplo n.º 10
0
 def title(self):
     """
     Return a titled version of the artifact name.
     """
     from titandash.utils import title
     return title(self.name)
Ejemplo n.º 11
0
    def json(self, condense=False, hide_sensitive=False):
        """
        Return a JSON compliant dictionary for current configuration.

        Use the condense flag to ensure that foreign key or many to many fields are condensed into simple values.
        """
        from titandash.utils import title
        dct = {
            "Runtime": {
                "name": self.name,
                "soft_shutdown_on_critical_error":
                self.soft_shutdown_on_critical_error,
                "soft_shutdown_update_stats": self.soft_shutdown_update_stats,
                "post_action_min_wait_time": self.post_action_min_wait_time,
                "post_action_max_wait_time": self.post_action_max_wait_time
            },
            "Generic": {
                "enable_tapping": self.enable_tapping,
                "tapping_repeat": self.tapping_repeat,
                "enable_daily_rewards": self.enable_daily_rewards,
                "enable_clan_crates": self.enable_clan_crates,
                "enable_egg_collection": self.enable_egg_collection,
                "enable_tournaments": self.enable_tournaments,
                "enable_tournament_parsing": self.enable_tournament_parsing
            },
            "Minigames": {
                "enable_minigames": self.enable_minigames,
                "minigames_repeat": self.minigames_repeat,
                "enable_coordinated_offensive":
                self.enable_coordinated_offensive,
                "enable_astral_awakening": self.enable_astral_awakening,
                "enable_heart_of_midas": self.enable_heart_of_midas,
                "enable_flash_zip": self.enable_flash_zip,
                "enable_forbidden_contract": self.enable_forbidden_contract,
                "enable_summon_dagger": self.enable_summon_dagger
            },
            "Breaks": {
                "enable_breaks": self.enable_breaks,
                "breaks_jitter": self.breaks_jitter,
                "breaks_minutes_required": self.breaks_minutes_required,
                "breaks_minutes_max": self.breaks_minutes_max,
                "breaks_minutes_min": self.breaks_minutes_min
            },
            "Daily Achievement": {
                "enable_daily_achievements":
                self.enable_daily_achievements,
                "daily_achievements_check_on_start":
                self.daily_achievements_check_on_start,
                "daily_achievements_check_every_x_hours":
                self.daily_achievements_check_every_x_hours
            },
            "Raid Notifications": {
                "enable_raid_notifications":
                self.enable_raid_notifications,
                "raid_notifications_check_on_start":
                self.raid_notifications_check_on_start,
                "raid_notifications_check_every_x_minutes":
                self.raid_notifications_check_every_x_minutes,
                "raid_notifications_twilio_account_sid":
                self.raid_notifications_twilio_account_sid,
                "raid_notifications_twilio_auth_token":
                self.raid_notifications_twilio_auth_token,
                "raid_notifications_twilio_from_number":
                self.raid_notifications_twilio_from_number,
                "raid_notifications_twilio_to_number":
                self.raid_notifications_twilio_to_number
            },
            "Master Action": {
                "enable_master": self.enable_master,
                "master_level_every_x_seconds":
                self.master_level_every_x_seconds,
                "master_level_on_start": self.master_level_on_start,
                "master_level_only_once": self.master_level_only_once,
                "master_level_intensity": self.master_level_intensity
            },
            "Heroes Action": {
                "enable_heroes": self.enable_heroes,
                "hero_level_every_x_seconds": self.hero_level_every_x_seconds,
                "hero_level_on_start": self.hero_level_on_start,
                "hero_level_intensity": self.hero_level_intensity
            },
            "Level Skills Action": {
                "enable_level_skills": self.enable_level_skills,
                "level_skills_every_x_seconds":
                self.level_skills_every_x_seconds,
                "level_skills_on_start": self.level_skills_on_start,
                "level_heavenly_strike_cap": self.level_heavenly_strike_cap,
                "level_deadly_strike_cap": self.level_deadly_strike_cap,
                "level_hand_of_midas_cap": self.level_hand_of_midas_cap,
                "level_fire_sword_cap": self.level_fire_sword_cap,
                "level_war_cry_cap": self.level_war_cry_cap,
                "level_shadow_clone_cap": self.level_shadow_clone_cap,
            },
            "Activate Skills Action": {
                "enable_activate_skills": self.enable_activate_skills,
                "activate_skills_every_x_seconds":
                self.activate_skills_every_x_seconds,
                "activate_skills_on_start": self.activate_skills_on_start,
                "interval_heavenly_strike": self.interval_heavenly_strike,
                "interval_deadly_strike": self.interval_deadly_strike,
                "interval_hand_of_midas": self.interval_hand_of_midas,
                "interval_fire_sword": self.interval_fire_sword,
                "interval_war_cry": self.interval_war_cry,
                "interval_shadow_clone": self.interval_shadow_clone,
            },
            "Perks": {
                "enable_perk_usage": self.enable_perk_usage,
                "enable_perk_diamond_purchase":
                self.enable_perk_diamond_purchase,
                "enable_perk_only_tournament":
                self.enable_perk_only_tournament,
                "use_perks_on_start": self.use_perk_on_prestige,
                "use_perks_every_x_hours": self.use_perks_every_x_hours,
                "use_perk_on_prestige": self.use_perk_on_prestige,
                "enable_mega_boost": self.enable_mega_boost,
                "enable_power_of_swiping": self.enable_power_of_swiping,
                "enable_adrenaline_rush": self.enable_adrenaline_rush,
                "enable_make_it_rain": self.enable_make_it_rain,
                "enable_mana_potion": self.enable_mana_potion,
                "enable_doom": self.enable_doom,
                "enable_clan_crate": self.enable_clan_crate,
            },
            "Prestige Action": {
                "enable_auto_prestige": self.enable_auto_prestige,
                "enable_prestige_threshold_randomization":
                self.enable_prestige_threshold_randomization,
                "prestige_random_min_time": self.prestige_random_min_time,
                "prestige_random_max_time": self.prestige_random_max_time,
                "prestige_x_minutes": self.prestige_x_minutes,
                "prestige_at_stage": self.prestige_at_stage,
                "prestige_at_max_stage": self.prestige_at_max_stage,
                "prestige_at_max_stage_percent":
                self.prestige_at_max_stage_percent
            },
            "Artifacts Action": {
                "enable_artifact_discover_enchant":
                self.enable_artifact_discover_enchant,
                "enable_artifact_purchase":
                self.enable_artifact_purchase,
                "upgrade_owned_tier":
                [tier.json() for tier in self.upgrade_owned_tier.all()],
                "shuffle_artifacts":
                self.shuffle_artifacts,
                "ignore_artifacts":
                [art.json() for art in self.ignore_artifacts.all()],
                "upgrade_artifacts":
                [art.json() for art in self.upgrade_artifacts.all()]
            },
            "Stats": {
                "enable_stats": self.enable_stats,
                "update_stats_on_start": self.update_stats_on_start,
                "update_stats_every_x_minutes":
                self.update_stats_every_x_minutes
            },
        }

        if condense:
            dct["Artifacts Action"]["upgrade_owned_tier"] = ", ".join(
                [title(t.name) for t in self.upgrade_owned_tier.all()])
            dct["Artifacts Action"]["ignore_artifacts"] = ", ".join(
                [title(a.name) for a in self.ignore_artifacts.all()])
            dct["Artifacts Action"]["upgrade_artifacts"] = ", ".join(
                [title(a.name) for a in self.upgrade_artifacts.all()])

        if hide_sensitive:
            if dct["Raid Notifications"][
                    "raid_notifications_twilio_account_sid"]:
                dct["Raid Notifications"][
                    "raid_notifications_twilio_account_sid"] = "************"
            if dct["Raid Notifications"][
                    "raid_notifications_twilio_auth_token"]:
                dct["Raid Notifications"][
                    "raid_notifications_twilio_auth_token"] = "************"
            if dct["Raid Notifications"][
                    "raid_notifications_twilio_from_number"]:
                dct["Raid Notifications"][
                    "raid_notifications_twilio_from_number"] = "************"
            if dct["Raid Notifications"][
                    "raid_notifications_twilio_to_number"]:
                dct["Raid Notifications"][
                    "raid_notifications_twilio_to_number"] = "************"

        return dct
Ejemplo n.º 12
0
    def json(self):
        """
        Convert the BotInstance into a JSON compliant dictionary.
        """
        from django.urls import reverse
        from titandash.utils import title
        from titandash.models.artifact import Artifact
        dct = {
            "id":
            self.pk,
            "name":
            self.name,
            "state":
            self.state.upper(),
            "started": {
                "datetime":
                str(self.started) if self.started else None,
                "formatted":
                self.started.astimezone().strftime(DATETIME_FMT)
                if self.started else None
            },
            "current_function": {
                "function":
                self.current_function,
                "title":
                title(self.current_function)
                if self.current_function else None,
            },
            "last_prestige":
            self.last_prestige.json() if self.last_prestige else "N/A",
            "log_file":
            reverse('log', kwargs={'pk': self.log.pk}) if self.log else "N/A",
            "current_stage": {
                "stage": self.current_stage,
                "diff_from_max": self.get_diff_from_max_stage(),
                "percent_from_max": self.get_diff_from_max_stage(percent=True)
            },
            "newest_hero": {
                "title": title(self.newest_hero) if self.newest_hero else None,
            },
            "next_artifact_upgrade": {
                "title":
                title(self.next_artifact_upgrade)
                if self.next_artifact_upgrade else None,
                "image":
                "{dir}{path}".format(
                    dir=settings.STATIC_URL,
                    path=Artifact.objects.get(
                        name=self.next_artifact_upgrade).image)
                if self.next_artifact_upgrade else None
            },
            "next_master_level": {
                "datetime":
                str(self.next_master_level)
                if self.next_master_level else None,
                "formatted":
                self.next_master_level.astimezone().strftime(DATETIME_FMT)
                if self.next_master_level else None
            },
            "next_heroes_level": {
                "datetime":
                str(self.next_heroes_level)
                if self.next_heroes_level else None,
                "formatted":
                self.next_heroes_level.astimezone().strftime(DATETIME_FMT)
                if self.next_heroes_level else None
            },
            "next_skills_level": {
                "datetime":
                str(self.next_skills_level)
                if self.next_skills_level else None,
                "formatted":
                self.next_skills_level.astimezone().strftime(DATETIME_FMT)
                if self.next_skills_level else None
            },
            "next_skills_activation": {
                "datetime":
                str(self.next_skills_activation)
                if self.next_skills_activation else None,
                "formatted":
                self.next_skills_activation.astimezone().strftime(DATETIME_FMT)
                if self.next_skills_activation else None
            },
            "next_miscellaneous_actions": {
                "datetime":
                str(self.next_miscellaneous_actions)
                if self.next_miscellaneous_actions else None,
                "formatted":
                self.next_miscellaneous_actions.astimezone().strftime(
                    DATETIME_FMT) if self.next_miscellaneous_actions else None
            },
            "next_headgear_swap": {
                "datetime":
                str(self.next_headgear_swap)
                if self.next_headgear_swap else None,
                "formatted":
                self.next_headgear_swap.astimezone().strftime(DATETIME_FMT)
                if self.next_headgear_swap else None
            },
            "next_perk_check": {
                "datetime":
                str(self.next_perk_check) if self.next_perk_check else None,
                "formatted":
                self.next_perk_check.astimezone().strftime(DATETIME_FMT)
                if self.next_perk_check else None
            },
            "next_prestige": {
                "datetime":
                str(self.next_prestige) if self.next_prestige else None,
                "formatted":
                self.next_prestige.astimezone().strftime(DATETIME_FMT)
                if self.next_prestige else None
            },
            "next_randomized_prestige": {
                "datetime":
                str(self.next_randomized_prestige)
                if self.next_randomized_prestige else None,
                "formatted":
                self.next_randomized_prestige.astimezone().strftime(
                    DATETIME_FMT) if self.next_randomized_prestige else None
            },
            "next_stats_update": {
                "datetime":
                str(self.next_stats_update)
                if self.next_stats_update else None,
                "formatted":
                self.next_stats_update.astimezone().strftime(DATETIME_FMT)
                if self.next_stats_update else None
            },
            "next_daily_achievement_check": {
                "datetime":
                str(self.next_daily_achievement_check)
                if self.next_daily_achievement_check else None,
                "formatted":
                self.next_daily_achievement_check.astimezone().strftime(
                    DATETIME_FMT)
                if self.next_daily_achievement_check else None
            },
            "next_milestone_check": {
                "datetime":
                str(self.next_milestone_check)
                if self.next_milestone_check else None,
                "formatted":
                self.next_milestone_check.astimezone().strftime(DATETIME_FMT)
                if self.next_milestone_check else None
            },
            "next_raid_notifications_check": {
                "datetime":
                str(self.next_raid_notifications_check)
                if self.next_raid_notifications_check else None,
                "formatted":
                self.next_raid_notifications_check.astimezone().strftime(
                    DATETIME_FMT)
                if self.next_raid_notifications_check else None
            },
            "next_raid_attack_reset": {
                "datetime":
                str(self.next_raid_attack_reset)
                if self.next_raid_attack_reset else None,
                "formatted":
                self.next_raid_attack_reset.astimezone().strftime(DATETIME_FMT)
                if self.next_raid_attack_reset else None
            },
            "next_clan_results_parse": {
                "datetime":
                str(self.next_clan_results_parse)
                if self.next_clan_results_parse else None,
                "formatted":
                self.next_clan_results_parse.astimezone().strftime(
                    DATETIME_FMT) if self.next_clan_results_parse else None
            },
            "next_heavenly_strike": {
                "datetime":
                str(self.next_heavenly_strike)
                if self.next_heavenly_strike else None,
                "formatted":
                self.next_heavenly_strike.astimezone().strftime(DATETIME_FMT)
                if self.next_heavenly_strike else None
            },
            "next_deadly_strike": {
                "datetime":
                str(self.next_deadly_strike)
                if self.next_deadly_strike else None,
                "formatted":
                self.next_deadly_strike.astimezone().strftime(DATETIME_FMT)
                if self.next_deadly_strike else None
            },
            "next_hand_of_midas": {
                "datetime":
                str(self.next_hand_of_midas)
                if self.next_hand_of_midas else None,
                "formatted":
                self.next_hand_of_midas.astimezone().strftime(DATETIME_FMT)
                if self.next_hand_of_midas else None
            },
            "next_fire_sword": {
                "datetime":
                str(self.next_fire_sword) if self.next_fire_sword else None,
                "formatted":
                self.next_fire_sword.astimezone().strftime(DATETIME_FMT)
                if self.next_fire_sword else None
            },
            "next_war_cry": {
                "datetime":
                str(self.next_war_cry) if self.next_war_cry else None,
                "formatted":
                self.next_war_cry.astimezone().strftime(DATETIME_FMT)
                if self.next_war_cry else None
            },
            "next_shadow_clone": {
                "datetime":
                str(self.next_shadow_clone)
                if self.next_shadow_clone else None,
                "formatted":
                self.next_shadow_clone.astimezone().strftime(DATETIME_FMT)
                if self.next_shadow_clone else None
            },
            "next_break": {
                "datetime":
                str(self.next_break) if self.next_break else None,
                "formatted":
                self.next_break.astimezone().strftime(DATETIME_FMT)
                if self.next_break else None
            },
            "resume_from_break": {
                "datetime":
                str(self.resume_from_break)
                if self.resume_from_break else None,
                "formatted":
                self.resume_from_break.astimezone().strftime(DATETIME_FMT)
                if self.resume_from_break else None
            },
        }

        if self.session:
            dct["session"] = {
                "url": reverse('session', kwargs={"uuid": self.session.uuid}),
                "uuid": self.session.uuid
            }
        if self.configuration:
            dct["configuration"] = {
                "id":
                self.configuration.pk,
                "url":
                reverse("configuration", kwargs={"pk": self.configuration.pk}),
                "name":
                self.configuration.name
            }
        if self.window:
            dct["window"] = self.window
        if self.shortcuts:
            dct["shortcuts"] = self.shortcuts

        return dct
Ejemplo n.º 13
0
 def __str__(self):
     from titandash.utils import title
     return "Queued: {function}".format(function=title(self.function))
Ejemplo n.º 14
0
    def json(self, condense=False):
        """
        Return a JSON compliant dictionary for current configuration.

        Use the condense flag to ensure that foreign key or many to many fields are condensed into simple values.
        """
        from titandash.utils import title
        dct = {
            # RUNTIME.
            "Runtime": {
                "name": self.name,
                "soft_shutdown_on_critical_error": self.soft_shutdown_on_critical_error,
                "soft_shutdown_update_stats": self.soft_shutdown_update_stats,
                "post_action_min_wait_time": self.post_action_min_wait_time,
                "post_action_max_wait_time": self.post_action_max_wait_time
            },
            "Device": {
                "emulator": self.emulator
            },
            "Ad": {
                "enable_ad_collection": self.enable_ad_collection,
                "enable_premium_ad_collect": self.enable_premium_ad_collect,
            },
            "Generic": {
                "enable_egg_collection": self.enable_egg_collection,
                "enable_tapping": self.enable_tapping,
                "enable_tournaments": self.enable_tournaments
            },
            "Breaks": {
                "enable_breaks": self.enable_breaks,
                "breaks_jitter": self.breaks_jitter,
                "breaks_minutes_required": self.breaks_minutes_required,
                "breaks_minutes_max": self.breaks_minutes_max,
                "breaks_minutes_min": self.breaks_minutes_min
            },
            "Daily Achievement": {
                "enable_daily_achievements": self.enable_daily_achievements,
                "daily_achievements_check_on_start": self.daily_achievements_check_on_start,
                "daily_achievements_check_every_x_hours": self.daily_achievements_check_every_x_hours
            },
            "Raid Notifications": {
                "enable_raid_notifications": self.enable_raid_notifications,
                "raid_notifications_check_on_start": self.raid_notifications_check_on_start,
                "raid_notifications_check_every_x_minutes": self.raid_notifications_check_every_x_minutes,
                "raid_notifications_twilio_account_sid": self.raid_notifications_twilio_account_sid,
                "raid_notifications_twilio_auth_token": self.raid_notifications_twilio_auth_token,
                "raid_notifications_twilio_from_number": self.raid_notifications_twilio_from_number,
                "raid_notifications_twilio_to_number": self.raid_notifications_twilio_to_number
            },
            "General Actions": {
                "run_actions_every_x_seconds": self.run_actions_every_x_seconds,
                "run_actions_on_start": self.run_actions_on_start,
                "order_level_heroes": self.order_level_heroes,
                "order_level_master": self.order_level_master,
                "order_level_skills": self.order_level_skills
            },
            "Master Actions": {
                "enable_master": self.enable_master,
                "master_level_intensity": self.master_level_intensity
            },
            "Heroes": {
                "enable_heroes": self.enable_heroes,
                "hero_level_intensity": self.hero_level_intensity
            },
            "Skills": {
                "enable_skills": self.enable_skills,
                "activate_skills_on_start": self.activate_skills_on_start,
                "interval_heavenly_strike": self.interval_heavenly_strike,
                "interval_deadly_strike": self.interval_deadly_strike,
                "interval_hand_of_midas": self.interval_hand_of_midas,
                "interval_fire_sword": self.interval_fire_sword,
                "interval_war_cry": self.interval_war_cry,
                "interval_shadow_clone": self.interval_shadow_clone,
                "force_enabled_skills_wait": self.force_enabled_skills_wait,
                "max_skill_if_possible": self.max_skill_if_possible,
                "skill_level_intensity": self.skill_level_intensity
            },
            "Prestige Action": {
                "enable_auto_prestige": self.enable_auto_prestige,
                "prestige_x_minutes": self.prestige_x_minutes,
                "prestige_at_stage": self.prestige_at_stage,
                "prestige_at_max_stage": self.prestige_at_max_stage,
                "prestige_at_max_stage_percent": self.prestige_at_max_stage_percent
            },
            "Artifacts Action": {
                "enable_artifact_discover_enchant": self.enable_artifact_discover_enchant,
                "enable_artifact_purchase": self.enable_artifact_purchase,
                "upgrade_owned_tier": [tier.json() for tier in self.upgrade_owned_tier.all()],
                "shuffle_artifacts": self.shuffle_artifacts,
                "ignore_artifacts": [art.json() for art in self.ignore_artifacts.all()],
                "upgrade_artifacts": [art.json() for art in self.upgrade_artifacts.all()]
            },
            "Stats": {
                "enable_stats": self.enable_stats,
                "update_stats_on_start": self.update_stats_on_start,
                "update_stats_every_x_minutes": self.update_stats_every_x_minutes
            },
            "Raid Parsing": {
                "enable_clan_results_parse": self.enable_clan_results_parse,
                "parse_clan_results_on_start": self.parse_clan_results_on_start,
                "parse_clan_results_every_x_minutes": self.parse_clan_results_every_x_minutes
            },
            "Recovery": {
                "recovery_check_interval_minutes": self.recovery_check_interval_minutes,
                "recovery_allowed_failures": self.recovery_allowed_failures
            },
            "Logging": {
                "enable_logging": self.enable_logging,
                "logging_level": self.logging_level
            }
        }

        if condense:
            dct["Artifacts Action"]["upgrade_owned_tier"] = ", ".join([title(t.name) for t in self.upgrade_owned_tier.all()])
            dct["Artifacts Action"]["ignore_artifacts"] = ", ".join([title(a.name) for a in self.ignore_artifacts.all()])
            dct["Artifacts Action"]["upgrade_artifacts"] = ", ".join([title(a.name) for a in self.upgrade_artifacts.all()])

        return dct