virtualcommons-developer Mailing List for Virtual Commons Experiment Software (Page 2)
Status: Beta
Brought to you by:
alllee
You can subscribe to this list here.
2011 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(103) |
Jul
(85) |
Aug
(229) |
Sep
(70) |
Oct
(12) |
Nov
(16) |
Dec
(25) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2012 |
Jan
(41) |
Feb
(66) |
Mar
(150) |
Apr
(148) |
May
(109) |
Jun
(8) |
Jul
(20) |
Aug
(20) |
Sep
(16) |
Oct
(13) |
Nov
(58) |
Dec
(22) |
2013 |
Jan
(41) |
Feb
(108) |
Mar
(152) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <com...@bi...> - 2013-03-26 08:42:10
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/e1c60488c39b/ Changeset: e1c60488c39b User: alllee Date: 2013-03-26 09:41:57 Summary: working on client-side logic for disabling form / chat components and adding player status to the view model Affected #: 3 files diff -r 43d6889919a6ba860f22a16cb0807afd9a82e48f -r e1c60488c39b6e7bbd4f6ff568e187ab863d7c32 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -292,6 +292,9 @@ cost_of_living = get_cost_of_living(round_data.round_configuration) for pgr in experiment.participant_group_relationships: player_status_dv = get_player_status_dv(pgr, round_data) + player_alive = player_status_dv.boolean_value + if not player_alive: + continue harvest_decision = get_harvest_decision(pgr, round_data) storage_dv = get_storage_dv(pgr, round_data) updated_storage = storage_dv.int_value + harvest_decision - cost_of_living diff -r 43d6889919a6ba860f22a16cb0807afd9a82e48f -r e1c60488c39b6e7bbd4f6ff568e187ab863d7c32 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -424,34 +424,33 @@ return model.resourcesToDisplay() * 30 + "px"; }); model.resourceImageHeight = ko.observable("79px"); - model.startChatTimer = function() { + model.startRound = function() { model.enableChat(); + model.setFormDisabled(true); model.secondsLeft(60); model.setCurrentInterval( setInterval(function() { model.tick(); + if (model.secondsLeft() == 30) { + model.setFormDisabled(false); + } if (! model.isTimerRunning()) { + model.submitDecision(); model.disableChat(); model.clearCurrentInterval(); } }, 1000)); }; - model.startHarvestDecisionTimer = function() { - model.secondsLeft(10); - model.setCurrentInterval(setInterval(function() { - model.tick(); - if (! model.isTimerRunning()) { - model.submitDecision(); - model.clearCurrentInterval(); - } - }, - 1000)); - }; + model.setFormDisabled = function(toggle) { + // disable all form inputs + $('#vcweb-form :input').attr("disabled", toggle); + } model.submitDecision = function(data, evt) { if (evt) { evt.preventDefault(); } + model.setFormDisabled(true); var formData = $('#vcweb-form').serialize(); $.post('submit-harvest-decision', formData, function(jsonString) { console.log(jsonString); diff -r 43d6889919a6ba860f22a16cb0807afd9a82e48f -r e1c60488c39b6e7bbd4f6ff568e187ab863d7c32 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -9,9 +9,9 @@ from vcweb.boundaries.forms import HarvestDecisionForm from vcweb.boundaries.models import (get_experiment_metadata, get_regrowth_rate, get_harvest_decision_parameter, get_cost_of_living, get_resource_level, get_initial_resource_level, get_total_storage, get_storage, - get_last_harvest_decision, set_harvest_decision, can_observe_other_group) + get_last_harvest_decision, set_harvest_decision, can_observe_other_group, get_player_status) + import logging - logger = logging.getLogger(__name__) @participant_required @@ -93,12 +93,14 @@ experiment_model_dict['playerData'] = [{ 'id': pgr.participant_number, 'lastHarvestDecision': get_last_harvest_decision(pgr, round_data=previous_round_data), + 'alive': get_player_status(pgr, current_round_data), 'storage': get_storage(pgr, current_round_data), } for pgr in own_group.participant_group_relationship_set.all()] # FIXME: redundancy with playerData experiment_model_dict['lastHarvestDecision'] = last_harvest_decision experiment_model_dict['storage'] = get_storage(participant_group_relationship, current_round_data) experiment_model_dict['resourceLevel'] = own_resource_level + experiment_model_dict['alive'] = get_player_status(participant_group_relationship, current_round_data) # participant group data parameters are only needed if this round is a data round or the previous round was a data round if previous_round.is_playable_round or current_round.is_playable_round: experiment_model_dict['chatMessages'] = [{ Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-26 07:58:42
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/43d6889919a6/ Changeset: 43d6889919a6 User: alllee Date: 2013-03-26 08:55:59 Summary: fixing typo bugs in ParticipantGroupRelationship.copy_to_next_round and changing KO participantReady function to refer to the ko model instead of the template variable otherwise deactivating / reactivating an experiment will cause connected participants to 404 as they update. Affected #: 6 files diff -r 21e94d0241082db760e07fd098b9be814051a534 -r 43d6889919a6ba860f22a16cb0807afd9a82e48f vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -231,7 +231,7 @@ # FIXME: would be nicer to extend Group behavior and have group.get_total_harvest() instead of # get_total_harvest(group, ...) total_harvest = get_total_harvest(group, round_data) - logger.debug("total harvest for playable round: %d", total_harvest) + logger.debug("Harvest: total group harvest for playable round: %s", total_harvest) if current_resource_level > 0 and total_harvest > 0: if total_harvest > current_resource_level: # divide remaining trees evenly among every participant @@ -285,6 +285,7 @@ shared_resource_level_dv.save() if experiment.has_next_round: ''' transfer shared resource levels to next round ''' + group.log("Transferring shared resource level %s to next round" % current_resource_level_dv.int_value) group_cluster.copy_to_next_round(shared_resource_level_dv) def update_participants(experiment, round_data): @@ -292,14 +293,17 @@ for pgr in experiment.participant_group_relationships: player_status_dv = get_player_status_dv(pgr, round_data) harvest_decision = get_harvest_decision(pgr, round_data) - existing_storage = get_storage(pgr, round_data) - updated_storage = existing_storage + harvest_decision - cost_of_living + storage_dv = get_storage_dv(pgr, round_data) + updated_storage = storage_dv.int_value + harvest_decision - cost_of_living if updated_storage < 0: # player has "died" player_status_dv.boolean_value = False player_status_dv.save() - - set_storage(pgr, round_data, updated_storage) + storage_dv.int_value = updated_storage + storage_dv.save() + logger.debug("updating participant %s (storage: %s, harvest: %s, status: %s)", pgr, storage_dv.int_value, + harvest_decision, player_status_dv.boolean_value) + pgr.copy_to_next_round(player_status_dv, storage_dv) @receiver(signals.round_ended, sender=EXPERIMENT_METADATA_NAME) def round_ended_handler(sender, experiment=None, **kwargs): @@ -312,7 +316,10 @@ logger.debug("ending boundaries round: %s", round_configuration) if round_configuration.is_playable_round: regrowth_rate = get_regrowth_rate(round_configuration) -# FIXME: generify and merge update_shared_resource_level and update_resource_level to operate on "group-like" objects + # zero out unsubmitted harvest decisions + ParticipantRoundDataValue.objects.filter(round_data=round_data, parameter=get_harvest_decision_parameter(), + submitted=False).update(int_value=0) + # FIXME: generify and merge update_shared_resource_level and update_resource_level to operate on "group-like" objects if possible if is_shared_resource_enabled(round_configuration): for group_cluster in GroupCluster.objects.for_experiment(experiment, session_id=round_configuration.session_id): diff -r 21e94d0241082db760e07fd098b9be814051a534 -r 43d6889919a6ba860f22a16cb0807afd9a82e48f vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -395,7 +395,7 @@ model.roundType("TREATMENT_INSTRUCTIONS"); } model.participantReady = function() { - $.post('/experiment/participant-ready', { participant_group_id: {{ participant_group_relationship.pk }} }, function(response) { + $.post('/experiment/participant-ready', { participant_group_id: model.participantGroupId() }, function(response) { console.debug("successfully posted to server, notifying sockjs"); console.debug(response); getWebSocket().send(createMessageEvent("Participant finished reading instructions", "client_ready")); diff -r 21e94d0241082db760e07fd098b9be814051a534 -r 43d6889919a6ba860f22a16cb0807afd9a82e48f vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -41,7 +41,7 @@ participant_group_id = form.cleaned_data['participant_group_id'] pgr = get_object_or_404(ParticipantGroupRelationship, pk=participant_group_id) harvest_decision = form.cleaned_data['harvest_decision'] - set_harvest_decision(pgr, harvest_decision, experiment.current_round_data) + set_harvest_decision(pgr, harvest_decision, experiment.current_round_data, submitted=True) return JsonResponse(dumps({ 'success': True, 'experimentModelJson': get_view_model_json(experiment, pgr)})) for field in form: if field.errors: diff -r 21e94d0241082db760e07fd098b9be814051a534 -r 43d6889919a6ba860f22a16cb0807afd9a82e48f vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -1321,6 +1321,7 @@ converted_value = self.parameter.convert(obj) setattr(self, self.parameter.value_field_name, converted_value) + def to_dict(self, cacheable=False, **kwargs): p = self.parameter data = {'pk' : self.pk, @@ -1606,20 +1607,19 @@ gcdv.value = value gcdv.save() - def copy_to_next_round(self, data_value): + def copy_to_next_round(self, *data_values): e = self.experiment if e.is_last_round: - logger.error("Trying to transfer data value %s past the last round of the experiment", - data_value) - return None - parameter = data_value.parameter - value = data_value.value - next_round_data, created = RoundData.objects.get_or_create(experiment=e, round_configuration=e.next_round) - gcdv, created = GroupClusterDataValue.objects.get_or_create(group=self, round_data=next_round_data, parameter=parameter) - logger.debug("transferred group cluster data value: %s (%s)", gcdv, created) - gcdv.value = value - gcdv.save() - return gcdv + logger.error("Trying to transfer data values %s past the last round of the experiment, aborting", + data_values) + else: + next_round_data, created = RoundData.objects.get_or_create(experiment=e, round_configuration=e.next_round) + for data_value in data_values: + parameter = data_value.parameter + gcdv, created = GroupClusterDataValue.objects.get_or_create(group=self, round_data=next_round_data, parameter=parameter) + logger.debug("transferred group cluster data value: %s (%s)", gcdv, created) + gcdv.value = data_value.value + gcdv.save() def __unicode__(self): return u"group cluster %s (%s)" % (self.name, self.experiment) @@ -1854,6 +1854,16 @@ else: logger.warning("Unable to set data value %s on round data %s for %s", value, round_data, parameter) + def copy_to_next_round(self, *data_values): + e = self.experiment + next_round_data, created = RoundData.objects.get_or_create(experiment=e, round_configuration=e.next_round) + for existing_dv in data_values: + parameter = existing_dv.parameter + new_dv, created = ParticipantRoundDataValue.objects.get_or_create(participant_group_relationship=self, + round_data=next_round_data, parameter=parameter) + new_dv.value = existing_dv.value + new_dv.save() + def __unicode__(self): return u"{0}: #{1} (in {2})".format(self.participant, self.participant_number, self.group) diff -r 21e94d0241082db760e07fd098b9be814051a534 -r 43d6889919a6ba860f22a16cb0807afd9a82e48f vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -540,7 +540,9 @@ def participant_ready(request): form = ParticipantGroupIdForm(request.POST or None) if form.is_valid(): - pgr = get_object_or_404(ParticipantGroupRelationship.objects.select_related('group__experiment'), pk=form.cleaned_data['participant_group_id']) + participant_group_id = form.cleaned_data.get('participant_group_id') + pgr = get_object_or_404(ParticipantGroupRelationship.objects.select_related('group__experiment'), + pk=participant_group_id) experiment = pgr.group.experiment round_data = experiment.current_round_data prdv = ParticipantRoundDataValue.objects.get(participant_group_relationship=pgr, diff -r 21e94d0241082db760e07fd098b9be814051a534 -r 43d6889919a6ba860f22a16cb0807afd9a82e48f vcweb/forestry/models.py --- a/vcweb/forestry/models.py +++ b/vcweb/forestry/models.py @@ -93,10 +93,11 @@ def get_initial_resource_level_parameter(): return Parameter.objects.for_round(name='initial_resource_level') -def set_harvest_decision(participant_group_relationship=None, value=None, round_data=None): +def set_harvest_decision(participant_group_relationship=None, value=None, round_data=None, submitted=False): if round_data is None: round_data = participant_group_relationship.current_round_data prdv = participant_group_relationship.get_data_value(parameter=get_harvest_decision_parameter(), round_data=round_data) + prdv.submitted = submitted prdv.int_value = value prdv.save() Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-26 05:46:30
|
2 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/cef61a4f36d4/ Changeset: cef61a4f36d4 User: alllee Date: 2013-03-26 01:47:05 Summary: adding fabric to pip requirements Affected #: 1 file diff -r d3928beb04c36cfced6be01d65fc3d5e0b9fd127 -r cef61a4f36d4939003a855141eb2e542ab49ffb5 vcweb/requirements.pip --- a/vcweb/requirements.pip +++ b/vcweb/requirements.pip @@ -1,4 +1,5 @@ Django +fabric django-dajaxice django-extensions django-kronos https://bitbucket.org/virtualcommons/vcweb/commits/21e94d024108/ Changeset: 21e94d024108 User: alllee Date: 2013-03-26 06:46:12 Summary: fixing bugs in data value getters, tagged some FIXMEs on ways to improve the data model API Affected #: 5 files diff -r cef61a4f36d4939003a855141eb2e542ab49ffb5 -r 21e94d0241082db760e07fd098b9be814051a534 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -5,17 +5,17 @@ from vcweb.forestry.models import (get_harvest_decision_parameter, get_harvest_decision, get_regrowth_rate_parameter, get_group_harvest_parameter, get_reset_resource_level_parameter, get_resource_level, get_initial_resource_level as forestry_initial_resource_level, set_resource_level, get_regrowth_parameter, - get_resource_level_parameter, has_resource_level, get_resource_level_dv as get_unshared_resource_level_dv, get_harvest_decisions, - set_group_harvest, set_regrowth) + get_resource_level_parameter, has_resource_level, get_resource_level_dv as get_unshared_resource_level_dv, + set_group_harvest, set_regrowth, set_harvest_decision) import logging logger = logging.getLogger(__name__) # FIXME: hacky, should figure out a better way to bind this module with the ExperimentMetadata instance that it is -# dependent on that leaves the data in a single place. per-app settings files that define experiment metadata -# singletons? +# dependent on EXPERIMENT_METADATA_NAME = intern('bound') +# constants that should live in configuration as well MAX_RESOURCE_LEVEL = 240 ''' @@ -144,13 +144,15 @@ storage_dv.save() return storage_dv +def get_player_status_dv(participant_group_relationship, round_data): + return participant_group_relationship.get_data_value(parameter=get_player_status_parameter(), + round_data=round_data) + def get_player_status(participant_group_relationship, round_data): - return participant_group_relationship.get_data_value(parameter=get_player_status_parameter(), - round_data=round_data).boolean_value + return get_player_status_dv(participant_group_relationship, round_data).boolean_value def set_player_status(participant_group_relationship, round_data, value): - status_dv = participant_group_relationship.get_data_value(parameter=get_player_status_parameter(), - round_data=round_data) + status_dv = get_player_status_dv(participant_group_relationship, round_data) status_dv.boolean_value = value status_dv.save() return status_dv @@ -194,13 +196,13 @@ # FIXME: make sure that this is expected behavior - if the resource level is reset, reset storage to 0 ParticipantRoundDataValue.objects.for_group(group, parameter=get_storage_parameter(), round_data=round_data).update(int_value=0) + # reset all player statuses to True + ParticipantRoundDataValue.objects.for_group(group, parameter=get_player_status_parameter(), + round_data=round_data).update(boolean_value=True) def get_total_harvest(group, round_data): - q = ParticipantRoundDataValue.objects.for_group( - group=group, - parameter=get_harvest_decision_parameter(), - round_data=round_data).aggregate(total_harvest=Sum('int_value')) + q = ParticipantRoundDataValue.objects.for_group(group=group, parameter=get_harvest_decision_parameter(), round_data=round_data).aggregate(total_harvest=Sum('int_value')) return q['total_harvest'] @@ -215,20 +217,19 @@ parameter=get_harvest_decision_parameter(), round_data=round_data).update(is_active=False) # create new harvest decision data values - cost_of_living = get_cost_of_living(round_data.round_configuration) for pgr in group.participant_group_relationship_set.all(): ParticipantRoundDataValue.objects.create(round_data=round_data, participant_group_relationship=pgr, parameter=get_harvest_decision_parameter(), int_value=individual_harvest) - updated_storage = get_storage(pgr, round_data) + individual_harvest - cost_of_living - set_storage(pgr, round_data, updated_storage) return adjusted_harvest -def adjust_resource_level(experiment, group, round_data, regrowth_rate, max_resource_level=MAX_RESOURCE_LEVEL): +def update_resource_level(experiment, group, round_data, regrowth_rate, max_resource_level=MAX_RESOURCE_LEVEL): current_resource_level_dv = get_resource_level_dv(group) current_resource_level = current_resource_level_dv.int_value +# FIXME: would be nicer to extend Group behavior and have group.get_total_harvest() instead of +# get_total_harvest(group, ...) total_harvest = get_total_harvest(group, round_data) logger.debug("total harvest for playable round: %d", total_harvest) if current_resource_level > 0 and total_harvest > 0: @@ -247,6 +248,7 @@ set_regrowth(group, resource_regrowth, round_data) current_resource_level_dv.int_value = min(current_resource_level + resource_regrowth, max_resource_level) current_resource_level_dv.save() + ''' XXX: transfer resource levels across chat and quiz rounds if they exist ''' if experiment.has_next_round: ''' set group round data resource_level for each group + regrowth ''' @@ -254,9 +256,8 @@ group.copy_to_next_round(current_resource_level_dv) -# FIXME: a lot of duplication between this and adjust_resource_level, see if we can reduce it by operating on group -# cluster data values instead of group data values -def adjust_shared_resource_level(experiment, group_cluster, round_data, regrowth_rate, max_resource_level=MAX_RESOURCE_LEVEL): +# FIXME: try to reduce duplication between this and update_resource_level +def update_shared_resource_level(experiment, group_cluster, round_data, regrowth_rate, max_resource_level=MAX_RESOURCE_LEVEL): shared_resource_level_dv = get_shared_resource_level_dv(cluster=group_cluster, round_data=round_data) shared_resource_level = shared_resource_level_dv.int_value shared_group_harvest = 0 @@ -286,6 +287,19 @@ ''' transfer shared resource levels to next round ''' group_cluster.copy_to_next_round(shared_resource_level_dv) +def update_participants(experiment, round_data): + cost_of_living = get_cost_of_living(round_data.round_configuration) + for pgr in experiment.participant_group_relationships: + player_status_dv = get_player_status_dv(pgr, round_data) + harvest_decision = get_harvest_decision(pgr, round_data) + existing_storage = get_storage(pgr, round_data) + updated_storage = existing_storage + harvest_decision - cost_of_living + if updated_storage < 0: + # player has "died" + player_status_dv.boolean_value = False + player_status_dv.save() + + set_storage(pgr, round_data, updated_storage) @receiver(signals.round_ended, sender=EXPERIMENT_METADATA_NAME) def round_ended_handler(sender, experiment=None, **kwargs): @@ -298,13 +312,15 @@ logger.debug("ending boundaries round: %s", round_configuration) if round_configuration.is_playable_round: regrowth_rate = get_regrowth_rate(round_configuration) +# FIXME: generify and merge update_shared_resource_level and update_resource_level to operate on "group-like" objects if is_shared_resource_enabled(round_configuration): for group_cluster in GroupCluster.objects.for_experiment(experiment, session_id=round_configuration.session_id): - adjust_shared_resource_level(experiment, group_cluster, round_data, regrowth_rate) + update_shared_resource_level(experiment, group_cluster, round_data, regrowth_rate) else: for group in experiment.group_set.all(): - adjust_resource_level(experiment, group, round_data, regrowth_rate) + update_resource_level(experiment, group, round_data, regrowth_rate) + update_participants(experiment, round_data) def calculate_regrowth(resource_level, regrowth_rate, max_resource_level=MAX_RESOURCE_LEVEL): diff -r cef61a4f36d4939003a855141eb2e542ab49ffb5 -r 21e94d0241082db760e07fd098b9be814051a534 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -374,25 +374,25 @@ }); // activate instructions click bindings model.activateInstructionsPageOne = function() { - model.templateName('GENERAL_INSTRUCTIONS'); + model.roundType('GENERAL_INSTRUCTIONS'); }; model.activateInstructionsPageTwo = function() { - model.templateName('GENERAL_INSTRUCTIONS2'); + model.roundType('GENERAL_INSTRUCTIONS2'); }; model.activateInstructionsPageThree = function() { - model.templateName('GENERAL_INSTRUCTIONS3'); + model.roundType('GENERAL_INSTRUCTIONS3'); }; model.activateWaitingRoomPage = function() { - model.templateName('WAITING_ROOM'); + model.roundType('WAITING_ROOM'); } model.readyParticipantsPercentage = ko.computed(function() { return (model.readyParticipants() / model.totalNumberOfParticipants()) * 100; }); model.activatePracticeRoundInstructions = function() { - model.templateName("PRACTICE_ROUND_INSTRUCTIONS"); + model.roundType("PRACTICE_ROUND_INSTRUCTIONS"); } model.activateTreatmentInstructions = function() { - model.templateName("TREATMENT_INSTRUCTIONS"); + model.roundType("TREATMENT_INSTRUCTIONS"); } model.participantReady = function() { $.post('/experiment/participant-ready', { participant_group_id: {{ participant_group_relationship.pk }} }, function(response) { diff -r cef61a4f36d4939003a855141eb2e542ab49ffb5 -r 21e94d0241082db760e07fd098b9be814051a534 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -9,7 +9,7 @@ from vcweb.boundaries.forms import HarvestDecisionForm from vcweb.boundaries.models import (get_experiment_metadata, get_regrowth_rate, get_harvest_decision_parameter, get_cost_of_living, get_resource_level, get_initial_resource_level, get_total_storage, get_storage, - get_last_harvest_decision, can_observe_other_group) + get_last_harvest_decision, set_harvest_decision, can_observe_other_group) import logging logger = logging.getLogger(__name__) @@ -41,10 +41,7 @@ participant_group_id = form.cleaned_data['participant_group_id'] pgr = get_object_or_404(ParticipantGroupRelationship, pk=participant_group_id) harvest_decision = form.cleaned_data['harvest_decision'] - ParticipantRoundDataValue.objects.create(participant_group_relationship=pgr, int_value=harvest_decision, - round_data=experiment.current_round_data, parameter=get_harvest_decision_parameter()) - # set harvest decision for participant - # FIXME: inconsistency, GET returns HTML and POST return JSON.. + set_harvest_decision(pgr, harvest_decision, experiment.current_round_data) return JsonResponse(dumps({ 'success': True, 'experimentModelJson': get_view_model_json(experiment, pgr)})) for field in form: if field.errors: @@ -88,26 +85,28 @@ if current_round.is_regular_round: experiment_model_dict['chatEnabled'] = current_round.chat_enabled -# participant group data parameters are only needed if this round is a data round or the previous round was a data round + # FIXME: these need to be added so KO doesn't get unhappy when we switch templates from instructions rounds to + # practice rounds. + own_group = participant_group_relationship.group + own_resource_level = get_resource_level(own_group) + last_harvest_decision = get_last_harvest_decision(participant_group_relationship, round_data=previous_round_data) + experiment_model_dict['playerData'] = [{ + 'id': pgr.participant_number, + 'lastHarvestDecision': get_last_harvest_decision(pgr, round_data=previous_round_data), + 'storage': get_storage(pgr, current_round_data), + } for pgr in own_group.participant_group_relationship_set.all()] + # FIXME: redundancy with playerData + experiment_model_dict['lastHarvestDecision'] = last_harvest_decision + experiment_model_dict['storage'] = get_storage(participant_group_relationship, current_round_data) + experiment_model_dict['resourceLevel'] = own_resource_level + # participant group data parameters are only needed if this round is a data round or the previous round was a data round if previous_round.is_playable_round or current_round.is_playable_round: - own_group = participant_group_relationship.group - own_resource_level = get_resource_level(own_group) - last_harvest_decision = get_last_harvest_decision(participant_group_relationship, round_data=previous_round_data) - experiment_model_dict['playerData'] = [{ - 'id': pgr.participant_number, - 'lastHarvestDecision': get_last_harvest_decision(pgr, round_data=previous_round_data), - 'storage': get_storage(pgr, current_round_data), - } for pgr in own_group.participant_group_relationship_set.all()] experiment_model_dict['chatMessages'] = [{ 'pk': cm.pk, 'participant_number': cm.participant_group_relationship.participant_number, 'message': cm.string_value, 'date_created': cm.date_created.strftime("%I:%M:%S") } for cm in ChatMessage.objects.for_group(own_group)] -# FIXME: some redundancy with playerData - experiment_model_dict['lastHarvestDecision'] = last_harvest_decision - experiment_model_dict['storage'] = get_storage(participant_group_relationship, current_round_data) - experiment_model_dict['resourceLevel'] = own_resource_level experiment_model_dict['canObserveOtherGroup'] = can_observe_other_group(current_round) if not current_round.is_practice_round and experiment_model_dict['canObserveOtherGroup']: gr = GroupRelationship.objects.select_related('cluster').get(group=own_group) diff -r cef61a4f36d4939003a855141eb2e542ab49ffb5 -r 21e94d0241082db760e07fd098b9be814051a534 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -41,6 +41,33 @@ def __getattr__(self, name): return self.value +class ParameterizedValueQuerySetMixin(models.query.QuerySet): + def _data_parameter_criteria(self, parameter=None, parameter_name=None, round_data=None, **kwargs): + return dict([ + ('is_active', True), + ('parameter', parameter) if parameter else ('parameter__name', parameter_name), + ('round_data', self.current_round_data if round_data is None else round_data) + ], **kwargs) + + def set_data_value(self, parameter=None, value=None, round_data=None, **kwargs): + if parameter is None or value is None or round_data is None: + raise ValueError("need parameter, value, and round data to set") + dv = self.get(round_data=round_data, parameter=parameter, **kwargs) + dv.value = value + dv.save() + + def get_data_value(self, parameter=None, parameter_name=None, round_data=None, default=None): + if round_data is None: + round_data = self.current_round_data + criteria = self._data_parameter_criteria(parameter=parameter, parameter_name=parameter_name, round_data=round_data) + try: + return self.data_value_set.select_related('parameter', 'group', 'round_data').get(**criteria) + except self.model.DoesNotExist as e: + if default is None: + raise e + else: + return DefaultValue(default) + class AutoDateTimeField(models.DateTimeField): def pre_save(self, model_instance, add): return datetime.now() @@ -1373,10 +1400,7 @@ @property def current_round_data(self): - return self.experiment.get_round_data(round_configuration=self.current_round) - - def get_round_data(self, round_configuration=None): - return self.experiment.get_round_data(round_configuration) + return self.experiment.current_round_data @property def is_full(self): @@ -1782,9 +1806,6 @@ def current_round_data(self): return self.group.current_round_data - def get_round_data(self, round_configuration=None): - return self.group.get_round_data(round_configuration) - @property def full_name(self): fn = self.participant.user.get_full_name() diff -r cef61a4f36d4939003a855141eb2e542ab49ffb5 -r 21e94d0241082db760e07fd098b9be814051a534 vcweb/forestry/models.py --- a/vcweb/forestry/models.py +++ b/vcweb/forestry/models.py @@ -29,13 +29,7 @@ return group.has_data_parameter(parameter=get_resource_level_parameter()) def get_harvest_decision(participant_group_relationship, round_data=None): - if round_data is None: - round_data = participant_group_relationship.get_round_data() - try: - return ParticipantRoundDataValue.objects.for_participant(participant_group_relationship=participant_group_relationship, - round_data=round_data, parameter=get_harvest_decision_parameter()) - except ParticipantRoundDataValue.DoesNotExist: - return None + return participant_group_relationship.get_data_value(round_data=round_data, parameter=get_harvest_decision_parameter(), default=0).int_value def get_harvest_decisions(group=None): return group.get_participant_data_values(parameter__name='harvest_decision') if group else [] @@ -102,10 +96,7 @@ def set_harvest_decision(participant_group_relationship=None, value=None, round_data=None): if round_data is None: round_data = participant_group_relationship.current_round_data - prdv = ParticipantRoundDataValue.objects.get(parameter=get_harvest_decision_parameter(), - participant_group_relationship=participant_group_relationship, - round_data=round_data - ) + prdv = participant_group_relationship.get_data_value(parameter=get_harvest_decision_parameter(), round_data=round_data) prdv.int_value = value prdv.save() Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-26 01:46:18
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/d3928beb04c3/ Changeset: d3928beb04c3 User: alllee Date: 2013-03-26 02:46:16 Summary: fixing KO computed functions and moving templateName determination from django -> KO starting to implement participant storage, getting itchy to refactor data value API Affected #: 5 files diff -r 85e9dd101760220784f54c7fc9815a2dc0fd4bd7 -r d3928beb04c36cfced6be01d65fc3d5e0b9fd127 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -65,6 +65,7 @@ ''' value accessors ''' +''' round and experiment configuration accessors ''' def get_regrowth_rate(round_configuration): return round_configuration.get_parameter_value(parameter=get_regrowth_rate_parameter(), default=0.40).float_value @@ -78,7 +79,22 @@ return round_configuration.get_parameter_value(parameter=get_shared_resource_enabled_parameter(), default=False).boolean_value +def get_initial_resource_level(round_configuration, default=MAX_RESOURCE_LEVEL): + return forestry_initial_resource_level(round_configuration, default) +def should_reset_resource_level(round_configuration): + return round_configuration.get_parameter_value(parameter=get_reset_resource_level_parameter(), + default=False).boolean_value + +def get_cost_of_living(round_configuration): + return round_configuration.get_parameter_value(get_cost_of_living_parameter(), default=5).int_value + + +def get_max_harvest(experiment): + return experiment.get_parameter_value(parameter=get_max_harvest_decision_parameter(), default=10).int_value + + +''' group data accessors ''' def get_resource_level_dv(group, round_data=None, round_configuration=None): ''' Returns either the GroupClusterDataValue (shared resource condition) or the GroupRoundDataValue (standard @@ -106,25 +122,14 @@ cluster = group_relationship.cluster return cluster.get_data_value(parameter=get_resource_level_parameter(), round_data=round_data) +''' participant data value accessors ''' -def get_initial_resource_level(round_configuration, default=MAX_RESOURCE_LEVEL): - return forestry_initial_resource_level(round_configuration, default) +def get_storage_dv(participant_group_relationship, round_data=None, default=None): + return participant_group_relationship.get_data_value(parameter=get_storage_parameter(), round_data=round_data, default=default) -def get_max_harvest(experiment): - return experiment.get_parameter_value(parameter=get_max_harvest_decision_parameter(), default=10).int_value - - -def get_cost_of_living(current_round): - return current_round.get_parameter_value(get_cost_of_living_parameter(), default=5).int_value - - -def get_storage_dv(participant_group_relationship, round_data=None): - return participant_group_relationship.get_data_value(parameter=get_storage_parameter(), round_data=round_data) - - -def get_storage(participant_group_relationship, round_data=None): - return get_storage_dv(participant_group_relationship, round_data).int_value +def get_storage(participant_group_relationship, round_data=None, default=0): + return get_storage_dv(participant_group_relationship, round_data, default).int_value # returns the sum of all stored resources for each member in the group def get_total_storage(group): @@ -133,15 +138,22 @@ return sum([pdv.value for pdv in group.get_participant_data_values(parameter=get_storage_parameter())]) -def set_storage(participant_group_relationship, value=0): - storage_dv = participant_group_relationship.set_data_value(parameter=get_storage_parameter(), value=value) - logger.debug("set storage variable: %s", storage_dv) +def set_storage(participant_group_relationship, round_data, value): + storage_dv = get_storage_dv(participant_group_relationship, round_data) + storage_dv.int_value = value + storage_dv.save() return storage_dv +def get_player_status(participant_group_relationship, round_data): + return participant_group_relationship.get_data_value(parameter=get_player_status_parameter(), + round_data=round_data).boolean_value -def should_reset_resource_level(round_configuration): - return round_configuration.get_parameter_value(parameter=get_reset_resource_level_parameter(), - default=False).boolean_value +def set_player_status(participant_group_relationship, round_data, value): + status_dv = participant_group_relationship.get_data_value(parameter=get_player_status_parameter(), + round_data=round_data) + status_dv.boolean_value = value + status_dv.save() + return status_dv def get_last_harvest_decision(participant_group_relationship, round_data=None): @@ -179,6 +191,9 @@ "Setting resource level (%s) to initial value [%s]" % (existing_resource_level, initial_resource_level)) existing_resource_level.int_value = initial_resource_level existing_resource_level.save() + # FIXME: make sure that this is expected behavior - if the resource level is reset, reset storage to 0 + ParticipantRoundDataValue.objects.for_group(group, parameter=get_storage_parameter(), + round_data=round_data).update(int_value=0) def get_total_harvest(group, round_data): @@ -200,11 +215,14 @@ parameter=get_harvest_decision_parameter(), round_data=round_data).update(is_active=False) # create new harvest decision data values + cost_of_living = get_cost_of_living(round_data.round_configuration) for pgr in group.participant_group_relationship_set.all(): ParticipantRoundDataValue.objects.create(round_data=round_data, participant_group_relationship=pgr, parameter=get_harvest_decision_parameter(), int_value=individual_harvest) + updated_storage = get_storage(pgr, round_data) + individual_harvest - cost_of_living + set_storage(pgr, round_data, updated_storage) return adjusted_harvest diff -r 85e9dd101760220784f54c7fc9815a2dc0fd4bd7 -r d3928beb04c36cfced6be01d65fc3d5e0b9fd127 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -234,7 +234,7 @@ <h3>My Status</h3><div data-bind='if: isTimerRunning'><div class='alert alert-error'> - <b><i class='icon-time'></i> Time left:</b> + <b><i class='icon-time'></i> Time left:</b><span data-bind='text: secondsLeft'></span>s </div></div> @@ -347,6 +347,14 @@ var model = ko.mapping.fromJS(experimentModelJson); model.secondsLeft = ko.observable(0); model.currentInterval = ko.observable(); + model.templateName = ko.computed(function() { + switch ( model.roundType() ) { + case 'PRACTICE': + return 'REGULAR'; + default: + return model.roundType(); + } + }); model.setCurrentInterval = function(intervalId) { model.clearCurrentInterval(); model.currentInterval(intervalId); @@ -402,11 +410,11 @@ model.harvestDecision = ko.observable(0); model.numberOfTreesPerRow = ko.observable(10); model.isResourceEmpty = ko.computed(function() { - return model.resourceLevel == 0; + return model.resourceLevel() == 0; }) model.resourcesToDisplay = ko.computed(function() { - if (model.resourceLevel > 0) { - return Math.min(model.resourceLevel, model.maximumResourcesToDisplay()); + if (model.resourceLevel() > 0) { + return Math.min(model.resourceLevel(), model.maximumResourcesToDisplay()); } return 0; }); diff -r 85e9dd101760220784f54c7fc9815a2dc0fd4bd7 -r d3928beb04c36cfced6be01d65fc3d5e0b9fd127 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -78,6 +78,7 @@ experiment_model_dict['initialResourceLevel'] = get_initial_resource_level(current_round) experiment_model_dict['dollarsPerToken'] = float(ec.exchange_rate) + experiment_model_dict['resourceLevel'] = 0 experiment_model_dict['totalNumberOfParticipants'] = experiment.participant_set.count() experiment_model_dict['participantNumber'] = participant_group_relationship.participant_number experiment_model_dict['participantGroupId'] = participant_group_relationship.pk @@ -86,10 +87,6 @@ experiment_model_dict['chatEnabled'] = False if current_round.is_regular_round: experiment_model_dict['chatEnabled'] = current_round.chat_enabled - if current_round.is_practice_round: - experiment_model_dict['templateName'] = 'REGULAR' - else: - experiment_model_dict['templateName'] = current_round.round_type # participant group data parameters are only needed if this round is a data round or the previous round was a data round if previous_round.is_playable_round or current_round.is_playable_round: @@ -98,7 +95,7 @@ last_harvest_decision = get_last_harvest_decision(participant_group_relationship, round_data=previous_round_data) experiment_model_dict['playerData'] = [{ 'id': pgr.participant_number, - 'lastHarvestDecision': last_harvest_decision, + 'lastHarvestDecision': get_last_harvest_decision(pgr, round_data=previous_round_data), 'storage': get_storage(pgr, current_round_data), } for pgr in own_group.participant_group_relationship_set.all()] experiment_model_dict['chatMessages'] = [{ @@ -107,7 +104,7 @@ 'message': cm.string_value, 'date_created': cm.date_created.strftime("%I:%M:%S") } for cm in ChatMessage.objects.for_group(own_group)] -# FIXME: this is redundant +# FIXME: some redundancy with playerData experiment_model_dict['lastHarvestDecision'] = last_harvest_decision experiment_model_dict['storage'] = get_storage(participant_group_relationship, current_round_data) experiment_model_dict['resourceLevel'] = own_resource_level @@ -128,6 +125,7 @@ # FIXME: defaults hard coded in for now experiment_model_dict['maxEarnings'] = 20.00 + experiment_model_dict['maximumResourcesToDisplay'] = 20 experiment_model_dict['warningCountdownTime'] = 10 experiment_model_dict['maxHarvestDecision'] = 10 experiment_model_dict['hasSubmit'] = False diff -r 85e9dd101760220784f54c7fc9815a2dc0fd4bd7 -r d3928beb04c36cfced6be01d65fc3d5e0b9fd127 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -1747,12 +1747,12 @@ class ParticipantGroupRelationshipQuerySet(models.query.QuerySet): - def for_experiment(self, experiment): - return self.select_related('group', 'participant').filter(group__experiment=experiment) + def for_experiment(self, experiment, **kwargs): + return self.select_related('group', 'participant').filter(group__experiment=experiment, **kwargs) # FIXME: deprecated, for backwards compatibility - def by_experiment(self, experiment): - return self.for_experiment(experiment) + def by_experiment(self, experiment, **kwargs): + return self.for_experiment(experiment, **kwargs) def get_relationship(self, participant, experiment): try: diff -r 85e9dd101760220784f54c7fc9815a2dc0fd4bd7 -r d3928beb04c36cfced6be01d65fc3d5e0b9fd127 vcweb/forestry/models.py --- a/vcweb/forestry/models.py +++ b/vcweb/forestry/models.py @@ -4,13 +4,10 @@ import logging logger = logging.getLogger(__name__) -def forestry_second_tick(): - print "Monitoring Forestry Experiments." - ''' - check all forestry experiments. - ''' +EXPERIMENT_METADATA_NAME = intern('forestry') +MAX_RESOURCE_LEVEL = 100 -def get_resource_level_dv(group, round_data=None, default=100): +def get_resource_level_dv(group, round_data=None, default=MAX_RESOURCE_LEVEL): return group.get_data_value(parameter=get_resource_level_parameter(), round_data=round_data, default=default) def get_resource_level(group, round_data=None, **kwargs): @@ -52,7 +49,7 @@ def should_reset_resource_level(round_configuration): return round_configuration.get_parameter_value(parameter=get_reset_resource_level_parameter(), default=False).boolean_value -def get_initial_resource_level(round_configuration, default=100): +def get_initial_resource_level(round_configuration, default=MAX_RESOURCE_LEVEL): return round_configuration.get_parameter_value(parameter=get_initial_resource_level_parameter(), default=default).int_value def get_max_harvest_decision(resource_level): @@ -115,7 +112,8 @@ def set_resource_level(group, value, round_data=None): return group.set_data_value(parameter=get_resource_level_parameter(), round_data=round_data, value=value) -def round_setup(experiment, **kwargs): +@receiver(signals.round_started, sender=EXPERIMENT_METADATA_NAME) +def round_started_handler(sender, experiment=None, **kwargs): round_configuration = experiment.current_round logger.debug("setting up boundaries round %s", round_configuration) if round_configuration.is_playable_round: @@ -143,14 +141,16 @@ group.log("Setting resource level to initial value [%s]" % initial_resource_level) set_resource_level(group, initial_resource_level, round_data=round_data) -def round_teardown(experiment, **kwargs): +@receiver(signals.round_ended, sender=EXPERIMENT_METADATA_NAME) +def round_ended_handler(sender, experiment=None, **kwargs): + logger.debug("forestry handling round ended signal") ''' calculates new resource levels for practice or regular rounds based on the group harvest and resultant regrowth. also responsible for transferring those parameters to the next round as needed. ''' current_round_configuration = experiment.current_round logger.debug("current round: %s", current_round_configuration) - max_resource_level = 100 + max_resource_level = MAX_RESOURCE_LEVEL for group in experiment.group_set.all(): # FIXME: simplify logic logger.debug("group %s has resource level", group) @@ -176,28 +176,3 @@ ''' set group round data resource_level for each group + regrowth ''' group.log("Transferring resource level %s to next round" % current_resource_level_dv.int_value) group.copy_to_next_round(current_resource_level_dv) - -''' -FIXME: figure out a better way to tie these signal handlers to a specific -ExperimentMetadata instance. Using ExperimentMetadata.namespace is problematic -due to the python builtin id used by dispatcher.py and utf-8 strings... -for an example, try -e = Experiment.objects.get(pk=1) -id(e.namespace) -id(u'forestry') -id(repr(u'forestry')) -id(repr(e.namespace)) -even using django.util.encodings smart_unicode and smart_str functions don't help. -''' -FORESTRY_SENDER = intern('forestry') -@receiver(signals.round_started, sender=FORESTRY_SENDER) -def round_started_handler(sender, experiment=None, **kwargs): - round_setup(experiment, **kwargs) - -@receiver(signals.round_ended, sender=FORESTRY_SENDER) -def round_ended_handler(sender, experiment=None, **kwargs): - logger.debug("forestry handling round ended signal") - round_teardown(experiment, **kwargs) - - - Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-25 23:09:41
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/85e9dd101760/ Changeset: 85e9dd101760 User: alllee Date: 2013-03-26 00:09:44 Summary: fixing bug in Experiment.all_participants_ready Affected #: 2 files diff -r 45b6aa258a7b3a508f4ecbe242b39d40e81222f1 -r 85e9dd101760220784f54c7fc9815a2dc0fd4bd7 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -523,7 +523,7 @@ @property def all_participants_ready(self): - return self.ready_participants == self.participant_set.count() + return self.number_of_ready_participants == self.participant_set.count() def get_participant_experiment_relationship(self, participant): return self.participant_relationship_set.select_related('participant__user').get(participant=participant) diff -r 45b6aa258a7b3a508f4ecbe242b39d40e81222f1 -r 85e9dd101760220784f54c7fc9815a2dc0fd4bd7 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -181,7 +181,7 @@ var notes = $('#experimenterNotesText').val(); Dajaxice.vcweb.core.save_experimenter_notes(function(data) { if (data.success) { - $('#submitExperimenterNotesButton').val('Saved!'); + model.addMessage("Saved experimenter notes."); } }, { experiment_id: {{ experiment.pk }}, notes: notes }); Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-25 22:57:22
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/45b6aa258a7b/ Changeset: 45b6aa258a7b User: alllee Date: 2013-03-25 23:57:24 Summary: patching number_of_ready_participants some more, should be based on whether or not a round is in progress, not just active Affected #: 1 file diff -r 89b9e73f241bd887d264dc1e466d36d40b279487 -r 45b6aa258a7b3a508f4ecbe242b39d40e81222f1 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -516,7 +516,7 @@ @property def number_of_ready_participants(self): - if self.is_active: + if self.is_round_in_progress: return ParticipantRoundDataValue.objects.filter(parameter=get_participant_ready_parameter(), round_data=self.current_round_data, boolean_value=True).count() else: return 0 @@ -768,16 +768,6 @@ self.current_round_sequence_number = max(self.current_round_sequence_number - 1, 1) self.save() - def move_to_next_round(self): - if self.is_round_in_progress: - self.end_round() - if self.has_next_round: - self.current_round_elapsed_time = 0 - self.current_round_sequence_number += 1 - return True - else: - logger.warning("trying to advance past the last round - no-op") - def invoke(self, action_name): if action_name in ('advance_to_next_round', 'end_round', 'start_round', 'activate', 'deactivate', 'complete'): getattr(self, action_name)() @@ -785,8 +775,14 @@ raise AttributeError("Invalid experiment action %s requested of experiment %s" % (action_name, self)) def advance_to_next_round(self): - if self.move_to_next_round(): + if self.is_round_in_progress: + self.end_round() + if self.has_next_round: + self.current_round_elapsed_time = 0 + self.current_round_sequence_number += 1 self.start_round() + else: + logger.warning("trying to advance past the last round - no-op") def create_round_data(self): round_data, created = self.round_data_set.get_or_create(round_configuration=self.current_round) Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-25 22:31:16
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/89b9e73f241b/ Changeset: 89b9e73f241b User: alllee Date: 2013-03-25 23:31:20 Summary: adding authz check to monitor Affected #: 1 file diff -r 5dbe2c2b8850266d8162160df6246ca3891a7caf -r 89b9e73f241bd887d264dc1e466d36d40b279487 vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -267,12 +267,19 @@ context = self.get_context_data(object=self.object) return self.render_to_response(context) +@experimenter_required def monitor(request, pk=None): experiment = get_object_or_404(Experiment.objects.select_related('experiment_configuration', 'experimenter'), pk=pk) - return render(request, 'experimenter/monitor.html', { - 'experiment': experiment, - 'experimentModelJson': experiment.to_json(), - }) + user = request.user + if is_experimenter(user, experiment.experimenter): + return render(request, 'experimenter/monitor.html', { + 'experiment': experiment, + 'experimentModelJson': experiment.to_json(), + }) + else: + logger.warning("unauthorized access to experiment %s by user %s", experiment, user) + raise PermissionDenied("You do not have access to %s" % experiment) + def upload_excel_participants_file(request): if request.method == 'POST': Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-25 21:52:08
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/5dbe2c2b8850/ Changeset: 5dbe2c2b8850 User: alllee Date: 2013-03-25 22:52:08 Summary: fixing bug when clone()ing an experiment, number_of_ready_participants throws an error as there is no round data set yet Affected #: 1 file diff -r b4a91124c201482e06c225c8a5fd6f6552ae47a4 -r 5dbe2c2b8850266d8162160df6246ca3891a7caf vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -516,7 +516,10 @@ @property def number_of_ready_participants(self): - return ParticipantRoundDataValue.objects.filter(parameter=get_participant_ready_parameter(), round_data=self.current_round_data, boolean_value=True).count() + if self.is_active: + return ParticipantRoundDataValue.objects.filter(parameter=get_participant_ready_parameter(), round_data=self.current_round_data, boolean_value=True).count() + else: + return 0 @property def all_participants_ready(self): Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-25 21:13:51
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/b4a91124c201/ Changeset: b4a91124c201 User: alllee Date: 2013-03-25 22:13:54 Summary: broadcast should also notify the experimenter Affected #: 1 file diff -r 01ecaf4c3dc8cd940393ec906c995a0ec04cdf4a -r b4a91124c201482e06c225c8a5fd6f6552ae47a4 vcweb/vcweb-sockjs.py --- a/vcweb/vcweb-sockjs.py +++ b/vcweb/vcweb-sockjs.py @@ -219,6 +219,7 @@ participant_connections.append(participant_group_id) connection.send(message) logger.debug("sent message %s to %s", message, participant_connections) + self.send_to_experimenter(message, experiment=experiment) return participant_connections def send_to_group(self, group, json): Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-25 21:06:50
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/01ecaf4c3dc8/ Changeset: 01ecaf4c3dc8 User: alllee Date: 2013-03-25 22:06:51 Summary: pushing readyParticipants field into Experiment.to_dict Affected #: 2 files diff -r 558d2d7f7082a8aa23a918d4dd309eabc139ab1d -r 01ecaf4c3dc8cd940393ec906c995a0ec04cdf4a vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -70,7 +70,6 @@ # round / experiment configuration data regrowth_rate = get_regrowth_rate(current_round) cost_of_living = get_cost_of_living(current_round) - experiment_model_dict['readyParticipants'] = experiment.ready_participants experiment_model_dict['costOfLiving'] = cost_of_living # instructions round parameters if current_round.is_instructions_round: diff -r 558d2d7f7082a8aa23a918d4dd309eabc139ab1d -r 01ecaf4c3dc8cd940393ec906c995a0ec04cdf4a vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -879,6 +879,7 @@ 'isActive': self.is_active, 'isArchived': self.is_archived, 'dollarsPerToken': float(ec.exchange_rate), + 'readyParticipants': self.number_of_ready_participants, } if include_round_data: experiment_dict['allRoundData'] = self.all_round_data() Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-25 21:00:51
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/558d2d7f7082/ Changeset: 558d2d7f7082 User: alllee Date: 2013-03-25 22:00:54 Summary: implementing resource regrowth function N = N + rN(1-N/K) Affected #: 1 file diff -r b0685824f3278311fb2784b1eb38aba2fc1e8bd2 -r 558d2d7f7082a8aa23a918d4dd309eabc139ab1d vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -2,7 +2,7 @@ from django.dispatch import receiver from vcweb.core import signals, simplecache from vcweb.core.models import (ExperimentMetadata, Parameter, ParticipantRoundDataValue, GroupRelationship, GroupCluster, GroupClusterDataValue) -from vcweb.forestry.models import (get_harvest_decision_parameter, get_harvest_decision, get_regrowth_rate, +from vcweb.forestry.models import (get_harvest_decision_parameter, get_harvest_decision, get_regrowth_rate_parameter, get_group_harvest_parameter, get_reset_resource_level_parameter, get_resource_level, get_initial_resource_level as forestry_initial_resource_level, set_resource_level, get_regrowth_parameter, get_resource_level_parameter, has_resource_level, get_resource_level_dv as get_unshared_resource_level_dv, get_harvest_decisions, @@ -65,6 +65,9 @@ ''' value accessors ''' +def get_regrowth_rate(round_configuration): + return round_configuration.get_parameter_value(parameter=get_regrowth_rate_parameter(), default=0.40).float_value + def can_observe_other_group(round_configuration): return round_configuration.get_parameter_value(parameter=get_observe_other_group_parameter(), @@ -205,7 +208,7 @@ return adjusted_harvest -def adjust_resource_level(experiment, group, round_data, max_resource_level=MAX_RESOURCE_LEVEL): +def adjust_resource_level(experiment, group, round_data, regrowth_rate, max_resource_level=MAX_RESOURCE_LEVEL): current_resource_level_dv = get_resource_level_dv(group) current_resource_level = current_resource_level_dv.int_value total_harvest = get_total_harvest(group, round_data) @@ -221,7 +224,7 @@ group.log("Harvest: removing %s from current resource level %s" % (total_harvest, current_resource_level)) set_group_harvest(group, total_harvest, round_data) current_resource_level = current_resource_level - total_harvest - resource_regrowth = calculate_regrowth(current_resource_level) + resource_regrowth = calculate_regrowth(current_resource_level, regrowth_rate, max_resource_level) group.log("Regrowth: adding %s to current resource level %s" % (resource_regrowth, current_resource_level)) set_regrowth(group, resource_regrowth, round_data) current_resource_level_dv.int_value = min(current_resource_level + resource_regrowth, max_resource_level) @@ -235,7 +238,7 @@ # FIXME: a lot of duplication between this and adjust_resource_level, see if we can reduce it by operating on group # cluster data values instead of group data values -def adjust_shared_resource_level(experiment, group_cluster, round_data, max_resource_level=MAX_RESOURCE_LEVEL): +def adjust_shared_resource_level(experiment, group_cluster, round_data, regrowth_rate, max_resource_level=MAX_RESOURCE_LEVEL): shared_resource_level_dv = get_shared_resource_level_dv(cluster=group_cluster, round_data=round_data) shared_resource_level = shared_resource_level_dv.int_value shared_group_harvest = 0 @@ -255,7 +258,7 @@ set_group_harvest(group, group_harvest, round_data) shared_resource_level = shared_resource_level - group_harvest # set regrowth after shared_resource_level has been modified by all groups in this cluster - resource_regrowth = calculate_regrowth(shared_resource_level) + resource_regrowth = calculate_regrowth(shared_resource_level, regrowth_rate, max_resource_level) group.log("Regrowth: adding %s to shared resource level %s" % (resource_regrowth, shared_resource_level)) group_cluster.set_data_value(parameter=get_regrowth_parameter(), round_data=round_data, value=resource_regrowth) @@ -275,17 +278,17 @@ round_configuration = experiment.current_round round_data = experiment.get_round_data(round_configuration) logger.debug("ending boundaries round: %s", round_configuration) - # FIXME: need to clarify logic for keeping track of resource levels across rounds if round_configuration.is_playable_round: + regrowth_rate = get_regrowth_rate(round_configuration) if is_shared_resource_enabled(round_configuration): for group_cluster in GroupCluster.objects.for_experiment(experiment, session_id=round_configuration.session_id): - adjust_shared_resource_level(experiment, group_cluster, round_data) + adjust_shared_resource_level(experiment, group_cluster, round_data, regrowth_rate) else: for group in experiment.group_set.all(): - adjust_resource_level(experiment, group, round_data) + adjust_resource_level(experiment, group, round_data, regrowth_rate) -def calculate_regrowth(resource_level): - # FIXME: re-implement based on Tim's logic, this is leftover from forestry - return resource_level / 10 +def calculate_regrowth(resource_level, regrowth_rate, max_resource_level=MAX_RESOURCE_LEVEL): + return (regrowth_rate * resource_level) * (1 - (resource_level / float(max_resource_level))) + Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-25 20:44:38
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/b0685824f327/ Changeset: b0685824f327 User: alllee Date: 2013-03-25 21:44:41 Summary: setting up resource level adjustments that take into account group clustering / shared resources and the corner case where the group harvest > actual resource level Affected #: 3 files diff -r b11d7744a4fb0e21a3340e8224aa2191086a821c -r b0685824f3278311fb2784b1eb38aba2fc1e8bd2 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -1,13 +1,15 @@ +from django.db.models import Sum from django.dispatch import receiver from vcweb.core import signals, simplecache -from vcweb.core.models import ExperimentMetadata, Parameter, ParticipantRoundDataValue +from vcweb.core.models import (ExperimentMetadata, Parameter, ParticipantRoundDataValue, GroupRelationship, GroupCluster, GroupClusterDataValue) from vcweb.forestry.models import (get_harvest_decision_parameter, get_harvest_decision, get_regrowth_rate, - get_group_harvest_parameter, get_reset_resource_level_parameter, get_resource_level, - get_initial_resource_level as forestry_initial_resource_level, set_resource_level, get_regrowth_parameter, - get_resource_level_parameter, has_resource_level, get_resource_level_dv as get_forestry_resource_level_dv, get_harvest_decisions, - set_group_harvest, set_regrowth) + get_group_harvest_parameter, get_reset_resource_level_parameter, get_resource_level, + get_initial_resource_level as forestry_initial_resource_level, set_resource_level, get_regrowth_parameter, + get_resource_level_parameter, has_resource_level, get_resource_level_dv as get_unshared_resource_level_dv, get_harvest_decisions, + set_group_harvest, set_regrowth) import logging + logger = logging.getLogger(__name__) # FIXME: hacky, should figure out a better way to bind this module with the ExperimentMetadata instance that it is @@ -19,49 +21,60 @@ ''' Experiment Parameters and Metadata Accessors ''' + + @simplecache def get_experiment_metadata(): return ExperimentMetadata.objects.get(namespace=EXPERIMENT_METADATA_NAME) + @simplecache def get_player_status_parameter(): return Parameter.objects.for_participant(name='player_status') + @simplecache def get_storage_parameter(): return Parameter.objects.for_participant(name='storage') + @simplecache def get_survival_cost_parameter(): return Parameter.objects.for_round(name='survival_cost') + @simplecache def get_max_harvest_decision_parameter(): return Parameter.objects.for_experiment(name='max_harvest_decision') + @simplecache def get_cost_of_living_parameter(): return Parameter.objects.for_round(name='cost_of_living') + @simplecache def get_observe_other_group_parameter(): return Parameter.objects.for_round(name='observe_other_group') + @simplecache def get_shared_resource_enabled_parameter(): return Parameter.objects.for_round(name='shared_resource') + ''' value accessors ''' + def can_observe_other_group(round_configuration): - return round_configuration.get_parameter_value(parameter=get_observe_other_group_parameter(), default=False).boolean_value + return round_configuration.get_parameter_value(parameter=get_observe_other_group_parameter(), + default=False).boolean_value -# players can either be dead or alive -def get_player_status_dv(participant_group_relationship_id): - return ParticipantRoundDataValue.objects.get(parameter=get_player_status_parameter(), participant_group_relationship__pk=participant_group_relationship_id) def is_shared_resource_enabled(round_configuration): - return round_configuration.get_parameter_value(parameter=get_shared_resource_enabled_parameter(), default=False).boolean_value + return round_configuration.get_parameter_value(parameter=get_shared_resource_enabled_parameter(), + default=False).boolean_value + def get_resource_level_dv(group, round_data=None, round_configuration=None): ''' @@ -75,30 +88,38 @@ if is_shared_resource_enabled(round_configuration): return get_shared_resource_level_dv(group, round_data) else: - return get_forestry_resource_level_dv(group, round_data) + return get_unshared_resource_level_dv(group, round_data) -def get_shared_resource_level(group, round_data=None): - return get_shared_resource_level_dv(group, round_data).int_value -def get_shared_resource_level_dv(group, round_data=None): +def get_shared_resource_level(group, round_data=None, cluster=None): + return get_shared_resource_level_dv(group, round_data, cluster).int_value + + +def get_shared_resource_level_dv(group=None, round_data=None, cluster=None): if round_data is None: round_data = group.current_round_data - group_relationship = GroupRelationship.objects.select_related('group_cluster').get(group=group) - cluster = group_relationship.cluster + if cluster is None: + group_relationship = GroupRelationship.objects.select_related('group_cluster').get(group=group) + cluster = group_relationship.cluster return cluster.get_data_value(parameter=get_resource_level_parameter(), round_data=round_data) + def get_initial_resource_level(round_configuration, default=MAX_RESOURCE_LEVEL): return forestry_initial_resource_level(round_configuration, default) + def get_max_harvest(experiment): return experiment.get_parameter_value(parameter=get_max_harvest_decision_parameter(), default=10).int_value + def get_cost_of_living(current_round): return current_round.get_parameter_value(get_cost_of_living_parameter(), default=5).int_value + def get_storage_dv(participant_group_relationship, round_data=None): return participant_group_relationship.get_data_value(parameter=get_storage_parameter(), round_data=round_data) + def get_storage(participant_group_relationship, round_data=None): return get_storage_dv(participant_group_relationship, round_data).int_value @@ -108,17 +129,22 @@ # appropriate default value return sum([pdv.value for pdv in group.get_participant_data_values(parameter=get_storage_parameter())]) + def set_storage(participant_group_relationship, value=0): storage_dv = participant_group_relationship.set_data_value(parameter=get_storage_parameter(), value=value) logger.debug("set storage variable: %s", storage_dv) return storage_dv + def should_reset_resource_level(round_configuration): - return round_configuration.get_parameter_value(parameter=get_reset_resource_level_parameter(), default=False).boolean_value + return round_configuration.get_parameter_value(parameter=get_reset_resource_level_parameter(), + default=False).boolean_value + def get_last_harvest_decision(participant_group_relationship, round_data=None): return participant_group_relationship.get_data_value(parameter=get_harvest_decision_parameter(), - round_data=round_data, default=0).int_value + round_data=round_data, default=0).int_value + @receiver(signals.round_started, sender=EXPERIMENT_METADATA_NAME) def round_started_handler(sender, experiment=None, **kwargs): @@ -130,9 +156,11 @@ # initialize group and participant data values if round_configuration.is_playable_round: experiment.initialize_data_values( - group_parameters=(get_regrowth_parameter(), get_group_harvest_parameter(), get_resource_level_parameter()), - participant_parameters=[get_harvest_decision_parameter(), get_storage_parameter(), get_player_status_parameter()] - ) + group_cluster_parameters=(get_regrowth_parameter(), get_resource_level_parameter(),), + group_parameters=(get_regrowth_parameter(), get_group_harvest_parameter(), get_resource_level_parameter(),), + participant_parameters=(get_harvest_decision_parameter(), get_storage_parameter(), + get_player_status_parameter(),) + ) ''' during a practice or regular round, set up resource levels, participant harvest decision parameters, and group formation @@ -144,9 +172,99 @@ for group in experiment.group_set.all(): ''' set resource level to initial default ''' existing_resource_level = get_resource_level_dv(group, round_data, round_configuration) - group.log("Setting resource level (%s) to initial value [%s]" % (existing_resource_level, initial_resource_level)) + group.log( + "Setting resource level (%s) to initial value [%s]" % (existing_resource_level, initial_resource_level)) existing_resource_level.int_value = initial_resource_level - existing_resource.save() + existing_resource_level.save() + + +def get_total_harvest(group, round_data): + q = ParticipantRoundDataValue.objects.for_group( + group=group, + parameter=get_harvest_decision_parameter(), + round_data=round_data).aggregate(total_harvest=Sum('int_value')) + return q['total_harvest'] + + +def adjust_harvest_decisions(current_resource_level, group, group_size, round_data, total_harvest): + individual_harvest = current_resource_level / group_size + adjusted_harvest = individual_harvest * group_size + group.log( + "GROUP HARVEST ADJUSTMENT - original total harvest: %s, resource level: %s, individual harvest: %s, adjusted group harvest: %s" % + (total_harvest, current_resource_level, individual_harvest, adjusted_harvest)) + # deactivate old participant round data value decisions + ParticipantRoundDataValue.objects.for_group(group=group, + parameter=get_harvest_decision_parameter(), + round_data=round_data).update(is_active=False) + # create new harvest decision data values + for pgr in group.participant_group_relationship_set.all(): + ParticipantRoundDataValue.objects.create(round_data=round_data, + participant_group_relationship=pgr, + parameter=get_harvest_decision_parameter(), + int_value=individual_harvest) + return adjusted_harvest + + +def adjust_resource_level(experiment, group, round_data, max_resource_level=MAX_RESOURCE_LEVEL): + current_resource_level_dv = get_resource_level_dv(group) + current_resource_level = current_resource_level_dv.int_value + total_harvest = get_total_harvest(group, round_data) + logger.debug("total harvest for playable round: %d", total_harvest) + if current_resource_level > 0 and total_harvest > 0: + if total_harvest > current_resource_level: + # divide remaining trees evenly among every participant + group_size = group.size + adjusted_harvest = adjust_harvest_decisions(current_resource_level, group, group_size, round_data, + total_harvest) + total_harvest = adjusted_harvest + + group.log("Harvest: removing %s from current resource level %s" % (total_harvest, current_resource_level)) + set_group_harvest(group, total_harvest, round_data) + current_resource_level = current_resource_level - total_harvest + resource_regrowth = calculate_regrowth(current_resource_level) + group.log("Regrowth: adding %s to current resource level %s" % (resource_regrowth, current_resource_level)) + set_regrowth(group, resource_regrowth, round_data) + current_resource_level_dv.int_value = min(current_resource_level + resource_regrowth, max_resource_level) + current_resource_level_dv.save() + ''' XXX: transfer resource levels across chat and quiz rounds if they exist ''' + if experiment.has_next_round: + ''' set group round data resource_level for each group + regrowth ''' + group.log("Transferring resource level %s to next round" % current_resource_level_dv.int_value) + group.copy_to_next_round(current_resource_level_dv) + + +# FIXME: a lot of duplication between this and adjust_resource_level, see if we can reduce it by operating on group +# cluster data values instead of group data values +def adjust_shared_resource_level(experiment, group_cluster, round_data, max_resource_level=MAX_RESOURCE_LEVEL): + shared_resource_level_dv = get_shared_resource_level_dv(cluster=group_cluster, round_data=round_data) + shared_resource_level = shared_resource_level_dv.int_value + shared_group_harvest = 0 + total_group_size = 0 + group_harvest_dict = {} + for group_relationship in group_cluster.group_relationship_set.all(): + group = group_relationship.group + total_group_size += group.size + group_harvest = get_total_harvest(group, round_data) + group_harvest_dict[group] = group_harvest + shared_group_harvest += group_harvest + group.log("total group harvest: %s" % group_harvest) + for group, group_harvest in group_harvest_dict.items(): + if shared_group_harvest > shared_resource_level: + # adjust each individual harvest for each group in this cluster + group_harvest = adjust_harvest_decisions(shared_resource_level, group, total_group_size, round_data, group_harvest) + set_group_harvest(group, group_harvest, round_data) + shared_resource_level = shared_resource_level - group_harvest + # set regrowth after shared_resource_level has been modified by all groups in this cluster + resource_regrowth = calculate_regrowth(shared_resource_level) + group.log("Regrowth: adding %s to shared resource level %s" % (resource_regrowth, shared_resource_level)) + group_cluster.set_data_value(parameter=get_regrowth_parameter(), round_data=round_data, + value=resource_regrowth) + shared_resource_level_dv.int_value = min(shared_resource_level + resource_regrowth, max_resource_level) + shared_resource_level_dv.save() + if experiment.has_next_round: + ''' transfer shared resource levels to next round ''' + group_cluster.copy_to_next_round(shared_resource_level_dv) + @receiver(signals.round_ended, sender=EXPERIMENT_METADATA_NAME) def round_ended_handler(sender, experiment=None, **kwargs): @@ -157,32 +275,16 @@ round_configuration = experiment.current_round round_data = experiment.get_round_data(round_configuration) logger.debug("ending boundaries round: %s", round_configuration) - max_resource_level = MAX_RESOURCE_LEVEL -# FIXME: need to clarify logic for keeping track of resource levels across rounds + # FIXME: need to clarify logic for keeping track of resource levels across rounds if round_configuration.is_playable_round: - for group in experiment.group_set.all(): - current_resource_level_dv = get_resource_level_dv(group) - current_resource_level = current_resource_level_dv.int_value - q = ParticipantRoundDataValue.objects.for_group(group=group, - parameter=get_harvest_decision_parameter(), round_data=round_data).aggregate(total_harvest=Sum('int_value')) - total_harvest = q['total_harvest'] - logger.debug("total harvest for playable round: %d", total_harvest) - if current_resource_level > 0 and total_harvest > 0: - group.log("Harvest: removing %s from current resource level %s" % (total_harvest, current_resource_level)) - set_group_harvest(group, total_harvest) - current_resource_level = max(current_resource_level - total_harvest, 0) - resource_regrowth = calculate_regrowth(current_resource_level) -# FIXME: if this is a shared resource we should only be doing this once for the shared resource (otherwise we'll apply -# regrowth two or more times depending on group cluster size) - group.log("Regrowth: adding %s to current resource level %s" % (resource_regrowth, current_resource_level)) - set_regrowth(group, resource_regrowth) - current_resource_level_dv.int_value = min(current_resource_level + resource_regrowth, max_resource_level) - current_resource_level_dv.save() - ''' XXX: transfer resource levels across chat and quiz rounds if they exist ''' - if experiment.has_next_round: - ''' set group round data resource_level for each group + regrowth ''' - group.log("Transferring resource level %s to next round" % current_resource_level_dv.int_value) - group.copy_to_next_round(current_resource_level_dv) + if is_shared_resource_enabled(round_configuration): + for group_cluster in GroupCluster.objects.for_experiment(experiment, + session_id=round_configuration.session_id): + adjust_shared_resource_level(experiment, group_cluster, round_data) + else: + for group in experiment.group_set.all(): + adjust_resource_level(experiment, group, round_data) + def calculate_regrowth(resource_level): # FIXME: re-implement based on Tim's logic, this is leftover from forestry diff -r b11d7744a4fb0e21a3340e8224aa2191086a821c -r b0685824f3278311fb2784b1eb38aba2fc1e8bd2 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -1459,6 +1459,7 @@ def _data_parameter_criteria(self, parameter=None, parameter_name=None, round_data=None, **kwargs): criteria = dict([ + ('is_active', True), ('parameter__pk', parameter.pk) if parameter else ('parameter__name', parameter_name), ('round_data__pk', self.current_round_data.pk if round_data is None else round_data.pk) ]) @@ -1559,13 +1560,14 @@ return GroupRelationship.objects.create(cluster=self, group=group) def get_data_value(self, parameter=None, round_data=None, default=None): - # FIXME: factor out the duplication in all the get_data_value methods + # FIXME: factor out duplication in the various get_data_value methods if parameter is None: raise ValueError("cannot get a data value without a parameter") if round_data is None: round_data = self.experiment.current_round_data try: - return GroupClusterDataValue.objects.get(group_cluster=self, round_data=round_data, parameter=parameter) + return GroupClusterDataValue.objects.get(group_cluster=self, round_data=round_data, parameter=parameter, + is_active=True) except GroupClusterDataValue.DoesNotExist as e: if default is None: raise e @@ -1580,6 +1582,21 @@ gcdv.value = value gcdv.save() + def copy_to_next_round(self, data_value): + e = self.experiment + if e.is_last_round: + logger.error("Trying to transfer data value %s past the last round of the experiment", + data_value) + return None + parameter = data_value.parameter + value = data_value.value + next_round_data, created = RoundData.objects.get_or_create(experiment=e, round_configuration=e.next_round) + gcdv, created = GroupClusterDataValue.objects.get_or_create(group=self, round_data=next_round_data, parameter=parameter) + logger.debug("transferred group cluster data value: %s (%s)", gcdv, created) + gcdv.value = value + gcdv.save() + return gcdv + def __unicode__(self): return u"group cluster %s (%s)" % (self.name, self.experiment) @@ -1795,7 +1812,7 @@ if round_data is None: round_data = self.current_round_data try: - return ParticipantRoundDataValue.objects.get(round_data=round_data, parameter=parameter, participant_group_relationship=self) + return ParticipantRoundDataValue.objects.get(is_active=True, round_data=round_data, parameter=parameter, participant_group_relationship=self) except ParticipantRoundDataValue.DoesNotExist as e: if default is None: raise e @@ -1823,13 +1840,25 @@ ordering = ['group', 'participant_number'] class ParticipantRoundDataValueQuerySet(models.query.QuerySet): - def for_group(self, group=None, **kwargs): + def for_participant(self, participant_group_relationship=None, **kwargs): + if participant_group_relationship is None: + raise ValueError("Must specify a participant_group_relationship keyword in this query") return self.select_related( 'parameter', 'participant_group_relationship__participant__user', 'participant_group_relationship__group', 'target_data_value__participant_group_relationship', - ).filter(participant_group_relationship__group=group, **kwargs).order_by('-date_created') + ).filter(participant_group_relationship=participant_group_relationship, is_active=True, **kwargs).order_by('-date_created') + + def for_group(self, group=None, **kwargs): + if group is None: + raise ValueError("Must specify a group in this query") + return self.select_related( + 'parameter', + 'participant_group_relationship__participant__user', + 'participant_group_relationship__group', + 'target_data_value__participant_group_relationship', + ).filter(participant_group_relationship__group=group, is_active=True, **kwargs).order_by('-date_created') class ParticipantRoundDataValue(ParameterizedValue): def __init__(self, *args, **kwargs): diff -r b11d7744a4fb0e21a3340e8224aa2191086a821c -r b0685824f3278311fb2784b1eb38aba2fc1e8bd2 vcweb/forestry/models.py --- a/vcweb/forestry/models.py +++ b/vcweb/forestry/models.py @@ -31,24 +31,23 @@ def has_resource_level(group=None): return group.has_data_parameter(parameter=get_resource_level_parameter()) -# FIXME: revamp def get_harvest_decision(participant_group_relationship, round_data=None): if round_data is None: round_data = participant_group_relationship.get_round_data() try: - return ParticipantRoundDataValue.objects.get(participant_group_relationship=participant_group_relationship, - round_data=round_data, parameter__name='harvest_decision') + return ParticipantRoundDataValue.objects.for_participant(participant_group_relationship=participant_group_relationship, + round_data=round_data, parameter=get_harvest_decision_parameter()) except ParticipantRoundDataValue.DoesNotExist: return None def get_harvest_decisions(group=None): return group.get_participant_data_values(parameter__name='harvest_decision') if group else [] -def set_regrowth(group, value): - group.set_data_value(parameter=get_regrowth_parameter(), value=value) +def set_regrowth(group, value, round_data=None): + group.set_data_value(parameter=get_regrowth_parameter(), value=value, round_data=round_data) -def set_group_harvest(group, value): - group.set_data_value(parameter=get_group_harvest_parameter(), value=value) +def set_group_harvest(group, value, round_data=None): + group.set_data_value(parameter=get_group_harvest_parameter(), value=value, round_data=round_data) def should_reset_resource_level(round_configuration): return round_configuration.get_parameter_value(parameter=get_reset_resource_level_parameter(), default=False).boolean_value Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-25 08:21:58
|
2 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/54ab54ba4be5/ Changeset: 54ab54ba4be5 User: alllee Date: 2013-03-25 08:17:51 Summary: setting up fab pip to upgrade packages as needed as well (semi-dangerous to do in production, need to verify in dev first) Affected #: 1 file diff -r ca9597abc89a4ff252d53debb85779e8b384fb77 -r 54ab54ba4be5c41b284ad36db005501e02de5fc6 fabfile.py --- a/fabfile.py +++ b/fabfile.py @@ -88,7 +88,7 @@ def pip(): ''' looks for requirements.pip in the django project directory ''' - _virtualenv(local, 'pip install -r %(project_path)s/vcweb/requirements.pip' % env) + _virtualenv(local, 'pip install -U -r %(project_path)s/vcweb/requirements.pip' % env) #with cd(env.virtualenv_path): # sudo_chain('chgrp -R %(deploy_group)s .' % env, 'chmod -R g+rw' % env, pty=True) https://bitbucket.org/virtualcommons/vcweb/commits/b11d7744a4fb/ Changeset: b11d7744a4fb User: alllee Date: 2013-03-25 09:21:43 Summary: starting to refactor round ended / started logic and resource level calculations, more refinement needed Affected #: 1 file diff -r 54ab54ba4be5c41b284ad36db005501e02de5fc6 -r b11d7744a4fb0e21a3340e8224aa2191086a821c vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -4,7 +4,7 @@ from vcweb.forestry.models import (get_harvest_decision_parameter, get_harvest_decision, get_regrowth_rate, get_group_harvest_parameter, get_reset_resource_level_parameter, get_resource_level, get_initial_resource_level as forestry_initial_resource_level, set_resource_level, get_regrowth_parameter, - get_resource_level_parameter, has_resource_level, get_resource_level_dv, get_harvest_decisions, + get_resource_level_parameter, has_resource_level, get_resource_level_dv as get_forestry_resource_level_dv, get_harvest_decisions, set_group_harvest, set_regrowth) import logging @@ -48,9 +48,11 @@ return Parameter.objects.for_round(name='observe_other_group') @simplecache -def get_shared_resource_parameter(): +def get_shared_resource_enabled_parameter(): return Parameter.objects.for_round(name='shared_resource') +''' value accessors ''' + def can_observe_other_group(round_configuration): return round_configuration.get_parameter_value(parameter=get_observe_other_group_parameter(), default=False).boolean_value @@ -58,15 +60,32 @@ def get_player_status_dv(participant_group_relationship_id): return ParticipantRoundDataValue.objects.get(parameter=get_player_status_parameter(), participant_group_relationship__pk=participant_group_relationship_id) +def is_shared_resource_enabled(round_configuration): + return round_configuration.get_parameter_value(parameter=get_shared_resource_enabled_parameter(), default=False).boolean_value -''' value accessors ''' +def get_resource_level_dv(group, round_data=None, round_configuration=None): + ''' + Returns either the GroupClusterDataValue (shared resource condition) or the GroupRoundDataValue (standard + resource per group condition) for the given group + ''' + if round_data is None: + round_data = group.current_round_data + if round_configuration is None: + round_configuration = round_data.round_configuration + if is_shared_resource_enabled(round_configuration): + return get_shared_resource_level_dv(group, round_data) + else: + return get_forestry_resource_level_dv(group, round_data) def get_shared_resource_level(group, round_data=None): + return get_shared_resource_level_dv(group, round_data).int_value + +def get_shared_resource_level_dv(group, round_data=None): if round_data is None: round_data = group.current_round_data group_relationship = GroupRelationship.objects.select_related('group_cluster').get(group=group) cluster = group_relationship.cluster - return cluster.get_data_value(parameter=get_resource_level_parameter(), round_data=round_data).int_value + return cluster.get_data_value(parameter=get_resource_level_parameter(), round_data=round_data) def get_initial_resource_level(round_configuration, default=MAX_RESOURCE_LEVEL): return forestry_initial_resource_level(round_configuration, default) @@ -124,8 +143,10 @@ round_data = experiment.get_round_data(round_configuration) for group in experiment.group_set.all(): ''' set resource level to initial default ''' - group.log("Setting resource level to initial value [%s]" % initial_resource_level) - set_resource_level(group, initial_resource_level, round_data=round_data) + existing_resource_level = get_resource_level_dv(group, round_data, round_configuration) + group.log("Setting resource level (%s) to initial value [%s]" % (existing_resource_level, initial_resource_level)) + existing_resource_level.int_value = initial_resource_level + existing_resource.save() @receiver(signals.round_ended, sender=EXPERIMENT_METADATA_NAME) def round_ended_handler(sender, experiment=None, **kwargs): @@ -133,31 +154,36 @@ calculates new resource levels for practice or regular rounds based on the group harvest and resultant regrowth. also responsible for transferring those parameters to the next round as needed. ''' - current_round_configuration = experiment.current_round - logger.debug("ending boundaries round: %s", current_round_configuration) -# FIXME: should read max resource level from the experiment / round configuration instead + round_configuration = experiment.current_round + round_data = experiment.get_round_data(round_configuration) + logger.debug("ending boundaries round: %s", round_configuration) max_resource_level = MAX_RESOURCE_LEVEL - for group in experiment.group_set.all(): - logger.debug("group %s has resource level", group) - if has_resource_level(group): +# FIXME: need to clarify logic for keeping track of resource levels across rounds + if round_configuration.is_playable_round: + for group in experiment.group_set.all(): current_resource_level_dv = get_resource_level_dv(group) current_resource_level = current_resource_level_dv.int_value - if current_round_configuration.is_playable_round: - total_harvest = sum( [ hd.value for hd in get_harvest_decisions(group).all() ]) - logger.debug("total harvest for playable round: %d", total_harvest) - if current_resource_level > 0 and total_harvest > 0: - group.log("Harvest: removing %s from current resource level %s" % (total_harvest, current_resource_level)) - set_group_harvest(group, total_harvest) - current_resource_level = max(current_resource_level - total_harvest, 0) - # implements regrowth function inline - # FIXME: parameterize regrowth rate. - regrowth = current_resource_level / 10 - group.log("Regrowth: adding %s to current resource level %s" % (regrowth, current_resource_level)) - set_regrowth(group, regrowth) - current_resource_level_dv.int_value = min(current_resource_level + regrowth, max_resource_level) - current_resource_level_dv.save() - ''' transfer resource levels across chat and quiz rounds if they exist ''' + q = ParticipantRoundDataValue.objects.for_group(group=group, + parameter=get_harvest_decision_parameter(), round_data=round_data).aggregate(total_harvest=Sum('int_value')) + total_harvest = q['total_harvest'] + logger.debug("total harvest for playable round: %d", total_harvest) + if current_resource_level > 0 and total_harvest > 0: + group.log("Harvest: removing %s from current resource level %s" % (total_harvest, current_resource_level)) + set_group_harvest(group, total_harvest) + current_resource_level = max(current_resource_level - total_harvest, 0) + resource_regrowth = calculate_regrowth(current_resource_level) +# FIXME: if this is a shared resource we should only be doing this once for the shared resource (otherwise we'll apply +# regrowth two or more times depending on group cluster size) + group.log("Regrowth: adding %s to current resource level %s" % (resource_regrowth, current_resource_level)) + set_regrowth(group, resource_regrowth) + current_resource_level_dv.int_value = min(current_resource_level + resource_regrowth, max_resource_level) + current_resource_level_dv.save() + ''' XXX: transfer resource levels across chat and quiz rounds if they exist ''' if experiment.has_next_round: ''' set group round data resource_level for each group + regrowth ''' group.log("Transferring resource level %s to next round" % current_resource_level_dv.int_value) group.copy_to_next_round(current_resource_level_dv) + +def calculate_regrowth(resource_level): + # FIXME: re-implement based on Tim's logic, this is leftover from forestry + return resource_level / 10 Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-24 10:33:52
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/ca9597abc89a/ Changeset: ca9597abc89a User: alllee Date: 2013-03-24 11:33:38 Summary: refactoring using Experiment.number_of_ready_participants and adding missing related_name for Experiment.group_cluster_set Affected #: 3 files diff -r daeac8b896fb70e7e6fc9c85ab2c73b16b58df91 -r ca9597abc89a4ff252d53debb85779e8b384fb77 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -515,7 +515,7 @@ return self.current_round.instructions @property - def ready_participants(self): + def number_of_ready_participants(self): return ParticipantRoundDataValue.objects.filter(parameter=get_participant_ready_parameter(), round_data=self.current_round_data, boolean_value=True).count() @property @@ -1551,7 +1551,7 @@ date_created = models.DateTimeField(default=datetime.now) name = models.CharField(max_length=64, null=True, blank=True) session_id = models.CharField(max_length=64, null=True, blank=True) - experiment = models.ForeignKey(Experiment) + experiment = models.ForeignKey(Experiment, related_name='group_cluster_set') objects = PassThroughManager.for_queryset_class(GroupClusterQuerySet)() @@ -2042,7 +2042,6 @@ return Parameter.objects.get(name='participant_ready', scope=Parameter.Scope.PARTICIPANT) - def is_experimenter(user, experimenter=None): """ returns true if user.experimenter exists and is an Experimenter instance. If an experimenter is passed in as a diff -r daeac8b896fb70e7e6fc9c85ab2c73b16b58df91 -r ca9597abc89a4ff252d53debb85779e8b384fb77 vcweb/core/urls.py --- a/vcweb/core/urls.py +++ b/vcweb/core/urls.py @@ -3,7 +3,7 @@ from vcweb import settings from vcweb.core.views import (Dashboard, LoginView, LogoutView, RegistrationView, monitor, CloneExperimentView, RegisterEmailListView, RegisterSimpleParticipantsView, ClearParticipantsExperimentView, add_experiment, - Participate, download_data, export_configuration, api_logger, participant_ready, number_of_ready_participants, deactivate) + Participate, download_data, export_configuration, api_logger, participant_ready, get_number_of_ready_participants, deactivate) import logging import urllib @@ -21,7 +21,7 @@ url(r'^participate/(?P<namespace>\w+)/instructions', 'instructions', name='namespace_instructions'), url(r'^experiment/add$', add_experiment, name='add_experiment'), url(r'^experiment/participant-ready$', participant_ready, name='participant_ready'), - url(r'^experiment/(?P<pk>\d+)/ready-participants$', number_of_ready_participants, name='number_of_ready_participants'), + url(r'^experiment/(?P<pk>\d+)/ready-participants$', get_number_of_ready_participants, name='number_of_ready_participants'), url(r'^experiment/(?P<pk>\d+)/monitor$', monitor, name='monitor_experiment'), url(r'^experiment/(?P<pk>\d+)/register-email-list$', RegisterEmailListView.as_view(), name='register_email_list'), url(r'^experiment/(?P<pk>\d+)/register-simple$', RegisterSimpleParticipantsView.as_view(), name='register_simple'), diff -r daeac8b896fb70e7e6fc9c85ab2c73b16b58df91 -r ca9597abc89a4ff252d53debb85779e8b384fb77 vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -541,16 +541,13 @@ prdv.submitted = True prdv.boolean_value = True prdv.save() - n = ParticipantRoundDataValue.objects.filter(round_data=round_data, parameter=get_participant_ready_parameter()).count() - return JsonResponse(dumps({'success': True, 'number_of_ready_participants': n})) + return JsonResponse(dumps({'success': True, 'number_of_ready_participants': experiment.number_of_ready_participants})) return JsonResponse(dumps({'success': False})) @participant_required -def number_of_ready_participants(request, pk=None): +def get_number_of_ready_participants(request, pk=None): experiment = get_object_or_404(Experiment, pk=pk) - n = ParticipantRoundDataValue.objects.filter(round_data=experiment.current_round_data, - parameter=get_participant_ready_parameter(), boolean_value=True).count() - return JsonResponse(dumps({'success': True, 'number_of_ready_participants': n})) + return JsonResponse(dumps({'success': True, 'number_of_ready_participants': experiment.number_of_ready_participants})) def handler500(request): return render(request, '500.html') Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-24 10:01:30
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/daeac8b896fb/ Changeset: daeac8b896fb User: alllee Date: 2013-03-24 11:01:09 Summary: adding waiting room template that's aware of of the number of ready participants in the given experiment. Affected #: 6 files diff -r 30368ee049297693877796986c699caefc2b40c6 -r daeac8b896fb70e7e6fc9c85ab2c73b16b58df91 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -114,7 +114,6 @@ group_parameters=(get_regrowth_parameter(), get_group_harvest_parameter(), get_resource_level_parameter()), participant_parameters=[get_harvest_decision_parameter(), get_storage_parameter(), get_player_status_parameter()] ) - ''' during a practice or regular round, set up resource levels, participant harvest decision parameters, and group formation diff -r 30368ee049297693877796986c699caefc2b40c6 -r daeac8b896fb70e7e6fc9c85ab2c73b16b58df91 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -194,7 +194,7 @@ <a href='javascript:void();' data-bind='click: activateInstructionsPageThree'>Back</a></li><li class='next'> -<a href='javascript: void();' data-bind='click: finishedInstructions'>I have fully read and understand these instructions</a> +<a href='javascript: void();' data-bind='click: participantReady'>I have fully read and understand these instructions</a></li></ul></script> @@ -386,11 +386,12 @@ model.activateTreatmentInstructions = function() { model.templateName("TREATMENT_INSTRUCTIONS"); } - model.finishedInstructions = function() { - console.debug("instructions were finished, notifying experimenter"); + model.participantReady = function() { $.post('/experiment/participant-ready', { participant_group_id: {{ participant_group_relationship.pk }} }, function(response) { - console.debug("successfully posted to server, notifying sockjs: " + response); - getWebSocket().send(createMessageEvent("Instructions completed", "client_ready")); + console.debug("successfully posted to server, notifying sockjs"); + console.debug(response); + getWebSocket().send(createMessageEvent("Participant finished reading instructions", "client_ready")); + model.readyParticipants(response.number_of_ready_participants); model.activateWaitingRoomPage(); }); } @@ -501,6 +502,13 @@ $('#progress-modal').modal('show'); experimentModel.update(); break; + case 'participant_ready': + $.get('/experiment/{{experiment.pk}}/ready-participants', function(response) { + console.debug("ready participants response"); + console.debug(response) + experimentModel.readyParticipants(response.number_of_ready_participants); + }); + break; default: console.debug("unhandled json message:" + json); break; diff -r 30368ee049297693877796986c699caefc2b40c6 -r daeac8b896fb70e7e6fc9c85ab2c73b16b58df91 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -1432,7 +1432,7 @@ return round_configuration_value def get_data_value(self, parameter=None, parameter_name=None, round_data=None, default=None): - ''' returns a tuple of (scalar data value, entity DataValue). if no entity data value exists, returns (default value, None) ''' + # FIXME: factor out the duplication in all the get_data_value methods if round_data is None: round_data = self.current_round_data criteria = self._data_parameter_criteria(parameter=parameter, parameter_name=parameter_name, round_data=round_data) @@ -1558,12 +1558,18 @@ def add(self, group): return GroupRelationship.objects.create(cluster=self, group=group) - def get_data_value(self, parameter=None, round_data=None): + def get_data_value(self, parameter=None, round_data=None, default=None): + # FIXME: factor out the duplication in all the get_data_value methods if parameter is None: raise ValueError("cannot get a data value without a parameter") if round_data is None: round_data = self.experiment.current_round_data - return GroupClusterDataValue.objects.get(group_cluster=self, round_data=round_data, parameter=parameter) + try: + return GroupClusterDataValue.objects.get(group_cluster=self, round_data=round_data, parameter=parameter) + except GroupClusterDataValue.DoesNotExist as e: + if default is None: + raise e + return DefaultValue(default) def set_data_value(self, parameter=None, value=None, round_data=None): if parameter is None or value is None: @@ -1785,6 +1791,7 @@ return self.group.get_round_configuration_value(**kwargs) def get_data_value(self, parameter=None, round_data=None, default=None): + # FIXME: factor out the duplication in all the get_data_value methods if round_data is None: round_data = self.current_round_data try: diff -r 30368ee049297693877796986c699caefc2b40c6 -r daeac8b896fb70e7e6fc9c85ab2c73b16b58df91 vcweb/core/urls.py --- a/vcweb/core/urls.py +++ b/vcweb/core/urls.py @@ -3,7 +3,7 @@ from vcweb import settings from vcweb.core.views import (Dashboard, LoginView, LogoutView, RegistrationView, monitor, CloneExperimentView, RegisterEmailListView, RegisterSimpleParticipantsView, ClearParticipantsExperimentView, add_experiment, - Participate, download_data, export_configuration, api_logger, participant_ready, deactivate) + Participate, download_data, export_configuration, api_logger, participant_ready, number_of_ready_participants, deactivate) import logging import urllib @@ -21,6 +21,7 @@ url(r'^participate/(?P<namespace>\w+)/instructions', 'instructions', name='namespace_instructions'), url(r'^experiment/add$', add_experiment, name='add_experiment'), url(r'^experiment/participant-ready$', participant_ready, name='participant_ready'), + url(r'^experiment/(?P<pk>\d+)/ready-participants$', number_of_ready_participants, name='number_of_ready_participants'), url(r'^experiment/(?P<pk>\d+)/monitor$', monitor, name='monitor_experiment'), url(r'^experiment/(?P<pk>\d+)/register-email-list$', RegisterEmailListView.as_view(), name='register_email_list'), url(r'^experiment/(?P<pk>\d+)/register-simple$', RegisterSimpleParticipantsView.as_view(), name='register_simple'), diff -r 30368ee049297693877796986c699caefc2b40c6 -r daeac8b896fb70e7e6fc9c85ab2c73b16b58df91 vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -532,16 +532,25 @@ @participant_required def participant_ready(request): form = ParticipantGroupIdForm(request.POST or None) - valid_form = form.is_valid() - if valid_form: + if form.is_valid(): pgr = get_object_or_404(ParticipantGroupRelationship.objects.select_related('group__experiment'), pk=form.cleaned_data['participant_group_id']) experiment = pgr.group.experiment + round_data = experiment.current_round_data prdv = ParticipantRoundDataValue.objects.get(participant_group_relationship=pgr, - round_data=experiment.get_round_data(), parameter=get_participant_ready_parameter()) + round_data=round_data, parameter=get_participant_ready_parameter()) prdv.submitted = True prdv.boolean_value = True prdv.save() - return JsonResponse(dumps({'success': valid_form})) + n = ParticipantRoundDataValue.objects.filter(round_data=round_data, parameter=get_participant_ready_parameter()).count() + return JsonResponse(dumps({'success': True, 'number_of_ready_participants': n})) + return JsonResponse(dumps({'success': False})) + +@participant_required +def number_of_ready_participants(request, pk=None): + experiment = get_object_or_404(Experiment, pk=pk) + n = ParticipantRoundDataValue.objects.filter(round_data=experiment.current_round_data, + parameter=get_participant_ready_parameter(), boolean_value=True).count() + return JsonResponse(dumps({'success': True, 'number_of_ready_participants': n})) def handler500(request): return render(request, '500.html') diff -r 30368ee049297693877796986c699caefc2b40c6 -r daeac8b896fb70e7e6fc9c85ab2c73b16b58df91 vcweb/vcweb-sockjs.py --- a/vcweb/vcweb-sockjs.py +++ b/vcweb/vcweb-sockjs.py @@ -185,14 +185,14 @@ experimenter functions ''' def send_refresh(self, experimenter, experiment): - return self.broadcast(experimenter, experiment, REFRESH_EVENT) + return self.broadcast(experiment, REFRESH_EVENT, experimenter) def send_update_event(self, experimenter, experiment): - return self.broadcast(experimenter, experiment, UPDATE_EVENT) + return self.broadcast(experiment, UPDATE_EVENT, experimenter) def send_goto(self, experimenter, experiment, url): message = json.dumps({'event_type': 'goto', 'url': url}) - return self.broadcast(experimenter, experiment, message) + return self.broadcast(experiment, message, experimenter) def send_to_experimenter(self, json, experiment_id=None, experimenter_id=None, experiment=None): if experimenter_id is None and experiment_id is None: @@ -208,7 +208,12 @@ logger.debug("no experimenter found with pk %s in experimenters set %s", experimenter_tuple, self.experimenter_to_connection) - def broadcast(self, experimenter, experiment, message): + def broadcast(self, experiment=None, message=None, experimenter=None): + if experimenter is None: + experimenter = experiment.experimenter + if message is None: + logger.error("Tried to broadcast an empty message to %s", experiment) + raise ValueError("Cannot broadcast an empty message to %s" % experiment) participant_connections = [] for (participant_group_id, connection) in self.all_participants(experimenter, experiment): participant_connections.append(participant_group_id) @@ -279,8 +284,7 @@ logger.debug("handling client ready event %s for experiment %s", event, experiment) (per, valid) = self.verify_auth_token(event) if valid: - connection_manager.send_to_experimenter(create_message_event("Participant %s is ready." % per.participant), - experiment=experiment) + connection_manager.broadcast(experiment, create_message_event("Participant %s is ready." % per.participant, event_type='participant_ready')) else: logger.warning("Invalid auth token for participant %s", per) self.send(UNAUTHORIZED_EVENT) Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-23 09:37:12
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/30368ee04929/ Changeset: 30368ee04929 User: alllee Date: 2013-03-23 10:36:54 Summary: getting rid of _ROUND parameter scopes for the time being, they are not used at all and are easily confused with the group / participant parameters Affected #: 3 files diff -r 67eb8845e0e2ff735d924d87a969a38ef53e6dd3 -r 30368ee049297693877796986c699caefc2b40c6 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -61,6 +61,13 @@ ''' value accessors ''' +def get_shared_resource_level(group, round_data=None): + if round_data is None: + round_data = group.current_round_data + group_relationship = GroupRelationship.objects.select_related('group_cluster').get(group=group) + cluster = group_relationship.cluster + return cluster.get_data_value(parameter=get_resource_level_parameter(), round_data=round_data).int_value + def get_initial_resource_level(round_configuration, default=MAX_RESOURCE_LEVEL): return forestry_initial_resource_level(round_configuration, default) @@ -129,7 +136,7 @@ ''' current_round_configuration = experiment.current_round logger.debug("ending boundaries round: %s", current_round_configuration) -# FIXME: should really read max resource level from the experiment / round configuration instead +# FIXME: should read max resource level from the experiment / round configuration instead max_resource_level = MAX_RESOURCE_LEVEL for group in experiment.group_set.all(): logger.debug("group %s has resource level", group) diff -r 67eb8845e0e2ff735d924d87a969a38ef53e6dd3 -r 30368ee049297693877796986c699caefc2b40c6 vcweb/broker/migrations/0002_add_broker_parameters.py --- a/vcweb/broker/migrations/0002_add_broker_parameters.py +++ b/vcweb/broker/migrations/0002_add_broker_parameters.py @@ -26,13 +26,13 @@ creator=experimenter) Parameter.objects.create( name='group_local_bonus', - scope='group_round', + scope='group', type='int', description='Local group bonus based on summed group conservation', creator=experimenter) Parameter.objects.create( name='group_cluster_bonus', - scope='group_cluster_round', + scope='group_cluster', type='int', description='Group cluster bonus based on summed group cluster conservation', creator=experimenter) diff -r 67eb8845e0e2ff735d924d87a969a38ef53e6dd3 -r 30368ee049297693877796986c699caefc2b40c6 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -642,7 +642,7 @@ if participant_parameters is None: participant_parameters = self.parameters(scope=Parameter.Scope.PARTICIPANT) if group_cluster_parameters is None: - group_cluster_parameters = self.parameters(scope=Parameter.Scope.GROUP_CLUSTER_ROUND) + group_cluster_parameters = self.parameters(scope=Parameter.Scope.GROUP_CLUSTER) if round_data is None: round_data = self.current_round_data @@ -1116,32 +1116,33 @@ def for_group(self, **kwargs): return self.get(scope=Parameter.Scope.GROUP, **kwargs) - def for_group_round(self, **kwargs): - return self.get(scope=Parameter.Scope.GROUP_ROUND, **kwargs) - def for_round(self, **kwargs): return self.get(scope=Parameter.Scope.ROUND, **kwargs) def for_experiment(self, **kwargs): return self.get(scope=Parameter.Scope.EXPERIMENT, **kwargs) + def for_group_cluster(self, **kwargs): + return self.get(scope=Parameter.Scope.GROUP_CLUSTER, **kwargs) + class ParameterPassThroughManager(PassThroughManager): def get_by_natural_key(self, name): return self.get(name=name) class Parameter(models.Model): - ParameterType = Choices(('int', 'Integer value'), + ParameterType = Choices( + ('int', 'Integer value'), ('string', 'String value'), ('foreignkey', 'Foreign key'), ('float', 'Floating-point number'), ('boolean', 'Boolean value (true/false)'), ('enum', 'Enumeration')) - Scope = Choices(('round', 'ROUND', 'Parameter applies to the entire round across all groups'), - ('experiment', 'EXPERIMENT', 'Parameter applies to the entire experiment across all groups and rounds'), - ('group', 'GROUP', 'Parameter applies to a group for the duration of the experiment'), - ('group_round', 'GROUP_ROUND', 'Parameter applies to a group for a given round'), - ('group_cluster_round', 'GROUP_CLUSTER_ROUND', 'Parameter applies to a group cluster for a given round'), - ('participant', 'PARTICIPANT', 'Parameter applies for a single participant for a given round')) + Scope = Choices( + ('round', 'ROUND', 'Round configuration parameter applies across all groups for a given round'), + ('experiment', 'EXPERIMENT', 'Experiment configuration parameter applies to the entire experiment across all groups and rounds'), + ('group', 'GROUP', 'Parameter applies to a group for a given round'), + ('group_cluster', 'GROUP_CLUSTER', 'Group cluster data parameter applies to a single group cluster for a given round'), + ('participant', 'PARTICIPANT', 'Participant data parameter applies for a single participant for a given round')) # FIXME: arcane, see if we can encapsulate this better. used to provide sane default values for each parameter type # when the parameter is null NONE_VALUES_DICT = dict(map(lambda x,y: (x[0], y), ParameterType, [0, '', -1, 0.0, False, None])) Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-23 00:25:05
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/67eb8845e0e2/ Changeset: 67eb8845e0e2 User: alllee Date: 2013-03-23 01:25:06 Summary: refactoring group cluster set/get data values and adding hook to Experiment.initialize_data_values to initialize group cluster data values properly Affected #: 2 files diff -r b1d31762954466199f86eda7e502069c46f99c62 -r 67eb8845e0e2ff735d924d87a969a38ef53e6dd3 vcweb/broker/models.py --- a/vcweb/broker/models.py +++ b/vcweb/broker/models.py @@ -68,7 +68,8 @@ # initialize group and participant data values if round_configuration.is_playable_round: experiment.initialize_data_values( - group_parameters=(get_group_local_bonus_parameter(), get_group_cluster_bonus_parameter()), + group_cluster_parameters=(get_group_cluster_bonus_parameter(),), + group_parameters=(get_group_local_bonus_parameter(),), participant_parameters=[get_harvest_decision_parameter(), get_conservation_decision_parameter(), get_participant_link_parameter()] ) diff -r b1d31762954466199f86eda7e502069c46f99c62 -r 67eb8845e0e2ff735d924d87a969a38ef53e6dd3 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -633,14 +633,24 @@ users.append(user) self.register_participants(users=users, institution=institution, password=password) - def initialize_data_values(self, group_parameters=None, participant_parameters=None, round_data=None): +# FIXME: figure out how to declaratively do this so experiments can more easily notify "I have these data values to +# initialize at the start of each round. + def initialize_data_values(self, group_parameters=None, participant_parameters=None, group_cluster_parameters=None, round_data=None): logger.debug("initializing [participant params: %s] [group parameters: %s] ", participant_parameters, group_parameters) if group_parameters is None: group_parameters = self.parameters(scope=Parameter.Scope.GROUP) if participant_parameters is None: participant_parameters = self.parameters(scope=Parameter.Scope.PARTICIPANT) + if group_cluster_parameters is None: + group_cluster_parameters = self.parameters(scope=Parameter.Scope.GROUP_CLUSTER_ROUND) if round_data is None: round_data = self.current_round_data + +# create group cluster parameter data values + for group_cluster in self.group_cluster_set.all(): + for parameter in group_cluster_parameters: + gcdv, created = GroupClusterDataValue.objects.get_or_create(round_data=round_data, parameter=parameter, cluster=group_cluster) + for group in self.group_set.select_related('parameter').all(): for parameter in group_parameters: group_data_value, created = GroupRoundDataValue.objects.get_or_create(round_data=round_data, group=group, parameter=parameter) @@ -1547,15 +1557,21 @@ def add(self, group): return GroupRelationship.objects.create(cluster=self, group=group) + def get_data_value(self, parameter=None, round_data=None): + if parameter is None: + raise ValueError("cannot get a data value without a parameter") + if round_data is None: + round_data = self.experiment.current_round_data + return GroupClusterDataValue.objects.get(group_cluster=self, round_data=round_data, parameter=parameter) + def set_data_value(self, parameter=None, value=None, round_data=None): if parameter is None or value is None: raise ValueError("need a parameter and value to set") if round_data is None: round_data = self.experiment.current_round_data -# FIXME: this should follow the get / set style of the other setters, but we're not initializing cluster data values yet - return GroupClusterDataValue.objects.create(group_cluster=self, - round_data=round_data, value=value, parameter=parameter) - + gcdv = GroupClusterDataValue.objects.get(group_cluster=self, round_data=round_data, parameter=parameter) + gcdv.value = value + gcdv.save() def __unicode__(self): return u"group cluster %s (%s)" % (self.name, self.experiment) Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-22 22:42:55
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/b1d317629544/ Changeset: b1d317629544 User: alllee Date: 2013-03-22 23:42:55 Summary: adding GroupCluster logic to round ended for calculating harvest decision / conservation decision bonuses Affected #: 3 files diff -r c8198aae5658342c84413233ce304daeedf8f077 -r b1d31762954466199f86eda7e502069c46f99c62 vcweb/broker/models.py --- a/vcweb/broker/models.py +++ b/vcweb/broker/models.py @@ -1,8 +1,8 @@ from django.db import models from django.dispatch import receiver from vcweb.core import signals, simplecache -from vcweb.core.models import Parameter, ParticipantRoundDataValue -from vcweb.forestry.models import get_harvest_decision_parameter, set_harvest_decision +from vcweb.core.models import (Parameter, ParticipantRoundDataValue, GroupCluster) +from vcweb.forestry.models import get_harvest_decision_parameter, set_harvest_decision, get_harvest_decision import logging logger = logging.getLogger(__name__) @@ -39,6 +39,10 @@ def get_group_local_bonus_threshold_parameter(): return Parameter.objects.get(name='group_local_bonus_threshold') +def get_conservation_decision(participant_group_relationship, round_data=None): + return participant_group_relationship.get_data_value(parameter=get_conservation_decision_parameter(), + round_data=round_data, default=0).int_value + def set_conservation_decision(participant_group_relationship, value, round_data=None): if round_data is None: round_data = participant_group_relationship.current_round_data @@ -48,6 +52,12 @@ prdv.int_value = value prdv.save() +def get_group_local_bonus_threshold(round_configuration): + return round_configuration.get_parameter_value(parameter=get_group_local_bonus_parameter(), default=5).int_value + +def get_group_cluster_bonus_threshold(round_configuration): + return round_configuration.get_parameter_value(parameter=get_group_cluster_bonus_parameter(), default=22).int_value + @receiver(signals.round_started, sender=EXPERIMENT_METADATA_NAME) def round_started_handler(sender, experiment=None, **kwargs): if experiment is None: @@ -70,3 +80,22 @@ ''' current_round_configuration = experiment.current_round logger.debug("ending boundaries round: %s", current_round_configuration) + round_data = experiment.current_round_data + if current_round_configuration.is_playable_round: + local_threshold = get_group_local_bonus_threshold(current_round_configuration) + group_cluster_threshold = get_group_cluster_bonus_threshold(current_round_configuration) + for group_cluster in GroupCluster.objects.for_experiment(experiment): + group_cluster_conservation_hours = 0 + for group_relationship in group_cluster.group_relationship_set.all(): + group_conservation_hours = 0 + group = group_relationship.group + for pgr in group.participant_group_relationship_set.all(): + conservation_hours = get_conservation_decision(pgr, round_data=round_data) + group_conservation_hours += conservation_hours + # calculate local group conservation bonus + local_bonus = calculate_group_local_bonus(group_conservation_hours, local_threshold) + group.set_data_value(parameter=get_group_local_bonus_parameter(), value=local_bonus) + group_cluster_conservation_hours += group_conservation_hours + group_cluster_bonus = calculate_group_cluster_bonus(group_cluster_conservation_hours, + group_cluster_threshold) + group_cluster.set_data_value(parameter=get_group_cluster_bonus_parameter(), value=group_cluster_bonus) diff -r c8198aae5658342c84413233ce304daeedf8f077 -r b1d31762954466199f86eda7e502069c46f99c62 vcweb/broker/views.py --- a/vcweb/broker/views.py +++ b/vcweb/broker/views.py @@ -8,7 +8,8 @@ ParticipantExperimentRelationship, RoundConfiguration, ChatMessage, ParticipantRoundDataValue) from vcweb.broker.models import (get_max_harvest_hours, get_harvest_decision_parameter, - get_conservation_decision_parameter, set_harvest_decision, set_conservation_decision) + get_conservation_decision_parameter, set_harvest_decision, set_conservation_decision, get_harvest_decision, + get_conservation_decision) import random @@ -60,6 +61,7 @@ group = participant_group_relationship.group experiment_configuration = experiment.experiment_configuration round_configuration = experiment.current_round + previous_round_data = experiment.get_round_data(round_configuration=experiment.previous_round) round_data = experiment.current_round_data # experiment configuration data @@ -97,7 +99,8 @@ experiment_model_dict['globalThreshold'] = group.get_data_value(parameter_name='group_cluster_bonus_threshold', round_data=round_data, default=22).int_value # data from the last round - experiment_model_dict['lastRoundHarvestDecision'] = 5 + experiment_model_dict['lastRoundHarvestDecision'] = get_harvest_decision(participant_group_relationship, round_data=previous_round_data) + experiment_model_dict['lastRoundConservationDecision'] = get_conservation_decision(participant_group_relationship, round_data=previous_round_data) experiment_model_dict['lastRoundMyGroupConservation'] = 10 experiment_model_dict['lastRoundGlobalConservation'] = 10 experiment_model_dict['lastRoundGroupLocalBonus'] = 10 diff -r c8198aae5658342c84413233ce304daeedf8f077 -r b1d31762954466199f86eda7e502069c46f99c62 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -1532,15 +1532,31 @@ class Meta: ordering = ['experiment', 'number'] +class GroupClusterQuerySet(models.query.QuerySet): + def for_experiment(self, experiment, **kwargs): + return self.prefetch_related('group_relationship_set').filter(experiment=experiment, **kwargs) + class GroupCluster(models.Model): date_created = models.DateTimeField(default=datetime.now) name = models.CharField(max_length=64, null=True, blank=True) session_id = models.CharField(max_length=64, null=True, blank=True) experiment = models.ForeignKey(Experiment) + objects = PassThroughManager.for_queryset_class(GroupClusterQuerySet)() + def add(self, group): return GroupRelationship.objects.create(cluster=self, group=group) + def set_data_value(self, parameter=None, value=None, round_data=None): + if parameter is None or value is None: + raise ValueError("need a parameter and value to set") + if round_data is None: + round_data = self.experiment.current_round_data +# FIXME: this should follow the get / set style of the other setters, but we're not initializing cluster data values yet + return GroupClusterDataValue.objects.create(group_cluster=self, + round_data=round_data, value=value, parameter=parameter) + + def __unicode__(self): return u"group cluster %s (%s)" % (self.name, self.experiment) Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-22 22:16:38
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/c8198aae5658/ Changeset: c8198aae5658 User: alllee Date: 2013-03-22 23:16:38 Summary: fixing bugs in GroupRelationship / GroupCluster creation Affected #: 1 file diff -r 382e0877518b5f426e9ca3f8959df4c223266160 -r c8198aae5658342c84413233ce304daeedf8f077 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -735,11 +735,11 @@ group_cluster_size, len(groups)) return random.shuffle(groups) - g = GroupCluster.objects.create(session_id=session_id, experiment=self) + gc = GroupCluster.objects.create(session_id=session_id, experiment=self) for group in groups: - if g.group_set.count() == group_cluster_size: - g = GroupCluster.objects.create(session_id=session_id, experiment=self) - g.group_set.add(group) + if gc.group_relationship_set.count() == group_cluster_size: + gc = GroupCluster.objects.create(session_id=session_id, experiment=self) + gc.add(group) def get_round_configuration(self, sequence_number): return RoundConfiguration.objects.get(experiment_configuration__experiment=self, sequence_number=sequence_number) @@ -1538,6 +1538,9 @@ session_id = models.CharField(max_length=64, null=True, blank=True) experiment = models.ForeignKey(Experiment) + def add(self, group): + return GroupRelationship.objects.create(cluster=self, group=group) + def __unicode__(self): return u"group cluster %s (%s)" % (self.name, self.experiment) @@ -1546,7 +1549,7 @@ class GroupRelationship(models.Model): date_created = models.DateTimeField(default=datetime.now) - cluster = models.ForeignKey(GroupCluster, related_name='group_set') + cluster = models.ForeignKey(GroupCluster, related_name='group_relationship_set') group = models.ForeignKey(Group) def __unicode__(self): Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-22 22:10:43
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/382e0877518b/ Changeset: 382e0877518b User: alllee Date: 2013-03-22 23:10:42 Summary: removing unused group cluster max size field Affected #: 1 file diff -r df784a63c10db920b457e5254b1a26b991b29ed0 -r 382e0877518b5f426e9ca3f8959df4c223266160 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -1536,7 +1536,6 @@ date_created = models.DateTimeField(default=datetime.now) name = models.CharField(max_length=64, null=True, blank=True) session_id = models.CharField(max_length=64, null=True, blank=True) - max_size = models.PositiveIntegerField(default=0) experiment = models.ForeignKey(Experiment) def __unicode__(self): Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-22 22:06:13
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/df784a63c10d/ Changeset: df784a63c10d User: alllee Date: 2013-03-22 23:06:09 Summary: fixing bug in set_harvest_decision, including round_data Affected #: 1 file diff -r 26a1a25514a4daaa9ac84b1ed65084b9cb323f66 -r df784a63c10db920b457e5254b1a26b991b29ed0 vcweb/forestry/models.py --- a/vcweb/forestry/models.py +++ b/vcweb/forestry/models.py @@ -103,8 +103,15 @@ def get_initial_resource_level_parameter(): return Parameter.objects.for_round(name='initial_resource_level') -def set_harvest_decision(participant_group_relationship=None, value=None): - participant_group_relationship.set_data_value(parameter=get_harvest_decision_parameter(), value=value) +def set_harvest_decision(participant_group_relationship=None, value=None, round_data=None): + if round_data is None: + round_data = participant_group_relationship.current_round_data + prdv = ParticipantRoundDataValue.objects.get(parameter=get_harvest_decision_parameter(), + participant_group_relationship=participant_group_relationship, + round_data=round_data + ) + prdv.int_value = value + prdv.save() def set_resource_level(group, value, round_data=None): return group.set_data_value(parameter=get_resource_level_parameter(), round_data=round_data, value=value) Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-22 22:03:19
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/26a1a25514a4/ Changeset: 26a1a25514a4 User: alllee Date: 2013-03-22 23:03:18 Summary: setting harvest and conservation decisions properly on submit decision Affected #: 3 files diff -r 0584aaebd11d1ec9e0ddba2e542c334fc4455837 -r 26a1a25514a4daaa9ac84b1ed65084b9cb323f66 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -8,7 +8,6 @@ set_group_harvest, set_regrowth) import logging - logger = logging.getLogger(__name__) # FIXME: hacky, should figure out a better way to bind this module with the ExperimentMetadata instance that it is diff -r 0584aaebd11d1ec9e0ddba2e542c334fc4455837 -r 26a1a25514a4daaa9ac84b1ed65084b9cb323f66 vcweb/broker/models.py --- a/vcweb/broker/models.py +++ b/vcweb/broker/models.py @@ -1,14 +1,72 @@ from django.db import models +from django.dispatch import receiver +from vcweb.core import signals, simplecache +from vcweb.core.models import Parameter, ParticipantRoundDataValue +from vcweb.forestry.models import get_harvest_decision_parameter, set_harvest_decision -from vcweb.core import simplecache -from vcweb.core.models import Parameter -from vcweb.forestry.models import get_harvest_decision_parameter +import logging +logger = logging.getLogger(__name__) + +EXPERIMENT_METADATA_NAME = 'broker' def get_max_harvest_hours(experiment): - return experiment.experiment_configuration.get_parameter_value(name='max_harvest_hours', default=10).int_value + return experiment.experiment_configuration.get_parameter_value(name='max_hours', default=10).int_value -# FIXME: this is currently broken +''' participant parameters ''' @simplecache -def get_conservation_hours_parameter(): - return Parameter.objects.get(name='conservation_hours') +def get_participant_link_parameter(): + return Parameter.objects.get(name='participant_link') +@simplecache +def get_conservation_decision_parameter(): + return Parameter.objects.get(name='conservation_decision') + +''' group round parameters ''' +@simplecache +def get_group_local_bonus_parameter(): + return Parameter.objects.get(name='group_local_bonus') + +@simplecache +def get_group_cluster_bonus_parameter(): + return Parameter.objects.get(name='group_cluster_bonus') + +''' round configuration parameters ''' +@simplecache +def get_group_cluster_bonus_threshold_parameter(): + return Parameter.objects.get(name='group_cluster_bonus_threshold') + +@simplecache +def get_group_local_bonus_threshold_parameter(): + return Parameter.objects.get(name='group_local_bonus_threshold') + +def set_conservation_decision(participant_group_relationship, value, round_data=None): + if round_data is None: + round_data = participant_group_relationship.current_round_data + prdv = ParticipantRoundDataValue.objects.get(parameter=get_conservation_decision_parameter(), + participant_group_relationship=participant_group_relationship, + round_data=round_data) + prdv.int_value = value + prdv.save() + +@receiver(signals.round_started, sender=EXPERIMENT_METADATA_NAME) +def round_started_handler(sender, experiment=None, **kwargs): + if experiment is None: + logger.error("Received round started signal with no experiment: %s", sender) + raise ValueError("Received round started signal with no experiment") + round_configuration = experiment.current_round + logger.debug("setting up round %s", round_configuration) + # initialize group and participant data values + if round_configuration.is_playable_round: + experiment.initialize_data_values( + group_parameters=(get_group_local_bonus_parameter(), get_group_cluster_bonus_parameter()), + participant_parameters=[get_harvest_decision_parameter(), get_conservation_decision_parameter(), get_participant_link_parameter()] + ) + +@receiver(signals.round_ended, sender=EXPERIMENT_METADATA_NAME) +def round_ended_handler(sender, experiment=None, **kwargs): + ''' + calculates new resource levels for practice or regular rounds based on the group harvest and resultant regrowth. + also responsible for transferring those parameters to the next round as needed. + ''' + current_round_configuration = experiment.current_round + logger.debug("ending boundaries round: %s", current_round_configuration) diff -r 0584aaebd11d1ec9e0ddba2e542c334fc4455837 -r 26a1a25514a4daaa9ac84b1ed65084b9cb323f66 vcweb/broker/views.py --- a/vcweb/broker/views.py +++ b/vcweb/broker/views.py @@ -7,7 +7,8 @@ from vcweb.core.models import (is_participant, is_experimenter, Experiment, ParticipantGroupRelationship, ParticipantExperimentRelationship, RoundConfiguration, ChatMessage, ParticipantRoundDataValue) -from vcweb.broker.models import get_max_harvest_hours, get_harvest_decision_parameter, get_conservation_hours_parameter +from vcweb.broker.models import (get_max_harvest_hours, get_harvest_decision_parameter, + get_conservation_decision_parameter, set_harvest_decision, set_conservation_decision) import random @@ -25,13 +26,9 @@ pgr = get_object_or_404(ParticipantGroupRelationship, pk=participant_group_id) harvest_hours = form.cleaned_data['integer_decision'] conservation_hours = get_max_harvest_hours(experiment) - harvest_hours - round_data = experiment.get_round_data() - ParticipantRoundDataValue.objects.create(participant_group_relationship=pgr, int_value=harvest_hours, - round_data=round_data, parameter=get_harvest_decision_parameter()) - pgr.participant_data_value_set.create(int_value=conservation_hours, round_data=round_data, - parameter=get_conservation_hours_parameter()) - # set harvest decision for participant - # FIXME: inconsistency, GET returns HTML and POST return JSON.. + round_data = experiment.current_round_data + set_harvest_decision(pgr, harvest_hours, round_data=round_data) + set_conservation_decision(pgr, conservation_hours, round_data=round_data) return JsonResponse(dumps({ 'success': True, 'experimentModelJson': get_view_model_json(experiment, pgr)})) for field in form: if field.errors: Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-22 21:45:01
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/0584aaebd11d/ Changeset: 0584aaebd11d User: alllee Date: 2013-03-22 22:44:58 Summary: creating data migration for broker experiment parameters unfortunately class variables don't appear to be available in south migrations Affected #: 3 files diff -r 9418327389116cb15600c3e1ba52cf76ccd0cb8a -r 0584aaebd11d1ec9e0ddba2e542c334fc4455837 vcweb/broker/migrations/0002_add_broker_parameters.py --- /dev/null +++ b/vcweb/broker/migrations/0002_add_broker_parameters.py @@ -0,0 +1,453 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + + def forwards(self, orm): + "Write your forwards methods here." + # Note: Remember to use orm['appname.ModelName'] rather than "from appname.models..." + Experimenter = orm['core.Experimenter'] + Parameter = orm['core.Parameter'] + experimenter = Experimenter.objects.get(pk=1) + Parameter.objects.create( + name='conservation_decision', + type='int', + description='Number of hours devoted to conservation', + creator=experimenter) + Parameter.objects.create( + name='max_hours', + scope='experiment', + type='int', + default_value_string="10", + description='Maximum number of hours available to devote to conservation or harvesting', + creator=experimenter) + Parameter.objects.create( + name='group_local_bonus', + scope='group_round', + type='int', + description='Local group bonus based on summed group conservation', + creator=experimenter) + Parameter.objects.create( + name='group_cluster_bonus', + scope='group_cluster_round', + type='int', + description='Group cluster bonus based on summed group cluster conservation', + creator=experimenter) + Parameter.objects.create( + name='participant_link', + scope='participant', + type='int', + class_name='core.ParticipantGroupRelationship', + description='Linkage between two participant group relationships (e.g., an edge)', + creator=experimenter) + Parameter.objects.create( + name='group_local_bonus_threshold', + scope='round', + type='int', + default_value_string="5", + description="Local group bonus threshold for conservation hours contributed by the entire group to receive a bonus", + creator=experimenter) + Parameter.objects.create( + name='group_cluster_bonus_threshold', + scope='round', + type='int', + default_value_string="22", + description="Group cluster bonus threshold for conservation hours contributed by the entire group cluster to receive a bonus", + creator=experimenter) + + def backwards(self, orm): + "Write your backwards methods here." + Parameter = orm['core.Parameter'] + Parameter.objects.get(name='conservation_decision').delete() + Parameter.objects.get(name='max_hours').delete() + Parameter.objects.get(name='group_local_bonus').delete() + Parameter.objects.get(name='group_cluster_bonus').delete() + Parameter.objects.get(name='participant_link').delete() + Parameter.objects.get(name='group_local_bonus_threshold').delete() + Parameter.objects.get(name='group_cluster_bonus_threshold').delete() + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'core.activitylog': { + 'Meta': {'object_name': 'ActivityLog'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'log_message': ('django.db.models.fields.TextField', [], {}) + }, + u'core.address': { + 'Meta': {'object_name': 'Address'}, + 'city': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'state': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), + 'street1': ('django.db.models.fields.CharField', [], {'max_length': '256'}), + 'street2': ('django.db.models.fields.CharField', [], {'max_length': '256'}), + 'zipcode': ('django.db.models.fields.CharField', [], {'max_length': '8', 'blank': 'True'}) + }, + u'core.chatmessage': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'ChatMessage', '_ormbases': [u'core.ParticipantRoundDataValue']}, + u'participantrounddatavalue_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ParticipantRoundDataValue']", 'unique': 'True', 'primary_key': 'True'}), + 'target_participant': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'target_participant_chat_message_set'", 'null': 'True', 'to': u"orm['core.ParticipantGroupRelationship']"}) + }, + u'core.comment': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'Comment', '_ormbases': [u'core.ParticipantRoundDataValue']}, + u'participantrounddatavalue_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ParticipantRoundDataValue']", 'unique': 'True', 'primary_key': 'True'}) + }, + u'core.experiment': { + 'Meta': {'ordering': "['date_created', 'status']", 'object_name': 'Experiment'}, + 'amqp_exchange_name': ('django.db.models.fields.CharField', [], {'default': "'vcweb.default.exchange'", 'max_length': '64'}), + 'authentication_code': ('django.db.models.fields.CharField', [], {'default': "'vcweb.auth.code'", 'max_length': '32'}), + 'current_repeated_round_sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'current_round_elapsed_time': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'current_round_sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'current_round_start_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentConfiguration']"}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentMetadata']"}), + 'experimenter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experimenter']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'start_date_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'INACTIVE'", 'max_length': '32'}), + 'tick_duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'total_elapsed_time': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + }, + u'core.experimentactivitylog': { + 'Meta': {'object_name': 'ExperimentActivityLog', '_ormbases': [u'core.ActivityLog']}, + u'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': u"orm['core.Experiment']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.experimentconfiguration': { + 'Meta': {'ordering': "['experiment_metadata', 'creator', 'date_created']", 'object_name': 'ExperimentConfiguration'}, + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': u"orm['core.Experimenter']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'exchange_rate': ('django.db.models.fields.DecimalField', [], {'default': '0.2', 'null': 'True', 'max_digits': '6', 'decimal_places': '2', 'blank': 'True'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': u"orm['core.ExperimentMetadata']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation_subject': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'is_experimenter_driven': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'max_group_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), + 'max_number_of_participants': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'treatment_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}) + }, + u'core.experimenter': { + 'Meta': {'ordering': "['user']", 'object_name': 'Experimenter'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'authentication_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'failed_password_attempts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'institution': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Institution']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'experimenter'", 'unique': 'True', 'to': u"orm['auth.User']"}) + }, + u'core.experimenterrequest': { + 'Meta': {'object_name': 'ExperimenterRequest'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'}) + }, + u'core.experimentmetadata': { + 'Meta': {'ordering': "['namespace', 'date_created']", 'object_name': 'ExperimentMetadata'}, + 'about_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'default_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentConfiguration']", 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'namespace': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'short_name': ('django.db.models.fields.SlugField', [], {'max_length': '32', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'core.experimentparametervalue': { + 'Meta': {'object_name': 'ExperimentParameterValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_parameter_value_set'", 'to': u"orm['core.ExperimentConfiguration']"}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.experimentsession': { + 'Meta': {'object_name': 'ExperimentSession'}, + 'capacity': ('django.db.models.fields.PositiveIntegerField', [], {'default': '20'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_session_set'", 'to': u"orm['auth.User']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_session_set'", 'to': u"orm['core.ExperimentMetadata']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'scheduled_date': ('django.db.models.fields.DateTimeField', [], {}), + 'scheduled_end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.group': { + 'Meta': {'ordering': "['experiment', 'number']", 'object_name': 'Group'}, + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'max_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), + 'number': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.groupactivitylog': { + 'Meta': {'object_name': 'GroupActivityLog', '_ormbases': [u'core.ActivityLog']}, + u'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': u"orm['core.Group']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.groupcluster': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'GroupCluster'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'max_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.groupclusterdatavalue': { + 'Meta': {'object_name': 'GroupClusterDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'group_cluster': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.GroupCluster']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'round_data': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_cluster_data_value_set'", 'to': u"orm['core.RoundData']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.grouprelationship': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'GroupRelationship'}, + 'cluster': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_set'", 'to': u"orm['core.GroupCluster']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'core.grouprounddatavalue': { + 'Meta': {'ordering': "['round_data', 'group', 'parameter']", 'object_name': 'GroupRoundDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'data_value_set'", 'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'round_data': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_data_value_set'", 'to': u"orm['core.RoundData']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.institution': { + 'Meta': {'object_name': 'Institution'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}) + }, + u'core.invitation': { + 'Meta': {'object_name': 'Invitation'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment_session': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentSession']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'participant': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Participant']"}), + 'sender': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + }, + u'core.like': { + 'Meta': {'ordering': "['-date_created', 'round_data', 'participant_group_relationship', 'parameter']", 'object_name': 'Like', '_ormbases': [u'core.ParticipantRoundDataValue']}, + u'participantrounddatavalue_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ParticipantRoundDataValue']", 'unique': 'True', 'primary_key': 'True'}) + }, + u'core.parameter': { + 'Meta': {'ordering': "['name']", 'unique_together': "(('name', 'experiment_metadata', 'scope'),)", 'object_name': 'Parameter'}, + 'class_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experimenter']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'default_value_string': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '512', 'null': 'True', 'blank': 'True'}), + 'display_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'enum_choices': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentMetadata']", 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_required': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'scope': ('django.db.models.fields.CharField', [], {'default': "'round'", 'max_length': '32'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + u'core.participant': { + 'Meta': {'ordering': "['user']", 'object_name': 'Participant'}, + 'address': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Address']", 'null': 'True', 'blank': 'True'}), + 'authentication_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'birthdate': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'can_receive_invitations': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'experiments': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'participant_set'", 'symmetrical': 'False', 'through': u"orm['core.ParticipantExperimentRelationship']", 'to': u"orm['core.Experiment']"}), + 'failed_password_attempts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'gender': ('django.db.models.fields.CharField', [], {'max_length': '1', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'participant_set'", 'symmetrical': 'False', 'through': u"orm['core.ParticipantGroupRelationship']", 'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'institution': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Institution']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'participant'", 'unique': 'True', 'to': u"orm['auth.User']"}) + }, + u'core.participantexperimentrelationship': { + 'Meta': {'object_name': 'ParticipantExperimentRelationship'}, + 'additional_data': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'current_location': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_relationship_set'", 'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_completed_round_sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'participant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_relationship_set'", 'to': u"orm['core.Participant']"}), + 'participant_identifier': ('django.db.models.fields.CharField', [], {'max_length': '32'}), + 'sequential_participant_identifier': ('django.db.models.fields.PositiveIntegerField', [], {}) + }, + u'core.participantgrouprelationship': { + 'Meta': {'ordering': "['group', 'participant_number']", 'object_name': 'ParticipantGroupRelationship'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'first_visit': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_group_relationship_set'", 'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'notifications_since': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'null': 'True', 'blank': 'True'}), + 'participant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_group_relationship_set'", 'to': u"orm['core.Participant']"}), + 'participant_number': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'round_joined': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.participantrounddatavalue': { + 'Meta': {'ordering': "['-date_created', 'round_data', 'participant_group_relationship', 'parameter']", 'object_name': 'ParticipantRoundDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'participant_group_relationship': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_data_value_set'", 'to': u"orm['core.ParticipantGroupRelationship']"}), + 'round_data': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_data_value_set'", 'to': u"orm['core.RoundData']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'submitted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'target_data_value': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'target_data_value_set'", 'null': 'True', 'to': u"orm['core.ParticipantRoundDataValue']"}) + }, + u'core.participantsignup': { + 'Meta': {'object_name': 'ParticipantSignup'}, + 'attendance': ('django.db.models.fields.PositiveIntegerField', [], {'max_length': '1', 'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'signup_set'", 'to': u"orm['core.Invitation']"}), + 'participant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'signup_set'", 'to': u"orm['core.Participant']"}) + }, + u'core.quizquestion': { + 'Meta': {'object_name': 'QuizQuestion'}, + 'answer': ('django.db.models.fields.CharField', [], {'max_length': '64'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'default_quiz_question_set'", 'null': 'True', 'to': u"orm['core.Experiment']"}), + 'explanation': ('django.db.models.fields.CharField', [], {'max_length': '512'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'input_type': ('django.db.models.fields.CharField', [], {'max_length': '32'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '512'}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'quiz_question_set'", 'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.roundconfiguration': { + 'Meta': {'ordering': "['experiment_configuration', 'sequence_number', 'date_created']", 'object_name': 'RoundConfiguration'}, + 'chat_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'create_group_clusters': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'debriefing': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'display_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'duration': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_configuration_set'", 'to': u"orm['core.ExperimentConfiguration']"}), + 'group_cluster_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '2'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'instructions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'preserve_existing_groups': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'randomize_groups': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'repeat': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'round_type': ('django.db.models.fields.CharField', [], {'default': "'REGULAR'", 'max_length': '32'}), + 'sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'survey_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'template_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.rounddata': { + 'Meta': {'ordering': "['round_configuration']", 'unique_together': "(('round_configuration', 'experiment'),)", 'object_name': 'RoundData'}, + 'elapsed_time': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_data_set'", 'to': u"orm['core.Experiment']"}), + 'experimenter_notes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_data_set'", 'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.roundparametervalue': { + 'Meta': {'object_name': 'RoundParameterValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_parameter_value_set'", 'to': u"orm['core.RoundConfiguration']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.spoolparticipantstatistics': { + 'Meta': {'object_name': 'SpoolParticipantStatistics'}, + 'absences': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'discharges': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitations': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'participant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'spool_statistics_set'", 'to': u"orm['core.Participant']"}), + 'participations': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + } + } + + complete_apps = ['core', 'broker'] + symmetrical = True diff -r 9418327389116cb15600c3e1ba52cf76ccd0cb8a -r 0584aaebd11d1ec9e0ddba2e542c334fc4455837 vcweb/broker/views.py --- a/vcweb/broker/views.py +++ b/vcweb/broker/views.py @@ -68,8 +68,8 @@ # experiment configuration data experiment_model_dict['maxHarvestDecision'] = 10 experiment_model_dict['maxEarnings'] = 20.00 - experiment_model_dict['localBonus'] = experiment_configuration.get_parameter_value(name='local_bonus', default=50).int_value - experiment_model_dict['globalBonus'] = experiment_configuration.get_parameter_value(name='global_bonus', default=50).int_value + experiment_model_dict['localBonus'] = experiment_configuration.get_parameter_value(name='group_local_bonus', default=50).int_value + experiment_model_dict['globalBonus'] = experiment_configuration.get_parameter_value(name='group_cluster_bonus', default=50).int_value # round configuration data experiment_model_dict['chatEnabled'] = True @@ -92,13 +92,12 @@ experiment_model_dict['networkStructureImageBackgroundUrl'] = "{{ STATIC_URL }}images/broker/SES.jpg" - # round data # group data values # FIXME: make sure round_setup initializes these GroupRoundDataValues properly by looking them up from the # RoundConfiguration and assigning them - experiment_model_dict['localThreshold'] = group.get_data_value(parameter_name='local_threshold', round_data=round_data, default=5).int_value - experiment_model_dict['globalThreshold'] = group.get_data_value(parameter_name='global_threshold', round_data=round_data, default=5).int_value + experiment_model_dict['localThreshold'] = group.get_data_value(parameter_name='group_local_bonus_threshold', round_data=round_data, default=5).int_value + experiment_model_dict['globalThreshold'] = group.get_data_value(parameter_name='group_cluster_bonus_threshold', round_data=round_data, default=22).int_value # data from the last round experiment_model_dict['lastRoundHarvestDecision'] = 5 diff -r 9418327389116cb15600c3e1ba52cf76ccd0cb8a -r 0584aaebd11d1ec9e0ddba2e542c334fc4455837 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -1126,11 +1126,15 @@ ('float', 'Floating-point number'), ('boolean', 'Boolean value (true/false)'), ('enum', 'Enumeration')) - + Scope = Choices(('round', 'ROUND', 'Parameter applies to the entire round across all groups'), + ('experiment', 'EXPERIMENT', 'Parameter applies to the entire experiment across all groups and rounds'), + ('group', 'GROUP', 'Parameter applies to a group for the duration of the experiment'), + ('group_round', 'GROUP_ROUND', 'Parameter applies to a group for a given round'), + ('group_cluster_round', 'GROUP_CLUSTER_ROUND', 'Parameter applies to a group cluster for a given round'), + ('participant', 'PARTICIPANT', 'Parameter applies for a single participant for a given round')) # FIXME: arcane, see if we can encapsulate this better. used to provide sane default values for each parameter type # when the parameter is null NONE_VALUES_DICT = dict(map(lambda x,y: (x[0], y), ParameterType, [0, '', -1, 0.0, False, None])) - CONVERTERS = { 'int': int, 'string':str, @@ -1145,13 +1149,6 @@ NOTE: they expect already validated string data and will throw ValueErrors on invalid input. ''' - - Scope = Choices(('round', 'ROUND', 'Parameter applies to the entire round across all groups'), - ('experiment', 'EXPERIMENT', 'Parameter applies to the entire experiment across all groups and rounds'), - ('group', 'GROUP', 'Parameter applies to a group for the duration of the experiment'), - ('group_round', 'GROUP_ROUND', 'Parameter applies to a group for a given round'), - ('participant', 'PARTICIPANT', 'Parameter applies for a single participant')) - scope = models.CharField(max_length=32, choices=Scope, default=Scope.ROUND) name = models.CharField(max_length=255, unique=True) display_name = models.CharField(max_length=255, null=True, blank=True) Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/941832738911/ Changeset: 941832738911 User: dieg...@gmail.com Date: 2013-03-22 22:07:10 Summary: setting up round transitions and participant / experimenter synchronization and wiring up submit decision and conservation decisions Affected #: 3 files diff -r 4d70504fa520013746cd744640e5525c32005f57 -r 9418327389116cb15600c3e1ba52cf76ccd0cb8a vcweb/broker/templates/broker/participate.html --- a/vcweb/broker/templates/broker/participate.html +++ b/vcweb/broker/templates/broker/participate.html @@ -369,12 +369,13 @@ <td><div><div class='control-group'> - <div class='controls'> - <input id='participantGroupId' type='hidden' name='participant_group_id'/> + <div class='controls input-append'> + <input id='participantGroupId' type='hidden' name='participant_group_id' value="{{ participant_group_relationship.pk }}"/><input id='harvestDecisionId' type="number" size="1" maxlength="1" - name='harvest_decision' - class='required' min="0" + name='integer_decision' + class='required input-mini' min="0" data-bind="value: harvestDecision, attr: { max: maxHarvestDecision }"/> + <span class='add-on'>hrs</span><button id='submitDecision' data-bind='click: submitDecision' type='submit' class='btn'> @@ -390,10 +391,11 @@ <td><div> - <div class='controls'> + <div class='input-append'><input id='conservationDecision' type="number" size="1" maxlength="1" - name='conservation_decision' class='disabled' min="0" + name='conservation_decision' class='input-mini disabled' disabled min="0" data-bind="value: conservationDecision"/> + <span class='add-on'>hrs</span></div> @@ -469,6 +471,7 @@ var self = this; var model = ko.mapping.fromJS(experimentModelJson); + model.isTimeOut = ko.observable(0) model.hasSubmit = ko.observable(0) model.secondsLeft = ko.observable(0); @@ -513,7 +516,6 @@ } }); }; - model.templateName = ko.observable("WELCOME"); // activate instructions click bindings model.activateInstructionsPageOne = function () { model.templateName('GENERAL_INSTRUCTIONS'); @@ -540,19 +542,17 @@ model.networkStructure = ko.observable("{{STATIC_URL}}images/broker/SES.jpg"); model.networkStructureImageWidth = ko.observable("600px"); model.networkStructureImageHeight = ko.observable("80px"); - model.finishedInstructions = function () { - {% comment %}console.debug("instructions were finished, notifying experimenter"); + model.participantReady = function () { $.post('/experiment/participant-ready', { participant_group_id: {{ participant_group_relationship.pk }} }, function (response) { console.debug("successfully posted to server, notifying sockjs: " + response); - getWebSocket().send(createMessageEvent("Instructions completed", "client_ready"));{% endcomment %} - model.templateName("PRACTICE"); - - } + getWebSocket().send(createMessageEvent("Participant ready", "client_ready")); + }); + }; model.chatEnabled = ko.observable(false); // round configurations model.chatOptionEnabled = ko.observable(false); // round configurations model.harvestDecision = ko.observable(0); model.conservationDecision = ko.computed(function () { - return model.conservationDecision == model.maxHarvestDecision() - model.harvestDecision(); + return model.maxHarvestDecision() - model.harvestDecision(); }); // model.numberOfTreesPerRow = ko.observable(10); // model.isResourceEmpty = ko.computed(function() { @@ -603,21 +603,20 @@ }, 1000)); }; - // model.submitDecision = function(data, evt) { -// if (evt) { -// evt.preventDefault(); -// } -// var formData = $('#vcweb-form').serialize(); -// $.post('submit-harvest-decision', formData, function(jsonString) { -// console.log(jsonString); -// // FIXME: should probably update the entire model after we remove the test panel -// // update(data.experimentModelJson); -// // ko.mapping.fromJSON(data.experimentModelJson, model); -// model.secondsLeft(0); -// model.hasSubmit(true); -// model.clearCurrentInterval(); -// }); -// } + model.submitDecision = function(data, evt) { + var formData = $('#vcweb-form').serialize(); + $.post('submit-decision', formData, function(response) { + console.log(response); + if (response.success) { + console.debug("updating view model"); + ko.mapping.fromJSON(response.experimentModelJson, model); + getWebSocket().send() + } + // model.secondsLeft(0); + // model.hasSubmit(true); + // model.clearCurrentInterval(); + }); + }; // model.submitChatMessage = function(data, evt) { // evt.preventDefault(); // console.log("clicking chat message"); @@ -654,6 +653,7 @@ function initialize(experimentModelJson) { var experimentModel = new ExperimentModel(experimentModelJson); ko.applyBindings(experimentModel); + console.debug("CURRENT TEMPLATE: " + experimentModel.templateName()); var s = connect(); s.onmessage = function (json) { console.debug(json); @@ -664,7 +664,7 @@ experimentModel.chatMessages.unshift(data); console.debug("received chat message:" + json); break; - case 'update_view_model': + case 'update': console.debug("updating view model"); experimentModel.update(); break; @@ -784,6 +784,7 @@ var experimentModelJson = $.parseJSON("{{ experimentModelJson|escapejs }}"); initialize(experimentModelJson); + }); </script> {% endblock %} diff -r 4d70504fa520013746cd744640e5525c32005f57 -r 9418327389116cb15600c3e1ba52cf76ccd0cb8a vcweb/broker/urls.py --- a/vcweb/broker/urls.py +++ b/vcweb/broker/urls.py @@ -3,7 +3,7 @@ urlpatterns = patterns('vcweb.broker.views', url(r'^(?P<experiment_id>\d+)?/participate/?$', participate, name='participate'), - url(r'^(?P<experiment_id>\d+)/submit-harvest-decision$', submit_decision, name='submit_decision'), + url(r'^(?P<experiment_id>\d+)/submit-decision$', submit_decision, name='submit_decision'), url(r'^(?P<experiment_id>\d+)/view-model$', get_view_model, name='get_view_model'), ) diff -r 4d70504fa520013746cd744640e5525c32005f57 -r 9418327389116cb15600c3e1ba52cf76ccd0cb8a vcweb/broker/views.py --- a/vcweb/broker/views.py +++ b/vcweb/broker/views.py @@ -5,7 +5,7 @@ from vcweb.core.forms import ParticipantGroupIdForm, SingleIntegerDecisionForm from vcweb.core.http import JsonResponse from vcweb.core.models import (is_participant, is_experimenter, Experiment, ParticipantGroupRelationship, - ParticipantExperimentRelationship, ChatMessage, ParticipantRoundDataValue) + ParticipantExperimentRelationship, RoundConfiguration, ChatMessage, ParticipantRoundDataValue) from vcweb.broker.models import get_max_harvest_hours, get_harvest_decision_parameter, get_conservation_hours_parameter @@ -47,6 +47,7 @@ return render(request, 'broker/participate.html', { 'experiment': experiment, + 'participant_experiment_relationship': experiment.get_participant_experiment_relationship(participant), 'participant_group_relationship': participant_group_relationship, 'experimentModelJson': get_view_model_json(experiment, participant_group_relationship), }) @@ -76,7 +77,9 @@ experiment_model_dict['networkStructure'] = 10 practice_round = round_configuration.is_practice_round experiment_model_dict['practiceRound'] = practice_round - + experiment_model_dict['templateName'] = round_configuration.round_type + if practice_round: + experiment_model_dict['templateName'] = RoundConfiguration.RoundType.REGULAR if practice_round and round_configuration.sequence_number == 3: experiment_model_dict['isFirstPracticeRound'] = True experiment_model_dict['isSecondPracticeRound'] = False Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-22 20:15:55
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/4d70504fa520/ Changeset: 4d70504fa520 User: alllee Date: 2013-03-22 21:15:55 Summary: fixing incorrect block reference and s/experimentModel/model Affected #: 2 files diff -r 40c7da4dad18138eb5d2fcfd7a901c1a929c0241 -r 4d70504fa520013746cd744640e5525c32005f57 vcweb/core/templates/experimenter/dashboard.html --- a/vcweb/core/templates/experimenter/dashboard.html +++ b/vcweb/core/templates/experimenter/dashboard.html @@ -39,7 +39,7 @@ {% endfor %} </div> {% endblock page %} -{% block footer %} +{% block javascript %} {{ block.super }} <script type='text/javascript'> $(function() { diff -r 40c7da4dad18138eb5d2fcfd7a901c1a929c0241 -r 4d70504fa520013746cd744640e5525c32005f57 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -202,7 +202,7 @@ confirmAction(element, function(confirmed, action) { $('#progress-modal').modal('show'); Dajaxice.vcweb.core.experiment_controller(function(data) { - ko.mapping.fromJS(data, experimentModel); + ko.mapping.fromJS(data, model); if (updateParticipants) { sendUpdateEvent(); } Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |