diff --git a/task_api.py b/task_api.py index 2629e62..cc6935c 100644 --- a/task_api.py +++ b/task_api.py @@ -99,6 +99,7 @@ def apiv2_get_user_profile(user: UserDatabaseObject): 'username': user.username, 'is_official': user.is_official, 'is_lms_enabled': user.lms_enabled, + 'hide_below': user.effective_hide_below, 'has_migrated': user.has_migrated, 'active_task_id': user.current_task_id(), 'completed_tasks': [ diff --git a/task_database.py b/task_database.py index 6b576b2..80ea2bb 100644 --- a/task_database.py +++ b/task_database.py @@ -95,6 +95,7 @@ def add_task_account(username, is_official, lms_enabled): "username": str(username), "isOfficial": bool(is_official), "lmsEnabled": bool(lms_enabled), + "hideBelow": 'easy', "discordLinked": False, "discordNameSyncEnabled": False, "completedTasks": [], @@ -494,6 +495,27 @@ def get_first_task_instance(generated_task: TaskData, incomplete_tasks: list[Tas __set_current_task(username, f'{tier}Tasks', first_task_instance.id, True) return first_task_instance + +def set_hide_below(username: str, hide_below: str) -> None: + if hide_below not in user_dao.ROLLABLE_TIERS: + raise ValueError(f"Invalid minimum rollable tier: {hide_below}") + + result = mydb['taskLists'].update_one( + {'username': username, 'isOfficial': False}, + {'$set': {'hideBelow': hide_below}} + ) + if result.matched_count == 0: + user = mydb['taskLists'].find_one( + {'username': username}, + {'_id': 0, 'isOfficial': 1} + ) + if user is None: + raise LookupError(f"No task account found for username {username}") + if user.get('isOfficial', False): + raise PermissionError("Hide Tasks Below is only available for unofficial accounts.") + raise LookupError(f"Could not update task account for username {username}") + + # If user has just completed a task of the given tier and the progress is 100, then they've just completed the last task def __get_firework_variables(username, tier): user = get_user(username) diff --git a/taskapp.py b/taskapp.py index dcedfa4..d7c9e27 100644 --- a/taskapp.py +++ b/taskapp.py @@ -13,7 +13,8 @@ get_lms_status, lms_status_change, update_imported_tasks, official_status_change, username_change, get_taskCurrent_tier, generate_task_for_tier, complete_task_unofficial_tier, get_user, get_leaderboard, - get_roll_candidates_for_tier, get_discord_name_sync_enabled, clear_leaderboard_cache) + get_roll_candidates_for_tier, get_discord_name_sync_enabled, clear_leaderboard_cache, + set_hide_below) import send_grid_email from templesync import check_logs, temple_player_data, import_logs from task_types import CollectionLogVerificationData @@ -22,6 +23,7 @@ import task_api import discord_api import command_api +from user_dao import ROLLABLE_TIERS ''' @@ -1083,6 +1085,8 @@ def profile(): email_val=user_info.email_val, official=user_info.official, lms_status=user_info.user.lms_enabled, + hide_below=user_info.user.hide_below, + rollable_tiers=ROLLABLE_TIERS, discord_status=user_info.user.discord_linked, discord_default_username=discord_default_username, discord_name_sync_enabled=user_info.user.discord_name_sync_enabled, @@ -1142,6 +1146,26 @@ def change_lms_status(): lms_status_change(username, data) return {'success' : True} + +@app.route("/profile/change-hide-below/", methods=['POST']) +@login_required +def change_hide_below(): + user = get_user(session['username']) + if user.is_official: + return {'success': False, 'error': 'Hide Tasks Below is only available for unofficial accounts.'}, 403 + + hide_below = request.form.get('hide_below') + if hide_below not in ROLLABLE_TIERS: + return {'success': False, 'error': 'Invalid minimum task tier.'}, 400 + + try: + set_hide_below(session['username'], hide_below) + except PermissionError as error: + return {'success': False, 'error': str(error)}, 403 + + return {'success': True} + + # AJAX route to change offical status @app.route("/profile/change-official/", methods=['POST']) @login_required diff --git a/templates/profile.html b/templates/profile.html index 0841556..9c3ef0b 100644 --- a/templates/profile.html +++ b/templates/profile.html @@ -82,6 +82,14 @@

{{username}} Profile

+ {% if not official %} +

Hide Tasks Below

+ + {% endif %}
@@ -366,7 +374,21 @@

Discord Settings

}); } - + $('#hide_below').on('change', function() { + const hideBelow = $(this).val(); + $.ajax({ + url: '/profile/change-hide-below/', + type: 'POST', + data: {hide_below: hideBelow} + }).done(function(data) { + if (!data.success) { + alert(data.error || 'Could not update the minimum task tier.'); + } + }).fail(function() { + alert('Could not update the minimum task tier.'); + }); + }); + $('#discord_name_sync_enabled').on('change', function(e) { var discord_name_sync_enabled = e.target.checked; req = $.ajax({ @@ -418,5 +440,3 @@

Discord Settings

}); {% endblock%} - - diff --git a/user_dao.py b/user_dao.py index 20b4bc5..6571fa6 100644 --- a/user_dao.py +++ b/user_dao.py @@ -30,6 +30,7 @@ "5cbcc790-10d1-4c17-8b39-cad7b48dadf8", "4a387bb0-dfc3-4374-aa35-9bacfc2fc92d", } +ROLLABLE_TIERS = ('easy', 'medium', 'hard', 'elite', 'master') @dataclass class UserDatabaseObject: @@ -37,6 +38,7 @@ class UserDatabaseObject: username: str is_official: bool lms_enabled: bool + hide_below: str discord_linked: bool discord_name_sync_enabled: bool has_migrated: bool @@ -99,14 +101,23 @@ def current_tier(self) -> str: else: return None - def current_rollable_tier(self) -> str | None: - for tier in ['easy', 'medium', 'hard', 'elite', 'master']: + def current_rollable_tier(self) -> str | None: + hide_below = self.effective_hide_below + if hide_below not in ROLLABLE_TIERS: + raise ValueError(f"Invalid minimum rollable tier: {hide_below}") + + first_tier_index = ROLLABLE_TIERS.index(hide_below) + for tier in ROLLABLE_TIERS[first_tier_index:]: tasks = self.get_incomplete_tasks(tier) if len(tasks) != 0: return tier return None + @property + def effective_hide_below(self) -> str: + return self.hide_below if not self.is_official else ROLLABLE_TIERS[0] + def get_incomplete_tasks(self, tier: str) -> list[TaskData]: all_tasks = tasklists.list_for_tier(tier, self.lms_enabled) completed_task_ids = list(map(lambda x: x.id, self.get_task_list(tier).completed_tasks)) @@ -252,6 +263,9 @@ def task_info_for_id(task_list: list[TaskData], task_id: str) -> tasklists.TaskD def convert_database_user(user_data: dict) -> UserDatabaseObject: tiers = user_data['tiers'] lms_enabled = user_data.get('lmsEnabled', False) + hide_below = user_data.get('hideBelow', 'easy') + if hide_below not in ROLLABLE_TIERS: + raise ValueError(f"Invalid stored minimum rollable tier: {hide_below}") def to_item_ids(value) -> list[int]: if not isinstance(value, list): @@ -343,6 +357,7 @@ def convert_database_tier(tier: str) -> UserTaskList: username=user_data['username'], is_official=user_data['isOfficial'], lms_enabled=user_data['lmsEnabled'], + hide_below=hide_below, has_migrated=user_data.get('hasMigrated', False), discord_linked=user_data.get('discordLinked', False), discord_name_sync_enabled=user_data.get('discordNameSyncEnabled', False),