New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix time spent on bubble choice = sum of sub-level time spent #40117
Fix time spent on bubble choice = sum of sub-level time spent #40117
Conversation
@@ -342,41 +342,6 @@ def section_level_progress | |||
} | |||
end | |||
|
|||
# Get level progress for a set of users within this script. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to users_helper
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
46705c3
to
5c3f09f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not quite done yet but sending out some questions before a long stretch of meetings.
This is an excellent improvement! One of the things I've been wondering about is how to structure all the special-case logic for calculating progress for different level types and this change really helps reveal some of the structure here.
completion_status = activity_css_class(user_level) | ||
locked = user_level.try(:show_as_locked?, script_level.lesson) || script_level.lesson.lockable? && !user_level | ||
|
||
# if the level has not been tried, less progress data is necessary |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you elaborate a bit more on why we need a special case for not_tried
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup! So if a level status is not tried there are two possible things that happen:
- If it's not locked we don't merge any progress for that level
- If it is locked then we merge only
status
andlocked
state for the progress for that level
In either one of those cases we don't need a full set of progress data so we return just what we need. I'll update the comment and try to make it more clear.
readonly_answers: !!user_level.try(:readonly_answers) || nil, | ||
paired: (paired_user_levels.include? user_level.try(:id)) || nil, | ||
last_progress_at: include_timestamp ? user_level&.updated_at&.to_i : nil, | ||
time_spent: user_level&.time_spent&.to_i |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are .try
and &.
equivalent? If so, maybe we can be more consistent about using one or the other, at least within a function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually had to look this up. So it sounds like the main difference is that using try, if a method is called that doesn't exist for the object then it will swallow the NoMethodError
and return nil. I think moving towards &
seems like the right call here. I'll update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL! thanks for that distinction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay so turns out Free Response levels have a peer_reviewable
method but other types of levels don't so that's a valid use of try
that I'll need to leave there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Nicely done!
@@ -342,41 +342,6 @@ def section_level_progress | |||
} | |||
end | |||
|
|||
# Get level progress for a set of users within this script. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
@@ -160,6 +195,8 @@ def user_summary(user) | |||
# this in advance for many users in some use cases. | |||
# @param [Enumerable<Integer>] paired_user_levels | |||
# A collection of UserLevel ids where the user was pairing. | |||
# @param [Boolean] include_timestamp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are there any cases where we don't pass true
for this? i can't think of a use case for that. if we're not using it, let's remove it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
true
isn't passed in here https://github.com/code-dot-org/code-dot-org/blob/staging/dashboard/app/helpers/users_helper.rb#L143
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmmm. i find that questionable. from a brief inspection it looks like we only include that data for the teacher dashboard, but i can't think of a reason for that. it doesn't require any extra db queries and would result in very minor data bloat, so imo it would be worth the reduction in complexity to remove it. could you try to find out if there's a specific reason we're excluding it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree we should investigate, going to punt this for now to avoid increasing the scope of this ticket
}.compact | ||
end | ||
end | ||
end | ||
progress | ||
end | ||
|
||
# Summarizes a user's level progress for bubble choice level (parent level and sublevels) | ||
private def get_bubble_choice_progress(level, user, user_levels_by_level, script_level, paired_user_levels, include_timestamp) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: in terms of figuring out how this code works, imo get_level_progress
should come before this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that said, i do think factoring this out into its own helper function really improves the readability of merge_user_progress_by_level
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll move it down!
Links
Testing story
Added unit tests and manually tested a bubble choice by adding progress on multiple choice levels, then checking time spent in the progress table.
Deployment strategy
Follow-up work
Privacy
Security
Caching
PR Checklist: