Merge pull request #100 from ThommyH/seperate_user_in_ABC

Seperate user in groups for experiment in OOP2017
This commit is contained in:
rteusner
2017-03-24 15:42:13 +01:00
committed by GitHub
5 changed files with 131 additions and 85 deletions

View File

@ -323,9 +323,7 @@ configureEditors: function () {
var button = $('#requestComments'); var button = $('#requestComments');
button.prop('disabled', true); button.prop('disabled', true);
button.on('click', function () { button.on('click', function () {
if ($('#editor').data('show-interventions') == true){ $('#rfc_intervention_text').hide()
$('#rfc_intervention_text').hide()
}
$('#comment-modal').modal('show'); $('#comment-modal').modal('show');
}); });
@ -578,64 +576,63 @@ configureEditors: function () {
* interventions * interventions
* */ * */
initializeInterventionTimer: function() { initializeInterventionTimer: function() {
$.ajax({ if ($('#editor').data('rfc-interventions') == true || $('#editor').data('break-interventions') == true) { // split in break or rfc intervention
data: { $.ajax({
exercise_id: $('#editor').data('exercise-id'), data: {
user_id: $('#editor').data('user-id') exercise_id: $('#editor').data('exercise-id'),
}, user_id: $('#editor').data('user-id')
dataType: 'json', },
method: 'GET', dataType: 'json',
// get working times for this exercise method: 'GET',
url: $('#editor').data('working-times-url'), // get working times for this exercise
success: function (data) { url: $('#editor').data('working-times-url'),
var percentile75 = data['working_time_75_percentile']; success: function (data) {
var accumulatedWorkTimeUser = data['working_time_accumulated']; var percentile75 = data['working_time_75_percentile'];
var accumulatedWorkTimeUser = data['working_time_accumulated'];
var timeUntilBreak = 20 * 60 * 1000; var minTimeIntervention = 10 * 60 * 1000;
var minTimeUntilAskQuestion = 15 * 60 * 1000;
if ((accumulatedWorkTimeUser - percentile75) > 0) { if ((accumulatedWorkTimeUser - percentile75) > 0) {
// working time is already over 75 percentile // working time is already over 75 percentile
var timeUntilAskQuestion = minTimeUntilAskQuestion; var timeUntilIntervention = minTimeIntervention;
} else { } else {
// working time is less than 75 percentile // working time is less than 75 percentile
// ensure we give user at least 10 minutes before we bother the user // ensure we give user at least minTimeIntervention before we bother the user
var timeUntilAskForRFC = (percentile75 - accumulatedWorkTimeUser) > minTimeUntilAskQuestion ? (percentile75 - accumulatedWorkTimeUser) : minTimeUntilAskQuestion; var timeUntilIntervention = Math.max(percentile75 - accumulatedWorkTimeUser, minTimeIntervention);
}
if ($('#editor').data('break-interventions')){
setTimeout(function () {
$('#break-intervention-modal').modal('show');
$.ajax({
data: {
intervention_type: 'BreakIntervention'
},
dataType: 'json',
type: 'POST',
url: $('#editor').data('intervention-save-url')
});
}, timeUntilIntervention);
} else if ($('#editor').data('rfc-interventions')) {
setTimeout(function () {
var button = $('#requestComments');
// only show intervention if user did not requested for a comment already
if (!button.prop('disabled')) {
$('#rfc_intervention_text').show();
$('#comment-modal').modal('show');
$.ajax({
data: {
intervention_type: 'QuestionIntervention'
},
dataType: 'json',
type: 'POST',
url: $('#editor').data('intervention-save-url')
});
};
}, timeUntilIntervention);
}
} }
});
// if notifications are too close to each other, ensure some time differences between them }
if (Math.abs(timeUntilAskForRFC - timeUntilBreak) < 5 * 1000 * 60){
timeUntilBreak = timeUntilBreak * 2;
}
setTimeout(function() {
$('#break-intervention-modal').modal('show');
$.ajax({
data: {
intervention_type: 'BreakIntervention'
},
dataType: 'json',
type: 'POST',
url: $('#editor').data('intervention-save-url')});
}, timeUntilBreak);
setTimeout(function() {
var button = $('#requestComments');
if (!button.prop('disabled')){
$('#rfc_intervention_text').show();
$('#comment-modal').modal('show');
$.ajax({
data: {
intervention_type: 'QuestionIntervention'
},
dataType: 'json',
type: 'POST',
url: $('#editor').data('intervention-save-url')});
};
}, timeUntilAskForRFC);
}
});
}, },
initializeSearchButton: function(){ initializeSearchButton: function(){
@ -671,9 +668,7 @@ configureEditors: function () {
this.initializeDescriptionToggle(); this.initializeDescriptionToggle();
this.initializeSideBarTooltips(); this.initializeSideBarTooltips();
this.initializeTooltips(); this.initializeTooltips();
if ($('#editor').data('show-interventions') == true){ this.initializeInterventionTimer();
this.initializeInterventionTimer();
}
this.initializeSearchButton(); this.initializeSearchButton();
this.initPrompt(); this.initPrompt();
this.renderScore(); this.renderScore();

View File

@ -21,7 +21,7 @@ class ExercisesController < ApplicationController
private :authorize! private :authorize!
def max_intervention_count def max_intervention_count
3 2
end end
@ -168,7 +168,15 @@ class ExercisesController < ApplicationController
user_got_enough_interventions = UserExerciseIntervention.where(exercise: @exercise, user: current_user).count >= max_intervention_count user_got_enough_interventions = UserExerciseIntervention.where(exercise: @exercise, user: current_user).count >= max_intervention_count
is_java_course = @course_token && @course_token.eql?(java_course_token) is_java_course = @course_token && @course_token.eql?(java_course_token)
@show_interventions = (!is_java_course || user_got_enough_interventions) ? "false" : "true" user_intervention_group = UserGroupSeparator.getInterventionGroup(current_user)
case user_intervention_group
when :no_intervention
when :break_intervention
@show_break_interventions = (!is_java_course || user_got_enough_interventions) ? "false" : "true"
when :rfc_intervention
@show_rfc_interventions = (!is_java_course || user_got_enough_interventions) ? "false" : "true"
end
@search = Search.new @search = Search.new
@search.exercise = @exercise @search.exercise = @exercise

View File

@ -53,28 +53,43 @@ class ProxyExercise < ActiveRecord::Base
end end
def find_matching_exercise(user) def find_matching_exercise(user)
exercises_user_has_accessed = user.submissions.where("cause IN ('submit','assess')").map{|s| s.exercise}.uniq user_group = UserGroupSeparator.getProxyExerciseGroup(user)
tags_user_has_seen = exercises_user_has_accessed.map{|ex| ex.tags}.uniq.flatten case user_group
Rails.logger.debug("exercises_user_has_accessed #{exercises_user_has_accessed.map{|e|e.id}.join(",")}") when :dummy_assigment
rec_ex = select_easiest_exercise(exercises)
@reason[:reason] = "dummy group"
Rails.logger.debug("assigned user to dummy group, and gave him exercise: #{rec_ex.title}")
rec_ex
when :random_assigment
@reason[:reason] = "random group"
rec_ex = exercises.shuffle.first
Rails.logger.debug("assigned user to random group, and gave him exercise: #{rec_ex.title}")
rec_ex
when :recommended_assignment
exercises_user_has_accessed = user.submissions.where("cause IN ('submit','assess')").map{|s| s.exercise}.uniq.compact
tags_user_has_seen = exercises_user_has_accessed.map{|ex| ex.tags}.uniq.flatten
Rails.logger.debug("exercises_user_has_accessed #{exercises_user_has_accessed.map{|e|e.id}.join(",")}")
# find execises # find execises
potential_recommended_exercises = [] potential_recommended_exercises = []
exercises.each do |ex| exercises.each do |ex|
## find exercises which have only tags the user has already seen ## find exercises which have only tags the user has already seen
if (ex.tags - tags_user_has_seen).empty? if (ex.tags - tags_user_has_seen).empty?
potential_recommended_exercises << ex potential_recommended_exercises << ex
end end
end end
Rails.logger.debug("potential_recommended_exercises: #{potential_recommended_exercises.map{|e|e.id}}") Rails.logger.debug("potential_recommended_exercises: #{potential_recommended_exercises.map{|e|e.id}}")
# if all exercises contain tags which the user has never seen, recommend easiest exercise # if all exercises contain tags which the user has never seen, recommend easiest exercise
if potential_recommended_exercises.empty? if potential_recommended_exercises.empty?
Rails.logger.debug("matched easiest exercise in pool") Rails.logger.debug("matched easiest exercise in pool")
@reason[:reason] = "easiest exercise in pool. empty potential exercises" @reason[:reason] = "easiest exercise in pool. empty potential exercises"
select_easiest_exercise(exercises) select_easiest_exercise(exercises)
else else
recommended_exercise = select_best_matching_exercise(user, exercises_user_has_accessed, potential_recommended_exercises) recommended_exercise = select_best_matching_exercise(user, exercises_user_has_accessed, potential_recommended_exercises)
recommended_exercise recommended_exercise
end
end end
end end
private :find_matching_exercise private :find_matching_exercise

View File

@ -1,8 +1,9 @@
- external_user_external_id = @current_user.respond_to?(:external_id) ? @current_user.external_id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '') - external_user_external_id = @current_user.respond_to?(:external_id) ? @current_user.external_id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '')
- external_user_id = @current_user.respond_to?(:external_id) ? @current_user.id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '') - external_user_id = @current_user.respond_to?(:external_id) ? @current_user.id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '')
- consumer_id = @current_user.respond_to?(:external_id) ? @current_user.consumer_id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '') - consumer_id = @current_user.respond_to?(:external_id) ? @current_user.consumer_id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '')
- show_interventions = @show_interventions || "false" - show_break_interventions = @show_break_interventions || "false"
#editor.row data-exercise-id=exercise.id data-message-depleted=t('exercises.editor.depleted') data-message-timeout=t('exercises.editor.timeout', permitted_execution_time: @exercise.execution_environment.permitted_execution_time) data-errors-url=execution_environment_errors_path(exercise.execution_environment) data-submissions-url=submissions_path data-user-id=@current_user.id data-user-external-id=external_user_external_id data-working-times-url=working_times_exercise_path data-intervention-save-url=intervention_exercise_path data-show-interventions=show_interventions data-course_token=@course_token data-search-save-url=search_exercise_path - show_rfc_interventions = @show_rfc_interventions || "false"
#editor.row data-exercise-id=exercise.id data-message-depleted=t('exercises.editor.depleted') data-message-timeout=t('exercises.editor.timeout', permitted_execution_time: @exercise.execution_environment.permitted_execution_time) data-errors-url=execution_environment_errors_path(exercise.execution_environment) data-submissions-url=submissions_path data-user-id=@current_user.id data-user-external-id=external_user_external_id data-working-times-url=working_times_exercise_path data-intervention-save-url=intervention_exercise_path data-rfc-interventions=show_rfc_interventions data-break-interventions=show_break_interventions data-course_token=@course_token data-search-save-url=search_exercise_path
div id="sidebar" class=(@exercise.hide_file_tree ? 'sidebar-col-collapsed' : 'sidebar-col') = render('editor_file_tree', exercise: @exercise, files: @files) div id="sidebar" class=(@exercise.hide_file_tree ? 'sidebar-col-collapsed' : 'sidebar-col') = render('editor_file_tree', exercise: @exercise, files: @files)
div id='output_sidebar' class='output-col-collapsed' = render('exercises/editor_output', external_user_id: external_user_id, consumer_id: consumer_id ) div id='output_sidebar' class='output-col-collapsed' = render('exercises/editor_output', external_user_id: external_user_id, consumer_id: consumer_id )
div id='frames' class='editor-col' div id='frames' class='editor-col'

View File

@ -0,0 +1,27 @@
class UserGroupSeparator
# seperates user into 30% no intervention, 30% break intervention, 40% rfc intervention
def self.getInterventionGroup(user)
lastDigitId = user.id % 10
if lastDigitId < 3 # 0,1,2
:no_intervention
elsif lastDigitId < 6 # 3,4,5
:break_intervention
else # 6,7,8,9
:rfc_intervention
end
end
# seperates user into 20% dummy assignment, 20% random assignemnt, 60% recommended assignment
def self.getProxyExerciseGroup(user)
lastDigitCreatedAt = user.created_at.to_i % 10
if lastDigitCreatedAt < 2 # 0,1
:dummy_assigment
elsif lastDigitCreatedAt < 4 # 2,3
:random_assigment
else # 4,5,6,7,8,9
:recommended_assignment
end
end
end