virtualcommons-svn Mailing List for Virtual Commons Experiment Software (Page 11)
Status: Beta
Brought to you by:
alllee
You can subscribe to this list here.
2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
(21) |
Aug
(31) |
Sep
(6) |
Oct
(15) |
Nov
(2) |
Dec
(9) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2009 |
Jan
(4) |
Feb
(6) |
Mar
(12) |
Apr
(52) |
May
(14) |
Jun
(19) |
Jul
(81) |
Aug
(115) |
Sep
(36) |
Oct
(88) |
Nov
(46) |
Dec
(58) |
2010 |
Jan
(52) |
Feb
(55) |
Mar
(48) |
Apr
(15) |
May
(5) |
Jun
(38) |
Jul
(27) |
Aug
(24) |
Sep
(28) |
Oct
(1) |
Nov
(2) |
Dec
(29) |
2011 |
Jan
(87) |
Feb
(39) |
Mar
(63) |
Apr
(42) |
May
(26) |
Jun
(53) |
Jul
(23) |
Aug
(43) |
Sep
(37) |
Oct
(25) |
Nov
(4) |
Dec
(7) |
2012 |
Jan
(73) |
Feb
(79) |
Mar
(62) |
Apr
(28) |
May
(12) |
Jun
(2) |
Jul
(9) |
Aug
(1) |
Sep
(8) |
Oct
|
Nov
(3) |
Dec
(3) |
2013 |
Jan
(8) |
Feb
(16) |
Mar
(38) |
Apr
(74) |
May
(62) |
Jun
(15) |
Jul
(49) |
Aug
(19) |
Sep
(9) |
Oct
|
Nov
|
Dec
|
2014 |
Jan
|
Feb
|
Mar
|
Apr
(2) |
May
(25) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <com...@bi...> - 2013-04-02 08:17:42
|
2 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/9b7e29ab8754/ Changeset: 9b7e29ab8754 User: alllee Date: 2013-04-02 10:10:27 Summary: patching adjust_harvest_decisions, fixes issue 99 added a basic test, need to add more corner cases next. Affected #: 4 files diff -r 11a6a09b532c0e8694da3b91ebdde2f386c3ca45 -r 9b7e29ab8754ecb594cd40027a9ce87ebc41814c vcweb/boundaries/fixtures/boundaries_parameters.json --- /dev/null +++ b/vcweb/boundaries/fixtures/boundaries_parameters.json @@ -0,0 +1,67 @@ +[ + { + "fields": { + "name":"player_status", + "experiment_metadata": 1, + "creator": 1, + "type": "int", + "date_created": "2011-01-01 15:13:03", + "last_modified": "2011-01-01 15:13:05", + "scope": "participant" + }, + "model": "core.parameter", + "pk": 1111 + }, + { + "fields": { + "name":"regrowth_rate", + "experiment_metadata": 1, + "creator": 1, + "type": "float", + "date_created": "2011-01-01 15:13:03", + "last_modified": "2011-01-01 15:13:05", + "scope": "round" + }, + "model": "core.parameter", + "pk": 1112 + }, + { + "fields": { + "name":"cost_of_living", + "experiment_metadata": 1, + "creator": 1, + "type": "float", + "date_created": "2011-01-01 15:13:03", + "last_modified": "2011-01-01 15:13:05", + "scope": "round" + }, + "model": "core.parameter", + "pk": 1113 + }, + { + "fields": { + "name":"shared_resource", + "experiment_metadata": 1, + "creator": 1, + "type": "boolean", + "date_created": "2011-01-01 15:13:03", + "last_modified": "2011-01-01 15:13:05", + "scope": "round" + }, + "model": "core.parameter", + "pk": 1114 + }, + { + "fields": { + "name":"storage", + "experiment_metadata": 1, + "creator": 1, + "type": "int", + "date_created": "2011-01-01 15:13:07", + "last_modified": "2011-01-01 15:15:05", + "scope": "participant" + }, + "model": "core.parameter", + "pk": 1115 + } +] diff -r 11a6a09b532c0e8694da3b91ebdde2f386c3ca45 -r 9b7e29ab8754ecb594cd40027a9ce87ebc41814c vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -4,7 +4,7 @@ from vcweb.core.models import (ExperimentMetadata, Parameter, ParticipantRoundDataValue, GroupRelationship, GroupCluster, GroupClusterDataValue) from vcweb.forestry.models import (get_harvest_decision_parameter, get_harvest_decision, get_harvest_decision_dv, get_regrowth_rate_parameter, get_group_harvest_parameter, get_reset_resource_level_parameter, get_resource_level as get_unshared_resource_level, - get_initial_resource_level as forestry_initial_resource_level, get_regrowth_parameter, + get_initial_resource_level as forestry_initial_resource_level, get_regrowth_parameter, set_resource_level, get_resource_level_parameter, get_resource_level_dv as get_unshared_resource_level_dv, set_group_harvest, set_regrowth, set_harvest_decision) @@ -100,10 +100,7 @@ return experiment_configuration.get_parameter_value(parameter=get_max_harvest_decision_parameter(), default=10).int_value def get_max_allowed_harvest_decision(participant_group_relationship, round_data=None, experiment_configuration=None): - group = participant_group_relationship.group - resource_level = get_resource_level(group, round_data) - return min(get_max_harvest_decision(experiment_configuration), resource_level / group.size) - + return get_max_harvest_decision(experiment_configuration) def get_resource_level(group, round_data=None, round_configuration=None, cluster=None): return get_resource_level_dv(group, round_data, round_configuration, cluster).int_value @@ -234,23 +231,40 @@ -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_harvest_decisions(current_resource_level, group, round_data, total_harvest, group_size=0): + if group_size == 0: + group_size = group.size +# pass in the group size to handle group cluster case + average_harvest = current_resource_level / group_size + group.log("GROUP HARVEST ADJUSTMENT - original total harvest: %s, resource level: %s, average harvest: %s" % + (total_harvest, current_resource_level, average_harvest)) + hds = ParticipantRoundDataValue.objects.for_group(group=group, parameter=get_harvest_decision_parameter(), + round_data=round_data, int_value__gt=0).order_by('int_value') + total_adjusted_harvest = 0 +# FIXME: should be the same as group.size + total_number_of_decisions = hds.count() + logger.debug("total number of decisions: %s - group size: %s", total_number_of_decisions, group_size) + decisions_allocated = 0 + for hd in hds: + if hd.int_value <= average_harvest: + group.log("preserving %s < average harvest" % hd) + total_adjusted_harvest += hd.int_value + else: +# now to assign the overs, find out how much resource level is remaining + remaining_resource_level = current_resource_level - total_adjusted_harvest + remaining_decisions = total_number_of_decisions - decisions_allocated + average_harvest = remaining_resource_level / remaining_decisions + hd.is_active = False + hd.save() + logger.debug("Assigning %s to hd %s", average_harvest, hd) + ParticipantRoundDataValue.objects.create(participant_group_relationship=hd.participant_group_relationship, + parameter=get_harvest_decision_parameter(), round_data=round_data, int_value=average_harvest, + submitted=True) + total_adjusted_harvest += average_harvest + decisions_allocated += 1 + + logger.debug("harvested total %s", total_adjusted_harvest) + return total_adjusted_harvest def update_resource_level(experiment, group, round_data, regrowth_rate, max_resource_level=None): @@ -264,10 +278,7 @@ logger.debug("Harvest: total group harvest for playable round: %s", total_harvest) if current_resource_level > 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) + adjusted_harvest = adjust_harvest_decisions(current_resource_level, group, round_data, total_harvest) total_harvest = adjusted_harvest group.log("Harvest: removing %s from current resource level %s" % (total_harvest, current_resource_level)) @@ -295,11 +306,11 @@ 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_cluster_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_cluster_size += group.size group_harvest = get_total_group_harvest(group, round_data) group_harvest_dict[group] = group_harvest shared_group_harvest += group_harvest @@ -307,7 +318,7 @@ 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) + group_harvest = adjust_harvest_decisions(shared_resource_level, group, round_data, group_harvest, group_size=group_cluster_size) 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 diff -r 11a6a09b532c0e8694da3b91ebdde2f386c3ca45 -r 9b7e29ab8754ecb594cd40027a9ce87ebc41814c vcweb/boundaries/tests.py --- a/vcweb/boundaries/tests.py +++ b/vcweb/boundaries/tests.py @@ -1,12 +1,38 @@ """ Tests for boundaries experiment """ -from django.test import TestCase +from vcweb.core.tests import BaseVcwebTest from vcweb.core.models import Parameter -from vcweb.boundaries.models import get_experiment_metadata +from vcweb.boundaries.models import * -class BaseTest(TestCase): - fixtures = [ 'boundaries_experiment_metadata' ] +import logging +logger = logging.getLogger(__name__) + + +class BaseTest(BaseVcwebTest): + fixtures = [ 'boundaries_experiment_metadata', 'forestry_experiment_metadata', 'boundaries_parameters', ] + + def create_harvest_decisions(self, value=10): + for pgr in self.experiment.participant_group_relationships: + logger.debug("setting harvest decision for %s to %s", pgr, value) + set_harvest_decision(pgr, value, submitted=True) + + def setUp(self, **kwargs): + super(BaseTest, self).setUp(experiment_metadata=get_experiment_metadata(), **kwargs) + logger.debug("boundaries test loaded experiment %s", self.experiment) + +class AdjustHarvestDecisionsTest(BaseTest): + def test_adjust_harvest_decisions(self): + e = self.experiment + e.activate() + self.create_harvest_decisions() + for g in e.groups: + set_resource_level(g, 25) + e.end_round() + for g in e.groups: + self.assertEqual(get_resource_level(g), 0) + for pgr in e.participant_group_relationships: + self.assertEqual(5, get_harvest_decision(pgr)) class InitialDataTest(BaseTest): def test_experiment_metadata(self): diff -r 11a6a09b532c0e8694da3b91ebdde2f386c3ca45 -r 9b7e29ab8754ecb594cd40027a9ce87ebc41814c vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -94,8 +94,8 @@ experiment_model_dict['templateName'] = current_round.template_name experiment_model_dict['isPracticeRound'] = current_round.is_practice_round experiment_model_dict['showTour'] = current_round.is_practice_round and not previous_round.is_practice_round -# FIXME: extend this to first 3 regular rounds of each session as well? - experiment_model_dict['waitThirtySeconds'] = current_round.is_practice_round and current_round.sequence_number < 6 + # FIXME: extend this to first 3 regular rounds of each session as well? + # experiment_model_dict['waitThirtySeconds'] = current_round.is_practice_round and current_round.sequence_number < 6 # instructions round parameters if current_round.is_instructions_round: experiment_model_dict['isInstructionsRound'] = True https://bitbucket.org/virtualcommons/vcweb/commits/56af1f18ed4d/ Changeset: 56af1f18ed4d User: alllee Date: 2013-04-02 10:17:28 Summary: adjusting harvest decisions to 0 if the current resource level is 0 Affected #: 2 files diff -r 9b7e29ab8754ecb594cd40027a9ce87ebc41814c -r 56af1f18ed4d23b02356b5187fd58a3b599bc074 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -289,6 +289,17 @@ 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() + else: + group.log("current resource level is 0, no one can harvest") + set_group_harvest(group, 0, round_data) + ParticipantRoundDataValue.objects.for_group(group, parameter=get_harvest_decision_parameter(), + round_data=round_data).update(is_active=False) + for pgr in group.participant_group_relationship_set.all(): + # Create adjusted data values + ParticipantRoundDataValue.objects.create(participant_group_relationship=pgr, + round_data=round_data, parameter=get_harvest_decision_parameter(), + int_value=0) + ''' XXX: transfer resource levels across chat and quiz rounds if they exist ''' if experiment.has_next_round: diff -r 9b7e29ab8754ecb594cd40027a9ce87ebc41814c -r 56af1f18ed4d23b02356b5187fd58a3b599bc074 vcweb/boundaries/tests.py --- a/vcweb/boundaries/tests.py +++ b/vcweb/boundaries/tests.py @@ -25,14 +25,16 @@ def test_adjust_harvest_decisions(self): e = self.experiment e.activate() - self.create_harvest_decisions() - for g in e.groups: - set_resource_level(g, 25) - e.end_round() - for g in e.groups: - self.assertEqual(get_resource_level(g), 0) - for pgr in e.participant_group_relationships: - self.assertEqual(5, get_harvest_decision(pgr)) + for rl in range(1, 40): + e.start_round() + self.create_harvest_decisions() + for g in e.groups: + set_resource_level(g, rl) + e.end_round() + for g in e.groups: + self.assertEqual(get_resource_level(g), 0) + for pgr in self.participant_group_relationships: + self.assertTrue(get_harvest_decision(pgr) <= 8) class InitialDataTest(BaseTest): def test_experiment_metadata(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-04-02 01:37:53
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/11a6a09b532c/ Changeset: 11a6a09b532c User: alllee Date: 2013-04-02 03:37:36 Summary: clamping get_storage to return 0 if storage is negative Affected #: 2 files diff -r 362d2af23b0cdeea2981cf3a026e5e5eb26013cc -r 11a6a09b532c0e8694da3b91ebdde2f386c3ca45 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -150,7 +150,7 @@ def get_storage(participant_group_relationship, round_data=None, default=0): dv = get_storage_dv(participant_group_relationship, round_data, default) - return default if dv.int_value is None else dv.int_value + return max(default if dv.int_value is None else dv.int_value, 0) def _zero_if_none(value): diff -r 362d2af23b0cdeea2981cf3a026e5e5eb26013cc -r 11a6a09b532c0e8694da3b91ebdde2f386c3ca45 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -112,7 +112,6 @@ experiment_model_dict['participantNumber'] = participant_group_relationship.participant_number experiment_model_dict['participantGroupId'] = participant_group_relationship.pk experiment_model_dict['participantHandle'] = participant_group_relationship.participant_handle - # FIXME: these should only need to be added for playable rounds but KO gets unhappy when we switch templates from # instructions rounds to practice rounds. own_group = participant_group_relationship.group 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-04-02 01:31:24
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/362d2af23b0c/ Changeset: 362d2af23b0c User: alllee Date: 2013-04-02 03:31:08 Summary: setting defaults on participant sockjs events Affected #: 4 files diff -r 2b6608320663b54339f72ce363e6e3c7f67d9f20 -r 362d2af23b0cdeea2981cf3a026e5e5eb26013cc vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -276,6 +276,8 @@ return self.filter(status='COMPLETED', **kwargs) def active(self, **kwargs): return self.filter(status__in=('ACTIVE', 'ROUND_IN_PROGRESS'), **kwargs) + def for_participant(self, participant, **kwargs): + return participant.experiments.filter(status__in=('ACTIVE', 'ROUND_IN_PROGRESS')) class Experiment(models.Model): """ diff -r 2b6608320663b54339f72ce363e6e3c7f67d9f20 -r 362d2af23b0cdeea2981cf3a026e5e5eb26013cc vcweb/core/templates/includes/participant.events.html --- a/vcweb/core/templates/includes/participant.events.html +++ b/vcweb/core/templates/includes/participant.events.html @@ -15,12 +15,12 @@ return JSON.stringify({ "event_type": event_type, "auth_token": "{{ request.user.participant.authentication_token }}", - "experiment_id": {{experiment.pk}}, + "experiment_id": {{experiment.pk|default:-1}}, {% if participant_group_relationship %} - "participant_group_relationship_id": {{participant_group_relationship.pk}}, + "participant_group_relationship_id": {{participant_group_relationship.pk|default:-1}}, {% endif %} {% if participant_experiment_relationship %} - "participant_experiment_relationship_id": {{participant_experiment_relationship.pk}}, + "participant_experiment_relationship_id": {{participant_experiment_relationship.pk|default:-1}}, {% endif %} "message": payload }); diff -r 2b6608320663b54339f72ce363e6e3c7f67d9f20 -r 362d2af23b0cdeea2981cf3a026e5e5eb26013cc vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -91,19 +91,20 @@ user = self.request.user if is_experimenter(user): return Experiment.objects.select_related('experimenter', 'experiment_metadata', 'experiment_configuration').filter(experimenter__pk=self.request.user.experimenter.pk) - else: + elif is_participant(user): # nested dictionary, {ExperimentMetadata -> { status -> [experiments,...] }} # FIXME: could also use collections.defaultdict or regroup template tag to # accomplish this.. experiment_dict = {} # FIXME: this needs to be refactored - for experiment in user.participant.experiments.exclude(status__in=(Experiment.Status.INACTIVE, Experiment.Status.PAUSED, Experiment.Status.COMPLETED)): + for experiment in Experiment.objects.for_participant(user.participant): if not experiment.experiment_metadata in experiment_dict: experiment_dict[experiment.experiment_metadata] = dict([(choice[0], list()) for choice in Experiment.Status]) experiment_dict[experiment.experiment_metadata][experiment.status].append(experiment) logger.info("experiment_dict %s", experiment_dict) return experiment_dict + def set_authentication_token(user, authentication_token=None): commons_user = None if is_participant(user): @@ -112,7 +113,7 @@ commons_user = user.experimenter else: logger.error("Invalid user: %s", user) - raise Http404 + return logger.debug("%s authentication_token=%s", commons_user, authentication_token) commons_user.authentication_token = authentication_token commons_user.save() diff -r 2b6608320663b54339f72ce363e6e3c7f67d9f20 -r 362d2af23b0cdeea2981cf3a026e5e5eb26013cc vcweb/lighterprints/models.py --- a/vcweb/lighterprints/models.py +++ b/vcweb/lighterprints/models.py @@ -468,6 +468,7 @@ if round_data is None: round_data = group.current_round_data activities_performed_qs = ParticipantRoundDataValue.objects.for_group(group, parameter=get_activity_performed_parameter(), round_data=round_data, date_created__range=(start, end)) + for activity_performed_dv in activities_performed_qs: logger.debug("checking activity performed: %s", activity_performed_dv) activity_points = activity_points_cache[activity_performed_dv.int_value] @@ -611,6 +612,7 @@ prdvs = ParticipantRoundDataValue.objects.filter(participant_group_relationship=participant_group_relationship, date_created__range=(start_date, end_date), parameter=get_activity_performed_parameter()) pks = prdvs.values_list('int_value', flat=True) + # XXX: assumes that an Activity can only be performed once per round (day) return Activity.objects.total(pks=pks) - # FIXME: this creates a query per participant round data value because of the design of foreign key data values. + # this generates a query per participant round data value, very inefficient #return sum(prdv.value.points for prdv in prdvs) 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-04-01 23:43:33
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/2b6608320663/ Changeset: 2b6608320663 User: alllee Date: 2013-04-02 01:43:14 Summary: refactoring get_individual_points Affected #: 2 files diff -r c8a3785e5b8714bb71cbc4ec50d3252c8169e998 -r 2b6608320663b54339f72ce363e6e3c7f67d9f20 vcweb/lighterprints/models.py --- a/vcweb/lighterprints/models.py +++ b/vcweb/lighterprints/models.py @@ -93,6 +93,13 @@ else: return self.filter(level=level) + def total(self, pks=None, field_name='points', **kwargs): + logger.debug("getting total for pks %s", pks) + if not pks: + return 0 + q = self.filter(pk__in=pks,**kwargs).aggregate(total=Sum(field_name)) + return q['total'] + class ActivityManager(TreeManager, PassThroughManager): def upcoming(self, level=1): current_time = datetime.now().time() @@ -597,9 +604,13 @@ messages.append(msg) return messages -def get_individual_points(participant_group_relationship): - today = date.today() - yesterday = today - timedelta(1) +def get_individual_points(participant_group_relationship, end_date=None): + if end_date is None: + end_date = date.today() + start_date = end_date - timedelta(1) prdvs = ParticipantRoundDataValue.objects.filter(participant_group_relationship=participant_group_relationship, - date_created__range=(yesterday, today), parameter=get_activity_performed_parameter()) - return sum(prdv.value.points for prdv in prdvs) + date_created__range=(start_date, end_date), parameter=get_activity_performed_parameter()) + pks = prdvs.values_list('int_value', flat=True) + return Activity.objects.total(pks=pks) + # FIXME: this creates a query per participant round data value because of the design of foreign key data values. + #return sum(prdv.value.points for prdv in prdvs) diff -r c8a3785e5b8714bb71cbc4ec50d3252c8169e998 -r 2b6608320663b54339f72ce363e6e3c7f67d9f20 vcweb/lighterprints/tests.py --- a/vcweb/lighterprints/tests.py +++ b/vcweb/lighterprints/tests.py @@ -55,7 +55,6 @@ def test_daily_points(self): e = self.experiment e.activate() - e.start_round() current_round_data = e.get_round_data() # initialize participant carbon savings for participant_group_relationship in ParticipantGroupRelationship.objects.filter(group__experiment=e): @@ -75,7 +74,6 @@ def test_group_activity(self): e = self.experiment e.activate() - e.start_round() performed_activities = self.perform_activities() for pgr in ParticipantGroupRelationship.objects.filter(group__experiment=e): (group_activity, chat_messages) = get_group_activity(pgr) @@ -85,7 +83,6 @@ def test_group_activity_email(self): e = self.experiment e.activate() - e.start_round() self.perform_activities() for group in e.group_set.all(): messages = create_group_summary_emails(group, 2) @@ -97,7 +94,6 @@ logger.debug("testing do activity view") e = self.experiment e.activate() - e.start_round() # gets all activities with no params activities = get_available_activities() for participant_group_relationship in ParticipantGroupRelationship.objects.filter(group__experiment=e): @@ -138,10 +134,17 @@ self.assertIsNotNone(json_object['viewModel']); class GroupScoreTest(ActivityTest): + def test_individual_points(self): + e = self.experiment + e.activate() + performed_activities = self.perform_activities() + for pgr in e.participant_group_relationships: + self.assertEqual(get_individual_points(pgr), 0) + self.assertTrue(get_individual_points(pgr, end_date=date.today() + timedelta(1)) > 0) + def test_group_score(self): e = self.experiment e.activate() - e.start_round() performed_activities = self.perform_activities() expected_avg_points_per_person = sum([activity.points for activity in performed_activities]) for group in e.group_set.all(): 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-04-01 20:53:51
|
2 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/7d93ebbb8cde/ Changeset: 7d93ebbb8cde User: alllee Date: 2013-04-01 21:33:06 Summary: should probably return the generator expression Affected #: 1 file diff -r 26c7643172c5a5b660e96d19d59736bddff002a7 -r 7d93ebbb8cdebeb15c2e5af726c705b8fe270b52 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -390,13 +390,13 @@ def current_session_id(self): session_id = self.current_round.session_id if not session_id: - # force session_id to be None if it turned into the empty string somehow + # force session_id to be None if empty (looks like this can happen via the admin interface) session_id = None return session_id @property def groups(self): - (group for group in self.group_set.filter(session_id=self.current_session_id)) + return (group for group in self.group_set.filter(session_id=self.current_session_id)) @property def participant_group_relationships(self): https://bitbucket.org/virtualcommons/vcweb/commits/c8a3785e5b87/ Changeset: c8a3785e5b87 User: alllee Date: 2013-04-01 22:53:31 Summary: removing unused greenbutton models, refining Experiment.initialize_data_values to allow for default parameter values and to only create data values for the parameters that have been sent to it Affected #: 4 files diff -r 7d93ebbb8cdebeb15c2e5af726c705b8fe270b52 -r c8a3785e5b8714bb71cbc4ec50d3252c8169e998 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -1,3 +1,4 @@ +from collections import defaultdict from datetime import datetime, timedelta from django.contrib.auth.forms import PasswordResetForm from django.contrib.auth.models import User @@ -23,6 +24,7 @@ import base64 import hashlib +import itertools import logging import random import re @@ -399,13 +401,15 @@ return (group for group in self.group_set.filter(session_id=self.current_session_id)) @property + def active_group_clusters(self): + return (group_cluster for group_cluster in self.group_cluster_set.filter(session_id=self.current_session_id)) + + @property def participant_group_relationships(self): ''' - Generator function for all participant group relationships in this experiment + Generator function for all active participant group relationships in this experiment ''' - for group in self.groups: - for pgr in group.participant_group_relationship_set.all(): - yield pgr + return itertools.chain.from_iterable(group.participant_group_relationship_set.all() for group in self.groups) @property def display_name(self): @@ -680,33 +684,34 @@ # 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): +# XXX: it can be dangerous to use empty lists as initial keyword args but we only iterate over them (e.g., +# http://effbot.org/zone/default-values.htm) +# defaults map parameter model instances to their default initial value, e.g., { footprint-level-parameter: 1, resource-level-parameter: 100 } + def initialize_data_values(self, group_parameters=[], participant_parameters=[], group_cluster_parameters=[], round_data=None, defaults={}): # logger.debug("initializing [participant params: %s] [group parameters: %s] [group_cluster_parameters: %s] ", participant_parameters, group_parameters, group_cluster_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) if round_data is None: round_data = self.current_round_data - + parameter_defaults = defaultdict(dict) + for parameter in itertools.chain(participant_parameters, group_parameters, group_cluster_parameters): + if parameter in defaults: + parameter_defaults[parameter] = { parameter.value_field_name: defaults[parameter] } + logger.debug("parameter default values: %s", parameter_defaults) # 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, group_cluster=group_cluster) - #logger.debug("%s (%s)", gcdv, created) - -# FIXME: this is wrong, need to create a way to iterate over the "active" groups in the experiment (e.g., when they -# switch from one session to another) + if group_cluster_parameters: + for group_cluster in self.active_group_clusters: + for parameter in group_cluster_parameters: + gcdv, created = GroupClusterDataValue.objects.get_or_create(round_data=round_data, parameter=parameter, group_cluster=group_cluster, + defaults=parameter_defaults[parameter]) + #logger.debug("%s (%s)", gcdv, created) for group in self.groups: for parameter in group_parameters: - group_data_value, created = GroupRoundDataValue.objects.get_or_create(round_data=round_data, group=group, parameter=parameter) + group_data_value, created = GroupRoundDataValue.objects.get_or_create(round_data=round_data, group=group, parameter=parameter, defaults=parameter_defaults[parameter]) #logger.debug("%s (%s)", group_data_value, created) if participant_parameters: for pgr in group.participant_group_relationship_set.all(): for parameter in participant_parameters: - participant_data_value, created = ParticipantRoundDataValue.objects.get_or_create(round_data=round_data, participant_group_relationship=pgr, parameter=parameter) + participant_data_value, created = ParticipantRoundDataValue.objects.get_or_create(round_data=round_data, participant_group_relationship=pgr, parameter=parameter, + defaults=parameter_defaults[parameter]) # logger.debug("%s (%s)", participant_data_value, created) def log(self, log_message): @@ -751,7 +756,6 @@ if pgr.group.session_id == current_group.session_id: logger.error("Participant %s is already in a group %s with the same session id, not adding them to %s", participant, pgr.group, current_group) return pgr - logger.debug("adding participant %s to group %s", participant, current_group) return current_group.add_participant(participant) def allocate_groups(self, randomize=True, preserve_existing_groups=False, session_id=None): @@ -1626,6 +1630,7 @@ ''' add the participant to this group if there is room, otherwise create and add to a fresh group ''' group = self if self.is_open else self.create_next_group() + logger.debug("adding participant %s to group %s", participant, group) pgr = ParticipantGroupRelationship.objects.create(participant=participant, group=group, round_joined=self.experiment.current_round, diff -r 7d93ebbb8cdebeb15c2e5af726c705b8fe270b52 -r c8a3785e5b8714bb71cbc4ec50d3252c8169e998 vcweb/lighterprints/migrations/0002_auto__del_greenbuttonintervalblock__del_greenbuttonintervalreading.py --- /dev/null +++ b/vcweb/lighterprints/migrations/0002_auto__del_greenbuttonintervalblock__del_greenbuttonintervalreading.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Deleting model 'GreenButtonIntervalBlock' + db.delete_table(u'lighterprints_greenbuttonintervalblock') + + # Deleting model 'GreenButtonIntervalReading' + db.delete_table(u'lighterprints_greenbuttonintervalreading') + + + def backwards(self, orm): + # Adding model 'GreenButtonIntervalBlock' + db.create_table(u'lighterprints_greenbuttonintervalblock', ( + ('total_duration', self.gf('django.db.models.fields.PositiveIntegerField')()), + ('start', self.gf('django.db.models.fields.PositiveIntegerField')()), + ('participant_group_relationship', self.gf('django.db.models.fields.related.ForeignKey')(related_name='gb_interval_block_set', to=orm['core.ParticipantGroupRelationship'])), + ('date', self.gf('django.db.models.fields.DateTimeField')()), + ('date_created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + )) + db.send_create_signal(u'lighterprints', ['GreenButtonIntervalBlock']) + + # Adding model 'GreenButtonIntervalReading' + db.create_table(u'lighterprints_greenbuttonintervalreading', ( + ('millicents', self.gf('django.db.models.fields.PositiveIntegerField')(null=True, blank=True)), + ('seconds_from_epoch', self.gf('django.db.models.fields.PositiveIntegerField')()), + ('interval_block', self.gf('django.db.models.fields.related.ForeignKey')(related_name='interval_reading_set', to=orm['lighterprints.GreenButtonIntervalBlock'])), + ('watt_hours', self.gf('django.db.models.fields.PositiveIntegerField')()), + ('date', self.gf('django.db.models.fields.DateTimeField')()), + ('date_created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('notes', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + )) + db.send_create_signal(u'lighterprints', ['GreenButtonIntervalReading']) + + + 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'lighterprints.activity': { + 'Meta': {'ordering': "['level', 'name']", 'object_name': 'Activity'}, + 'available_all_day': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'cooldown': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'null': 'True', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'description': ('django.db.models.fields.TextField', [], {}), + 'display_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'group_activity': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'icon': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'children_set'", 'null': 'True', 'to': u"orm['lighterprints.Activity']"}), + 'personal_benefits': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'points': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'savings': ('django.db.models.fields.DecimalField', [], {'default': '0.0', 'max_digits': '5', 'decimal_places': '2'}), + 'summary': ('django.db.models.fields.CharField', [], {'max_length': '256'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) + }, + u'lighterprints.activityavailability': { + 'Meta': {'ordering': "['activity', 'start_time']", 'object_name': 'ActivityAvailability'}, + 'activity': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'availability_set'", 'to': u"orm['lighterprints.Activity']"}), + 'end_time': ('django.db.models.fields.TimeField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'start_time': ('django.db.models.fields.TimeField', [], {'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['lighterprints'] \ No newline at end of file diff -r 7d93ebbb8cdebeb15c2e5af726c705b8fe270b52 -r c8a3785e5b8714bb71cbc4ec50d3252c8169e998 vcweb/lighterprints/models.py --- a/vcweb/lighterprints/models.py +++ b/vcweb/lighterprints/models.py @@ -23,6 +23,8 @@ import string logger = logging.getLogger(__name__) +EXPERIMENT_METADATA_NAME = intern('lighterprints') + @receiver(signals.midnight_tick) def update_active_experiments(sender, time=None, start=None, send_emails=True, **kwargs): # since this happens at midnight we need to look at the previous day @@ -34,7 +36,7 @@ for experiment in active_experiments: # calculate total carbon savings and decide if they move on to the next level round_data = experiment.current_round_data - for group in experiment.group_set.all(): + for group in experiment.groups: promoted = False completed = False footprint_level_grdv = get_footprint_level_dv(group, round_data=round_data) @@ -60,112 +62,25 @@ if send_emails: mail.get_connection().send_messages(messages) -LIGHTERPRINTS_SENDER = intern('lighterprints') -@receiver(signals.round_started, sender=LIGHTERPRINTS_SENDER) +@receiver(signals.round_started, sender=EXPERIMENT_METADATA_NAME) def round_started_handler(sender, experiment=None, **kwargs): - logger.debug("experiment %s started" % experiment) + logger.debug("starting lighter footprints %s", experiment) round_data = experiment.current_round_data # FIXME: experiment.initialize_parameters could do some of this except for setting the default values properly footprint_level_parameter = get_footprint_level_parameter() experiment_completed_parameter = get_experiment_completed_parameter() - for group in experiment.group_set.all(): - round_data.group_data_value_set.create(group=group, parameter=footprint_level_parameter, int_value=1) - round_data.group_data_value_set.create(group=group, parameter=experiment_completed_parameter, boolean_value=False) + experiment.initialize_data_values( + group_parameters=( footprint_level_parameter, experiment_completed_parameter, ), + round_data=round_data, + defaults={ + footprint_level_parameter: 1, + experiment_completed_parameter: False + } + ) + ActivityStatus = enum('AVAILABLE', 'COMPLETED', 'UNAVAILABLE') -class GreenButtonIntervalBlock(models.Model): - participant_group_relationship = models.ForeignKey(ParticipantGroupRelationship, related_name='gb_interval_block_set') - date_created = models.DateTimeField(default=datetime.now) - date = models.DateTimeField() - start = models.PositiveIntegerField(_('Seconds from epoch from GB data')) - total_duration = models.PositiveIntegerField(_('Total duration for this interval block')) - -class GreenButtonIntervalReading(models.Model): - interval_block = models.ForeignKey(GreenButtonIntervalBlock, related_name='interval_reading_set') - date_created = models.DateTimeField(default=datetime.now) - date = models.DateTimeField() - seconds_from_epoch = models.PositiveIntegerField(_('Number of seconds from epoch from GB data, should be the same as date')) - watt_hours = models.PositiveIntegerField(_('Energy meter reading in watt-hours')) - millicents = models.PositiveIntegerField(_('total millicents cost for this interval'), null=True, blank=True) - notes = models.TextField(null=True, blank=True) - -class GreenButtonParser(object): - xmlns = { 'gb': 'http://naesb.org/espi' } - - def __init__(self, xmltree=None, fh=None, **kwargs): - if xmltree is not None: - self.xmltree = xmltree - elif fh is not None: - fh.seek(0) - self.xmltree = etree.parse(fh) - else: - logger.warning("parser initialized without valid xmltree, make sure you set it before using any methods.") - - def find(self, expr, node=None, **kwargs): - if node is None: - node = self.xmltree - return node.find(expr, namespaces=self.xmlns) - - def findall(self, expr, node=None, **kwargs): - if node is None: - node = self.xmltree - return node.findall(expr, namespaces=self.xmlns) - - def interval_block(self): - return self.find('//gb:IntervalBlock') - - def interval_readings(self, node=None): - return self.findall('gb:IntervalReading', node) - - def interval_data(self, node=None): - return self.find('gb:interval', node) - - def extract(self, node, exprs=None, converter=int): - ''' returns a dict of expr -> value for each expr ''' - return collections.defaultdict(lambda: None, [(expr, converter(self.find('gb:%s' % expr, node).text)) for expr in exprs]) - - def get_interval_data(self, node=None): - interval_data = self.interval_data(node) - return self.extract(interval_data, exprs=['duration', 'start']) - - def get_interval_reading_data(self, interval_reading_node): - time_period = self.find('gb:timePeriod', interval_reading_node) - data = self.extract(time_period, exprs=['duration', 'start']) - data.update(self.extract(interval_reading_node, exprs=['value', 'cost'])) - return data - - def create_interval_block(self, participant_group_relationship): - interval_block = self.interval_block() - interval_data = self.get_interval_data(interval_block) - start = interval_data['start'] - total_duration = interval_data['duration'] - existing_interval_blocks = GreenButtonIntervalBlock.objects.filter(start=start) - if existing_interval_blocks.count() > 0: - logger.warning("green button data already exists, deleting existing set: %s", existing_interval_blocks) - existing_interval_blocks.delete() - gb_interval_block = GreenButtonIntervalBlock.objects.create(date=datetime.fromtimestamp(start), start=start, - total_duration=total_duration, participant_group_relationship=participant_group_relationship) - return interval_block, gb_interval_block - - def create_interval_reading(self, interval_reading_node, gb_interval_block): - data = self.get_interval_reading_data(interval_reading_node) - start = data['start'] - gb_interval_reading = gb_interval_block.interval_reading_set.create( - date=datetime.fromtimestamp(start), - seconds_from_epoch=start, - watt_hours=data['value'], - millicents=data['cost']) - return interval_reading_node, gb_interval_reading - - def create_models(self, participant_group_relationship): - interval_block_node, gb_interval_block = self.create_interval_block(participant_group_relationship) - models = [gb_interval_block] - for interval_reading_node in self.interval_readings(interval_block_node): - gb_interval_reading = self.create_interval_reading(interval_reading_node, gb_interval_block) - models.append(gb_interval_reading) - return models - class ActivityQuerySet(models.query.QuerySet): """ for the moment, categorizing Activities as tiered or leveled. Leveled activities are used in experiments, where @@ -547,6 +462,7 @@ round_data = group.current_round_data activities_performed_qs = ParticipantRoundDataValue.objects.for_group(group, parameter=get_activity_performed_parameter(), round_data=round_data, date_created__range=(start, end)) for activity_performed_dv in activities_performed_qs: + logger.debug("checking activity performed: %s", activity_performed_dv) activity_points = activity_points_cache[activity_performed_dv.int_value] total_group_points += activity_points if activity_performed_dv.participant_group_relationship == participant_group_relationship: @@ -686,4 +602,4 @@ yesterday = today - timedelta(1) prdvs = ParticipantRoundDataValue.objects.filter(participant_group_relationship=participant_group_relationship, date_created__range=(yesterday, today), parameter=get_activity_performed_parameter()) - return sum([prdv.value.points for prdv in prdvs]) + return sum(prdv.value.points for prdv in prdvs) diff -r 7d93ebbb8cdebeb15c2e5af726c705b8fe270b52 -r c8a3785e5b8714bb71cbc4ec50d3252c8169e998 vcweb/lighterprints/views.py --- a/vcweb/lighterprints/views.py +++ b/vcweb/lighterprints/views.py @@ -331,7 +331,7 @@ round_data = experiment.current_round_data compare_other_group = can_view_other_groups(round_configuration=round_configuration) group_data = [] - for group in experiment.group_set.all(): + for group in experiment.groups: (average_points, total_points, total_participant_points) = get_group_score(group, participant_group_relationship=participant_group_relationship, round_data=round_data) group_level = get_footprint_level(group, round_data=round_data) points_to_next_level = get_points_to_next_level(group_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: A L. <iss...@bi...> - 2013-03-30 22:11:33
|
New issue 99: boundary effects issues for Monday https://bitbucket.org/virtualcommons/vcweb/issue/99/boundary-effects-issues-for-monday A Lee: - disable wait 30 seconds - negative storage - allocating trees to participants that requested them ordered appropriately. Responsible: alllee -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |
From: <com...@bi...> - 2013-03-30 21:34:23
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/26c7643172c5/ Changeset: 26c7643172c5 User: alllee Date: 2013-03-30 22:34:09 Summary: fixing bugs with group iteration, adding groups property to Experiment that filters based on the current session id fixing typo in tour Affected #: 3 files diff -r 568c9f20f81eb5a6b8870126b45c8426d4bf73ea -r 26c7643172c5a5b660e96d19d59736bddff002a7 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -475,7 +475,7 @@ tour.addStep({ element: "#dashboard-storage", title: "Storage", placement: "top", content: "Your total storage will be displayed here. You must have at least " + - experimentModel.costOfLiving() + " trees stored to survive each round."}); + model.costOfLiving() + " trees stored to survive each round."}); tour.addStep({ element: "#dashboard-time", title: "Time Left", placement: "top", content: "The time remaining in this round will be displayed here. It will turn red when " + diff -r 568c9f20f81eb5a6b8870126b45c8426d4bf73ea -r 26c7643172c5a5b660e96d19d59736bddff002a7 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -387,15 +387,23 @@ return self.participant_set.count() @property + def current_session_id(self): + session_id = self.current_round.session_id + if not session_id: + # force session_id to be None if it turned into the empty string somehow + session_id = None + return session_id + + @property + def groups(self): + (group for group in self.group_set.filter(session_id=self.current_session_id)) + + @property def participant_group_relationships(self): ''' Generator function for all participant group relationships in this experiment ''' - session_id = self.current_round.session_id - if not session_id: - # force session_id to be None if it turned into the empty string somehow - session_id = None - for group in self.group_set.filter(session_id=session_id): + for group in self.groups: for pgr in group.participant_group_relationship_set.all(): yield pgr @@ -673,7 +681,7 @@ # 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] [group_cluster_parameters: %s] ", participant_parameters, group_parameters, group_cluster_parameters) + # logger.debug("initializing [participant params: %s] [group parameters: %s] [group_cluster_parameters: %s] ", participant_parameters, group_parameters, group_cluster_parameters) if group_parameters is None: group_parameters = self.parameters(scope=Parameter.Scope.GROUP) if participant_parameters is None: @@ -689,7 +697,9 @@ gcdv, created = GroupClusterDataValue.objects.get_or_create(round_data=round_data, parameter=parameter, group_cluster=group_cluster) #logger.debug("%s (%s)", gcdv, created) - for group in self.group_set.select_related('parameter').all(): +# FIXME: this is wrong, need to create a way to iterate over the "active" groups in the experiment (e.g., when they +# switch from one session to another) + for group in self.groups: for parameter in group_parameters: group_data_value, created = GroupRoundDataValue.objects.get_or_create(round_data=round_data, group=group, parameter=parameter) #logger.debug("%s (%s)", group_data_value, created) diff -r 568c9f20f81eb5a6b8870126b45c8426d4bf73ea -r 26c7643172c5a5b660e96d19d59736bddff002a7 vcweb/vcweb-sockjs.py --- a/vcweb/vcweb-sockjs.py +++ b/vcweb/vcweb-sockjs.py @@ -298,7 +298,7 @@ logger.debug("handling participant ready event %s for experiment %s", event, experiment) (per, valid) = self.verify_auth_token(event) if valid: - if not event.message: + if getattr(event, 'message', None): event.message = "Participant %s is ready." % per.participant # FIXME: any reason to bootstrap this connection_manager.broadcast(experiment, create_message_event(event.message, event_type=READY_EVENT_TYPE)) 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-29 19:08:51
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/568c9f20f81e/ Changeset: 568c9f20f81e User: alllee Date: 2013-03-29 20:08:29 Summary: resetting shouldShowOtherGroup on the start of a round and removing model view json from submit decision Affected #: 2 files diff -r 664fa4ef1e3d2ca6d4982bdc2494f72a22ffb6ff -r 568c9f20f81eb5a6b8870126b45c8426d4bf73ea vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -542,6 +542,8 @@ }); model.resourceImageHeight = ko.observable("79px"); model.startRound = function() { + // reset other group view + model.shouldShowOtherGroup(false); if (model.showTour()) { model.setupTour(); } @@ -579,12 +581,11 @@ console.debug(formData); $.post('submit-harvest-decision', formData, function(response) { console.log(response); - model.update($.parseJSON(response.experimentModelJson)); - // FIXME: forward the response message to the chat window should be handled completely on the server - // side instead of ping-ponging to the client side back to the real time server back out to all - // clients in this group + // model.update($.parseJSON(response.experimentModelJson)); getWebSocket().send(createReadyEvent(response.message)); + model.submitted(true); model.clearCurrentInterval(); + model.secondsLeft(0); }); } model.submitChatMessage = function(data, evt) { diff -r 664fa4ef1e3d2ca6d4982bdc2494f72a22ffb6ff -r 568c9f20f81eb5a6b8870126b45c8426d4bf73ea vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -43,7 +43,7 @@ experiment.log(message % (pgr.participant, harvest_decision)) response_dict = { 'success': True, - 'experimentModelJson': get_view_model_json(experiment, pgr), +# 'experimentModelJson': get_view_model_json(experiment, pgr), 'message': message % (pgr.participant_handle, harvest_decision), } return JsonResponse(dumps(response_dict)) 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: A L. <iss...@bi...> - 2013-03-29 18:15:41
|
New issue 98: boundaries: max resource level calculations https://bitbucket.org/virtualcommons/vcweb/issue/98/boundaries-max-resource-level-calculations A Lee: Need to set up max resource level to be K * group size, where K = 60 Responsible: alllee -- This is an issue notification from bitbucket.org. You are receiving this either because you are the owner of the issue, or you are following the issue. |
From: <com...@bi...> - 2013-03-29 16:31:32
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/664fa4ef1e3d/ Changeset: 664fa4ef1e3d User: alllee Date: 2013-03-29 17:31:18 Summary: fixing bug in update_resource_level Affected #: 1 file diff -r 3fd0a8d0a70241f2bd6f54a50ccadb09c622572f -r 664fa4ef1e3d2ca6d4982bdc2494f72a22ffb6ff vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -254,7 +254,7 @@ def update_resource_level(experiment, group, round_data, regrowth_rate, max_resource_level=None): - if max_resource_level: + if max_resource_level is None: max_resource_level = get_max_resource_level(experiment.experiment_configuration) current_resource_level_dv = get_resource_level_dv(group, round_data) current_resource_level = current_resource_level_dv.int_value @@ -365,6 +365,6 @@ update_participants(experiment, round_data) -def calculate_regrowth(resource_level, regrowth_rate, max_resource_level=MAX_RESOURCE_LEVEL): +def calculate_regrowth(resource_level, regrowth_rate, max_resource_level=240): 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-29 16:22:17
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/3fd0a8d0a702/ Changeset: 3fd0a8d0a702 User: alllee Date: 2013-03-29 17:22:04 Summary: updating get_initial_resource_level Affected #: 1 file diff -r f8968fe3fbcd209f37f047b9446a17c700bed119 -r 3fd0a8d0a70241f2bd6f54a50ccadb09c622572f vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -86,9 +86,7 @@ return RESOURCES_PER_PARTICIPANT * experiment_configuration.max_group_size def get_initial_resource_level(round_configuration, default=None): - if default is None: - default = get_max_resource_level(round_configuration.experiment_configuration) - return forestry_initial_resource_level(round_configuration, default) + return get_max_resource_level(round_configuration.experiment_configuration) def should_reset_resource_level(round_configuration): return round_configuration.get_parameter_value(parameter=get_reset_resource_level_parameter(), 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-29 16:20:22
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/f8968fe3fbcd/ Changeset: f8968fe3fbcd User: alllee Date: 2013-03-29 17:20:06 Summary: initial resource level shouldn't be a parameter anymore, calculated via RESOURCES_PER_PARTICIPANT * group size Affected #: 1 file diff -r d0174c7c0e46bafae53916d2f93f97925b946e26 -r f8968fe3fbcd209f37f047b9446a17c700bed119 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -19,6 +19,8 @@ MAX_RESOURCE_LEVEL = 240 MAX_SHARED_RESOURCE_LEVEL = 480 +RESOURCES_PER_PARTICIPANT = 60 + ''' Experiment Parameters and Metadata Accessors ''' @@ -80,7 +82,12 @@ 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): +def get_max_resource_level(experiment_configuration): + return RESOURCES_PER_PARTICIPANT * experiment_configuration.max_group_size + +def get_initial_resource_level(round_configuration, default=None): + if default is None: + default = get_max_resource_level(round_configuration.experiment_configuration) return forestry_initial_resource_level(round_configuration, default) def should_reset_resource_level(round_configuration): @@ -210,7 +217,7 @@ formation ''' if should_reset_resource_level(round_configuration): - initial_resource_level = get_initial_resource_level(round_configuration) + initial_resource_level = get_max_resource_level(round_configuration.experiment_configuration) logger.debug("Resetting resource level for %s to %d", round_configuration, initial_resource_level) round_data = experiment.get_round_data(round_configuration) for group in experiment.group_set.filter(session_id=round_configuration.session_id): @@ -248,7 +255,9 @@ return adjusted_harvest -def update_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=None): + if max_resource_level: + max_resource_level = get_max_resource_level(experiment.experiment_configuration) current_resource_level_dv = get_resource_level_dv(group, round_data) 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 @@ -280,8 +289,10 @@ # 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): +def update_shared_resource_level(experiment, group_cluster, round_data, regrowth_rate, max_resource_level=None): logger.debug("updating shared resource level") + if max_resource_level is None: + max_resource_level = get_max_resource_level(experiment.experiment_configuration) max_resource_level = max_resource_level * group_cluster.size 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 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-29 15:39:23
|
3 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/ec0331636019/ Changeset: ec0331636019 User: alllee Date: 2013-03-29 16:09:12 Summary: setting up redirect to monitor page after registering participants Affected #: 9 files diff -r 2bdfcbcab00d636dffbc2eac0588cd558f7e278b -r ec033163601966f6e25e594d7bfca0bb741e3965 vcweb/broker/templates/broker/participate.html --- a/vcweb/broker/templates/broker/participate.html +++ b/vcweb/broker/templates/broker/participate.html @@ -285,9 +285,12 @@ <h4>PRACTICE ROUND</h4> This is a practice round. The decisions you make in this round will <b>NOT</b> contribute to your earnings. + <span data-bind='if: isSecondPracticeRound'> + <button class='btn btn-primary' data-bind='click: setupSecondPracticeRoundTour'>Tutorial</button> + </span> + <span data-bind="if: isFirstPracticeRound"> - <button class='btn btn-primary' data-bind='click: setupFirstPracticeRoundTour'>Tour</button> - <a href="#" data-bind="">Show me 1st Instructions again</a> + <button class='btn btn-primary' data-bind='click: setupFirstPracticeRoundTour'>Tutorial</button></span></div> @@ -518,6 +521,7 @@ console.debug(tour); }; model.setupSecondPracticeRoundTour = function () { + console.debug("starting second tour"); var tourSecond = new Tour(); tourSecond.addStep({ element: "#lastRoundHarvestPayOff", @@ -569,7 +573,7 @@ title: "Chat rooms", content: "Remember that all your choices are independent and none will see what your decisions are.", }); - tourSecond.start(); + tourSecond.start(true); }; model.update = function () { $.get('view-model', { participant_group_id: model.participantGroupId(), }, diff -r 2bdfcbcab00d636dffbc2eac0588cd558f7e278b -r ec033163601966f6e25e594d7bfca0bb741e3965 vcweb/core/forms.py --- a/vcweb/core/forms.py +++ b/vcweb/core/forms.py @@ -122,8 +122,8 @@ return self.cleaned_data -class RegisterSimpleParticipantsForm(RegisterParticipantsForm): - username_suffix = forms.CharField(min_length=3, initial='asu', +class RegisterTestParticipantsForm(RegisterParticipantsForm): + username_suffix = forms.CharField(min_length=3, initial='asu', help_text=_('''Appended to every generated username before the "@" symbol, e.g., s1...@fo...''')) email_suffix = forms.CharField(min_length=3, initial='mailinator.com', help_text=_(''' diff -r 2bdfcbcab00d636dffbc2eac0588cd558f7e278b -r ec033163601966f6e25e594d7bfca0bb741e3965 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -738,6 +738,7 @@ if pgr.group.session_id == current_group.session_id: logger.error("Participant %s is already in a group %s with the same session id, not adding them to %s", participant, pgr.group, current_group) return pgr + logger.debug("adding participant %s to group %s", participant, current_group) return current_group.add_participant(participant) def allocate_groups(self, randomize=True, preserve_existing_groups=False, session_id=None): @@ -776,8 +777,8 @@ def create_group_clusters(self): round_configuration = self.current_round session_id = round_configuration.session_id - logger.debug("creating group clusters with session id %s", session_id) if round_configuration.create_group_clusters: + logger.debug("creating group clusters with session id %s", session_id) gcs = self.group_cluster_set.filter() gs = self.group_set.filter() if session_id: diff -r 2bdfcbcab00d636dffbc2eac0588cd558f7e278b -r ec033163601966f6e25e594d7bfca0bb741e3965 vcweb/core/templates/experimenter/dashboard.html --- a/vcweb/core/templates/experimenter/dashboard.html +++ b/vcweb/core/templates/experimenter/dashboard.html @@ -17,7 +17,7 @@ <a class='btn' data-content='Register participants for this experiment with actual email addresses' href='{{e.controller_url}}/register-email-list'><img src='{{STATIC_URL}}images/famfamfam/group_add.png' alt='register'/> register participants</a><a data-content='Register participants for this experiment with fake email addresses by providing an email suffix and the number of participants.' - class='btn' href='{{e.controller_url}}/register-simple'> + class='btn' href='{{e.controller_url}}/register-test-participants'><img src='{{STATIC_URL}}images/famfamfam/group_add.png' alt='register'/> test participants</a> {% else %} <a data-content='Remove all participants from the experiment, including any data they may have generated.' href='{{e.controller_url}}/clear-participants' class='btn confirm-experiment-action'> diff -r 2bdfcbcab00d636dffbc2eac0588cd558f7e278b -r ec033163601966f6e25e594d7bfca0bb741e3965 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -7,7 +7,7 @@ <h3>{{experiment}}</h3><div class='row-fluid'><div class='span6'> - <div class='alert alert-white' data-bind='if: isActive'> + <div class='alert alert-white' data-bind='visible: isActive'><h4>ROUND MANAGEMENT</h4><div class='btn-toolbar'><div class='btn-group'> @@ -45,7 +45,7 @@ <div class='alert alert-error alert-block'><h4>No participants</h4><i class='icon-warning-sign'></i><a href='{{experiment.controller_url}}/register-email-list'>Register bulk email addresses</a> or - <a href='{{experiment.controller_url}}/register-simple'>add test participants</a>? + <a href='{{experiment.controller_url}}/register-test-participants'>add test participants</a>? </div></div><div data-bind="if: hasParticipants"> diff -r 2bdfcbcab00d636dffbc2eac0588cd558f7e278b -r ec033163601966f6e25e594d7bfca0bb741e3965 vcweb/core/templates/experimenter/register-simple-participants.html --- a/vcweb/core/templates/experimenter/register-simple-participants.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "experimenter/register-participants.html" %} -{% block participant_registration_header %} -<h3>Test Participant Registration</h3> -<div class='alert alert-block alert-error'><h4 class='alert-heading'>NOTE</h4>This should only be used for testing experiments.</div> -{% endblock %} - - diff -r 2bdfcbcab00d636dffbc2eac0588cd558f7e278b -r ec033163601966f6e25e594d7bfca0bb741e3965 vcweb/core/templates/experimenter/register-test-participants.html --- /dev/null +++ b/vcweb/core/templates/experimenter/register-test-participants.html @@ -0,0 +1,7 @@ +{% extends "experimenter/register-participants.html" %} +{% block participant_registration_header %} +<h3>Test Participant Registration</h3> +<div class='alert alert-block alert-error'><h4 class='alert-heading'>NOTE</h4>This should only be used for testing experiments.</div> +{% endblock %} + + diff -r 2bdfcbcab00d636dffbc2eac0588cd558f7e278b -r ec033163601966f6e25e594d7bfca0bb741e3965 vcweb/core/urls.py --- a/vcweb/core/urls.py +++ b/vcweb/core/urls.py @@ -2,7 +2,7 @@ from django.contrib.auth.decorators import login_required from vcweb import settings from vcweb.core.views import (Dashboard, LoginView, LogoutView, RegistrationView, monitor, CloneExperimentView, - RegisterEmailListView, RegisterSimpleParticipantsView, ClearParticipantsExperimentView, add_experiment, + RegisterEmailListView, RegisterTestParticipantsView, ClearParticipantsExperimentView, add_experiment, Participate, download_data, export_configuration, api_logger, participant_ready, get_number_of_ready_participants, deactivate) import logging import urllib @@ -24,7 +24,7 @@ url(r'^experiment/(?P<pk>\d+)/check-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'), + url(r'^experiment/(?P<pk>\d+)/register-test-participants$', RegisterTestParticipantsView.as_view(), name='register_test_participants'), # FIXME: refactor these into POSTs using the ExperimentActionForm url(r'^experiment/(?P<pk>\d+)/deactivate$', deactivate, name='deactivate'), url(r'^experiment/(?P<pk>\d+)/clone$', CloneExperimentView.as_view(), name='clone'), diff -r 2bdfcbcab00d636dffbc2eac0588cd558f7e278b -r ec033163601966f6e25e594d7bfca0bb741e3965 vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -13,7 +13,7 @@ from vcweb.core import dumps from vcweb.core.decorators import anonymous_required, experimenter_required, participant_required from vcweb.core.forms import (RegistrationForm, LoginForm, ParticipantAccountForm, ExperimenterAccountForm, - ParticipantGroupIdForm, RegisterEmailListParticipantsForm, RegisterSimpleParticipantsForm, + ParticipantGroupIdForm, RegisterEmailListParticipantsForm, RegisterTestParticipantsForm, RegisterExcelParticipantsForm, LogMessageForm) from vcweb.core.http import JsonResponse from vcweb.core.models import (User, ChatMessage, Participant, ParticipantExperimentRelationship, ParticipantGroupRelationship, @@ -315,9 +315,9 @@ def get_success_url(self): return reverse('core:dashboard') -class RegisterSimpleParticipantsView(ExperimenterSingleExperimentMixin, FormView): - form_class = RegisterSimpleParticipantsForm - template_name = 'experimenter/register-simple-participants.html' +class RegisterTestParticipantsView(ExperimenterSingleExperimentMixin, FormView): + form_class = RegisterTestParticipantsForm + template_name = 'experimenter/register-test-participants.html' def form_valid(self, form): number_of_participants = form.cleaned_data.get('number_of_participants') @@ -330,10 +330,11 @@ email_suffix=email_suffix, username_suffix=username_suffix, password=experiment_passcode) - return super(RegisterSimpleParticipantsView, self).form_valid(form) + return super(RegisterTestParticipantsView, self).form_valid(form) def get_success_url(self): - return reverse('core:dashboard') + + return reverse('core:monitor_experiment', kwargs={'pk':self.object.pk}) # FIXME: these last two use GET (which should be idempotent) to modify database state which makes HTTP sadful class CloneExperimentView(ExperimenterSingleExperimentView): https://bitbucket.org/virtualcommons/vcweb/commits/e027e52f7508/ Changeset: e027e52f7508 User: alllee Date: 2013-03-29 16:10:10 Summary: redirect to monitor experiment page after participant registration Affected #: 1 file diff -r ec033163601966f6e25e594d7bfca0bb741e3965 -r e027e52f7508d42eca6b89e44081c2d99dc81c27 vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -313,7 +313,7 @@ password=experiment.authentication_code) return super(RegisterEmailListView, self).form_valid(form) def get_success_url(self): - return reverse('core:dashboard') + return reverse('core:monitor_experiment', kwargs={'pk':self.object.pk}) class RegisterTestParticipantsView(ExperimenterSingleExperimentMixin, FormView): form_class = RegisterTestParticipantsForm @@ -333,7 +333,6 @@ return super(RegisterTestParticipantsView, self).form_valid(form) def get_success_url(self): - return reverse('core:monitor_experiment', kwargs={'pk':self.object.pk}) # FIXME: these last two use GET (which should be idempotent) to modify database state which makes HTTP sadful https://bitbucket.org/virtualcommons/vcweb/commits/d0174c7c0e46/ Changeset: d0174c7c0e46 User: alllee Date: 2013-03-29 16:39:08 Summary: patch for session_id empty strings, adding some simple styling to alive status Affected #: 3 files diff -r e027e52f7508d42eca6b89e44081c2d99dc81c27 -r d0174c7c0e46bafae53916d2f93f97925b946e26 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -335,7 +335,7 @@ </div><div class='span4'><h3>Group Status</h3> - <table class='table table-bordered table-condensed'> + <table class='table table-bordered table-condensed table-striped'><thead><tr><th>Player</th><!-- ko foreach: playerData --> @@ -359,7 +359,7 @@ <tr><td>Alive</td><!-- ko foreach: playerData --> - <td data-bind='text: alive'></td> + <td data-bind='css: { "text-error": ! alive(), "text-success": alive() }, text: alive() ? "Yes" : "No"'></td><!-- /ko --></tr></tbody> diff -r e027e52f7508d42eca6b89e44081c2d99dc81c27 -r d0174c7c0e46bafae53916d2f93f97925b946e26 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -17,7 +17,7 @@ def participate(request, experiment_id=None): participant = request.user.participant logger.debug("handling participate request for %s and experiment %s", participant, experiment_id) - experiment = get_object_or_404(Experiment.objects.select_related('experiment_metadata', 'experiment_configuration').prefetch_related('group_set', 'experiment_configuration__round_configuration_set'), pk=experiment_id) + experiment = get_object_or_404(Experiment.objects.select_related('experiment_metadata', 'experiment_configuration'), pk=experiment_id) pgr = experiment.get_participant_group_relationship(participant) if experiment.experiment_metadata != get_experiment_metadata() or pgr.participant != request.user.participant: raise Http404 @@ -58,7 +58,6 @@ def get_view_model(request, experiment_id=None): experiment = get_object_or_404(Experiment.objects.select_related('experiment_metadata', 'experiment_configuration'), pk=experiment_id) pgr = experiment.get_participant_group_relationship(request.user.participant) - logger.debug("getting view model for participant: %s", pgr) return JsonResponse(get_view_model_json(experiment, pgr)) experiment_model_defaults = { diff -r e027e52f7508d42eca6b89e44081c2d99dc81c27 -r d0174c7c0e46bafae53916d2f93f97925b946e26 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -392,6 +392,9 @@ Generator function for all participant group relationships in this experiment ''' session_id = self.current_round.session_id + if not session_id: + # force session_id to be None if it turned into the empty string somehow + session_id = None for group in self.group_set.filter(session_id=session_id): for pgr in group.participant_group_relationship_set.all(): yield pgr @@ -670,7 +673,7 @@ # 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] [group_cluster_parameters: %s] ", participant_parameters, group_parameters, group_cluster_parameters) + #logger.debug("initializing [participant params: %s] [group parameters: %s] [group_cluster_parameters: %s] ", participant_parameters, group_parameters, group_cluster_parameters) if group_parameters is None: group_parameters = self.parameters(scope=Parameter.Scope.GROUP) if participant_parameters is 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-29 07:24:24
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/2bdfcbcab00d/ Changeset: 2bdfcbcab00d User: alllee Date: 2013-03-29 08:24:04 Summary: fixing a bug where regrowth wasn't being calculated if no one harvested adding waitThirtySeconds property to a bloated view model Affected #: 4 files diff -r bc2e245b0a67b2b30f6e7cc4a8d6ae59d1c01649 -r 2bdfcbcab00d636dffbc2eac0588cd558f7e278b vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -120,7 +120,6 @@ if round_configuration is None: round_configuration = round_data.round_configuration if is_shared_resource_enabled(round_configuration): - logger.debug("returning shared resource level") return get_shared_resource_level_dv(group, round_data, cluster) else: return get_unshared_resource_level_dv(group, round_data) @@ -256,7 +255,7 @@ # get_total_group_harvest(group, ...), see if we can enable this dynamically total_harvest = get_total_group_harvest(group, round_data) logger.debug("Harvest: total group harvest for playable round: %s", total_harvest) - if current_resource_level > 0 and total_harvest > 0: + if current_resource_level > 0: if total_harvest > current_resource_level: # divide remaining trees evenly among every participant group_size = group.size diff -r bc2e245b0a67b2b30f6e7cc4a8d6ae59d1c01649 -r 2bdfcbcab00d636dffbc2eac0588cd558f7e278b vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -557,7 +557,7 @@ model.setCurrentInterval( setInterval(function() { model.tick(); - if (model.secondsLeft() > 30 && ! model.isPracticeRound()) { + if (model.secondsLeft() > 30 && model.waitThirtySeconds()) { model.disableHarvestForm(); } else { diff -r bc2e245b0a67b2b30f6e7cc4a8d6ae59d1c01649 -r 2bdfcbcab00d636dffbc2eac0588cd558f7e278b vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -73,6 +73,7 @@ 'chatMessages': [], 'canObserveOtherGroup': False, 'isInstructionsRound': False, + 'waitThirtySeconds': False, 'totalHarvest': 0, } # FIXME: need to distinguish between instructions / welcome rounds and practice/regular rounds @@ -94,6 +95,8 @@ experiment_model_dict['templateName'] = current_round.template_name experiment_model_dict['isPracticeRound'] = current_round.is_practice_round experiment_model_dict['showTour'] = current_round.is_practice_round and not previous_round.is_practice_round +# FIXME: extend this to first 3 regular rounds of each session as well? + experiment_model_dict['waitThirtySeconds'] = current_round.is_practice_round and current_round.sequence_number < 6 # instructions round parameters if current_round.is_instructions_round: experiment_model_dict['isInstructionsRound'] = True @@ -137,7 +140,6 @@ logger.debug("already submitted, setting harvest decision to %s", experiment_model_dict['harvestDecision']) experiment_model_dict['chatMessages'] = [cm.to_dict() for cm in ChatMessage.objects.for_group(own_group)] - logger.debug("chat messages: %s", experiment_model_dict['chatMessages']) if can_observe_other_group(current_round): experiment_model_dict['canObserveOtherGroup'] = True other_group = own_group.get_related_group() diff -r bc2e245b0a67b2b30f6e7cc4a8d6ae59d1c01649 -r 2bdfcbcab00d636dffbc2eac0588cd558f7e278b vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -1907,7 +1907,6 @@ if default is None: raise e else: - logger.warning("unable to retrieve ParticipantRoundDataValue with parameter %s, returning default value %s", parameter, default) return DefaultValue(default) def set_data_value(self, parameter=None, value=None, round_data=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-29 06:53:25
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/bc2e245b0a67/ Changeset: bc2e245b0a67 User: alllee Date: 2013-03-29 07:53:09 Summary: adding bootstrap tour, fixing storage_dv reference when a player dies early on Affected #: 6 files diff -r 15c4d2d5527a53f314bde5fd2139e0c619e99cbd -r bc2e245b0a67b2b30f6e7cc4a8d6ae59d1c01649 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -314,13 +314,14 @@ group_cluster.copy_to_next_round(shared_resource_level_dv) def update_participants(experiment, round_data): + logger.debug("updating participants") 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) + storage_dv = get_storage_dv(pgr, round_data) player_alive = player_status_dv.boolean_value if player_alive: 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 if updated_storage < 0: # player has "died" diff -r 15c4d2d5527a53f314bde5fd2139e0c619e99cbd -r bc2e245b0a67b2b30f6e7cc4a8d6ae59d1c01649 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -36,7 +36,7 @@ <div class='chat-sidebar'><div id='chat-div'><div class='chat-messages' data-bind='foreach: chatMessages'> - <i class='icon-user muted'></i><strong>Participant <span data-bind='text: participant_number'></strong><b class='pull-right muted' data-bind='text: date_created'></b> + <i class='icon-user muted'></i><strong>Participant <span data-bind='text: participant_number'></strong><b class='pull-right muted' data-bind='text: short_date_created'></b><p><small><i class='icon-double-angle-right'></i></small><span data-bind='text: message'></span></p> @@ -312,19 +312,19 @@ <h3>My Status</h3><div class='row'><div class='alert boundaries-status-dashboard span2'> - <h4>Last harvest <i class='icon-info-sign' data-content="The number of trees you harvested last round."></i></h4> + <h4 id="dashboard-last-harvest">Last harvest <i class='icon-info-sign' data-content="The number of trees you harvested last round."></i></h4><p><strong class='text-success'><span data-bind='text:lastHarvestDecision'></span><i class='icon-leaf'></i></strong></p></div> - <div class='alert boundaries-status-dashboard span1'> - <h4>Storage <i class='icon-info-sign' data-bind='attr: {"data-content": "You need at least " + costOfLiving() + " trees to survive each round."}'></i></h4> + <div class='alert boundaries-status-dashboard span2'> + <h4 id='dashboard-storage'>Storage <i class='icon-info-sign' data-bind='attr: {"data-content": "You need at least " + costOfLiving() + " trees to survive each round."}'></i></h4><p><strong data-bind='css: { "text-error": storage() < costOfLiving(), "text-success": storage() > costOfLiving()}'><span data-bind='text: storage'></span><i class='icon-leaf'></i></strong></p></div><div class='alert boundaries-status-dashboard span1'> - <h4><i class='icon-time'></i> Time</h4> + <h4 id='dashboard-time'><i class='icon-time'></i> Time</h4><p><strong data-bind='css: { "text-error": secondsLeft() < warningCountdownTime(), "text-info": secondsLeft() > warningCountdownTime()}'><span data-bind='text: secondsLeft'></span> s @@ -447,6 +447,7 @@ </form></div></script> +<script src='{% static "js/bootstrap-tour.js" %}'></script><script type="text/javascript"> $(function() { function ExperimentModel(experimentModelJson) { @@ -465,6 +466,28 @@ return model.templateName(); } }); + model.setupTour = function() { + var tour = new Tour(); + tour.addStep({ element: "#dashboard-last-harvest", title: "Last harvest", + placement: "top", + content: "Your last round's harvest decision will be displayed here. Since this is the first practice round this is currently 0." + }); + tour.addStep({ element: "#dashboard-storage", title: "Storage", + placement: "top", + content: "Your total storage will be displayed here. You must have at least " + + experimentModel.costOfLiving() + " trees stored to survive each round."}); + tour.addStep({ element: "#dashboard-time", title: "Time Left", + placement: "top", + content: "The time remaining in this round will be displayed here. It will turn red when " + + experimentModel.warningCountdownTime() + " seconds are left."}); + tour.addStep({ element: "#chatMessage", title: "Text Chat", + placement: "left", + content: "If chat is enabled, you can communicate with your group by typing messages into this box and hitting the enter key or clicking 'Send'."}); + tour.addStep({ element: "#harvestDecisionSelect", title: "Harvest Decision", + placement: "top", + content: "Enter the number of trees you'd like to harvest here. For the purposes of this practice round, please select 10 now and click the 'Submit' button."}); + tour.start(); + } model.setCurrentInterval = function(intervalId) { model.clearCurrentInterval(); model.currentInterval(intervalId); @@ -519,6 +542,9 @@ }); model.resourceImageHeight = ko.observable("79px"); model.startRound = function() { + if (model.showTour()) { + model.setupTour(); + } if (model.submitted() || ! model.alive()) { model.disableHarvestForm(); model.disableChatForm(); @@ -639,9 +665,9 @@ break; } }; + return experimentModel; } - var experimentModelJson = $.parseJSON("{{ experimentModelJson|escapejs }}"); - initialize(experimentModelJson); + var experimentModel = initialize($.parseJSON("{{ experimentModelJson|escapejs }}")); $('[data-content]').popover({placement: 'top', trigger: 'hover'}); }); </script> diff -r 15c4d2d5527a53f314bde5fd2139e0c619e99cbd -r bc2e245b0a67b2b30f6e7cc4a8d6ae59d1c01649 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -93,6 +93,7 @@ experiment_model_dict['maxHarvestDecision'] = get_max_allowed_harvest_decision(participant_group_relationship, current_round_data, ec) experiment_model_dict['templateName'] = current_round.template_name experiment_model_dict['isPracticeRound'] = current_round.is_practice_round + experiment_model_dict['showTour'] = current_round.is_practice_round and not previous_round.is_practice_round # instructions round parameters if current_round.is_instructions_round: experiment_model_dict['isInstructionsRound'] = True diff -r 15c4d2d5527a53f314bde5fd2139e0c619e99cbd -r bc2e245b0a67b2b30f6e7cc4a8d6ae59d1c01649 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -392,11 +392,7 @@ Generator function for all participant group relationships in this experiment ''' session_id = self.current_round.session_id - if session_id: - groups = self.group_set.filter(session_id=session_id) - else: - groups = self.group_set.all() - for group in groups: + for group in self.group_set.filter(session_id=session_id): for pgr in group.participant_group_relationship_set.all(): yield pgr @@ -863,10 +859,12 @@ # notify registered game handlers if sender is None: sender = intern(self.experiment_metadata.namespace.encode('utf8')) - return signals.round_started.send_robust(sender, experiment=self, time=datetime.now(), round_configuration=current_round_configuration) + signal_tuple = signals.round_started.send_robust(sender, experiment=self, time=datetime.now(), round_configuration=current_round_configuration) + logger.debug("round started signal returned %s", signal_tuple) + return signal_tuple def stop_round(self, sender=None, **kwargs): - self.end_round() + return self.end_round() def end_round(self, sender=None): self.status = Experiment.Status.ACTIVE diff -r 15c4d2d5527a53f314bde5fd2139e0c619e99cbd -r bc2e245b0a67b2b30f6e7cc4a8d6ae59d1c01649 vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -273,6 +273,7 @@ user = request.user if is_experimenter(user, experiment.experimenter): registered_participants = [ { "group": pgr.group, "participant_group_relationship": pgr } for pgr in experiment.participant_group_relationships ] + logger.debug("registered participants: %s", registered_participants) return render(request, 'experimenter/monitor.html', { 'experiment': experiment, 'registeredParticipants': registered_participants, diff -r 15c4d2d5527a53f314bde5fd2139e0c619e99cbd -r bc2e245b0a67b2b30f6e7cc4a8d6ae59d1c01649 vcweb/static/css/boundaries/style.css --- a/vcweb/static/css/boundaries/style.css +++ b/vcweb/static/css/boundaries/style.css @@ -24,7 +24,7 @@ } .boundaries-status-dashboard { height: 100px; - min-width: 80px; + width: 110px; margin-right: 0px; padding: 8px 8px 8px 8px; } 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-29 06:05:52
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/15c4d2d5527a/ Changeset: 15c4d2d5527a User: alllee Date: 2013-03-29 07:05:35 Summary: implementing shared group resource level for treatment D Affected #: 5 files diff -r bbc7674fbbca76bda3740eaf376df51758f529e1 -r 15c4d2d5527a53f314bde5fd2139e0c619e99cbd vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -3,7 +3,7 @@ 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_harvest_decision_dv, get_regrowth_rate_parameter, - get_group_harvest_parameter, get_reset_resource_level_parameter, get_resource_level, + get_group_harvest_parameter, get_reset_resource_level_parameter, get_resource_level as get_unshared_resource_level, get_initial_resource_level as forestry_initial_resource_level, get_regrowth_parameter, get_resource_level_parameter, get_resource_level_dv as get_unshared_resource_level_dv, set_group_harvest, set_regrowth, set_harvest_decision) @@ -17,6 +17,7 @@ EXPERIMENT_METADATA_NAME = intern('bound') # constants that should live in configuration as well MAX_RESOURCE_LEVEL = 240 +MAX_SHARED_RESOURCE_LEVEL = 480 ''' Experiment Parameters and Metadata Accessors @@ -99,14 +100,17 @@ return min(get_max_harvest_decision(experiment_configuration), resource_level / group.size) +def get_resource_level(group, round_data=None, round_configuration=None, cluster=None): + return get_resource_level_dv(group, round_data, round_configuration, cluster).int_value + ''' group data accessors ''' def get_average_harvest(group, round_data): - return get_total_harvest(group, round_data) / float(group.size) + return get_total_group_harvest(group, round_data) / float(group.size) def get_average_storage(group, round_data): return get_total_storage(group, round_data) / float(group.size) -def get_resource_level_dv(group, round_data=None, round_configuration=None): +def get_resource_level_dv(group, round_data=None, round_configuration=None, cluster=None): ''' Returns either the GroupClusterDataValue (shared resource condition) or the GroupRoundDataValue (standard resource per group condition) for the given group @@ -116,7 +120,8 @@ 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) + logger.debug("returning shared resource level") + return get_shared_resource_level_dv(group, round_data, cluster) else: return get_unshared_resource_level_dv(group, round_data) @@ -147,11 +152,16 @@ def _zero_if_none(value): return 0 if value is None else value -def get_total_harvest(group, round_data): +def get_total_group_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 _zero_if_none(q['total_harvest']) +def get_total_harvest(participant_group_relationship, session_id): + q = ParticipantRoundDataValue.objects.for_participant(participant_group_relationship, parameter=get_harvest_decision_parameter(), + participant_group_relationship__group__session_id=session_id).aggregate(total_harvest=Sum('int_value')) + return _zero_if_none(q['total_harvest']) + # returns the sum of all stored resources for each member in the group def get_total_storage(group, round_data): q = ParticipantRoundDataValue.objects.for_group(group=group, parameter=get_storage_parameter(), round_data=round_data).aggregate(total_storage=Sum('int_value')) @@ -204,7 +214,7 @@ initial_resource_level = get_initial_resource_level(round_configuration) logger.debug("Resetting resource level for %s to %d", round_configuration, initial_resource_level) round_data = experiment.get_round_data(round_configuration) - for group in experiment.group_set.all(): + for group in experiment.group_set.filter(session_id=round_configuration.session_id): ''' set resource level to initial default ''' existing_resource_level = get_resource_level_dv(group, round_data, round_configuration) group.log( @@ -240,11 +250,11 @@ 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_dv = get_resource_level_dv(group, round_data) 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) +# get_total_group_harvest(group, ...), see if we can enable this dynamically + total_harvest = get_total_group_harvest(group, round_data) 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: @@ -272,6 +282,8 @@ # 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): + logger.debug("updating shared resource level") + max_resource_level = max_resource_level * group_cluster.size 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 @@ -280,7 +292,7 @@ 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 = get_total_group_harvest(group, round_data) group_harvest_dict[group] = group_harvest shared_group_harvest += group_harvest group.log("total group harvest: %s" % group_harvest) @@ -293,13 +305,12 @@ # set regrowth after shared_resource_level has been modified by all groups in this cluster 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) + 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.log("Transferring shared resource level %s to next round" % current_resource_level_dv.int_value) + group.log("Transferring shared resource level %s to next round" % shared_resource_level_dv.int_value) group_cluster.copy_to_next_round(shared_resource_level_dv) def update_participants(experiment, round_data): @@ -337,11 +348,10 @@ 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): + for group_cluster in GroupCluster.objects.for_experiment(experiment, session_id=round_configuration.session_id): update_shared_resource_level(experiment, group_cluster, round_data, regrowth_rate) else: - for group in experiment.group_set.all(): + for group in experiment.group_set.filter(session_id=round_configuration.session_id): update_resource_level(experiment, group, round_data, regrowth_rate) update_participants(experiment, round_data) diff -r bbc7674fbbca76bda3740eaf376df51758f529e1 -r 15c4d2d5527a53f314bde5fd2139e0c619e99cbd vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -48,6 +48,26 @@ {% block javascript %} {{ block.super }} <!-- ko templates --> +<script type='text/html' id='TREATMENT_RESULTS'> + <h3>Session <span data-bind='text: sessionId'></span> Summary</h3> + <table class='table table-compact'> + <thead> + <tr><th>Trees left in the forest</th><th>Trees harvested</th><th>Trees in storage</th><th>Earnings</th></tr> + </thead> + <tbody> + <tr><td data-bind='text: resourceLevel'></td><td data-bind='text: totalHarvest'></td><td data-bind='text:storage'></td><td class='text-success' data-bind='text: totalEarnings'></td></tr> + </tbody> + </table> + <div class='alert alert-info'> + <i class='icon-info-sign'></i> Remember, only <b>one</b> of your sessions will be selected at random for + payment. We will now move on to the next session. + </div> + <ul class='pager'> + <li class='next'> + <a href='javascript: void()' data-bind='click: participantReady.bind($data, participantHandle() + " finished reading session summary.") '>Ok, I'm ready</a> + </li> + </ul> +</script><script type='text/html' id='PRACTICE_ROUND_RESULTS'><h3>Practice Round Results</h3><p> diff -r bbc7674fbbca76bda3740eaf376df51758f529e1 -r 15c4d2d5527a53f314bde5fd2139e0c619e99cbd vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -8,7 +8,7 @@ from vcweb.boundaries.models import (get_experiment_metadata, get_regrowth_rate, get_max_allowed_harvest_decision, get_cost_of_living, get_resource_level, get_initial_resource_level, get_total_storage, get_storage, get_last_harvest_decision, get_harvest_decision_dv, get_harvest_decision_parameter, set_harvest_decision, - can_observe_other_group, get_player_status, get_average_harvest, get_average_storage) + can_observe_other_group, get_player_status, get_average_harvest, get_average_storage, get_total_harvest) import logging logger = logging.getLogger(__name__) @@ -73,6 +73,7 @@ 'chatMessages': [], 'canObserveOtherGroup': False, 'isInstructionsRound': False, + 'totalHarvest': 0, } # FIXME: need to distinguish between instructions / welcome rounds and practice/regular rounds def get_view_model_json(experiment, participant_group_relationship, **kwargs): @@ -101,6 +102,9 @@ if current_round.is_regular_round: experiment_model_dict['chatEnabled'] = current_round.chat_enabled + if current_round.is_debriefing_round: + experiment_model_dict['totalHarvest'] = get_total_harvest(participant_group_relationship, current_round.session_id) + # participant data experiment_model_dict['participantNumber'] = participant_group_relationship.participant_number experiment_model_dict['participantGroupId'] = participant_group_relationship.pk diff -r bbc7674fbbca76bda3740eaf376df51758f529e1 -r 15c4d2d5527a53f314bde5fd2139e0c619e99cbd vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -875,7 +875,9 @@ sender = intern(self.experiment_metadata.namespace.encode('utf8')) if sender is None else sender #sender = self.namespace.encode('utf-8') logger.debug("about to send round ended signal with sender %s", sender) - return signals.round_ended.send_robust(sender, experiment=self, round_configuration=self.current_round) + signal_tuple = signals.round_ended.send_robust(sender, experiment=self, round_configuration=self.current_round) + logger.debug("signal tuple: %s", signal_tuple) + return signal_tuple def activate(self): if self.is_archived: @@ -1637,6 +1639,10 @@ objects = PassThroughManager.for_queryset_class(GroupClusterQuerySet)() + @property + def size(self): + return self.group_relationship_set.count() + def add(self, group): return GroupRelationship.objects.create(cluster=self, group=group) @@ -1672,9 +1678,9 @@ 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) + gcdv, created = GroupClusterDataValue.objects.get_or_create(group_cluster=self, round_data=next_round_data, parameter=parameter) + gcdv.value = data_value.value logger.debug("transferred group cluster data value: %s (%s)", gcdv, created) - gcdv.value = data_value.value gcdv.save() def __unicode__(self): diff -r bbc7674fbbca76bda3740eaf376df51758f529e1 -r 15c4d2d5527a53f314bde5fd2139e0c619e99cbd vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -345,11 +345,12 @@ case 'update': console.debug("FIXME: ignoring update requests, patch sockjs broadcast to not send certain messages"); break; - case 'participant_ready': - experimentModel.checkAllParticipantsReady(); case 'chat': experimentModel.chatMessages.unshift(experiment_event); break; + case 'participant_ready': + experimentModel.checkAllParticipantsReady(); + // explicit fall through case 'info': default: experimentModel.addMessage(experiment_event.message); 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-29 04:24:17
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/bbc7674fbbca/ Changeset: bbc7674fbbca User: alllee Date: 2013-03-29 05:23:58 Summary: chat should not be enabled when participant is deceased Affected #: 3 files diff -r 43ca15dc1ece50789d9b201a55eea52b0e630f82 -r bbc7674fbbca76bda3740eaf376df51758f529e1 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -580,8 +580,9 @@ model.setFormDisabled("#chat-form", true); } model.setupChat = function() { - var chatDisabled = model.isPracticeRound() || ! model.chatEnabled(); + var chatDisabled = model.isPracticeRound() || ! model.chatEnabled() || ! model.alive(); model.setFormDisabled("#chat-form", chatDisabled); + model.chatEnabled(! chatDisabled); } model.afterRenderTemplate = function(elements) { if (model.templateId() === "REGULAR") { diff -r 43ca15dc1ece50789d9b201a55eea52b0e630f82 -r bbc7674fbbca76bda3740eaf376df51758f529e1 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -478,7 +478,7 @@ @property def all_chat_messages(self): - return ChatMessage.objects.filter(round_data__experiment=self) + return ChatMessage.objects.filter(round_data__experiment=self).reverse() @property def all_quiz_questions(self): @@ -2074,6 +2074,9 @@ ) return data + def to_json(self, **kwargs): + return dumps(self.to_dict()) + def __unicode__(self): """ return this participant's sequence number combined with the message """ participant_number = self.participant_group_relationship.participant_number diff -r 43ca15dc1ece50789d9b201a55eea52b0e630f82 -r bbc7674fbbca76bda3740eaf376df51758f529e1 vcweb/vcweb-sockjs.py --- a/vcweb/vcweb-sockjs.py +++ b/vcweb/vcweb-sockjs.py @@ -328,7 +328,7 @@ string_value=event.message, round_data=current_round_data ) - connection_manager.send_to_group(pgr.group, json.dumps(chat_message.to_dict())) + connection_manager.send_to_group(pgr.group, chat_message.to_json()) def on_message(self, json_string): logger.debug("message: %s", json_string) 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-29 04:07:42
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/43ca15dc1ece/ Changeset: 43ca15dc1ece User: alllee Date: 2013-03-29 05:07:27 Summary: silly typo Affected #: 1 file diff -r 93747c6f39fa256aa6f25fc2b50683f9924ecea1 -r 43ca15dc1ece50789d9b201a55eea52b0e630f82 vcweb/vcweb-sockjs.py --- a/vcweb/vcweb-sockjs.py +++ b/vcweb/vcweb-sockjs.py @@ -328,7 +328,7 @@ string_value=event.message, round_data=current_round_data ) - connection_manager.send_to_group(pgr.group, dumps(chat_message.to_dict())) + connection_manager.send_to_group(pgr.group, json.dumps(chat_message.to_dict())) def on_message(self, json_string): logger.debug("message: %s", json_string) 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-29 04:03:45
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/93747c6f39fa/ Changeset: 93747c6f39fa User: alllee Date: 2013-03-29 05:03:27 Summary: refactoring chat messages serialization and fixing more bugs in group creation when session ids are in play Affected #: 7 files diff -r 6921335ac35ad5da022ad65dc8c8ef8472127d3a -r 93747c6f39fa256aa6f25fc2b50683f9924ecea1 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -143,10 +143,19 @@ dv = get_storage_dv(participant_group_relationship, round_data, default) return default if dv.int_value is None else dv.int_value + +def _zero_if_none(value): + return 0 if value is None else value + +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 _zero_if_none(q['total_harvest']) + + # returns the sum of all stored resources for each member in the group def get_total_storage(group, round_data): q = ParticipantRoundDataValue.objects.for_group(group=group, parameter=get_storage_parameter(), round_data=round_data).aggregate(total_storage=Sum('int_value')) - return q['total_storage'] + return _zero_if_none(q['total_storage']) def set_storage(participant_group_relationship, round_data, value): storage_dv = get_storage_dv(participant_group_relationship, round_data) @@ -210,10 +219,6 @@ 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')) - 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 diff -r 6921335ac35ad5da022ad65dc8c8ef8472127d3a -r 93747c6f39fa256aa6f25fc2b50683f9924ecea1 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -405,7 +405,6 @@ <div class='alert alert-error'><b><i class='icon-ambulance'></i></b> You didn't harvest enough trees to meet the cost of living and are now <b>deceased</b>. You will not be able to chat or submit harvest decisions until this session is over. - Please wait quietly. </div></div><div data-bind='ifnot: isResourceEmpty'> diff -r 6921335ac35ad5da022ad65dc8c8ef8472127d3a -r 93747c6f39fa256aa6f25fc2b50683f9924ecea1 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -131,12 +131,8 @@ experiment_model_dict['harvestDecision'] = harvest_decision.int_value logger.debug("already submitted, setting harvest decision to %s", experiment_model_dict['harvestDecision']) - 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)] + experiment_model_dict['chatMessages'] = [cm.to_dict() for cm in ChatMessage.objects.for_group(own_group)] + logger.debug("chat messages: %s", experiment_model_dict['chatMessages']) if can_observe_other_group(current_round): experiment_model_dict['canObserveOtherGroup'] = True other_group = own_group.get_related_group() diff -r 6921335ac35ad5da022ad65dc8c8ef8472127d3a -r 93747c6f39fa256aa6f25fc2b50683f9924ecea1 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -719,7 +719,7 @@ parameter_set = self.experiment_metadata.parameter_set return parameter_set.filter(scope=scope) if scope else parameter_set - def add_participant(self, participant, current_group=None, max_group_size=None): + def add_participant(self, participant, current_group=None, max_group_size=None, session_id=None): # FIXME: simplify logic where possible if participant not in self.participant_set.all(): logger.warning("participant %s not a member of this experiment %s, adding them", participant, self) @@ -727,12 +727,15 @@ created_by=participant.user) pgrs = ParticipantGroupRelationship.objects.filter(group__experiment=self, participant=participant) if current_group is None: - if self.group_set.count() == 0: + # try to add them to the last group in group_set with the same session id + session_id_groups = self.group_set.filter(session_id=session_id) + if session_id_groups: + current_group = session_id_groups.reverse()[0] + number_of_groups = self.group_set.count() + if current_group is None or number_of_groups == 0: # create a new group - current_group = self.group_set.create(number=0, max_size=max_group_size) - else: - # pick the last group in group_set - current_group = self.group_set.reverse()[0] + current_group = self.group_set.create(number=number_of_groups, max_size=max_group_size, session_id=session_id) + if pgrs.count() > 0: # ensure that any existing group that this participant is in has a different session id from this group for pgr in pgrs: @@ -742,7 +745,7 @@ return current_group.add_participant(participant) def allocate_groups(self, randomize=True, preserve_existing_groups=False, session_id=None): - logger.debug("allocating groups for %s (randomize? %s)" % (self, randomize)) + logger.debug("allocating groups for %s with session_id %s (randomize? %s)" % (self, session_id, randomize)) # clear out all existing groups # FIXME: record previous mappings in activity log. max_group_size = self.experiment_configuration.max_group_size @@ -770,7 +773,7 @@ # add each participant to the next available group current_group = None for p in participants: - pgr = self.add_participant(p, current_group, max_group_size) + pgr = self.add_participant(p, current_group, max_group_size, session_id) current_group = pgr.group self.create_group_clusters() @@ -2059,10 +2062,16 @@ def to_dict(self, **kwargs): data = super(ChatMessage, self).to_dict(cacheable=True) - data['message'] = self.message + pgr = self.participant_group_relationship group = self.participant_group_relationship.group - data['group_id'] = group.pk - data['group'] = unicode(group) + data.update( + message=self.message, + group_id=group.pk, + group=unicode(group), + participant_handle=pgr.participant_handle, + participant_number=pgr.participant_number, + event_type='chat', + ) return data def __unicode__(self): diff -r 6921335ac35ad5da022ad65dc8c8ef8472127d3a -r 93747c6f39fa256aa6f25fc2b50683f9924ecea1 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -132,6 +132,21 @@ </div></div><h3>Experiment Data</h3> +<div class='accordion' id='experiment-chat-accordion'> + <div class='accordion-group'> + <div class='accordion-heading'> + <a class='accordion-toggle' data-toggle='collapse' data-parent='#experiment-chat-accordion' href='#experiment-chat-messages'>All Chat Messages</a> + </div> + <div id='experiment-chat-messages' class='scrollable-messages accordion-body collapse'> + <div class='alert' data-bind='foreach: chatMessages'> + <div> + <span data-bind='text: participant_handle'></span>(<span data-bind='text: group'></span>): <strong data-bind='text: message'></strong> + <span class='pull-right' data-bind='text: short_date_created'></span> + </div> + </div> + </div> + </div> +</div><div class='accordion' id='round-data-accordion' data-bind='foreach: allRoundData'><div class='accordion-group'> @@ -179,20 +194,6 @@ </div></div></div> -<div class='accordion' id='experiment-chat-accordion'> - <div class='accordion-group'> - <div class='accordion-heading'> - <a class='accordion-toggle' data-toggle='collapse' data-parent='#experiment-chat-accordion' href='#experiment-chat-messages'>All Chat Messages</a> - </div> - <div id='experiment-chat-messages' class='scrollable-messages accordion-body collapse'> - <div class='alert' data-bind='foreach: chatMessages'> - <div> - (<span data-bind='text: group'></span>) <span data-bind='text: message'></span> - </div> - </div> - </div> - </div> -</div><div id='progress-modal' class='modal hide fade'><div class='model-header'><h3>Updating experiment data</h3> @@ -347,6 +348,8 @@ case 'participant_ready': experimentModel.checkAllParticipantsReady(); case 'chat': + experimentModel.chatMessages.unshift(experiment_event); + break; case 'info': default: experimentModel.addMessage(experiment_event.message); diff -r 6921335ac35ad5da022ad65dc8c8ef8472127d3a -r 93747c6f39fa256aa6f25fc2b50683f9924ecea1 vcweb/static/css/boundaries/style.css --- a/vcweb/static/css/boundaries/style.css +++ b/vcweb/static/css/boundaries/style.css @@ -23,6 +23,8 @@ border-bottom: 1px solid #ccc; } .boundaries-status-dashboard { - height: 80px; + height: 100px; + min-width: 80px; + margin-right: 0px; padding: 8px 8px 8px 8px; } diff -r 6921335ac35ad5da022ad65dc8c8ef8472127d3a -r 93747c6f39fa256aa6f25fc2b50683f9924ecea1 vcweb/vcweb-sockjs.py --- a/vcweb/vcweb-sockjs.py +++ b/vcweb/vcweb-sockjs.py @@ -227,10 +227,10 @@ self.send_to_experimenter(message, experiment=experiment) return participant_connections - def send_to_group(self, group, json): + def send_to_group(self, group, event): for participant_group_id, connection in self.connections(group): - connection.send(json) - self.send_to_experimenter(json, experiment=group.experiment) + connection.send(event) + self.send_to_experimenter(event, experiment=group.experiment) connection_manager = ConnectionManager() @@ -328,15 +328,7 @@ string_value=event.message, round_data=current_round_data ) - chat_message = json.dumps({ - "pk": chat_message.pk, - 'round_data_pk': current_round_data.pk, - 'participant_number': pgr.participant_number, - "date_created": chat_message.date_created.strftime("%I:%M:%S"), - "message" : event.message, - "event_type": 'chat', - }) - connection_manager.send_to_group(pgr.group, chat_message) + connection_manager.send_to_group(pgr.group, dumps(chat_message.to_dict())) def on_message(self, json_string): logger.debug("message: %s", json_string) 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-29 03:15:51
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/6921335ac35a/ Changeset: 6921335ac35a User: alllee Date: 2013-03-29 04:15:37 Summary: fixing a bug in update_participants where storage and player status wasn't being copied appropriately after the player "died". adding treatment D instructions Affected #: 3 files diff -r d6b8248c0ea92566a4d7d22b2d9bc96141b63a34 -r 6921335ac35ad5da022ad65dc8c8ef8472127d3a vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -140,7 +140,8 @@ def get_storage(participant_group_relationship, round_data=None, default=0): - return get_storage_dv(participant_group_relationship, round_data, default).int_value + dv = get_storage_dv(participant_group_relationship, round_data, default) + return default if dv.int_value is None else dv.int_value # returns the sum of all stored resources for each member in the group def get_total_storage(group, round_data): @@ -301,20 +302,18 @@ 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: - logger.debug("Skipping deceased participant %s", pgr) - 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 - if updated_storage < 0: - # player has "died" - player_status_dv.boolean_value = False - player_status_dv.save() - 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) + if player_alive: + 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 + if updated_storage < 0: + # player has "died" + player_status_dv.boolean_value = False + player_status_dv.save() + 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) diff -r d6b8248c0ea92566a4d7d22b2d9bc96141b63a34 -r 6921335ac35ad5da022ad65dc8c8ef8472127d3a vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -94,7 +94,7 @@ <a href='javascript: void()' data-bind='click: activateTemplate.bind($data, "PRACTICE_ROUND_RESULTS")'>Back</a></li><li class='next'> - <a href='javascript: void()' data-bind='click: participantReady'>Ok, I understand</a> + <a href='javascript: void()' data-bind='click: participantReady.bind($data, participantHandle() + " finished paid experiment instructions") '>Ok, I understand</a></li></ul></script> @@ -114,7 +114,24 @@ </ul><ul class='pager'><li class='next'> - <a href='javascript: void()' data-bind='click: participantReady'>Ok, I am ready to start</a> + <a href='javascript: void()' data-bind='click: participantReady.bind($data, participantHandle() + " finished treatment A instructions")'>Ok, I am ready to start</a> + </li> +</ul> +</script> +<script type='text/html' id='TREATMENT_D_INSTRUCTIONS'> +<h3>Session <span data-bind='text: sessionId'></span> Instructions</h3> +<p> +In this session, there are two groups or villages. Both groups are sharing a forest to harvest. The shared forest has +twice the capacity of a single-group forest. +</p> +<h3>Key points</h3> +<ul> + <li>Two groups</li> + <li>Groups share a forest</li> +</ul> +<ul class='pager'> + <li class='next'> + <a href='javascript: void()' data-bind='click: participantReady.bind($data, participantHandle() + " finished treatment D instructions")'>Ok, I am ready to start</a></li></ul></script> @@ -265,7 +282,7 @@ <a href='javascript:void();' data-bind='click: activateTemplate.bind($data, "GENERAL_INSTRUCTIONS3")'>Back</a></li><li class='next'> -<a href='javascript: void();' data-bind='click: participantReady'>I have fully read and understand these instructions</a> +<a href='javascript: void();' data-bind='click: participantReady.bind($data, participantHandle() + " finished practice round instructions")'>I have fully read and understand these instructions</a></li></ul></script> @@ -319,6 +336,12 @@ <td data-bind='text: storage'></td><!-- /ko --></tr> + <tr> + <td>Alive</td> + <!-- ko foreach: playerData --> + <td data-bind='text: alive'></td> + <!-- /ko --> + </tr></tbody></table></div> @@ -378,6 +401,13 @@ </div></div><h3>Harvest</h3> +<div data-bind='ifnot: alive'> + <div class='alert alert-error'> + <b><i class='icon-ambulance'></i></b> You didn't harvest enough trees to meet the cost of living and are now + <b>deceased</b>. You will not be able to chat or submit harvest decisions until this session is over. + Please wait quietly. + </div> +</div><div data-bind='ifnot: isResourceEmpty'><form id='vcweb-form' action='' method='post' class='form-horizontal' > {% csrf_token %} @@ -440,12 +470,12 @@ model.readyParticipantsPercentage = ko.computed(function() { return (model.readyParticipants() / model.participantCount()) * 100; }); - model.participantReady = function() { + model.participantReady = function(message) { $.post('/experiment/participant-ready', { participant_group_id: model.participantGroupId() }, function(response) { console.debug("successfully posted to server, notifying sockjs"); console.debug(response); model.readyParticipants(response.number_of_ready_participants); - getWebSocket().send(createReadyEvent("Participant finished reading instructions")); + getWebSocket().send(createReadyEvent(message)); model.activateTemplate("WAITING_ROOM"); }); } diff -r d6b8248c0ea92566a4d7d22b2d9bc96141b63a34 -r 6921335ac35ad5da022ad65dc8c8ef8472127d3a vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -90,23 +90,24 @@ cost_of_living = get_cost_of_living(current_round) experiment_model_dict['costOfLiving'] = cost_of_living experiment_model_dict['maxHarvestDecision'] = get_max_allowed_harvest_decision(participant_group_relationship, current_round_data, ec) + experiment_model_dict['templateName'] = current_round.template_name + experiment_model_dict['isPracticeRound'] = current_round.is_practice_round # instructions round parameters if current_round.is_instructions_round: experiment_model_dict['isInstructionsRound'] = True experiment_model_dict['participantsPerGroup'] = ec.max_group_size experiment_model_dict['regrowthRate'] = regrowth_rate experiment_model_dict['initialResourceLevel'] = get_initial_resource_level(current_round) - - experiment_model_dict['participantNumber'] = participant_group_relationship.participant_number - experiment_model_dict['participantGroupId'] = participant_group_relationship.pk - experiment_model_dict['templateName'] = current_round.template_name - experiment_model_dict['isPracticeRound'] = current_round.is_practice_round - if current_round.is_regular_round: experiment_model_dict['chatEnabled'] = current_round.chat_enabled - # FIXME: these need to be added so KO doesn't get unhappy when we switch templates from instructions rounds to - # practice rounds. +# participant data + experiment_model_dict['participantNumber'] = participant_group_relationship.participant_number + experiment_model_dict['participantGroupId'] = participant_group_relationship.pk + experiment_model_dict['participantHandle'] = participant_group_relationship.participant_handle + + # FIXME: these should only need to be added for playable rounds but KO gets 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) 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-28 21:05:47
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/d6b8248c0ea9/ Changeset: d6b8248c0ea9 User: alllee Date: 2013-03-28 22:05:32 Summary: tweaking bootstrap tour tip placement and fixing session_id bug in group cluster creation Affected #: 2 files diff -r 844d5e11ef17ef438928280e9eba95f834aea65d -r d6b8248c0ea92566a4d7d22b2d9bc96141b63a34 vcweb/broker/templates/broker/participate.html --- a/vcweb/broker/templates/broker/participate.html +++ b/vcweb/broker/templates/broker/participate.html @@ -498,13 +498,13 @@ element: "#harvestDecisionId", title: "Here's where you insert your harvesting decision", content: "For this practice round, go ahead and put 6 hours into harvesting. Each round you will have a maximum of 6 minute to make a harvest decision.", /* content of the popover */ - placement: "right" + placement: "top" }); tourFirst.addStep({ element: "#conservationDecision", title: "Your conservation decision", content: "Note that the rest of your available hours will be put into conservation.", - placement: "right" + placement: "bottom" }); tourFirst.addStep({ element: "#submitDecision", diff -r 844d5e11ef17ef438928280e9eba95f834aea65d -r d6b8248c0ea92566a4d7d22b2d9bc96141b63a34 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -779,11 +779,14 @@ session_id = round_configuration.session_id logger.debug("creating group clusters with session id %s", session_id) if round_configuration.create_group_clusters: - # NOTE: misconfiguration can cause data loss - # delete any group clusters with the same session id - self.group_cluster_set.filter(session_id=session_id).delete() + gcs = self.group_cluster_set.filter() + gs = self.group_set.filter() + if session_id: + gcs = gcs.filter(session_id=session_id) + gs = gs.filter(session_id=session_id) + gcs.delete() group_cluster_size = round_configuration.group_cluster_size - groups = list(self.group_set.filter(session_id=session_id)) + groups = list(gs) if len(groups) % group_cluster_size != 0: logger.error("trying to create clusters of size %s but we have %s groups which isn't evenly divisible - aborting.", group_cluster_size, len(groups)) @@ -793,6 +796,7 @@ for group in groups: if gc.group_relationship_set.count() == group_cluster_size: gc = GroupCluster.objects.create(session_id=session_id, experiment=self) +# adding group clusters gc.add(group) def get_round_configuration(self, sequence_number): @@ -877,7 +881,7 @@ self.allocate_groups() self.status = Experiment.Status.ACTIVE self.date_activated = datetime.now() - self.save() + self.start_round() return self def restart(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-28 18:40:14
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/844d5e11ef17/ Changeset: 844d5e11ef17 User: alllee Date: 2013-03-28 19:40:00 Summary: removing simplejson references from socketio realtime server Affected #: 1 file diff -r d5bc32627f515cc3a3e3beef09ee267d06a1f168 -r 844d5e11ef17ef438928280e9eba95f834aea65d vcweb/vcwebio.py --- a/vcweb/vcwebio.py +++ b/vcweb/vcwebio.py @@ -6,7 +6,7 @@ import os import sys import logging -import simplejson +import json sys.path.append(os.path.abspath('.')) os.environ['DJANGO_SETTINGS_MODULE'] = 'vcweb.settings' @@ -18,7 +18,7 @@ logger = logging.getLogger('tornadio.vcweb') def info_json(message): - return simplejson.dumps({'message_type': 'info', 'message': message}) + return json.dumps({'message_type': 'info', 'message': message}) class ConnectionManager: ''' @@ -36,7 +36,7 @@ FIXME: consider refactoring core so that an "all" group always exists in an experiment. ''' - refresh_json = simplejson.dumps({ 'message_type': 'refresh' }) + refresh_json = json.dumps({ 'message_type': 'refresh' }) def __str__(self): return u"Participants: %s------Experimenters: %s" % (self.participant_to_connection, self.experimenter_to_connection) @@ -129,30 +129,30 @@ def send_goto(self, connection, experiment, url): notified_participants = [] - json = simplejson.dumps({'message_type': 'goto', 'url': url}) + goto_json = json.dumps({'message_type': 'goto', 'url': url}) for (participant_group_pk, connection) in self.all_participants(connection, experiment): - connection.send(json) + connection.send(goto_json) notified_participants.append(participant_group_pk) return notified_participants - def send_to_experimenter(self, experimenter_tuple, json): + def send_to_experimenter(self, experimenter_tuple, message): (experimenter_pk, experiment_pk) = experimenter_tuple - logger.debug("sending %s to experimenter %s", json, experimenter_tuple) + logger.debug("sending %s to experimenter %s", message, experimenter_tuple) if experimenter_tuple in self.experimenter_to_connection: connection = self.experimenter_to_connection[experimenter_tuple] logger.debug("sending to connection %s", connection) - connection.send(json) + connection.send(message) else: logger.debug("no experimenter found with pk %s", experimenter_pk) logger.debug("all experimenters: %s", self.experimenter_to_connection) - def send_to_group(self, group, json): + def send_to_group(self, group, message): for participant_group_pk, connection in self.connections(group): - connection.send(json) + connection.send(message) experiment = group.experiment experimenter = experiment.experimenter - self.send_to_experimenter((experimenter.pk, experiment.pk), json) + self.send_to_experimenter((experimenter.pk, experiment.pk), message) # replace with namedtuple class Struct: @@ -212,7 +212,7 @@ experiment = participant_experiment_relationship.experiment experimenter_tuple = (experiment.experimenter.pk, experiment.pk) connection_manager.send_to_experimenter(experimenter_tuple, - simplejson.dumps({ + json.dumps({ 'message': "Participant %s connected." % participant_experiment_relationship.participant, 'message_type': 'info', })) @@ -240,9 +240,9 @@ event.participant_data_value_pk = prdv.pk event.participant_number = participant_group_relationship.participant_number event.participant_group = participant_group_relationship.group_number - json = simplejson.dumps(event.__dict__) - logger.debug("submit event json: %s", json) - connection_manager.send_to_experimenter(experimenter_tuple, json) + message = json.dumps(event.__dict__) + logger.debug("submit event json: %s", message) + connection_manager.send_to_experimenter(experimenter_tuple, message) if experiment.all_participants_have_submitted(): connection_manager.send_to_experimenter( experimenter_tuple, @@ -258,7 +258,7 @@ value=xhtml_escape(event.message), round_data=current_round_data ) - chat_json = simplejson.dumps({ + chat_json = json.dumps({ "pk": chat_message.pk, 'round_data_pk': current_round_data.pk, 'participant': unicode(participant_group_relationship.participant), 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-28 18:38:22
|
3 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/d3454c113f1f/ Changeset: d3454c113f1f User: alllee Date: 2013-03-28 19:30:58 Summary: totalNumberOfParticipants was already being included as participantCount setting up check-ready-participants in broker experiment Affected #: 3 files diff -r 202fb207161fbef187c02eaa60e175f99ee0a26c -r d3454c113f1fcd2717d7991369cee891eb14ac7a vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -124,7 +124,7 @@ Please wait. The experiment will continue shortly once all the participants are ready. <p><span class='badge' -data-bind='css: { "badge-important": readyParticipants() < (totalNumberOfParticipants() / 2), "badge-success": readyParticipants() > (totalNumberOfParticipants() / 2)}, text: readyParticipants'></span> of <span class='badge badge-success' data-bind='text: totalNumberOfParticipants'></span> participants are ready. +data-bind='css: { "badge-important": readyParticipants() < (participantCount() / 2), "badge-success": readyParticipants() > (participantCount() / 2)}, text: readyParticipants'></span> of <span class='badge badge-success' data-bind='text: participantCount'></span> participants are ready. </p></div></div> @@ -438,7 +438,7 @@ model.templateName(name); } model.readyParticipantsPercentage = ko.computed(function() { - return (model.readyParticipants() / model.totalNumberOfParticipants()) * 100; + return (model.readyParticipants() / model.participantCount()) * 100; }); model.participantReady = function() { $.post('/experiment/participant-ready', { participant_group_id: model.participantGroupId() }, function(response) { diff -r 202fb207161fbef187c02eaa60e175f99ee0a26c -r d3454c113f1fcd2717d7991369cee891eb14ac7a vcweb/broker/templates/broker/participate.html --- a/vcweb/broker/templates/broker/participate.html +++ b/vcweb/broker/templates/broker/participate.html @@ -22,8 +22,8 @@ <div> Please wait. The experiment will continue shortly once all the participants are ready. <p> - <span class='badge' data-bind='css: { "badge-important": readyParticipants() < (totalNumberOfParticipants() / 2), "badge-success": readyParticipants() > (totalNumberOfParticipants() / 2)}, text: readyParticipants'></span> - of <span class='badge badge-success' data-bind='text: totalNumberOfParticipants'></span> participants + <span class='badge' data-bind='css: { "badge-important": readyParticipants() < (participantCount() / 2), "badge-success": readyParticipants() > (participantCount() / 2)}, text: readyParticipants'></span> + of <span class='badge badge-success' data-bind='text: participantCount'></span> participants are ready. </p></div> @@ -185,8 +185,7 @@ <a href='javascript:void();' data-bind='click: activateInstructionsPageTwo'>Back</a></li><li class='next'> - <a href='javascript: void();' data-bind='click: participantReady'>I have fully read and understand - these instructions</a> + <a href='javascript: void();' data-bind='click: participantReady.bind($data, "Finished instructions")'>I have fully read and understand these instructions</a></li></ul></script> @@ -441,7 +440,7 @@ var self = this; var model = ko.mapping.fromJS(experimentModelJson); model.readyParticipantsPercentage = ko.computed(function () { - return (model.readyParticipants() / model.totalNumberOfParticipants()) * 100; + return (model.readyParticipants() / model.participantCount()) * 100; }); model.activateWaitingRoomPage = function () { console.debug("activating waiting room page"); @@ -466,8 +465,9 @@ console.debug("form data: "); console.debug(formData); $.post('submit-chat-preferences', formData, function(response) { - console.debug("received response"); + console.debug("chat preferences response"); console.debug(response); + $('#chatPreferencesForm').hide(); }); }; model.isTimeOut = ko.observable(0) @@ -611,14 +611,14 @@ model.networkStructure = ko.observable("{{STATIC_URL}}images/broker/SES.jpg"); model.networkStructureImageWidth = ko.observable("600px"); model.networkStructureImageHeight = ko.observable("80px"); - model.checkReadyParticipants = function () { + model.checkReadyParticipants = function() { $.get('/experiment/check-ready-participants', { participant_group_id: model.participantGroupId() }, function (response) { model.readyParticipants(response.number_of_ready_participants); }); } - model.participantReady = function () { + model.participantReady = function(message) { $.post('/experiment/participant-ready', { participant_group_id: model.participantGroupId() }, function (response) { - getWebSocket().send(createReadyEvent("Participant finished reading instructions")); + getWebSocket().send(createReadyEvent(message)); model.readyParticipants(response.number_of_ready_participants); model.activateWaitingRoomPage(); }); @@ -704,20 +704,17 @@ switch (data.event_type) { case 'chat': experimentModel.withinGroupChatMessages.unshift(data); - break; + break; case 'update': console.debug("updating view model"); experimentModel.update(); break; case 'participant_ready': - experimentModel.readyParticipants(Math.min(experimentModel.totalNumberOfParticipants(), experimentModel.readyParticipants() + 1)); - // FIXME: replace with this later - // experimentModel.checkReadyParticipants(); - break; - + experimentModel.checkReadyParticipants(); + break; default: console.debug("unhandled json message:" + json); - break; + break; } }; } diff -r 202fb207161fbef187c02eaa60e175f99ee0a26c -r d3454c113f1fcd2717d7991369cee891eb14ac7a vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -936,7 +936,6 @@ 'isArchived': self.is_archived, 'exchangeRate': float(ec.exchange_rate), 'readyParticipants': self.number_of_ready_participants, - 'totalNumberOfParticipants': self.participant_set.count(), } if include_round_data: experiment_dict['allRoundData'] = self.all_round_data() https://bitbucket.org/virtualcommons/vcweb/commits/e98fc6cf53aa/ Changeset: e98fc6cf53aa User: alllee Date: 2013-03-28 19:37:50 Summary: removing simplejson dependency Affected #: 2 files diff -r d3454c113f1fcd2717d7991369cee891eb14ac7a -r e98fc6cf53aa072f224f0eb8c719e713915e37d2 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -940,7 +940,7 @@ if include_round_data: experiment_dict['allRoundData'] = self.all_round_data() experiment_dict['chatMessages'] = [chat_message.to_dict() for chat_message in self.all_chat_messages] - experiment_dict['messages'] = [unicode(log) for log in self.activity_log_set.order_by('-date_created')] + experiment_dict['messages'] = [str(log) for log in self.activity_log_set.order_by('-date_created')] experiment_dict['experimenterNotes'] = self.current_round_data.experimenter_notes if self.is_round_in_progress else '' if default_value_dict: experiment_dict.update(default_value_dict, **kwargs) diff -r d3454c113f1fcd2717d7991369cee891eb14ac7a -r e98fc6cf53aa072f224f0eb8c719e713915e37d2 vcweb/core/services.py --- a/vcweb/core/services.py +++ b/vcweb/core/services.py @@ -2,8 +2,8 @@ from vcweb.core.models import ExperimentMetadata from vcweb.core.urls import foursquare_venue_search_url, foursquare_categories_url import logging -import simplejson as json import urllib2 +import json logger = logging.getLogger(__name__) class ExperimentService(object): https://bitbucket.org/virtualcommons/vcweb/commits/d5bc32627f51/ Changeset: d5bc32627f51 User: alllee Date: 2013-03-28 19:38:06 Summary: removing simplejson from pip requirements Affected #: 1 file diff -r e98fc6cf53aa072f224f0eb8c719e713915e37d2 -r d5bc32627f515cc3a3e3beef09ee267d06a1f168 vcweb/requirements.pip --- a/vcweb/requirements.pip +++ b/vcweb/requirements.pip @@ -7,7 +7,6 @@ django-social-auth django-mptt psycopg2 -simplejson tornado sockjs-tornado tornado-redis 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-28 18:11:13
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/88fd2ec2e64a/ Changeset: 88fd2ec2e64a Branch: stable User: alllee Date: 2013-03-28 19:10:55 Summary: merging default into stable Affected #: 108 files diff -r 8db0c6f3177a6963b6fa68d138c32ef0919d2498 -r 88fd2ec2e64a6d9ee5769965c3de08b60c89cd17 deploy/supervisord.conf --- /dev/null +++ b/deploy/supervisord.conf @@ -0,0 +1,5 @@ +[program:vcweb-sockjs] +directory=/opt/vcweb/ +command=/opt/virtualenvs/vcweb/bin/python /opt/vcweb/vcweb/vcweb-sockjs.py 8882 +autostart=true +redirect_stderr=true diff -r 8db0c6f3177a6963b6fa68d138c32ef0919d2498 -r 88fd2ec2e64a6d9ee5769965c3de08b60c89cd17 deploy/vcweb.apache.vhost --- /dev/null +++ b/deploy/vcweb.apache.vhost @@ -0,0 +1,28 @@ +WSGISocketPrefix run/wsgi +WSGIPythonHome /opt/virtualenvs/vcweb +<VirtualHost *:80> + ServerAdmin all...@as... + DocumentRoot /var/www/vcweb + ServerName vcweb.asu.edu + + Alias /static /var/www/vcweb/static + <FilesMatch "\.(html|js|png|jpg|gif|css)"> + ExpiresDefault "access plus 1 days" + ExpiresActive On + </FilesMatch> + + Alias /favicon.ico /var/www/vcweb/static/favicon.ico + Alias /robots.txt /var/www/vcweb/static/robots.txt + + WSGIDaemonProcess vcweb-production user=apache group=commons threads=25 python-path=/opt/virtualenvs/vcweb/lib/python2.6/site-packages + WSGIProcessGroup vcweb-production + WSGIScriptAlias / /opt/webapps/virtualcommons/vcweb/vcweb.wsgi + <Directory /opt/webapps/virtualcommons/vcweb/vcweb/> + Order deny,allow + Allow from all + </Directory> + ErrorLog /var/log/apache2/vcweb/error.log + LogLevel warn + CustomLog /var/log/apache2/vcweb/access.log combined +</VirtualHost> + diff -r 8db0c6f3177a6963b6fa68d138c32ef0919d2498 -r 88fd2ec2e64a6d9ee5769965c3de08b60c89cd17 fabfile.py --- a/fabfile.py +++ b/fabfile.py @@ -8,7 +8,7 @@ logger = logging.getLogger(__name__) # needed to push vcweb.settings onto the path. -sys.path.append(os.path.abspath('.')) +sys.path.append(os.path.abspath(os.path.dirname(__file__))) # default env configuration env.python = 'python' @@ -39,6 +39,9 @@ '%(python)s manage.py migrate' % env, ] +def migrate(): + local("{python} manage.py migrate".format(python=env.python), capture=False) + def psh(): local("{python} manage.py shell_plus".format(python=env.python), capture=False) @@ -88,9 +91,7 @@ def pip(): ''' looks for requirements.pip in the django project directory ''' - _virtualenv(local, 'pip install -r %(project_path)s/vcweb/requirements.pip' % env) - # install bootstrap forms from github - _virtualenv(local, 'pip install -e git+git://github.com/earle/django-bootstrap.git#egg=bootstrap') + _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) @@ -127,7 +128,7 @@ def dev(): env.project_path = env.deploy_path + env.project_name - env.hosts =['dev.commons.asu.edu'] + env.hosts =['sod51.asu.edu'] def prod(): env.project_path = env.deploy_path + env.project_name @@ -138,8 +139,7 @@ env.apache = 'apache2' env.hosts = ['localhost'] -def staticg(): - local('%(python)s manage.py generate_static_dajaxice > static/js/dajaxice.core.js' % env) +def collectstatic(): local('%(python)s manage.py collectstatic' % env) def setup(): @@ -152,8 +152,12 @@ pip() def _restart_command(): - return 'service %(apache)s restart' % env + return 'service %(apache)s restart && supervisorctl restart vcweb-sockjs' % env +def clean(): + with cd(env.project_path): + sudo('find . -name "*.pyc" -delete -print') + def restart(): sudo(_restart_command(), pty=True) @@ -163,17 +167,18 @@ def deploy(): from vcweb import settings as vcweb_settings """ deploys to an already setup environment """ - env.project_path = env.deploy_path + env.project_name push() if confirm("Deploy to %(hosts)s ?" % env): with cd(env.project_path): sudo_chain('hg pull && hg up -C', - 'chmod -R g+w logs', + 'chmod g+s logs', + 'chmod -R g+rw logs/', user=env.deploy_user, pty=True) env.static_root = vcweb_settings.STATIC_ROOT _virtualenv(run,'%(python)s manage.py collectstatic' % env) sudo_chain('chmod -R ug+rw .', 'find %(static_root)s -type d -exec chmod a+x {} \;' % env, + 'find %(static_root)s -type f -exec chmod a+r {} \;' % env, 'find . -type d -exec chmod ug+x {} \;', 'chown -R %(deploy_user)s:%(deploy_group)s . %(static_root)s' % env, _restart_command(), diff -r 8db0c6f3177a6963b6fa68d138c32ef0919d2498 -r 88fd2ec2e64a6d9ee5769965c3de08b60c89cd17 vcweb/boundaries/forms.py --- a/vcweb/boundaries/forms.py +++ b/vcweb/boundaries/forms.py @@ -1,3 +1,4 @@ +from vcweb.core.forms import ParticipantGroupIdForm, SingleIntegerDecisionForm from vcweb.forestry import forms diff -r 8db0c6f3177a6963b6fa68d138c32ef0919d2498 -r 88fd2ec2e64a6d9ee5769965c3de08b60c89cd17 vcweb/boundaries/migrations/0001_initial.py --- a/vcweb/boundaries/migrations/0001_initial.py +++ b/vcweb/boundaries/migrations/0001_initial.py @@ -1,404 +1,21 @@ # -*- coding: utf-8 -*- import datetime from south.db import db -from south.v2 import DataMigration +from south.v2 import SchemaMigration from django.db import models -class Migration(DataMigration): + +class Migration(SchemaMigration): def forwards(self, orm): from django.core.management import call_command call_command("loaddata", "boundaries_experiment_metadata.json") - ExperimentMetadata = orm['core.ExperimentMetadata'] - em = ExperimentMetadata.objects.get(namespace='bound') - ExperimentConfiguration = orm['core.ExperimentConfiguration'] - Experimenter = orm['core.Experimenter'] - experimenter = Experimenter.objects.get(pk=1) - ec = ExperimentConfiguration.objects.create( - experiment_metadata=em, - is_public=True, - max_group_size=10, - name='Boundary Effects Default Configuration', - creator=experimenter, - ) - em.default_configuration = ec - em.save() - Experiment = orm['core.Experiment'] - e = Experiment.objects.create( - experiment_metadata=em, - authentication_code='DEFAULT_BOUNDARIES', - experimenter=experimenter, - experiment_configuration=ec, - is_experimenter_driven=True) - # XXX: set up parameters and configuration as well in this migration - Parameter = orm['core.Parameter'] - Parameter.objects.create( - name='player_status', - type='boolean', - experiment_metadata=em, - scope='participant', - display_name='Player status', - description='Player status (true = alive, false = dead)', - creator=experimenter, - ) - Parameter.objects.create( - name='survival_cost', - type='int', - experiment_metadata=em, - scope='round', - display_name='Survival cost', - description='The minimum number of resources each player needs to have in storage each round to survive', - creator=experimenter, - ) - Parameter.objects.create( - name='storage', - type='int', - experiment_metadata=em, - scope='participant', - display_name='Storage', - description='The number of resources this player has accumulated.', - creator=experimenter, - ) -# create round configurations - RoundConfiguration = orm['core.RoundConfiguration'] - RoundConfiguration.objects.create( - experiment_configuration=ec, - instructions='Welcome to the boundary effects experiment.', - round_type='INSTRUCTIONS', - sequence_number=1, - ) - RoundConfiguration.objects.create( - experiment_configuration=ec, - instructions='This is the first practice round.', - round_type='PRACTICE', - sequence_number=2, - display_number=1, - ) def backwards(self, orm): pass models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - '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': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - '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': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - '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': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - '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'}), - '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'}) - }, - 'core.activitylog': { - 'Meta': {'object_name': 'ActivityLog'}, - 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'log_message': ('django.db.models.fields.TextField', [], {}) - }, - 'core.address': { - 'Meta': {'object_name': 'Address'}, - 'city': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), - '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'}) - }, - 'core.chatmessage': { - 'Meta': {'ordering': "['date_created']", 'object_name': 'ChatMessage', '_ormbases': ['core.ParticipantRoundDataValue']}, - 'participantrounddatavalue_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "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': "orm['core.ParticipantGroupRelationship']"}) - }, - 'core.comment': { - 'Meta': {'ordering': "['date_created']", 'object_name': 'Comment', '_ormbases': ['core.ParticipantRoundDataValue']}, - 'participantrounddatavalue_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['core.ParticipantRoundDataValue']", 'unique': 'True', 'primary_key': 'True'}) - }, - '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_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': "orm['core.ExperimentConfiguration']"}), - 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.ExperimentMetadata']"}), - 'experimenter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Experimenter']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_experimenter_driven': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), - 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '32', 'unique': 'True', 'null': 'True', 'blank': 'True'}), - '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'}) - }, - 'core.experimentactivitylog': { - 'Meta': {'object_name': 'ExperimentActivityLog', '_ormbases': ['core.ActivityLog']}, - 'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), - 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': "orm['core.Experiment']"}), - 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.RoundConfiguration']"}) - }, - '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': "orm['core.Experimenter']"}), - 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': "orm['core.ExperimentMetadata']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': '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'}) - }, - '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'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'institution': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Institution']", 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'experimenter'", 'unique': 'True', 'to': "orm['auth.User']"}) - }, - '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'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}) - }, - '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': "orm['core.ExperimentConfiguration']", 'null': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - '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'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - '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': "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': "orm['core.ExperimentMetadata']"}), - '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'}) - }, - 'core.group': { - 'Meta': {'ordering': "['experiment', 'number']", 'object_name': 'Group'}, - 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Experiment']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'max_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), - 'number': ('django.db.models.fields.PositiveIntegerField', [], {}) - }, - 'core.groupactivitylog': { - 'Meta': {'object_name': 'GroupActivityLog', '_ormbases': ['core.ActivityLog']}, - 'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), - 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': "orm['core.Group']"}), - 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.RoundConfiguration']"}) - }, - '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'}), - 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), - 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'data_value_set'", 'to': "orm['core.Group']"}), - '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': "orm['core.Parameter']"}), - 'round_data': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_data_value_set'", 'to': "orm['core.RoundData']"}), - 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) - }, - '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'}), - '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'}) - }, - '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': "orm['core.ExperimentSession']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'participant': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Participant']"}), - 'sender': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) - }, - 'core.like': { - 'Meta': {'ordering': "['-date_created', 'round_data', 'participant_group_relationship', 'parameter']", 'object_name': 'Like', '_ormbases': ['core.ParticipantRoundDataValue']}, - 'participantrounddatavalue_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['core.ParticipantRoundDataValue']", 'unique': 'True', 'primary_key': 'True'}) - }, - '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': "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': "orm['core.ExperimentMetadata']", 'null': 'True', 'blank': 'True'}), - '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'}) - }, - 'core.participant': { - 'Meta': {'ordering': "['user']", 'object_name': 'Participant'}, - 'address': ('django.db.models.fields.related.ForeignKey', [], {'to': "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': "orm['core.ParticipantExperimentRelationship']", 'to': "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': "orm['core.ParticipantGroupRelationship']", 'to': "orm['core.Group']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'institution': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Institution']", 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'participant'", 'unique': 'True', 'to': "orm['auth.User']"}) - }, - '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': "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': "orm['core.Experiment']"}), - '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': "orm['core.Participant']"}), - 'participant_identifier': ('django.db.models.fields.CharField', [], {'max_length': '32'}), - 'sequential_participant_identifier': ('django.db.models.fields.PositiveIntegerField', [], {}) - }, - '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'}), - 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_group_relationship_set'", 'to': "orm['core.Group']"}), - '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': "orm['core.Participant']"}), - 'participant_number': ('django.db.models.fields.PositiveIntegerField', [], {}), - 'round_joined': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.RoundConfiguration']"}) - }, - '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'}), - 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), - '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': "orm['core.Parameter']"}), - 'participant_group_relationship': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_data_value_set'", 'to': "orm['core.ParticipantGroupRelationship']"}), - 'round_data': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_data_value_set'", 'to': "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': "orm['core.ParticipantRoundDataValue']"}) - }, - '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'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'invitation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'signup_set'", 'to': "orm['core.Invitation']"}), - 'participant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'signup_set'", 'to': "orm['core.Participant']"}) - }, - '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': "orm['core.Experiment']"}), - 'explanation': ('django.db.models.fields.CharField', [], {'max_length': '512'}), - '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': "orm['core.RoundConfiguration']"}) - }, - 'core.roundconfiguration': { - 'Meta': {'ordering': "['experiment_configuration', 'sequence_number', 'date_created']", 'object_name': 'RoundConfiguration'}, - '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': "orm['core.ExperimentConfiguration']"}), - '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'}), - 'round_type': ('django.db.models.fields.CharField', [], {'default': "'REGULAR'", 'max_length': '32'}), - 'sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {}), - 'template_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) - }, - 'core.rounddata': { - 'Meta': {'ordering': "['round_configuration']", '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': "orm['core.Experiment']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_data_set'", 'to': "orm['core.RoundConfiguration']"}) - }, - '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'}), - 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), - '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': "orm['core.Parameter']"}), - 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_parameter_value_set'", 'to': "orm['core.RoundConfiguration']"}), - 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) - }, - 'core.spoolparticipantstatistics': { - 'Meta': {'object_name': 'SpoolParticipantStatistics'}, - 'absences': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), - 'discharges': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), - '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': "orm['core.Participant']"}), - 'participations': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) - } + } - complete_apps = ['boundaries', 'core'] + complete_apps = ['boundaries'] diff -r 8db0c6f3177a6963b6fa68d138c32ef0919d2498 -r 88fd2ec2e64a6d9ee5769965c3de08b60c89cd17 vcweb/boundaries/migrations/0002_max_harvest_decision.py --- /dev/null +++ b/vcweb/boundaries/migrations/0002_max_harvest_decision.py @@ -0,0 +1,405 @@ +# -*- 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..." + Parameter = orm['core.Parameter'] + Experimenter = orm['core.Experimenter'] + Parameter.objects.create(name='max_harvest_decision', + creator=Experimenter.objects.get(pk=1), + type='int', + scope='experiment', + default_value_string='10', + description='Maximum harvest decision a player can make in a typical harvesting experiment') + + + def backwards(self, orm): + "Write your backwards methods here." + + 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', [], {'related_name': "'group_cluster_set'", 'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + '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_relationship_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.mode... [truncated message content] |
From: <com...@bi...> - 2013-03-28 15:48:16
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/202fb207161f/ Changeset: 202fb207161f User: alllee Date: 2013-03-28 16:48:01 Summary: using existing event message if it exists Affected #: 1 file diff -r 2391be49b5fa81d27a4666f10fb80ed24ec8bee8 -r 202fb207161fbef187c02eaa60e175f99ee0a26c vcweb/vcweb-sockjs.py --- a/vcweb/vcweb-sockjs.py +++ b/vcweb/vcweb-sockjs.py @@ -298,7 +298,10 @@ logger.debug("handling participant ready event %s for experiment %s", event, experiment) (per, valid) = self.verify_auth_token(event) if valid: - connection_manager.broadcast(experiment, create_message_event("Participant %s is ready." % per.participant, event_type=READY_EVENT_TYPE)) + if not event.message: + event.message = "Participant %s is ready." % per.participant + # FIXME: any reason to bootstrap this + connection_manager.broadcast(experiment, create_message_event(event.message, event_type=READY_EVENT_TYPE)) 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. |