virtualcommons-developer Mailing List for Virtual Commons Experiment Software (Page 3)
Status: Beta
Brought to you by:
alllee
You can subscribe to this list here.
| 2011 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(103) |
Jul
(85) |
Aug
(229) |
Sep
(70) |
Oct
(12) |
Nov
(16) |
Dec
(25) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2012 |
Jan
(41) |
Feb
(66) |
Mar
(150) |
Apr
(148) |
May
(109) |
Jun
(8) |
Jul
(20) |
Aug
(20) |
Sep
(16) |
Oct
(13) |
Nov
(58) |
Dec
(22) |
| 2013 |
Jan
(41) |
Feb
(108) |
Mar
(152) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
|
From: <com...@bi...> - 2013-03-22 04:22:56
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/40c7da4dad18/ Changeset: 40c7da4dad18 User: alllee Date: 2013-03-22 05:22:40 Summary: fixing add_participant guard to only abort when the participant is already a member of another group in the experiment with the same session_id (and thus non-addressable) Affected #: 2 files diff -r e7bad1de4521f8a0ecfd23dc29e3795d123f98e7 -r 40c7da4dad18138eb5d2fcfd7a901c1a929c0241 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -670,25 +670,26 @@ 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): + def add_participant(self, participant, current_group=None, max_group_size=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) ParticipantExperimentRelationship.objects.create(participant=participant, experiment=self, created_by=participant.user) pgrs = ParticipantGroupRelationship.objects.filter(group__experiment=self, participant=participant) - # FIXME: full strictness should be pgrs.count() == 0 - if pgrs.count() > 0: - # return this ParticipantGroupRelationship if this participant is already a member of a group in this experiment. - return pgrs.all()[0] - if current_group is None: if self.group_set.count() == 0: # create a new group - current_group = self.group_set.create(number=1, max_size=self.experiment_configuration.max_group_size) + 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] + 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: + 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 return current_group.add_participant(participant) def allocate_groups(self, randomize=True, preserve_existing_groups=False, session_id=None): @@ -718,18 +719,17 @@ gqs.delete() # seed the initial group. current_group = self.group_set.create(number=self.group_set.count(), max_size=max_group_size, session_id=session_id) - logger.debug("created initial group %s", current_group) for p in participants: - pgr = self.add_participant(p, current_group) + pgr = self.add_participant(p, current_group, max_group_size) current_group = pgr.group self.create_group_clusters() - def create_group_cluster(self): + def create_group_clusters(self): round_configuration = self.current_round session_id = round_configuration.session_id if round_configuration.create_group_clusters: group_cluster_size = round_configuration.group_cluster_size - groups = list(self.group_set.all()) + groups = list(self.group_set.filter(session_id=session_id)) 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)) diff -r e7bad1de4521f8a0ecfd23dc29e3795d123f98e7 -r 40c7da4dad18138eb5d2fcfd7a901c1a929c0241 vcweb/core/tests.py --- a/vcweb/core/tests.py +++ b/vcweb/core/tests.py @@ -249,6 +249,10 @@ participant_data_value, created = ParticipantRoundDataValue.objects.get_or_create(round_data=current_round_data, participant_group_relationship=pgr, parameter=parameter) self.assertFalse(created) +class GroupClusterTest(BaseVcwebTest): + def test_group_cluster(self): + pass + class GroupTest(BaseVcwebTest): def test_set_data_value_activity_log(self): e = self.advance_to_data_round() Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
|
From: <com...@bi...> - 2013-03-22 00:45:45
|
2 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/da8eea0b33a9/ Changeset: da8eea0b33a9 User: alllee Date: 2013-03-22 01:24:19 Summary: adding session id to round configuration Affected #: 2 files diff -r 1ab9e8a11457c3af506d67f470dfc89253752bc3 -r da8eea0b33a92a398e77ea8054b6d64a1c1e3b0e vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -110,8 +110,8 @@ ) ''' - during a practice or regular round, set up resource levels, participant harvest decision parameters, and possibly - group formation + during a practice or regular round, set up resource levels, participant harvest decision parameters, and group + formation ''' if should_reset_resource_level(round_configuration): initial_resource_level = get_initial_resource_level(round_configuration) @@ -130,7 +130,7 @@ ''' current_round_configuration = experiment.current_round logger.debug("ending boundaries round: %s", current_round_configuration) -# FIXME: max resource level might need to be read from the experiment / round configuration instead +# FIXME: should really read max resource level from the experiment / round configuration instead max_resource_level = MAX_RESOURCE_LEVEL for group in experiment.group_set.all(): logger.debug("group %s has resource level", group) diff -r 1ab9e8a11457c3af506d67f470dfc89253752bc3 -r da8eea0b33a92a398e77ea8054b6d64a1c1e3b0e vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -1043,7 +1043,7 @@ return Template(template_string).substitute(kwargs, round_number=self.display_number, participant_id=participant_id) def __unicode__(self): - return u"%s %s (%s)" % (self.get_round_type_display(), self.sequence_label, self.experiment_configuration) + return u"%s %s (%s %s)" % (self.get_round_type_display(), self.sequence_label, self.experiment_configuration, self.session_id) @property def display_label(self): https://bitbucket.org/virtualcommons/vcweb/commits/e7bad1de4521/ Changeset: e7bad1de4521 User: alllee Date: 2013-03-22 01:45:41 Summary: adding initial cut at group cluster creation logic Affected #: 1 file diff -r da8eea0b33a92a398e77ea8054b6d64a1c1e3b0e -r e7bad1de4521f8a0ecfd23dc29e3795d123f98e7 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -700,6 +700,7 @@ participants = list(self.participant_set.all()) if randomize: random.shuffle(participants) + if gs.count() > 0: if preserve_existing_groups: # verify incoming session id is an actual value @@ -721,6 +722,24 @@ for p in participants: pgr = self.add_participant(p, current_group) current_group = pgr.group + self.create_group_clusters() + + def create_group_cluster(self): + round_configuration = self.current_round + session_id = round_configuration.session_id + if round_configuration.create_group_clusters: + group_cluster_size = round_configuration.group_cluster_size + groups = list(self.group_set.all()) + 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)) + return + random.shuffle(groups) + g = GroupCluster.objects.create(session_id=session_id, experiment=self) + for group in groups: + if g.group_set.count() == group_cluster_size: + g = GroupCluster.objects.create(session_id=session_id, experiment=self) + g.group_set.add(group) def get_round_configuration(self, sequence_number): return RoundConfiguration.objects.get(experiment_configuration__experiment=self, sequence_number=sequence_number) @@ -1520,6 +1539,7 @@ date_created = models.DateTimeField(default=datetime.now) name = models.CharField(max_length=64, null=True, blank=True) session_id = models.CharField(max_length=64, null=True, blank=True) + max_size = models.PositiveIntegerField(default=0) experiment = models.ForeignKey(Experiment) def __unicode__(self): Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
|
From: <com...@bi...> - 2013-03-21 23:42:33
|
5 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/406e80e3d2a2/ Changeset: 406e80e3d2a2 User: alllee Date: 2013-03-22 00:32:31 Summary: collapsing south migrations Affected #: 29 files diff -r c01f18439b84d0036ea4d6a43086c16fc962acfc -r 406e80e3d2a22d58f3444802a963d76669fa0cbf vcweb/core/migrations/0001_initial.py --- a/vcweb/core/migrations/0001_initial.py +++ /dev/null @@ -1,619 +0,0 @@ -# -*- 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): - # Adding model 'ExperimentMetadata' - db.create_table('core_experimentmetadata', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('title', self.gf('django.db.models.fields.CharField')(max_length=255)), - ('namespace', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)), - ('short_name', self.gf('django.db.models.fields.SlugField')(max_length=32, unique=True, null=True)), - ('description', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), - ('date_created', self.gf('django.db.models.fields.DateField')(auto_now_add=True, blank=True)), - ('last_modified', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), - ('about_url', self.gf('django.db.models.fields.URLField')(max_length=200, null=True, blank=True)), - ('logo_url', self.gf('django.db.models.fields.URLField')(max_length=200, null=True, blank=True)), - ('default_configuration', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.ExperimentConfiguration'], null=True, blank=True)), - )) - db.send_create_signal('core', ['ExperimentMetadata']) - - # Adding model 'Institution' - db.create_table('core_institution', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)), - ('description', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), - ('url', self.gf('django.db.models.fields.URLField')(max_length=200, null=True, blank=True)), - ('date_created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), - ('last_modified', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), - )) - db.send_create_signal('core', ['Institution']) - - # Adding model 'Experimenter' - db.create_table('core_experimenter', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('user', self.gf('django.db.models.fields.related.OneToOneField')(related_name='experimenter', unique=True, to=orm['auth.User'])), - ('failed_password_attempts', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), - ('institution', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.Institution'], null=True, blank=True)), - ('authentication_token', self.gf('django.db.models.fields.CharField')(max_length=64, null=True, blank=True)), - ('approved', self.gf('django.db.models.fields.BooleanField')(default=False)), - )) - db.send_create_signal('core', ['Experimenter']) - - # Adding model 'ExperimentConfiguration' - db.create_table('core_experimentconfiguration', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('experiment_metadata', self.gf('django.db.models.fields.related.ForeignKey')(related_name='experiment_configuration_set', to=orm['core.ExperimentMetadata'])), - ('creator', self.gf('django.db.models.fields.related.ForeignKey')(related_name='experiment_configuration_set', to=orm['core.Experimenter'])), - ('name', self.gf('django.db.models.fields.CharField')(max_length=255)), - ('max_number_of_participants', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), - ('date_created', self.gf('django.db.models.fields.DateField')(auto_now_add=True, blank=True)), - ('last_modified', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), - ('is_public', self.gf('django.db.models.fields.BooleanField')(default=True)), - ('max_group_size', self.gf('django.db.models.fields.PositiveIntegerField')(default=5)), - )) - db.send_create_signal('core', ['ExperimentConfiguration']) - - # Adding model 'Experiment' - db.create_table('core_experiment', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('authentication_code', self.gf('django.db.models.fields.CharField')(default='vcweb.auth.code', max_length=32)), - ('current_round_sequence_number', self.gf('django.db.models.fields.PositiveIntegerField')(default=1)), - ('experimenter', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.Experimenter'])), - ('experiment_metadata', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.ExperimentMetadata'])), - ('experiment_configuration', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.ExperimentConfiguration'])), - ('status', self.gf('django.db.models.fields.CharField')(default='INACTIVE', max_length=32)), - ('date_created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), - ('last_modified', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), - ('start_date_time', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)), - ('duration', self.gf('django.db.models.fields.CharField')(max_length=32, null=True, blank=True)), - ('tick_duration', self.gf('django.db.models.fields.CharField')(max_length=32, null=True, blank=True)), - ('total_elapsed_time', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), - ('current_round_start_time', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)), - ('current_round_elapsed_time', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), - ('is_experimenter_driven', self.gf('django.db.models.fields.BooleanField')(default=True)), - ('amqp_exchange_name', self.gf('django.db.models.fields.CharField')(default='vcweb.default.exchange', max_length=64)), - ('slug', self.gf('django.db.models.fields.SlugField')(max_length=16, unique=True, null=True, blank=True)), - )) - db.send_create_signal('core', ['Experiment']) - - # Adding model 'RoundConfiguration' - db.create_table('core_roundconfiguration', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('experiment_configuration', self.gf('django.db.models.fields.related.ForeignKey')(related_name='round_configuration_set', to=orm['core.ExperimentConfiguration'])), - ('sequence_number', self.gf('django.db.models.fields.PositiveIntegerField')()), - ('display_number', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), - ('date_created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), - ('last_modified', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), - ('duration', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), - ('instructions', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), - ('debriefing', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), - ('round_type', self.gf('django.db.models.fields.CharField')(default='REGULAR', max_length=32)), - ('template_name', self.gf('django.db.models.fields.CharField')(max_length=64, null=True, blank=True)), - )) - db.send_create_signal('core', ['RoundConfiguration']) - - # Adding model 'QuizQuestion' - db.create_table('core_quizquestion', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('label', self.gf('django.db.models.fields.CharField')(max_length=512)), - ('answer', self.gf('django.db.models.fields.CharField')(max_length=64)), - ('input_type', self.gf('django.db.models.fields.CharField')(max_length=32)), - ('explanation', self.gf('django.db.models.fields.CharField')(max_length=512)), - ('round_configuration', self.gf('django.db.models.fields.related.ForeignKey')(related_name='quiz_question_set', to=orm['core.RoundConfiguration'])), - ('experiment', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='default_quiz_question_set', null=True, to=orm['core.Experiment'])), - )) - db.send_create_signal('core', ['QuizQuestion']) - - # Adding model 'Parameter' - db.create_table('core_parameter', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('scope', self.gf('django.db.models.fields.CharField')(default='round', max_length=32)), - ('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)), - ('display_name', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)), - ('description', self.gf('django.db.models.fields.CharField')(max_length=512, null=True, blank=True)), - ('type', self.gf('django.db.models.fields.CharField')(max_length=32)), - ('default_value_string', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)), - ('date_created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), - ('last_modified', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), - ('creator', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.Experimenter'])), - ('experiment_metadata', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.ExperimentMetadata'], null=True, blank=True)), - ('enum_choices', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), - ('is_required', self.gf('django.db.models.fields.BooleanField')(default=False)), - )) - db.send_create_signal('core', ['Parameter']) - - # Adding unique constraint on 'Parameter', fields ['name', 'experiment_metadata', 'scope'] - db.create_unique('core_parameter', ['name', 'experiment_metadata_id', 'scope']) - - # Adding model 'RoundParameterValue' - db.create_table('core_roundparametervalue', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('parameter', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.Parameter'])), - ('string_value', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), - ('int_value', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)), - ('float_value', self.gf('django.db.models.fields.FloatField')(null=True, blank=True)), - ('boolean_value', self.gf('django.db.models.fields.NullBooleanField')(null=True, blank=True)), - ('date_created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), - ('last_modified', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), - ('is_active', self.gf('django.db.models.fields.BooleanField')(default=True)), - ('round_configuration', self.gf('django.db.models.fields.related.ForeignKey')(related_name='round_parameter_value_set', to=orm['core.RoundConfiguration'])), - )) - db.send_create_signal('core', ['RoundParameterValue']) - - # Adding model 'Group' - db.create_table('core_group', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('number', self.gf('django.db.models.fields.PositiveIntegerField')()), - ('max_size', self.gf('django.db.models.fields.PositiveIntegerField')(default=5)), - ('experiment', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.Experiment'])), - )) - db.send_create_signal('core', ['Group']) - - # Adding model 'RoundData' - db.create_table('core_rounddata', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('experiment', self.gf('django.db.models.fields.related.ForeignKey')(related_name='round_data_set', to=orm['core.Experiment'])), - ('round_configuration', self.gf('django.db.models.fields.related.ForeignKey')(related_name='round_data_set', to=orm['core.RoundConfiguration'])), - ('elapsed_time', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), - )) - db.send_create_signal('core', ['RoundData']) - - # Adding model 'GroupRoundDataValue' - db.create_table('core_grouprounddatavalue', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('parameter', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.Parameter'])), - ('string_value', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), - ('int_value', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)), - ('float_value', self.gf('django.db.models.fields.FloatField')(null=True, blank=True)), - ('boolean_value', self.gf('django.db.models.fields.NullBooleanField')(null=True, blank=True)), - ('date_created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), - ('last_modified', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), - ('is_active', self.gf('django.db.models.fields.BooleanField')(default=True)), - ('group', self.gf('django.db.models.fields.related.ForeignKey')(related_name='data_value_set', to=orm['core.Group'])), - ('round_data', self.gf('django.db.models.fields.related.ForeignKey')(related_name='group_data_value_set', to=orm['core.RoundData'])), - )) - db.send_create_signal('core', ['GroupRoundDataValue']) - - # Adding model 'Participant' - db.create_table('core_participant', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('user', self.gf('django.db.models.fields.related.OneToOneField')(related_name='participant', unique=True, to=orm['auth.User'])), - ('failed_password_attempts', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), - ('institution', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.Institution'], null=True, blank=True)), - ('authentication_token', self.gf('django.db.models.fields.CharField')(max_length=64, null=True, blank=True)), - ('can_receive_invitations', self.gf('django.db.models.fields.BooleanField')(default=False)), - )) - db.send_create_signal('core', ['Participant']) - - # Adding model 'ParticipantExperimentRelationship' - db.create_table('core_participantexperimentrelationship', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('participant', self.gf('django.db.models.fields.related.ForeignKey')(related_name='experiment_relationship_set', to=orm['core.Participant'])), - ('participant_identifier', self.gf('django.db.models.fields.CharField')(max_length=32)), - ('sequential_participant_identifier', self.gf('django.db.models.fields.PositiveIntegerField')()), - ('experiment', self.gf('django.db.models.fields.related.ForeignKey')(related_name='participant_relationship_set', to=orm['core.Experiment'])), - ('date_created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), - ('created_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), - ('last_completed_round_sequence_number', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), - ('current_location', self.gf('django.db.models.fields.CharField')(max_length=64, null=True, blank=True)), - ('additional_data', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), - )) - db.send_create_signal('core', ['ParticipantExperimentRelationship']) - - # Adding model 'ParticipantGroupRelationship' - db.create_table('core_participantgrouprelationship', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('participant_number', self.gf('django.db.models.fields.PositiveIntegerField')()), - ('participant', self.gf('django.db.models.fields.related.ForeignKey')(related_name='participant_group_relationship_set', to=orm['core.Participant'])), - ('group', self.gf('django.db.models.fields.related.ForeignKey')(related_name='participant_group_relationship_set', to=orm['core.Group'])), - ('round_joined', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.RoundConfiguration'])), - ('date_created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), - ('active', self.gf('django.db.models.fields.BooleanField')(default=True)), - ('notifications_since', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, null=True, blank=True)), - )) - db.send_create_signal('core', ['ParticipantGroupRelationship']) - - # Adding model 'ParticipantRoundDataValue' - db.create_table('core_participantrounddatavalue', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('parameter', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.Parameter'])), - ('string_value', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), - ('int_value', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)), - ('float_value', self.gf('django.db.models.fields.FloatField')(null=True, blank=True)), - ('boolean_value', self.gf('django.db.models.fields.NullBooleanField')(null=True, blank=True)), - ('date_created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), - ('last_modified', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), - ('is_active', self.gf('django.db.models.fields.BooleanField')(default=True)), - ('round_data', self.gf('django.db.models.fields.related.ForeignKey')(related_name='participant_data_value_set', to=orm['core.RoundData'])), - ('participant_group_relationship', self.gf('django.db.models.fields.related.ForeignKey')(related_name='participant_data_value_set', to=orm['core.ParticipantGroupRelationship'])), - ('submitted', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('target_data_value', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='target_data_value_set', null=True, to=orm['core.ParticipantRoundDataValue'])), - )) - db.send_create_signal('core', ['ParticipantRoundDataValue']) - - # Adding model 'ChatMessage' - db.create_table('core_chatmessage', ( - ('participantrounddatavalue_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['core.ParticipantRoundDataValue'], unique=True, primary_key=True)), - ('target_participant', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='target_participant_chat_message_set', null=True, to=orm['core.ParticipantGroupRelationship'])), - )) - db.send_create_signal('core', ['ChatMessage']) - - # Adding model 'Comment' - db.create_table('core_comment', ( - ('participantrounddatavalue_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['core.ParticipantRoundDataValue'], unique=True, primary_key=True)), - )) - db.send_create_signal('core', ['Comment']) - - # Adding model 'Like' - db.create_table('core_like', ( - ('participantrounddatavalue_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['core.ParticipantRoundDataValue'], unique=True, primary_key=True)), - )) - db.send_create_signal('core', ['Like']) - - # Adding model 'ActivityLog' - db.create_table('core_activitylog', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('log_message', self.gf('django.db.models.fields.TextField')()), - ('date_created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), - )) - db.send_create_signal('core', ['ActivityLog']) - - # Adding model 'GroupActivityLog' - db.create_table('core_groupactivitylog', ( - ('activitylog_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['core.ActivityLog'], unique=True, primary_key=True)), - ('group', self.gf('django.db.models.fields.related.ForeignKey')(related_name='activity_log_set', to=orm['core.Group'])), - ('round_configuration', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.RoundConfiguration'])), - )) - db.send_create_signal('core', ['GroupActivityLog']) - - # Adding model 'ExperimentActivityLog' - db.create_table('core_experimentactivitylog', ( - ('activitylog_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['core.ActivityLog'], unique=True, primary_key=True)), - ('experiment', self.gf('django.db.models.fields.related.ForeignKey')(related_name='activity_log_set', to=orm['core.Experiment'])), - ('round_configuration', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.RoundConfiguration'])), - )) - db.send_create_signal('core', ['ExperimentActivityLog']) - - def backwards(self, orm): - # Removing unique constraint on 'Parameter', fields ['name', 'experiment_metadata', 'scope'] - db.delete_unique('core_parameter', ['name', 'experiment_metadata_id', 'scope']) - - # Deleting model 'ExperimentMetadata' - db.delete_table('core_experimentmetadata') - - # Deleting model 'Institution' - db.delete_table('core_institution') - - # Deleting model 'Experimenter' - db.delete_table('core_experimenter') - - # Deleting model 'ExperimentConfiguration' - db.delete_table('core_experimentconfiguration') - - # Deleting model 'Experiment' - db.delete_table('core_experiment') - - # Deleting model 'RoundConfiguration' - db.delete_table('core_roundconfiguration') - - # Deleting model 'QuizQuestion' - db.delete_table('core_quizquestion') - - # Deleting model 'Parameter' - db.delete_table('core_parameter') - - # Deleting model 'RoundParameterValue' - db.delete_table('core_roundparametervalue') - - # Deleting model 'Group' - db.delete_table('core_group') - - # Deleting model 'RoundData' - db.delete_table('core_rounddata') - - # Deleting model 'GroupRoundDataValue' - db.delete_table('core_grouprounddatavalue') - - # Deleting model 'Participant' - db.delete_table('core_participant') - - # Deleting model 'ParticipantExperimentRelationship' - db.delete_table('core_participantexperimentrelationship') - - # Deleting model 'ParticipantGroupRelationship' - db.delete_table('core_participantgrouprelationship') - - # Deleting model 'ParticipantRoundDataValue' - db.delete_table('core_participantrounddatavalue') - - # Deleting model 'ChatMessage' - db.delete_table('core_chatmessage') - - # Deleting model 'Comment' - db.delete_table('core_comment') - - # Deleting model 'Like' - db.delete_table('core_like') - - # Deleting model 'ActivityLog' - db.delete_table('core_activitylog') - - # Deleting model 'GroupActivityLog' - db.delete_table('core_groupactivitylog') - - # Deleting model 'ExperimentActivityLog' - db.delete_table('core_experimentactivitylog') - - 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', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'log_message': ('django.db.models.fields.TextField', [], {}) - }, - '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', [], {'auto_now_add': 'True', 'blank': 'True'}), - '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': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '16', '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.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - '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'}), - 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'last_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - '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.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.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - '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': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - '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.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', [], {'auto_now_add': 'True', 'blank': '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': "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': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - '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', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - '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.like': { - 'Meta': {'ordering': "['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'}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Experimenter']"}), - 'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), - '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': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - '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'}, - 'authentication_token': ('django.db.models.fields.CharField', [], {'max_length': '64', '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'}), - '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', [], {'auto_now_add': 'True', 'blank': 'True'}), - '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', [], {'auto_now_add': 'True', 'blank': 'True'}), - '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', [], {'auto_now_add': 'True', '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': "['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', [], {'auto_now_add': 'True', 'blank': 'True'}), - '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': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - '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.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', [], {'auto_now_add': 'True', 'blank': 'True'}), - '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': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - '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', [], {'auto_now_add': 'True', 'blank': 'True'}), - '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': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - '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'}) - } - } - - complete_apps = ['core'] \ No newline at end of file diff -r c01f18439b84d0036ea4d6a43086c16fc962acfc -r 406e80e3d2a22d58f3444802a963d76669fa0cbf vcweb/core/migrations/0002_auto__add_experimenterrequest.py --- a/vcweb/core/migrations/0002_auto__add_experimenterrequest.py +++ /dev/null @@ -1,297 +0,0 @@ -# -*- 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): - # Adding model 'ExperimenterRequest' - db.create_table('core_experimenterrequest', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('user', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['auth.User'], unique=True)), - ('date_created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), - ('approved', self.gf('django.db.models.fields.BooleanField')(default=False)), - )) - db.send_create_signal('core', ['ExperimenterRequest']) - - def backwards(self, orm): - # Deleting model 'ExperimenterRequest' - db.delete_table('core_experimenterrequest') - - 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', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'log_message': ('django.db.models.fields.TextField', [], {}) - }, - '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', [], {'auto_now_add': 'True', 'blank': 'True'}), - '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': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '16', '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.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - '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'}), - 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'last_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - 'max_group_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), - 'max_number_of_participants': ('djan... [truncated message content] |
|
From: <com...@bi...> - 2013-03-21 23:21:19
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/c01f18439b84/ Changeset: c01f18439b84 User: alllee Date: 2013-03-22 00:21:17 Summary: fixing click bindings / refactoring experiment monitor confirmations Affected #: 2 files diff -r 02909e4e92ea99ac360cb0d0354605d9f7bca9c8 -r c01f18439b84d0036ea4d6a43086c16fc962acfc vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -2,9 +2,10 @@ from vcweb.core import signals, simplecache from vcweb.core.models import ExperimentMetadata, Parameter, ParticipantRoundDataValue from vcweb.forestry.models import (get_harvest_decision_parameter, get_harvest_decision, get_regrowth_rate, - get_group_harvest_parameter, get_reset_resource_level_parameter, get_resource_level, get_initial_resource_level - as forestry_initial_resource_level, set_resource_level, get_regrowth_parameter, get_resource_level_parameter, - has_resource_level, get_resource_level_dv, get_harvest_decisions, set_group_harvest, set_regrowth) + get_group_harvest_parameter, get_reset_resource_level_parameter, get_resource_level, + get_initial_resource_level as forestry_initial_resource_level, set_resource_level, get_regrowth_parameter, + get_resource_level_parameter, has_resource_level, get_resource_level_dv, get_harvest_decisions, + set_group_harvest, set_regrowth) import logging @@ -37,7 +38,7 @@ @simplecache def get_max_harvest_decision_parameter(): - return Parameter.objects.for_round(name='max_harvest_decision') + return Parameter.objects.for_experiment(name='max_harvest_decision') @simplecache def get_cost_of_living_parameter(): @@ -64,6 +65,9 @@ def get_initial_resource_level(round_configuration, default=MAX_RESOURCE_LEVEL): return forestry_initial_resource_level(round_configuration, default) +def get_max_harvest(experiment): + return experiment.get_parameter_value(parameter=get_max_harvest_decision_parameter(), default=10).int_value + def get_cost_of_living(current_round): return current_round.get_parameter_value(get_cost_of_living_parameter(), default=5).int_value @@ -104,11 +108,11 @@ group_parameters=(get_regrowth_parameter(), get_group_harvest_parameter(), get_resource_level_parameter()), participant_parameters=[get_harvest_decision_parameter(), get_storage_parameter(), get_player_status_parameter()] ) + ''' - during a practice or regular round, set up resource levels and participant - harvest decision parameters + during a practice or regular round, set up resource levels, participant harvest decision parameters, and possibly + group formation ''' - if should_reset_resource_level(round_configuration): initial_resource_level = get_initial_resource_level(round_configuration) logger.debug("Resetting resource level for %s to %d", round_configuration, initial_resource_level) diff -r 02909e4e92ea99ac360cb0d0354605d9f7bca9c8 -r c01f18439b84d0036ea4d6a43086c16fc962acfc vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -12,11 +12,15 @@ <li><div class='btn-toolbar'><div class='btn-group'> - <a class='btn btn-success' data-bind="click: confirmExperimentAction, css: { disabled: isRoundInProgress }" data-action='start_round' data-content='Starts the round.'><i class='icon-play'></i> start</a> - <a class='btn btn-success' data-bind='click: advanceToNextRound' data-action='advance_to_next_round' data-content='Advances to and starts the next round.'><i class='icon-step-forward'></i> next round</a> - <a class='btn btn-success' data-bind='click: updateParticipants' data-content='Updates all connected participants.' ><i class='icon-exchange'></i> update</a> - <a class='btn btn-primary' data-bind='click: update' data-content='Update this page and pull the latest data from the server.' ><i class='icon-refresh'></i></a> - <a class='btn btn-danger' data-bind='click: confirmExperimentAction' data-action='deactivate' data-content='Deactivates this experiment.'><i class='icon-off'></i></a> + <a class='btn btn-success' data-bind="click: confirmExperimentControllerAction.bind($data, true), css: { disabled: isRoundInProgress }" data-action='start_round' data-content='Starts the round.'><i class='icon-play'></i> start</a> + <a class='btn btn-success' data-bind='click: confirmExperimentControllerAction.bind($data, true)' data-action='advance_to_next_round' data-content='Advances to and starts the next round.'><i class='icon-step-forward'></i> next round</a> + </div> + </div> + <div class='btn-toolbar'> + <div class='btn-group'> + <a class='btn btn-success' data-bind='click: updateParticipants' data-content='Updates all connected participants.' ><i class='icon-exchange'></i> update participants</a> + <a class='btn btn-primary' data-bind='click: update' data-content='Update this page and pull the latest data from the server.' ><i class='icon-refresh'></i> refresh data</a> + <a class='btn btn-danger' data-bind='click: confirmExperimentControllerAction.bind($data, false)' data-action='deactivate' data-content='Deactivates this experiment.'><i class='icon-off'></i> deactivate</a></div></div></li> @@ -45,7 +49,7 @@ <p class='text-error'>NOTE: activating an experiment <b>will delete all existing data</b></p><a data-content='Starts this experiment, assigns participants to groups, etc.' - class='btn btn-success' data-bind='click: confirmExperimentAction' data-action='activate'><i class='icon-off'></i> activate</a> + class='btn btn-success' data-bind='click: confirmExperimentControllerAction.bind($data, false)' data-action='activate'><i class='icon-off'></i> activate</a></div></div></div> @@ -68,7 +72,7 @@ <li><a href='export/configuration.xml'><i class='icon-cog'></i>xml</a></li><li><a href='export/configuration.json'><i class='icon-pencil'></i>json</a></li></ul> - <a class='btn btn-danger' data-bind='css: { disabled: isArchived}, click: confirmExperimentAction' data-action='complete' data-content='Mark this experiment as completed and archive it.'><i class='icon-save'></i> archive</a> + <a class='btn btn-danger' data-bind='css: { disabled: isArchived}, click: confirmExperimentControllerAction.bind($data, false)' data-action='complete' data-content='Mark this experiment as completed and archive it.'><i class='icon-save'></i> archive</a></div></div><div class='span6'> @@ -182,27 +186,30 @@ }, { experiment_id: {{ experiment.pk }}, notes: notes }); } -// FIXME: code duplication here, prime candidate for refactoring + // FIXME: factor out the code duplication with this and confirmExperimentControllerAction for + // showing the modal and invoking the ajax call if possible model.update = function(localModel, evt) { $('#progress-modal').modal('show'); Dajaxice.vcweb.core.get_experiment_model(function (data) { ko.mapping.fromJS(data, model); $('#progress-modal').modal('hide');}, {pk: {{experiment.pk}}}); } - model.confirmExperimentAction = function(m, evt) { + model.confirmExperimentControllerAction = function(updateParticipants, localModel, evt) { element = evt.target; + console.debug(element); if ($(element).hasClass('disabled')) { - console.debug("aborting."); - return; + console.debug("aborting disabled action: " + element); + return false; } - confirmExperimentControllerAction(element, model); + confirmAction(element, function(confirmed, action) { + $('#progress-modal').modal('show'); + Dajaxice.vcweb.core.experiment_controller(function(data) { + ko.mapping.fromJS(data, experimentModel); + if (updateParticipants) { + sendUpdateEvent(); + } + $('#progress-modal').modal('hide'); + }, {pk: {{experiment.pk}}, 'action':action}); + }); } - model.advanceToNextRound = function(m, evt) { - confirmExperimentControllerAction(evt.target, m, function(confirmed) { - if (confirmed) { - console.debug("advancing to next round, notify all participants"); - sendUpdateEvent(); - } - }); - }; model.updateParticipants = function(m, evt) { confirmAction(evt.target, function(confirmed, action) { if (confirmed) { @@ -219,18 +226,6 @@ }); return model; } - function confirmExperimentControllerAction(element, experimentModel, callback) { - confirmAction(element, function(confirmed, action) { - $('#progress-modal').modal('show'); - Dajaxice.vcweb.core.experiment_controller(function(data) { - ko.mapping.fromJS(data, experimentModel); - if (callback) { - callback(confirmed, action); - } - $('#progress-modal').modal('hide'); - }, {pk: {{experiment.pk}}, 'action':action}); - }); - } function confirmAction(element, callback) { var self = $(element); var description = self.attr("data-content"); 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-21 10:37:53
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/02909e4e92ea/ changeset: 02909e4e92ea user: alllee date: 2013-03-21 11:37:33 summary: ensuring experimenterNotes is set in the experiment view model dict affected #: 2 files diff -r bda736d07dac7751c58cdf1d533d033aaa047b92 -r 02909e4e92ea99ac360cb0d0354605d9f7bca9c8 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -855,8 +855,7 @@ 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')] - if self.is_round_in_progress: - experiment_dict['experimenterNotes'] = self.current_round_data.experimenter_notes + experiment_dict['experimenterNotes'] = self.current_round_data.experimenter_notes if self.is_round_in_progress else '' return experiment_dict def as_dict(self, *args, **kwargs): diff -r bda736d07dac7751c58cdf1d533d033aaa047b92 -r 02909e4e92ea99ac360cb0d0354605d9f7bca9c8 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -182,9 +182,10 @@ }, { experiment_id: {{ experiment.pk }}, notes: notes }); } +// FIXME: code duplication here, prime candidate for refactoring model.update = function(localModel, evt) { $('#progress-modal').modal('show'); - Dajaxice.vcweb.core.get_experiment_model(update(model), {pk: {{experiment.pk}}}); + Dajaxice.vcweb.core.get_experiment_model(function (data) { ko.mapping.fromJS(data, model); $('#progress-modal').modal('hide');}, {pk: {{experiment.pk}}}); } model.confirmExperimentAction = function(m, evt) { element = evt.target; @@ -218,7 +219,7 @@ }); return model; } - function confirmExperimentControllerAction(element, m, callback) { + function confirmExperimentControllerAction(element, experimentModel, callback) { confirmAction(element, function(confirmed, action) { $('#progress-modal').modal('show'); Dajaxice.vcweb.core.experiment_controller(function(data) { @@ -244,10 +245,6 @@ } }); } - function update(experimentModel) { - return function(data) { - } - } function initialize(experimentModelJson) { var experimentModel = new ExperimentModel(experimentModelJson); // var experimentModel = new ExperimentModel(); 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-21 10:09:35
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/bda736d07dac/ changeset: bda736d07dac user: alllee date: 2013-03-21 11:09:18 summary: redirecting to experiment monitor page after cloning an experiment affected #: 4 files diff -r 7f7cd79155ad634a78404fa2a4f8ed2aa12576e1 -r bda736d07dac7751c58cdf1d533d033aaa047b92 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -736,6 +736,16 @@ self.current_round_sequence_number = max(self.current_round_sequence_number - 1, 1) self.save() + def move_to_next_round(self): + if self.is_round_in_progress: + self.end_round() + if self.has_next_round: + self.current_round_elapsed_time = 0 + self.current_round_sequence_number += 1 + return True + else: + logger.warning("trying to advance past the last round - no-op") + def invoke(self, action_name): if action_name in ('advance_to_next_round', 'end_round', 'start_round', 'activate', 'deactivate', 'complete'): getattr(self, action_name)() @@ -743,14 +753,8 @@ raise AttributeError("Invalid experiment action %s requested of experiment %s" % (action_name, self)) def advance_to_next_round(self): - if self.is_round_in_progress: - self.end_round() - if self.has_next_round: - self.current_round_elapsed_time = 0 - self.current_round_sequence_number += 1 + if self.move_to_next_round(): self.start_round() - else: - logger.warning("trying to advance past the last round - no-op") def create_round_data(self): round_data, created = self.round_data_set.get_or_create(round_configuration=self.current_round) @@ -851,7 +855,8 @@ 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['experimenterNotes'] = self.current_round_data.experimenter_notes + if self.is_round_in_progress: + experiment_dict['experimenterNotes'] = self.current_round_data.experimenter_notes return experiment_dict def as_dict(self, *args, **kwargs): diff -r 7f7cd79155ad634a78404fa2a4f8ed2aa12576e1 -r bda736d07dac7751c58cdf1d533d033aaa047b92 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -14,8 +14,8 @@ <div class='btn-group'><a class='btn btn-success' data-bind="click: confirmExperimentAction, css: { disabled: isRoundInProgress }" data-action='start_round' data-content='Starts the round.'><i class='icon-play'></i> start</a><a class='btn btn-success' data-bind='click: advanceToNextRound' data-action='advance_to_next_round' data-content='Advances to and starts the next round.'><i class='icon-step-forward'></i> next round</a> - <a class='btn btn-success' data-bind='click: refreshAllParticipants' data-content='Sends a page refresh to all connected participants.' ><i class='icon-exchange'></i> refresh participants</a>--> - <a class='btn btn-primary' data-bind='click: update' data-content='Refresh this page with the latest data from the server.' ><i class='icon-refresh'></i></a> + <a class='btn btn-success' data-bind='click: updateParticipants' data-content='Updates all connected participants.' ><i class='icon-exchange'></i> update</a> + <a class='btn btn-primary' data-bind='click: update' data-content='Update this page and pull the latest data from the server.' ><i class='icon-refresh'></i></a><a class='btn btn-danger' data-bind='click: confirmExperimentAction' data-action='deactivate' data-content='Deactivates this experiment.'><i class='icon-off'></i></a></div></div> @@ -68,7 +68,7 @@ <li><a href='export/configuration.xml'><i class='icon-cog'></i>xml</a></li><li><a href='export/configuration.json'><i class='icon-pencil'></i>json</a></li></ul> - <a class='btn btn-danger' data-bind='click: confirmExperimentAction' data-action='complete' data-content='Mark this experiment as completed and archive it.'><i class='icon-save'></i> archive</a> + <a class='btn btn-danger' data-bind='css: { disabled: isArchived}, click: confirmExperimentAction' data-action='complete' data-content='Mark this experiment as completed and archive it.'><i class='icon-save'></i> archive</a></div></div><div class='span6'> @@ -84,7 +84,7 @@ <h4>Experimenter Notes (<span data-bind='text: roundSequenceLabel'></span>)</h4><form id="experimenterNotesForm" class='form-inline'><div class='controls'> - <textarea class='input-block-level' id='experimenterNotes' data-bind='text: experimenterNotes' placeholder="Experimenter notes to be stored with this round's data" rows="3"></textarea> + <textarea class='input-block-level' id='experimenterNotesText' data-bind='text: experimenterNotes' placeholder="Experimenter notes to be stored with this round's data" rows="3"></textarea><button id='submitExperimenterNotesButton' class='btn btn-primary' type='submit' data-bind='click: saveExperimenterNotes'>Save</button></div></form> @@ -168,14 +168,13 @@ {% include "includes/experimenter.events.html" %} {% include "includes/sockjs.html" %} <script type='text/javascript'> -// FIXME: we should verify if exposing this here is the "right" thing to do. var experimentModelJson = $.parseJSON("{{ experimentModelJson|escapejs }}"); $(function() { function ExperimentModel(experimentModelJson) { var self = this; var model = ko.mapping.fromJS(experimentModelJson); model.saveExperimenterNotes = function(localModel, evt) { - var notes = $('#experimenterNotes').val(); + var notes = $('#experimenterNotesText').val(); Dajaxice.vcweb.core.save_experimenter_notes(function(data) { if (data.success) { $('#submitExperimenterNotesButton').val('Saved!'); @@ -187,18 +186,23 @@ $('#progress-modal').modal('show'); Dajaxice.vcweb.core.get_experiment_model(update(model), {pk: {{experiment.pk}}}); } - model.confirmExperimentAction = function(experimentModel, evt) { - confirmExperimentControllerAction(evt.target, model); + model.confirmExperimentAction = function(m, evt) { + element = evt.target; + if ($(element).hasClass('disabled')) { + console.debug("aborting."); + return; + } + confirmExperimentControllerAction(element, model); } - model.advanceToNextRound = function(localModel, evt) { - confirmExperimentControllerAction(evt.target, model, function(confirmed) { + model.advanceToNextRound = function(m, evt) { + confirmExperimentControllerAction(evt.target, m, function(confirmed) { if (confirmed) { console.debug("advancing to next round, notify all participants"); sendUpdateEvent(); } }); }; - model.refreshAllParticipants = function(localModel, evt) { + model.updateParticipants = function(m, evt) { confirmAction(evt.target, function(confirmed, action) { if (confirmed) { console.debug("sending update event"); @@ -214,7 +218,7 @@ }); return model; } - function confirmExperimentControllerAction(element, experimentModel, callback) { + function confirmExperimentControllerAction(element, m, callback) { confirmAction(element, function(confirmed, action) { $('#progress-modal').modal('show'); Dajaxice.vcweb.core.experiment_controller(function(data) { diff -r 7f7cd79155ad634a78404fa2a4f8ed2aa12576e1 -r bda736d07dac7751c58cdf1d533d033aaa047b92 vcweb/core/urls.py --- a/vcweb/core/urls.py +++ b/vcweb/core/urls.py @@ -4,7 +4,6 @@ from vcweb.core.views import (Dashboard, LoginView, LogoutView, RegistrationView, monitor, CloneExperimentView, RegisterEmailListView, RegisterSimpleParticipantsView, ClearParticipantsExperimentView, add_experiment, Participate, download_data, export_configuration, api_logger, participant_ready, deactivate) - import logging import urllib diff -r 7f7cd79155ad634a78404fa2a4f8ed2aa12576e1 -r bda736d07dac7751c58cdf1d533d033aaa047b92 vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -326,9 +326,10 @@ # FIXME: these last two use GET (which should be idempotent) to modify database state which makes HTTP sadful class CloneExperimentView(ExperimenterSingleExperimentView): def process(self): - return self.experiment.clone() + self.experiment = self.experiment.clone() + return self.experiment def render_to_response(self, context): - return redirect('core:dashboard') + return redirect('core:monitor_experiment', pk=self.experiment.pk) class ClearParticipantsExperimentView(ExperimenterSingleExperimentView): def process(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-21 07:40:13
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/7f7cd79155ad/ changeset: 7f7cd79155ad user: alllee date: 2013-03-21 08:39:53 summary: sendUpdateEvent needs to be embedded in the callback function. JS needs some refactoring, looks like we can merge the various confirmAction click bindings into a single confirmExperimentAction click binding and parameterize them at the DOM data-bind site create_round_data now get_or_creates participant ready parameters to avoid creating duplicates affected #: 4 files diff -r fda36cbf963bad78b3dfc3117af3dc0553ce1bee -r 7f7cd79155ad634a78404fa2a4f8ed2aa12576e1 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -500,6 +500,7 @@ case 'update': $('#progress-modal').modal('show'); experimentModel.update(); + break; default: console.debug("unhandled json message:" + json); break; diff -r fda36cbf963bad78b3dfc3117af3dc0553ce1bee -r 7f7cd79155ad634a78404fa2a4f8ed2aa12576e1 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -55,6 +55,7 @@ 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)) # FIXME: need to distinguish between instructions / welcome rounds and practice/regular rounds diff -r fda36cbf963bad78b3dfc3117af3dc0553ce1bee -r 7f7cd79155ad634a78404fa2a4f8ed2aa12576e1 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -12,7 +12,6 @@ from django.template.defaultfilters import slugify from django.template import Context from django.template.loader import select_template -from django.utils.html import escape from django.utils.translation import ugettext_lazy as _ from model_utils import Choices from model_utils.managers import InheritanceManager, PassThroughManager @@ -151,7 +150,6 @@ class Meta: abstract = True - class Experimenter(CommonsUser): approved = models.BooleanField(default=False) class Meta: @@ -760,8 +758,8 @@ # create participant ready data values for every round in experimenter driven experiments logger.debug("creating participant ready participant round data values") for pgr in self.participant_group_relationships: - ParticipantRoundDataValue.objects.create(participant_group_relationship=pgr, boolean_value=False, - parameter=get_participant_ready_parameter(), round_data=round_data) + ParticipantRoundDataValue.objects.get_or_create(participant_group_relationship=pgr, + parameter=get_participant_ready_parameter(), round_data=round_data, defaults={'boolean_value': False}) if not created: logger.debug("already created round data: %s", round_data) return round_data diff -r fda36cbf963bad78b3dfc3117af3dc0553ce1bee -r 7f7cd79155ad634a78404fa2a4f8ed2aa12576e1 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -14,8 +14,8 @@ <div class='btn-group'><a class='btn btn-success' data-bind="click: confirmExperimentAction, css: { disabled: isRoundInProgress }" data-action='start_round' data-content='Starts the round.'><i class='icon-play'></i> start</a><a class='btn btn-success' data-bind='click: advanceToNextRound' data-action='advance_to_next_round' data-content='Advances to and starts the next round.'><i class='icon-step-forward'></i> next round</a> - <a class='btn btn-success' data-bind='click: refreshAllParticipants' data-content='Sends a page refresh to all connected participants.' ><i class='icon-exchange'></i> refresh participants</a> - <a class='btn btn-primary' data-bind='click: update' data-content='Refresh this page with the latest data from the server.' ><i class='icon-refresh'></i> update</a> + <a class='btn btn-success' data-bind='click: refreshAllParticipants' data-content='Sends a page refresh to all connected participants.' ><i class='icon-exchange'></i> refresh participants</a>--> + <a class='btn btn-primary' data-bind='click: update' data-content='Refresh this page with the latest data from the server.' ><i class='icon-refresh'></i></a><a class='btn btn-danger' data-bind='click: confirmExperimentAction' data-action='deactivate' data-content='Deactivates this experiment.'><i class='icon-off'></i></a></div></div> @@ -188,7 +188,6 @@ Dajaxice.vcweb.core.get_experiment_model(update(model), {pk: {{experiment.pk}}}); } model.confirmExperimentAction = function(experimentModel, evt) { - console.debug(evt.target); confirmExperimentControllerAction(evt.target, model); } model.advanceToNextRound = function(localModel, evt) { @@ -199,11 +198,11 @@ } }); }; - model.refreshAllParticipants = function(model, evt) { + model.refreshAllParticipants = function(localModel, evt) { confirmAction(evt.target, function(confirmed, action) { if (confirmed) { - console.debug("sending refresh event"); - sendRefreshEvent(); + console.debug("sending update event"); + sendUpdateEvent(); } }); } @@ -218,10 +217,13 @@ function confirmExperimentControllerAction(element, experimentModel, callback) { confirmAction(element, function(confirmed, action) { $('#progress-modal').modal('show'); - Dajaxice.vcweb.core.experiment_controller(update(experimentModel), {pk: {{experiment.pk}}, 'action':action}); - if (callback) { - callback(confirmed, action); - } + Dajaxice.vcweb.core.experiment_controller(function(data) { + ko.mapping.fromJS(data, experimentModel); + if (callback) { + callback(confirmed, action); + } + $('#progress-modal').modal('hide'); + }, {pk: {{experiment.pk}}, 'action':action}); }); } function confirmAction(element, callback) { @@ -240,8 +242,6 @@ } function update(experimentModel) { return function(data) { - ko.mapping.fromJS(data, experimentModel); - $('#progress-modal').modal('hide'); } } function initialize(experimentModelJson) { 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-21 00:18:14
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/fda36cbf963b/ changeset: fda36cbf963b user: alllee date: 2013-03-21 01:18:13 summary: no need to escape text in Python as KO already does that via the text binding affected #: 1 file diff -r 7d3ba834b10c9b0bd7d415e9cc447ed67c377724 -r fda36cbf963bad78b3dfc3117af3dc0553ce1bee vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -852,7 +852,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'] = [escape(log) for log in self.activity_log_set.order_by('-date_created')] + experiment_dict['messages'] = [unicode(log) for log in self.activity_log_set.order_by('-date_created')] experiment_dict['experimenterNotes'] = self.current_round_data.experimenter_notes return experiment_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: <com...@bi...> - 2013-03-21 00:06:29
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/7d3ba834b10c/ changeset: 7d3ba834b10c user: alllee date: 2013-03-21 01:02:25 summary: replacing jquery .on with ko click bindings to avoid issues with the dynamic DOM not replacing the event handlers properly affected #: 6 files diff -r da8dc042e5ba1444e21a2ef597e8f1fc5aa29508 -r 7d3ba834b10c9b0bd7d415e9cc447ed67c377724 vcweb/core/forms.py --- a/vcweb/core/forms.py +++ b/vcweb/core/forms.py @@ -153,6 +153,11 @@ heading = forms.FloatField(required=False) speed = forms.FloatField(required=False) +class ExperimentActionForm(forms.Form): + action = forms.CharField(max_length=64) + experiment_id = forms.IntegerField(widget=forms.HiddenInput) + experimenter_id = forms.IntegerField(widget=forms.HiddenInput) + class LikeForm(forms.Form): target_id = forms.IntegerField(widget=forms.HiddenInput) participant_group_id = forms.IntegerField(widget=forms.HiddenInput) diff -r da8dc042e5ba1444e21a2ef597e8f1fc5aa29508 -r 7d3ba834b10c9b0bd7d415e9cc447ed67c377724 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -393,6 +393,10 @@ return "/%s/configure" % self.get_absolute_url() @property + def monitor_url(self): + return "%s/monitor" % self.controller_url + + @property def complete_url(self): return "%s/complete" % self.controller_url @@ -401,11 +405,6 @@ return "%s/deactivate" % self.controller_url @property - def monitor_url(self): - return "%s/monitor" % self.controller_url - -# FIXME: deprecate and remove this, should be a POST not a GET - @property def clone_url(self): return "%s/clone" % self.controller_url @@ -740,7 +739,7 @@ self.save() def invoke(self, action_name): - if action_name in ('advance_to_next_round', 'end_round', 'start_round', 'activate', 'complete'): + if action_name in ('advance_to_next_round', 'end_round', 'start_round', 'activate', 'deactivate', 'complete'): getattr(self, action_name)() else: raise AttributeError("Invalid experiment action %s requested of experiment %s" % (action_name, self)) @@ -796,7 +795,9 @@ return signals.round_ended.send_robust(sender, experiment=self, round_configuration=self.current_round) def activate(self): - if not self.is_active: + if self.is_archived: + logger.debug("ignoring request to activate archived experiment, need manual intervention to perform this as it would wipe existing data.") + elif not self.is_active: self.allocate_groups() self.status = Experiment.Status.ACTIVE self.start_date_time = datetime.now() diff -r da8dc042e5ba1444e21a2ef597e8f1fc5aa29508 -r 7d3ba834b10c9b0bd7d415e9cc447ed67c377724 vcweb/core/templates/experimenter/dashboard.html --- a/vcweb/core/templates/experimenter/dashboard.html +++ b/vcweb/core/templates/experimenter/dashboard.html @@ -3,7 +3,7 @@ {% block page %} {{ block.super }} <h3>Experimenter Dashboard</h3> -{% comment %} FIXME: going to need to refine this UI as the list of experiments grows {% endcomment %} +{% comment %} FIXME: UI refinement needed as the list of experiments grows {% endcomment %} <div id="experiment-list"> {% for e in experiments %} <div class='alert alert-message'> @@ -24,8 +24,8 @@ <i class='icon-trash'></i> clear all participants</a></li> {% endif %} {% if e.is_active %} - <a data-content='Mark this experiment as completed' href='{{e.complete_url}}' class='btn confirm-experiment-action'><i class='icon-save'></i> archive</a> - <a data-content='deactivate this experiment' href='{{e.deactivate_url}}' class='btn confirm-experiment-action'><i class='icon-off'></i> deactivate</a> + <a data-action='complete' data-content='Mark this experiment as completed' href='{{e.complete_url}}' class='btn confirm-experiment-action'><i class='icon-save'></i> archive</a> + <a data-action='deactivate' data-content='deactivate this experiment' href='{{e.deactivate_url}}' class='btn confirm-experiment-action'><i class='icon-off'></i> deactivate</a> {% else %} <a class='btn' data-content='Configure this experiment' href='{{e.configure_url}}'><i class='icon-wrench'></i> configure</a> {% endif %} @@ -43,25 +43,21 @@ {{ block.super }} <script type='text/javascript'> $(function() { - $('.confirm-experiment-action', $('#experiment-list')).each(function() { - var confirmable = $(this); - var description = confirmable.attr("data-content"); - confirmable.click(function() { - confirmable.fastConfirm({ - questionText: description + " Continue?", - onProceed: function(trigger) { - $(trigger).fastConfirm('close'); - window.location = $(trigger).attr("href"); - }, - onCancel: function(trigger) { - $(trigger).fastConfirm('close'); - } - }); + $('a.confirm-experiment-action').on("click", function(evt) { + evt.preventDefault(); + var self = $(this); + var description = self.attr("data-content"); + var href = self.attr("href"); + if (self.hasClass('disabled')) { + console.debug("disabled action " + action + " - ignoring"); return false; + } + bootbox.confirm(description + " Continue?", function(confirmed) { + if (confirmed) { + window.location = self.attr("href"); + } }); - }); - $('.experiment-menu').each(function() { - $(this).find('li:last a').attr('style', 'background-image: none;'); + return false; }); }); </script> diff -r da8dc042e5ba1444e21a2ef597e8f1fc5aa29508 -r 7d3ba834b10c9b0bd7d415e9cc447ed67c377724 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -12,10 +12,11 @@ <li><div class='btn-toolbar'><div class='btn-group'> - <a class='btn btn-success confirm-experiment-action' data-bind="css: { disabled: isRoundInProgress }" data-action='start_round' data-content='Starts the round.'><i class='icon-play'></i> start</a> + <a class='btn btn-success' data-bind="click: confirmExperimentAction, css: { disabled: isRoundInProgress }" data-action='start_round' data-content='Starts the round.'><i class='icon-play'></i> start</a><a class='btn btn-success' data-bind='click: advanceToNextRound' data-action='advance_to_next_round' data-content='Advances to and starts the next round.'><i class='icon-step-forward'></i> next round</a><a class='btn btn-success' data-bind='click: refreshAllParticipants' data-content='Sends a page refresh to all connected participants.' ><i class='icon-exchange'></i> refresh participants</a><a class='btn btn-primary' data-bind='click: update' data-content='Refresh this page with the latest data from the server.' ><i class='icon-refresh'></i> update</a> + <a class='btn btn-danger' data-bind='click: confirmExperimentAction' data-action='deactivate' data-content='Deactivates this experiment.'><i class='icon-off'></i></a></div></div></li> @@ -35,25 +36,22 @@ </div></div><div data-bind="if: hasParticipants"> - <div class='alert alert-info alert-block'> - <h3>Inactive Experiment</h3> + <div class='alert alert-message'> + <h4>Inactive Experiment</h4><p> There are <span data-bind='text:participantCount' class='badge badge-info'></span> registered participants. - Activate the experiment whenever you are ready to collect data. (NOTE: this will wipe away any - existing data). + You can activate the experiment whenever you are ready to collect data. </p> - </div> - <div class='btn-toolbar'> - <div class='btn-group'> - <a data-content='Activate to begin collecting data for this experiment.' - class='btn btn-success confirm-experiment-action' data-action='activate'><i class='icon-off'></i> activate</a> - </div> + <p class='text-error'>NOTE: activating an experiment <b>will delete all existing data</b> + </p> + <a data-content='Starts this experiment, assigns participants to groups, etc.' + class='btn btn-success' data-bind='click: confirmExperimentAction' data-action='activate'><i class='icon-off'></i> activate</a></div></div></div><ul class='nav nav-list'><li class='nav-header'>round status</li> - <li><span data-bind='text:roundSequenceLabel'></span></li> + <li><b class='text-info' data-bind='text:roundSequenceLabel'></b></li><li><span data-bind='text:roundStatusLabel'></span></li><li>Experiment started on: <span data-bind='text:currentRoundStartTime'></span></li><li>Time remaining: <span data-bind='text:timeRemaining'></span></li> @@ -70,7 +68,7 @@ <li><a href='export/configuration.xml'><i class='icon-cog'></i>xml</a></li><li><a href='export/configuration.json'><i class='icon-pencil'></i>json</a></li></ul> - <a class='btn btn-danger confirm-experiment-action' data-action='complete' data-content='Mark this experiment as completed and archive it.'><i class='icon-save'></i> archive</a> + <a class='btn btn-danger' data-bind='click: confirmExperimentAction' data-action='complete' data-content='Mark this experiment as completed and archive it.'><i class='icon-save'></i> archive</a></div></div><div class='span6'> @@ -189,6 +187,10 @@ $('#progress-modal').modal('show'); Dajaxice.vcweb.core.get_experiment_model(update(model), {pk: {{experiment.pk}}}); } + model.confirmExperimentAction = function(experimentModel, evt) { + console.debug(evt.target); + confirmExperimentControllerAction(evt.target, model); + } model.advanceToNextRound = function(localModel, evt) { confirmExperimentControllerAction(evt.target, model, function(confirmed) { if (confirmed) { @@ -198,7 +200,7 @@ }); }; model.refreshAllParticipants = function(model, evt) { - confirmExperimentAction(evt.target, function(confirmed, action) { + confirmAction(evt.target, function(confirmed, action) { if (confirmed) { console.debug("sending refresh event"); sendRefreshEvent(); @@ -214,7 +216,7 @@ return model; } function confirmExperimentControllerAction(element, experimentModel, callback) { - confirmExperimentAction(element, function(confirmed, action) { + confirmAction(element, function(confirmed, action) { $('#progress-modal').modal('show'); Dajaxice.vcweb.core.experiment_controller(update(experimentModel), {pk: {{experiment.pk}}, 'action':action}); if (callback) { @@ -222,7 +224,7 @@ } }); } - function confirmExperimentAction(element, callback) { + function confirmAction(element, callback) { var self = $(element); var description = self.attr("data-content"); var action = self.attr("data-action"); @@ -252,11 +254,6 @@ console.log("Received event: " + evt); experimentModel.addMessage(jQuery.parseJSON(evt.data)); }; - $('a.confirm-experiment-action').on("click", function(evt) { - evt.preventDefault(); - confirmExperimentControllerAction(this, experimentModel); - return false; - }); return experimentModel; } $('[data-content]').popover({placement: 'top', trigger: 'hover'}); diff -r da8dc042e5ba1444e21a2ef597e8f1fc5aa29508 -r 7d3ba834b10c9b0bd7d415e9cc447ed67c377724 vcweb/core/urls.py --- a/vcweb/core/urls.py +++ b/vcweb/core/urls.py @@ -3,7 +3,7 @@ from vcweb import settings from vcweb.core.views import (Dashboard, LoginView, LogoutView, RegistrationView, monitor, CloneExperimentView, RegisterEmailListView, RegisterSimpleParticipantsView, ClearParticipantsExperimentView, add_experiment, - Participate, download_data, export_configuration, api_logger, participant_ready) + Participate, download_data, export_configuration, api_logger, participant_ready, deactivate) import logging import urllib @@ -25,6 +25,8 @@ 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'), + # 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'), url(r'^experiment/(?P<pk>\d+)/clear-participants', ClearParticipantsExperimentView.as_view(), name='clear_participants'), # url(r'^experiment/(?P<pk>\d+)/add-participants/(?P<count>[\d]+)$', 'add_participants', name='add_participants'), diff -r da8dc042e5ba1444e21a2ef597e8f1fc5aa29508 -r 7d3ba834b10c9b0bd7d415e9cc447ed67c377724 vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -90,7 +90,7 @@ def get_queryset(self): user = self.request.user if is_experimenter(user): - return Experiment.objects.filter(experimenter__pk=self.request.user.experimenter.pk) + return Experiment.objects.select_related('experimenter', 'experiment_metadata', 'experiment_configuration').filter(experimenter__pk=self.request.user.experimenter.pk) else: # nested dictionary, {ExperimentMetadata -> { status -> [experiments,...] }} # FIXME: could also use collections.defaultdict or regroup template tag to @@ -265,7 +265,7 @@ self.experiment = self.object = self.get_object() self.process() context = self.get_context_data(object=self.object) - return self.render(request, context) + return self.render_to_response(context) def monitor(request, pk=None): experiment = get_object_or_404(Experiment.objects.select_related('experiment_configuration', 'experimenter'), pk=pk) @@ -466,6 +466,16 @@ logger.warning(e) @experimenter_required +def deactivate(request, pk=None): + experiment = get_object_or_404(Experiment, pk=pk) + experimenter = request.user.experimenter + if experimenter == experiment.experimenter: + experiment.deactivate() + return redirect('core:monitor_experiment', pk=pk) + logger.warning("Invalid experiment deactivation request for %s by %s", experiment, experimenter) + return redirect('core:dashboard') + +@experimenter_required def experiment_controller(request, pk=None, experiment_action=None): try: experimenter = request.user.experimenter 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-20 22:14:30
|
2 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/e16bd8473799/ changeset: e16bd8473799 user: alllee date: 2013-03-20 22:54:35 summary: experimenter notes now fully functional on the monitor page affected #: 6 files diff -r 898a737430938ef8b03991a745c2247fa4a0d203 -r e16bd84737999a18f46363ff77e15594a8281510 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -1,5 +1,5 @@ from django.http import Http404 -from django.shortcuts import render_to_response, redirect, get_object_or_404 +from django.shortcuts import render, redirect, get_object_or_404 from django.template.context import RequestContext from vcweb.core import dumps from vcweb.core.decorators import participant_required @@ -24,14 +24,13 @@ raise Http404 # sends view model JSON to the template to be processed by knockout - return render_to_response('boundaries/participate.html', { + return render(request, 'boundaries/participate.html', { 'auth_token': participant.authentication_token, 'experiment': experiment, 'participant_experiment_relationship': experiment.get_participant_experiment_relationship(participant), 'participant_group_relationship': pgr, 'experimentModelJson': get_view_model_json(experiment, pgr), - }, - context_instance=RequestContext(request)) + }) @participant_required def submit_harvest_decision(request, experiment_id=None): diff -r 898a737430938ef8b03991a745c2247fa4a0d203 -r e16bd84737999a18f46363ff77e15594a8281510 vcweb/core/ajax.py --- a/vcweb/core/ajax.py +++ b/vcweb/core/ajax.py @@ -87,10 +87,13 @@ @experimenter_required @dajaxice_register -def submit_experimenter_notes(request, experiment_id, notes=None): +def save_experimenter_notes(request, experiment_id, notes=None): experiment = _get_experiment(request, experiment_id) - if notes: - current_round_data = experiment.current_round_data + current_round_data = experiment.current_round_data + current_experimenter_notes = current_round_data.experimenter_notes + if notes and notes != current_round_data.experimenter_notes: + if current_experimenter_notes: + experiment.log("Replacing existing experimenter notes: %s" % current_experimenter_notes) current_round_data.experimenter_notes = notes current_round_data.save() return dumps({ 'success': True }) diff -r 898a737430938ef8b03991a745c2247fa4a0d203 -r e16bd84737999a18f46363ff77e15594a8281510 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -827,6 +827,7 @@ rc = round_data.round_configuration all_round_data.append({ 'roundDataId': "roundData_%s" % round_data.pk, + 'experimenterNotes': round_data.experimenter_notes, 'roundType': rc.get_round_type_display(), 'roundNumber':rc.round_number, 'groupDataValues': group_data_values, diff -r 898a737430938ef8b03991a745c2247fa4a0d203 -r e16bd84737999a18f46363ff77e15594a8281510 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -79,11 +79,14 @@ <span data-bind='text: $data'></span></div></div> - <h4>Notes</h4> - <form id="experimenterLogForm" class='form-horizontal'> - <div class='controls-row'> + {% comment %} + FIXME: might want to put this functionality into each round data object + {% endcomment %} + <h4>Experimenter Notes (<span data-bind='text: roundSequenceLabel'></span>)</h4> + <form id="experimenterNotesForm" class='form-inline'> + <div class='controls'><textarea class='input-block-level' id='experimenterNotes' data-bind='text: experimenterNotes' placeholder="Experimenter notes to be stored with this round's data" rows="3" id='experimenterNote'></textarea> - <button id='submitExperimenterNotesButton' class='btn btn-primary' type='submit' data-bind='click: submitExperimenterNotes'>Save</button> + <button id='submitExperimenterNotesButton' class='btn btn-primary' type='submit' data-bind='click: saveExperimenterNotes'>Save</button></div></form></div> @@ -99,6 +102,11 @@ </div><div data-bind='attr: { id: roundDataId }' class='accordion-body collapse'><div class='accordion-inner'> + <div data-bind='if: experimenterNotes'> + <h4>Experimenter Notes</h4> + <div class='alert alert-message' data-bind='text: experimenterNotes'> + </div> + </div><table class='table table-striped table-bordered'><caption>Group data</caption><thead> @@ -161,14 +169,14 @@ {% include "includes/experimenter.events.html" %} {% include "includes/sockjs.html" %} <script type='text/javascript'> - var experimentModelJson = $.parseJSON("{{ experiment.to_json|escapejs }}"); + var experimentModelJson = $.parseJSON("{{ experimentModelJson|escapejs }}"); $(function() { function ExperimentModel(experimentModelJson) { var self = this; var model = ko.mapping.fromJS(experimentModelJson); - model.submitExperimenterNotes = function(localModel, evt) { + model.saveExperimenterNotes = function(localModel, evt) { var notes = $('#experimenterNotes').val(); - Dajaxice.vcweb.core.submit_experimenter_notes(function(data) { + Dajaxice.vcweb.core.save_experimenter_notes(function(data) { if (data.success) { $('#submitExperimenterNotesButton').val('Saved!'); } diff -r 898a737430938ef8b03991a745c2247fa4a0d203 -r e16bd84737999a18f46363ff77e15594a8281510 vcweb/core/urls.py --- a/vcweb/core/urls.py +++ b/vcweb/core/urls.py @@ -1,7 +1,7 @@ from django.conf.urls.defaults import patterns, url from django.contrib.auth.decorators import login_required from vcweb import settings -from vcweb.core.views import (Dashboard, LoginView, LogoutView, RegistrationView, MonitorExperimentView, CloneExperimentView, +from vcweb.core.views import (Dashboard, LoginView, LogoutView, RegistrationView, monitor, CloneExperimentView, RegisterEmailListView, RegisterSimpleParticipantsView, ClearParticipantsExperimentView, add_experiment, Participate, download_data, export_configuration, api_logger, participant_ready) @@ -22,7 +22,7 @@ url(r'^participate/(?P<namespace>\w+)/instructions', 'instructions', name='namespace_instructions'), url(r'^experiment/add$', add_experiment, name='add_experiment'), url(r'^experiment/participant-ready$', participant_ready, name='participant_ready'), - url(r'^experiment/(?P<pk>\d+)/monitor$', MonitorExperimentView.as_view(), name='monitor_experiment'), + 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+)/clone$', CloneExperimentView.as_view(), name='clone'), diff -r 898a737430938ef8b03991a745c2247fa4a0d203 -r e16bd84737999a18f46363ff77e15594a8281510 vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -3,7 +3,7 @@ from django.core.urlresolvers import reverse from django.core.exceptions import PermissionDenied from django.http import HttpResponse, Http404 -from django.shortcuts import render_to_response, redirect, get_object_or_404 +from django.shortcuts import render, redirect, get_object_or_404 from django.template.context import RequestContext from django.utils.decorators import method_decorator from django.views.generic import ListView, FormView, TemplateView @@ -199,7 +199,7 @@ form = ParticipantAccountForm() else: form = ExperimenterAccountForm(instance=user.experimenter) - return render_to_response('account/profile.html', { 'form': form }, context_instance=RequestContext(request)) + return render(request, 'account/profile.html', { 'form': form }) ''' participant views ''' class ParticipantMixin(object): @@ -210,8 +210,7 @@ @login_required def instructions(request, namespace=None): if namespace is not None: - return render_to_response('%s/instructions.html' % namespace, - context_instance=RequestContext(request)) + return render(request, '%s/instructions.html' % namespace) else: return redirect('home') @@ -241,7 +240,7 @@ def get_object(self, queryset=None): pk = self.kwargs.get('pk', None) - experiment = get_object_or_404(Experiment, pk=pk) + experiment = get_object_or_404(Experiment.objects.select_related('experiment_metadata', 'experiment_configuration', 'experimenter'), pk=pk) return self.check_user(experiment) class ParticipantSingleExperimentMixin(SingleExperimentMixin, ParticipantMixin): @@ -266,10 +265,14 @@ self.experiment = self.object = self.get_object() self.process() context = self.get_context_data(object=self.object) - return self.render_to_response(context) + return self.render(request, context) -class MonitorExperimentView(ExperimenterSingleExperimentMixin, DetailView): - template_name = 'experimenter/monitor.html' +def monitor(request, pk=None): + experiment = get_object_or_404(Experiment.objects.select_related('experiment_configuration', 'experimenter'), pk=pk) + return render(request, 'experimenter/monitor.html', { + 'experiment': experiment, + 'experimentModelJson': experiment.to_json(), + }) def upload_excel_participants_file(request): if request.method == 'POST': @@ -340,9 +343,8 @@ @experimenter_required def add_experiment(request): - return render_to_response('experimenter/add-experiment.html', - { 'experiment_list': ExperimentMetadata.objects.all() }, - context_instance=RequestContext(request)) + return render('experimenter/add-experiment.html', + { 'experiment_list': ExperimentMetadata.objects.all() }) class DataExportMixin(ExperimenterSingleExperimentMixin): file_extension = '.csv' @@ -531,6 +533,5 @@ return JsonResponse(dumps({'success': valid_form})) def handler500(request): - logger.debug("handling 500 request") - return render_to_response('500.html', context_instance=RequestContext(request)) + return render(request, '500.html') https://bitbucket.org/virtualcommons/vcweb/commits/da8dc042e5ba/ changeset: da8dc042e5ba user: alllee date: 2013-03-20 23:14:28 summary: adding experimenter update function affected #: 2 files diff -r e16bd84737999a18f46363ff77e15594a8281510 -r da8dc042e5ba1444e21a2ef597e8f1fc5aa29508 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -1270,8 +1270,7 @@ 'date_created': self.date_created, 'short_date_created': self.date_created.strftime('%I:%M:%S'), 'parameter_name': p.name, - 'parameter_label': p.label, - 'parameter': self.parameter + 'parameter_label': p.label } data['value'] = unicode(self.cached_value if cacheable else self.value) return data diff -r e16bd84737999a18f46363ff77e15594a8281510 -r da8dc042e5ba1444e21a2ef597e8f1fc5aa29508 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -14,7 +14,8 @@ <div class='btn-group'><a class='btn btn-success confirm-experiment-action' data-bind="css: { disabled: isRoundInProgress }" data-action='start_round' data-content='Starts the round.'><i class='icon-play'></i> start</a><a class='btn btn-success' data-bind='click: advanceToNextRound' data-action='advance_to_next_round' data-content='Advances to and starts the next round.'><i class='icon-step-forward'></i> next round</a> - <a class='btn btn-success' data-bind='click: refreshAllParticipants' data-content='Sends a page refresh to all connected participants.' ><i class='icon-refresh'></i> refresh participants</a> + <a class='btn btn-success' data-bind='click: refreshAllParticipants' data-content='Sends a page refresh to all connected participants.' ><i class='icon-exchange'></i> refresh participants</a> + <a class='btn btn-primary' data-bind='click: update' data-content='Refresh this page with the latest data from the server.' ><i class='icon-refresh'></i> update</a></div></div></li> @@ -85,7 +86,7 @@ <h4>Experimenter Notes (<span data-bind='text: roundSequenceLabel'></span>)</h4><form id="experimenterNotesForm" class='form-inline'><div class='controls'> - <textarea class='input-block-level' id='experimenterNotes' data-bind='text: experimenterNotes' placeholder="Experimenter notes to be stored with this round's data" rows="3" id='experimenterNote'></textarea> + <textarea class='input-block-level' id='experimenterNotes' data-bind='text: experimenterNotes' placeholder="Experimenter notes to be stored with this round's data" rows="3"></textarea><button id='submitExperimenterNotesButton' class='btn btn-primary' type='submit' data-bind='click: saveExperimenterNotes'>Save</button></div></form> @@ -169,6 +170,7 @@ {% include "includes/experimenter.events.html" %} {% include "includes/sockjs.html" %} <script type='text/javascript'> +// FIXME: we should verify if exposing this here is the "right" thing to do. var experimentModelJson = $.parseJSON("{{ experimentModelJson|escapejs }}"); $(function() { function ExperimentModel(experimentModelJson) { @@ -181,7 +183,11 @@ $('#submitExperimenterNotesButton').val('Saved!'); } }, - { 'experiment_id': {{ experiment.pk }}, 'notes': notes }); + { experiment_id: {{ experiment.pk }}, notes: notes }); + } + model.update = function(localModel, evt) { + $('#progress-modal').modal('show'); + Dajaxice.vcweb.core.get_experiment_model(update(model), {pk: {{experiment.pk}}}); } model.advanceToNextRound = function(localModel, evt) { confirmExperimentControllerAction(evt.target, model, function(confirmed) { @@ -210,7 +216,7 @@ function confirmExperimentControllerAction(element, experimentModel, callback) { confirmExperimentAction(element, function(confirmed, action) { $('#progress-modal').modal('show'); - Dajaxice.vcweb.core.experiment_controller(update(experimentModel), {'pk': {{experiment.pk}}, 'action':action}); + Dajaxice.vcweb.core.experiment_controller(update(experimentModel), {pk: {{experiment.pk}}, 'action':action}); if (callback) { callback(confirmed, action); } 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-20 20:34:00
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/898a73743093/ changeset: 898a73743093 user: alllee date: 2013-03-20 21:33:59 summary: removing static dajaxice js file and wiring up experimenter notes affected #: 8 files diff -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 -r 898a737430938ef8b03991a745c2247fa4a0d203 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' @@ -136,8 +136,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(): diff -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 -r 898a737430938ef8b03991a745c2247fa4a0d203 vcweb/core/ajax.py --- a/vcweb/core/ajax.py +++ b/vcweb/core/ajax.py @@ -76,7 +76,7 @@ return HttpResponse(render_template_block(t, block, c), mimetype=mimetype) def _get_experiment(request, pk): - experiment = get_object_or_404(Experiment, pk=pk) + experiment = get_object_or_404(Experiment.objects.select_related('experimenter'), pk=pk) if request.user.experimenter == experiment.experimenter: return experiment raise Experiment.DoesNotExist("Sorry, %s - you do not have access to experiment %s" % (experiment.experimenter, pk)) @@ -87,6 +87,19 @@ @experimenter_required @dajaxice_register +def submit_experimenter_notes(request, experiment_id, notes=None): + experiment = _get_experiment(request, experiment_id) + if notes: + current_round_data = experiment.current_round_data + current_round_data.experimenter_notes = notes + current_round_data.save() + return dumps({ 'success': True }) + else: + return dumps({ 'success': False }) + + +@experimenter_required +@dajaxice_register def get_experiment_model(request, pk): return _get_experiment(request, pk).to_json() @@ -94,14 +107,12 @@ @dajaxice_register def experiment_controller(request, pk, action=None): experiment = _get_experiment(request, pk) - if experiment.experimenter == request.user.experimenter: - try: - experiment.invoke(action) - return experiment.to_json() - except AttributeError as e: - logger.warning("no attribute %s on experiment %s (%s)", action, experiment.status_line, e) - - return dumps({ - 'success': False, - 'message': 'Invalid experiment action %s' % action - }) + try: + experiment.invoke(action) + return experiment.to_json() + except AttributeError as e: + logger.warning("no attribute %s on experiment %s (%s)", action, experiment.status_line, e) + return dumps({ + 'success': False, + 'message': 'Invalid experiment action %s' % action + }) diff -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 -r 898a737430938ef8b03991a745c2247fa4a0d203 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -851,6 +851,7 @@ 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'] = [escape(log) for log in self.activity_log_set.order_by('-date_created')] + experiment_dict['experimenterNotes'] = self.current_round_data.experimenter_notes return experiment_dict def as_dict(self, *args, **kwargs): diff -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 -r 898a737430938ef8b03991a745c2247fa4a0d203 vcweb/core/templates/base.html --- a/vcweb/core/templates/base.html +++ b/vcweb/core/templates/base.html @@ -1,3 +1,4 @@ +{% load dajaxice_templatetags %} {% load tags %} {% load url from future %} {% load static from staticfiles %} @@ -140,12 +141,7 @@ <script type='text/javascript' src='{{STATIC_URL}}js/ko/knockout.mapping.min.js'></script><script type='text/javascript' src='{{STATIC_URL}}js/common.js'></script><script type='text/javascript' src='//cdnjs.cloudflare.com/ajax/libs/d3/3.0.1/d3.v3.min.js'></script> - {% if DEBUG %} - {% load dajaxice_templatetags %} {% dajaxice_js_import %} - {% else %} - <script type='text/javascript' src='{{STATIC_URL}}js/dajaxice.core.js' charset='utf-8'></script> - {% endif %} {% block javascript %} {% endblock %} </footer> diff -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 -r 898a737430938ef8b03991a745c2247fa4a0d203 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -79,6 +79,13 @@ <span data-bind='text: $data'></span></div></div> + <h4>Notes</h4> + <form id="experimenterLogForm" class='form-horizontal'> + <div class='controls-row'> + <textarea class='input-block-level' id='experimenterNotes' data-bind='text: experimenterNotes' placeholder="Experimenter notes to be stored with this round's data" rows="3" id='experimenterNote'></textarea> + <button id='submitExperimenterNotesButton' class='btn btn-primary' type='submit' data-bind='click: submitExperimenterNotes'>Save</button> + </div> + </form></div></div><h3>Experiment Data</h3> @@ -159,6 +166,15 @@ function ExperimentModel(experimentModelJson) { var self = this; var model = ko.mapping.fromJS(experimentModelJson); + model.submitExperimenterNotes = function(localModel, evt) { + var notes = $('#experimenterNotes').val(); + Dajaxice.vcweb.core.submit_experimenter_notes(function(data) { + if (data.success) { + $('#submitExperimenterNotesButton').val('Saved!'); + } + }, + { 'experiment_id': {{ experiment.pk }}, 'notes': notes }); + } model.advanceToNextRound = function(localModel, evt) { confirmExperimentControllerAction(evt.target, model, function(confirmed) { if (confirmed) { diff -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 -r 898a737430938ef8b03991a745c2247fa4a0d203 vcweb/core/urls.py --- a/vcweb/core/urls.py +++ b/vcweb/core/urls.py @@ -3,7 +3,7 @@ from vcweb import settings from vcweb.core.views import (Dashboard, LoginView, LogoutView, RegistrationView, MonitorExperimentView, CloneExperimentView, RegisterEmailListView, RegisterSimpleParticipantsView, ClearParticipantsExperimentView, add_experiment, - Participate, download_data, export_configuration, experiment_controller, api_logger, participant_ready) + Participate, download_data, export_configuration, api_logger, participant_ready) import logging import urllib @@ -31,14 +31,9 @@ url(r'^experiment/(?P<pk>\d+)/download/(?P<file_type>[\w]+)$', download_data, name='download_data'), url(r'^experiment/(?P<pk>\d+)/export/configuration(?P<file_extension>.[\w]+)$', export_configuration, name='export_configuration'), # experiment controller actions are the most general, needs to be matched at the very end - url(r'^experiment/(?P<pk>\d+)/(?P<experiment_action>[\w-]+)$', experiment_controller, name='experiment_controller'), # deliberately match any prefix to api/2525/log url(r'api/log/(?P<participant_group_id>\d+)$', api_logger, name='api-logger'), ) -# add ajax actions -urlpatterns += patterns('vcweb.core.ajax', - url(r'^ajax/(?P<pk>\d+)/(<?P<experiment_action[\w-]+)$', 'experiment_controller'), - ) def foursquare_auth_dict(**kwargs): return dict(kwargs, client_id=settings.FOURSQUARE_CONSUMER_KEY, client_secret=settings.FOURSQUARE_CONSUMER_SECRET, v=settings.FOURSQUARE_CONSUMER_DATE_VERIFIED) diff -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 -r 898a737430938ef8b03991a745c2247fa4a0d203 vcweb/static/js/dajaxice.core.js --- a/vcweb/static/js/dajaxice.core.js +++ /dev/null @@ -1,100 +0,0 @@ -var Dajaxice = { - - vcweb: { - - - - - - core: { - - experiment_controller: function(callback_function, argv){ - Dajaxice.call('vcweb.core.experiment_controller', callback_function, argv); - } - - - - } - - - - } - , - - get_cookie: function(name) - { - var cookieValue = null; - if (document.cookie && document.cookie != '') { - var cookies = document.cookie.split(';'); - for (var i = 0; i < cookies.length; i++) { - var cookie = cookies[i].toString().replace(/^\s+/, "").replace(/\s+$/, ""); - // Does this cookie string begin with the name we want? - if (cookie.substring(0, name.length + 1) == (name + '=')) { - cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); - break; - } - } - } - return cookieValue; - }, - - call: function(dajaxice_function, dajaxice_callback, argv) - { - var send_data = []; - is_callback_a_function = (typeof(dajaxice_callback) == 'function'); - - if (!is_callback_a_function){ - /* Backward compatibility for old callback as string usage. */ - send_data.push('callback='+dajaxice_callback); - } - - send_data.push('argv='+encodeURIComponent(JSON.stringify(argv))); - send_data = send_data.join('&'); - var oXMLHttpRequest = new XMLHttpRequest; - oXMLHttpRequest.open('POST', '/dajaxice/'+dajaxice_function+'/'); - oXMLHttpRequest.setRequestHeader("X-Requested-With", "XMLHttpRequest"); - oXMLHttpRequest.setRequestHeader("X-CSRFToken",Dajaxice.get_cookie('csrftoken')); - oXMLHttpRequest.onreadystatechange = function() { - if (this.readyState == XMLHttpRequest.DONE) { - if (is_callback_a_function){ - try{ - dajaxice_callback(JSON.parse(this.responseText)); - } - catch(exception){ - dajaxice_callback(this.responseText); - } - } - else{ - /* Backward compatibility for old callback as string usage. */ - eval(this.responseText); - } - } - } - oXMLHttpRequest.send(send_data); - } -}; -Dajaxice.EXCEPTION = "DAJAXICE_EXCEPTION"; -window['Dajaxice'] = Dajaxice; - - - -(function(){function b(){this._object=i?new i:new window.ActiveXObject("Microsoft.XMLHTTP");this._listeners=[]}function k(a){b.onreadystatechange&&b.onreadystatechange.apply(a);a.dispatchEvent({type:"readystatechange",bubbles:false,cancelable:false,timeStamp:new Date+0})}function p(a){var c=a.responseXML,d=a.responseText;if(h&&d&&c&&!c.documentElement&&a.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)){c=new window.ActiveXObject("Microsoft.XMLDOM");c.async=false;c.validateOnParse=false; -c.loadXML(d)}if(c)if(h&&c.parseError!=0||!c.documentElement||c.documentElement&&c.documentElement.tagName=="parsererror")return null;return c}function o(a){try{a.responseText=a._object.responseText}catch(c){}try{a.responseXML=p(a._object)}catch(d){}try{a.status=a._object.status}catch(g){}try{a.statusText=a._object.statusText}catch(e){}}function l(a){a._object.onreadystatechange=new window.Function}var i=window.XMLHttpRequest,j=!!window.controllers,h=window.document.all&&!window.opera;if(j&&i.wrapped)b.wrapped= -i.wrapped;b.UNSENT=0;b.OPENED=1;b.HEADERS_RECEIVED=2;b.LOADING=3;b.DONE=4;b.prototype.readyState=b.UNSENT;b.prototype.responseText="";b.prototype.responseXML=null;b.prototype.status=0;b.prototype.statusText="";b.prototype.onreadystatechange=null;b.onreadystatechange=null;b.onopen=null;b.onsend=null;b.onabort=null;b.prototype.open=function(a,c,d,g,e){delete this._headers;if(arguments.length<3)d=true;this._async=d;var f=this,m=this.readyState,n;if(h&&d){n=function(){if(m!=b.DONE){l(f);f.abort()}};window.attachEvent("onunload", -n)}b.onopen&&b.onopen.apply(this,arguments);if(arguments.length>4)this._object.open(a,c,d,g,e);else arguments.length>3?this._object.open(a,c,d,g):this._object.open(a,c,d);if(!j&&!h){this.readyState=b.OPENED;k(this)}this._object.onreadystatechange=function(){if(!(j&&!d)){f.readyState=f._object.readyState;o(f);if(f._aborted)f.readyState=b.UNSENT;else{if(f.readyState==b.DONE){l(f);h&&d&&window.detachEvent("onunload",n)}m!=f.readyState&&k(f);m=f.readyState}}}};b.prototype.send=function(a){b.onsend&&b.onsend.apply(this, -arguments);if(a&&a.nodeType){a=window.XMLSerializer?(new window.XMLSerializer).serializeToString(a):a.xml;this._headers["Content-Type"]||this._object.setRequestHeader("Content-Type","application/xml")}this._object.send(a);if(j&&!this._async){this.readyState=b.OPENED;for(o(this);this.readyState<b.DONE;){this.readyState++;k(this);if(this._aborted)return}}};b.prototype.abort=function(){b.onabort&&b.onabort.apply(this,arguments);if(this.readyState>b.UNSENT)this._aborted=true;this._object.abort();l(this)}; -b.prototype.getAllResponseHeaders=function(){return this._object.getAllResponseHeaders()};b.prototype.getResponseHeader=function(a){return this._object.getResponseHeader(a)};b.prototype.setRequestHeader=function(a,c){if(!this._headers)this._headers={};this._headers[a]=c;return this._object.setRequestHeader(a,c)};b.prototype.addEventListener=function(a,c,d){for(var g=0,e;e=this._listeners[g];g++)if(e[0]==a&&e[1]==c&&e[2]==d)return;this._listeners.push([a,c,d])};b.prototype.removeEventListener=function(a, -c,d){for(var g=0,e;e=this._listeners[g];g++)if(e[0]==a&&e[1]==c&&e[2]==d)break;e&&this._listeners.splice(g,1)};b.prototype.dispatchEvent=function(a){a={type:a.type,target:this,currentTarget:this,eventPhase:2,bubbles:a.bubbles,cancelable:a.cancelable,timeStamp:a.timeStamp,stopPropagation:function(){},preventDefault:function(){},initEvent:function(){}};if(a.type=="readystatechange"&&this.onreadystatechange)(this.onreadystatechange.handleEvent||this.onreadystatechange).apply(this,[a]);for(var c=0,d;d= -this._listeners[c];c++)if(d[0]==a.type&&!d[2])(d[1].handleEvent||d[1]).apply(this,[a])};b.prototype.toString=function(){return"[object XMLHttpRequest]"};b.toString=function(){return"[XMLHttpRequest]"};if(!window.Function.prototype.apply)window.Function.prototype.apply=function(a,c){c||(c=[]);a.__func=this;a.__func(c[0],c[1],c[2],c[3],c[4]);delete a.__func};window.XMLHttpRequest=b})(); - - - - -if(!this.JSON)this.JSON={}; -(function(){function k(a){return a<10?"0"+a:a}function n(a){o.lastIndex=0;return o.test(a)?'"'+a.replace(o,function(c){var d=q[c];return typeof d==="string"?d:"\\u"+("0000"+c.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function l(a,c){var d,f,i=g,e,b=c[a];if(b&&typeof b==="object"&&typeof b.toJSON==="function")b=b.toJSON(a);if(typeof j==="function")b=j.call(c,a,b);switch(typeof b){case "string":return n(b);case "number":return isFinite(b)?String(b):"null";case "boolean":case "null":return String(b);case "object":if(!b)return"null"; -g+=m;e=[];if(Object.prototype.toString.apply(b)==="[object Array]"){f=b.length;for(a=0;a<f;a+=1)e[a]=l(a,b)||"null";c=e.length===0?"[]":g?"[\n"+g+e.join(",\n"+g)+"\n"+i+"]":"["+e.join(",")+"]";g=i;return c}if(j&&typeof j==="object"){f=j.length;for(a=0;a<f;a+=1){d=j[a];if(typeof d==="string")if(c=l(d,b))e.push(n(d)+(g?": ":":")+c)}}else for(d in b)if(Object.hasOwnProperty.call(b,d))if(c=l(d,b))e.push(n(d)+(g?": ":":")+c);c=e.length===0?"{}":g?"{\n"+g+e.join(",\n"+g)+"\n"+i+"}":"{"+e.join(",")+"}"; -g=i;return c}}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+k(this.getUTCMonth()+1)+"-"+k(this.getUTCDate())+"T"+k(this.getUTCHours())+":"+k(this.getUTCMinutes())+":"+k(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()}}var p=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, -o=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,g,m,q={"\u0008":"\\b","\t":"\\t","\n":"\\n","\u000c":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},j;if(typeof JSON.stringify!=="function")JSON.stringify=function(a,c,d){var f;m=g="";if(typeof d==="number")for(f=0;f<d;f+=1)m+=" ";else if(typeof d==="string")m=d;if((j=c)&&typeof c!=="function"&&(typeof c!=="object"||typeof c.length!=="number"))throw new Error("JSON.stringify");return l("", -{"":a})};if(typeof JSON.parse!=="function")JSON.parse=function(a,c){function d(f,i){var e,b,h=f[i];if(h&&typeof h==="object")for(e in h)if(Object.hasOwnProperty.call(h,e)){b=d(h,e);if(b!==undefined)h[e]=b;else delete h[e]}return c.call(f,i,h)}p.lastIndex=0;if(p.test(a))a=a.replace(p,function(f){return"\\u"+("0000"+f.charCodeAt(0).toString(16)).slice(-4)});if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, -"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){a=eval("("+a+")");return typeof c==="function"?d({"":a},""):a}throw new SyntaxError("JSON.parse");}})(); - diff -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 -r 898a737430938ef8b03991a745c2247fa4a0d203 vcweb/urls.py --- a/vcweb/urls.py +++ b/vcweb/urls.py @@ -24,7 +24,7 @@ url(r'^accounts/password_reset/done/$', 'django.contrib.auth.views.password_reset_done', { 'template_name': 'account/password_reset_done.html' }), url(r'^accounts/reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', 'django.contrib.auth.views.password_reset_confirm'), url(r'^accounts/reset/done/$', 'django.contrib.auth.views.password_reset_complete'), - +# dajaxice core url(dajaxice_config.dajaxice_url, include('dajaxice.urls')), # FIXME: ideally this should be set up dynamically by iterating through each @@ -48,8 +48,5 @@ handler500 = 'vcweb.core.views.handler500' if settings.DEBUG: - urlpatterns += patterns('', - (r'^500/$', TemplateView.as_view(template_name='500.html'),), - ) urlpatterns += staticfiles_urlpatterns() 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-20 19:02:12
|
2 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/82148e9a0f1e/ changeset: 82148e9a0f1e user: alllee date: 2013-03-20 19:15:34 summary: refactoring sockjs server, adding broadcast method to send a parameterized message to everyone in the experiment affected #: 1 file diff -r a1dd1c200888f982753d36439d02942166088b96 -r 82148e9a0f1eb69c8cdce15cf38dcef9b97fb997 vcweb/vcweb-sockjs.py --- a/vcweb/vcweb-sockjs.py +++ b/vcweb/vcweb-sockjs.py @@ -71,6 +71,7 @@ return json.dumps({ 'message': message, 'event_type': event_type}) REFRESH_EVENT = json.dumps({ 'event_type': 'refresh' }) +UPDATE_EVENT = json.dumps({ 'event_type': 'update' }) DISCONNECTION_EVENT = create_message_event('Your session has expired and you have been disconnected. You can only have one window open to a vcweb page.') UNAUTHORIZED_EVENT = create_message_event("You do not appear to be authorized to perform this action. If this problem persists, please contact us.") @@ -169,6 +170,9 @@ if participant_tuple in self.participant_to_connection: yield (participant_group_relationship.pk, self.participant_to_connection[participant_tuple]) + ''' + generator function yielding all (participant group relationship id, connection) tuples for the given experiment + ''' def all_participants(self, experimenter, experiment): experimenter_key = (experimenter.pk, experiment.pk) if experimenter_key in self.experimenter_to_connection: @@ -181,23 +185,14 @@ experimenter functions ''' def send_refresh(self, experimenter, experiment): - participant_connections = [] - for (participant_group_pk, connection) in self.all_participants(experimenter, experiment): - logger.debug("sending refresh to %s, %s", participant_group_pk, connection) - participant_connections.append(participant_group_pk) - connection.send(REFRESH_EVENT) - return participant_connections + return self.broadcast(experimenter, experiment, REFRESH_EVENT) - def send_update(self, experimenter, experiment): - pass + def send_update_event(self, experimenter, experiment): + return self.broadcast(experimenter, experiment, UPDATE_EVENT) def send_goto(self, experimenter, experiment, url): - notified_participants = [] message = json.dumps({'event_type': 'goto', 'url': url}) - for (participant_group_pk, connection) in self.all_participants(experimenter, experiment): - connection.send(message) - notified_participants.append(participant_group_pk) - return notified_participants + return self.broadcast(experimenter, experiment, message) def send_to_experimenter(self, json, experiment_id=None, experimenter_id=None, experiment=None): if experimenter_id is None and experiment_id is None: @@ -213,8 +208,16 @@ logger.debug("no experimenter found with pk %s in experimenters set %s", experimenter_tuple, self.experimenter_to_connection) + def broadcast(self, experimenter, experiment, message): + participant_connections = [] + for (participant_group_id, connection) in self.all_participants(experimenter, experiment): + participant_connections.append(participant_group_id) + connection.send(message) + logger.debug("sent message %s to %s", message, participant_connections) + return participant_connections + def send_to_group(self, group, json): - for participant_group_pk, connection in self.connections(group): + for participant_group_id, connection in self.connections(group): connection.send(json) self.send_to_experimenter(json, experiment=group.experiment) @@ -363,7 +366,7 @@ self.send(create_message_event("Refreshed all connected participant pgr_ids=%s)" % notified_participants)) def handle_update_participants(self, event, experiment, experimenter): - notified_participants = connection_manager.send_update(experimenter, experiment) + notified_participants = connection_manager.send_update_event(experimenter, experiment) self.send(create_message_event("Updating all connected participants pgr_ids=%s)" % notified_participants)) def on_close(self): https://bitbucket.org/virtualcommons/vcweb/commits/3aa5801c8f2e/ changeset: 3aa5801c8f2e user: alllee date: 2013-03-20 20:02:06 summary: experimenter now triggering transitions / updates on the client properly, still need to set up timers and fix some issues with invalid data affected #: 5 files diff -r 82148e9a0f1eb69c8cdce15cf38dcef9b97fb997 -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -2,9 +2,9 @@ from vcweb.core import signals, simplecache from vcweb.core.models import ExperimentMetadata, Parameter, ParticipantRoundDataValue from vcweb.forestry.models import (get_harvest_decision_parameter, get_harvest_decision, get_regrowth_rate, - get_group_harvest_parameter, get_resource_level, get_initial_resource_level as forestry_initial_resource_level, - set_resource_level, get_regrowth_parameter, get_resource_level_parameter, has_resource_level, - get_resource_level_dv, get_harvest_decisions, set_group_harvest, set_regrowth) + get_group_harvest_parameter, get_reset_resource_level_parameter, get_resource_level, get_initial_resource_level + as forestry_initial_resource_level, set_resource_level, get_regrowth_parameter, get_resource_level_parameter, + has_resource_level, get_resource_level_dv, get_harvest_decisions, set_group_harvest, set_regrowth) import logging diff -r 82148e9a0f1eb69c8cdce15cf38dcef9b97fb997 -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -48,9 +48,14 @@ {% include "forms/chat-template.html" %} </script><script type='text/html' id='WAITING_ROOM'> -<h3>Waiting Room</h3> +<h3>Waiting for other participants</h3><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 are ready. +</p> +</div></div><div class='progress progress-success progress-striped active'><div class='bar' data-bind='style: { width: readyParticipantsPercentage() + "%" }'></div> @@ -386,8 +391,6 @@ $.post('/experiment/participant-ready', { participant_group_id: {{ participant_group_relationship.pk }} }, function(response) { console.debug("successfully posted to server, notifying sockjs: " + response); getWebSocket().send(createMessageEvent("Instructions completed", "client_ready")); - // FIXME: transition to a waiting screen - model.readyParticipant(); model.activateWaitingRoomPage(); }); } diff -r 82148e9a0f1eb69c8cdce15cf38dcef9b97fb997 -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -11,7 +11,6 @@ get_cost_of_living, get_resource_level, get_initial_resource_level, get_total_storage, get_storage, get_last_harvest_decision, can_observe_other_group) import logging -import random logger = logging.getLogger(__name__) @@ -55,7 +54,7 @@ @participant_required def get_view_model(request, experiment_id=None): - experiment = get_object_or_404(Experiment.select_related('experiment_metadata', 'experiment_configuration'), 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(request.user.participant) return JsonResponse(get_view_model_json(experiment, pgr)) @@ -72,13 +71,17 @@ regrowth_rate = get_regrowth_rate(current_round) cost_of_living = get_cost_of_living(current_round) experiment_model_dict['readyParticipants'] = experiment.ready_participants - experiment_model_dict['participantsPerGroup'] = ec.max_group_size - experiment_model_dict['regrowthRate'] = regrowth_rate experiment_model_dict['costOfLiving'] = cost_of_living +# instructions round parameters + if current_round.is_instructions_round: + 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['dollarsPerToken'] = float(ec.exchange_rate) + experiment_model_dict['totalNumberOfParticipants'] = experiment.participant_set.count() experiment_model_dict['participantNumber'] = participant_group_relationship.participant_number experiment_model_dict['participantGroupId'] = participant_group_relationship.pk - experiment_model_dict['dollarsPerToken'] = float(ec.exchange_rate) experiment_model_dict['roundType'] = current_round.round_type experiment_model_dict['practiceRound'] = current_round.is_practice_round experiment_model_dict['chatEnabled'] = False @@ -105,11 +108,12 @@ '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['initialResourceLevel'] = get_initial_resource_level(current_round) +# FIXME: this is redundant experiment_model_dict['lastHarvestDecision'] = last_harvest_decision experiment_model_dict['storage'] = get_storage(participant_group_relationship, current_round_data) experiment_model_dict['resourceLevel'] = own_resource_level - if not current_round.is_practice_round and can_observe_other_group(current_round): + experiment_model_dict['canObserveOtherGroup'] = can_observe_other_group(current_round) + if not current_round.is_practice_round and experiment_model_dict['canObserveOtherGroup']: gr = GroupRelationship.objects.select_related('cluster').get(group=own_group) group_data = [] for group in gr.cluster.group_set.all(): diff -r 82148e9a0f1eb69c8cdce15cf38dcef9b97fb997 -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -887,7 +887,8 @@ ordering = ['date_created', 'status'] class RoundConfiguration(models.Model): -# maps round type name to (description, default_template_name) + # FIXME: refactor this into a single data structure + # maps round type name to (description, default_template_name) ROUND_TYPES_DICT = dict( WELCOME=('Initial welcome round', 'welcome.html'), GENERAL_INSTRUCTIONS=('General instructions round (introduction)', 'general-instructions.html'), @@ -899,8 +900,8 @@ QUIZ=('Quiz round', 'quiz.html')) ROUND_TYPES = (CHAT, DEBRIEFING, GENERAL_INSTRUCTIONS, INSTRUCTIONS, PRACTICE, QUIZ, REGULAR, WELCOME) = sorted(ROUND_TYPES_DICT.keys()) - ROUND_TYPE_CHOICES = Choices(*[(round_type, ROUND_TYPES_DICT[round_type][0]) for round_type in ROUND_TYPES]) - PLAYABLE_ROUND_CONFIGURATIONS = (PRACTICE, REGULAR) + RoundType = Choices(*[(round_type, ROUND_TYPES_DICT[round_type][0]) for round_type in ROUND_TYPES]) + PLAYABLE_ROUND_CONFIGURATIONS = (RoundType.PRACTICE, RoundType.REGULAR) experiment_configuration = models.ForeignKey(ExperimentConfiguration, related_name='round_configuration_set') sequence_number = models.PositiveIntegerField(help_text='Used internally to determine the ordering of the rounds in an experiment in ascending order, e.g., 1,2,3,4,5') @@ -919,8 +920,8 @@ debriefing = models.TextField(null=True, blank=True) """ debriefing, if any, to display after the round ends """ round_type = models.CharField(max_length=32, - choices=ROUND_TYPE_CHOICES, - default=REGULAR) + choices=RoundType, + default=RoundType.REGULAR) """ name of a custom template to be used this round. e.g., if set to quiz_2.html in the forestry experiment app, this would be loaded from @@ -982,27 +983,27 @@ @property def is_debriefing_round(self): - return self.round_type == RoundConfiguration.DEBRIEFING + return self.round_type == RoundConfiguration.RoundType.DEBRIEFING @property def is_chat_round(self): - return self.round_type == RoundConfiguration.CHAT + return self.round_type == RoundConfiguration.RoundType.CHAT @property def is_instructions_round(self): - return self.round_type == RoundConfiguration.INSTRUCTIONS + return self.round_type in (RoundConfiguration.RoundType.INSTRUCTIONS, RoundConfiguration.RoundType.GENERAL_INSTRUCTIONS) @property def is_quiz_round(self): - return self.round_type == RoundConfiguration.QUIZ + return self.round_type == RoundConfiguration.RoundType.QUIZ @property def is_practice_round(self): - return self.round_type == RoundConfiguration.PRACTICE + return self.round_type == RoundConfiguration.RoundType.PRACTICE @property def is_regular_round(self): - return self.round_type == RoundConfiguration.REGULAR + return self.round_type == RoundConfiguration.RoundType.REGULAR @property def is_playable_round(self): diff -r 82148e9a0f1eb69c8cdce15cf38dcef9b97fb997 -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 vcweb/forestry/tests.py --- a/vcweb/forestry/tests.py +++ b/vcweb/forestry/tests.py @@ -59,11 +59,11 @@ def test_get_template(self): e = self.experiment - rc = self.create_new_round_configuration(round_type=RoundConfiguration.QUIZ, template_name='quiz_23.html') + rc = self.create_new_round_configuration(round_type=RoundConfiguration.RoundType.QUIZ, template_name='quiz_23.html') e.current_round_sequence_number = rc.sequence_number self.assertEqual(e.current_round_template, 'forestry/quiz_23.html', 'should return specified quiz_template') - rc = self.create_new_round_configuration(round_type=RoundConfiguration.QUIZ) + rc = self.create_new_round_configuration(round_type=RoundConfiguration.RoundType.QUIZ) e.current_round_sequence_number = rc.sequence_number self.assertEqual(e.current_round_template, 'forestry/quiz.html', 'should return default quiz.html') Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
|
From: <com...@bi...> - 2013-03-20 08:41:54
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/a1dd1c200888/ changeset: a1dd1c200888 user: alllee date: 2013-03-20 09:41:39 summary: adding progress modals for participant updates and starting to wire up experimenter->sockjs->client update cycle affected #: 7 files diff -r f51624f9cb1b3b6e07b2e47a3915fde1da36ae34 -r a1dd1c200888f982753d36439d02942166088b96 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -7,6 +7,16 @@ {% block content %} <div data-bind='template: { name: templateName() }'></div> +<div id='progress-modal' class='modal hide fade'> + <div class='model-header'> + <h3>Updating experiment data</h3> + </div> + <div class='modal-body'> + <div class='progress progress-striped active'> + <div id='progress-bar' class='bar' style='width: 100%'></div> + </div> + </div> +</div> {% endblock content %} {% block sidebar %} @@ -433,9 +443,7 @@ var formData = $('#vcweb-form').serialize(); $.post('submit-harvest-decision', formData, function(jsonString) { console.log(jsonString); - // FIXME: should probably update the entire model after we remove the test panel - // update(data.experimentModelJson); - // ko.mapping.fromJSON(data.experimentModelJson, model); + //update($.parseJSON(jsonString.experimentModelJson)); model.secondsLeft(0); model.hasSubmit(true); model.clearCurrentInterval(); @@ -451,6 +459,14 @@ $('#chatText').focus(); } } + model.update = function() { + $.get('view-model', { participant_group_id: {{ participant_group_relationship.pk }} }, function(data) { + console.debug("retrieved view model successfully"); + console.debug(data); + ko.mapping.fromJS(data, model); + $('#progress-modal').modal('hide'); + }); + } model.disableChat = function() { $('#content').removeClass('span6').addClass('span9'); $('#sidebar').removeClass('span6').addClass('span3'); @@ -465,11 +481,6 @@ } return model; } - function update(experimentModel) { - return function(data) { - ko.mapping.fromJS(data, experimentModel); - } - } function initialize(experimentModelJson) { var experimentModel = new ExperimentModel(experimentModelJson); ko.applyBindings(experimentModel); @@ -483,17 +494,18 @@ experimentModel.chatMessages.unshift(data); console.debug("received chat message:" + json); break; + case 'update': + $('#progress-modal').modal('show'); + experimentModel.update(); default: console.debug("unhandled json message:" + json); break; } - update(json); }; $('#harvestDecision').keyup(function() { $('#harvestDecision').val(this.value.match(/\d+/)); }); } - //send the message when submit is clicked var experimentModelJson = $.parseJSON("{{ experimentModelJson|escapejs }}"); initialize(experimentModelJson); }); diff -r f51624f9cb1b3b6e07b2e47a3915fde1da36ae34 -r a1dd1c200888f982753d36439d02942166088b96 vcweb/boundaries/urls.py --- a/vcweb/boundaries/urls.py +++ b/vcweb/boundaries/urls.py @@ -1,10 +1,11 @@ from django.conf.urls.defaults import url, patterns -from vcweb.boundaries.views import (participate, submit_harvest_decision) +from vcweb.boundaries.views import (participate, submit_harvest_decision, get_view_model) urlpatterns = patterns('vcweb.boundaries.views', url(r'^$', 'index', name='index'), url(r'^(?P<experiment_id>\d+)/configure$', 'configure', name='configure'), url(r'^(?P<experiment_id>\d+)/experimenter$', 'monitor_experiment', name='monitor_experiment'), url(r'^(?P<experiment_id>\d+)/participate$', participate, name='participate'), + url(r'^(?P<experiment_id>\d+)/view-model$', get_view_model, name='view_model'), url(r'^(?P<experiment_id>\d+)/submit-harvest-decision$', submit_harvest_decision, name='submit_harvest_decision'), ) diff -r f51624f9cb1b3b6e07b2e47a3915fde1da36ae34 -r a1dd1c200888f982753d36439d02942166088b96 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -53,6 +53,11 @@ logger.debug("field %s had errors %s", field, field.errors) return JsonResponse(dumps({'success': False })) +@participant_required +def get_view_model(request, experiment_id=None): + experiment = get_object_or_404(Experiment.select_related('experiment_metadata', 'experiment_configuration'), pk=experiment_id) + pgr = experiment.get_participant_group_relationship(request.user.participant) + return JsonResponse(get_view_model_json(experiment, pgr)) # FIXME: need to distinguish between instructions / welcome rounds and practice/regular rounds def get_view_model_json(experiment, participant_group_relationship, **kwargs): diff -r f51624f9cb1b3b6e07b2e47a3915fde1da36ae34 -r a1dd1c200888f982753d36439d02942166088b96 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -140,7 +140,7 @@ </div><div id='progress-modal' class='modal hide fade'><div class='model-header'> - <h3>Updating experiment status</h3> + <h3>Updating experiment data</h3></div><div class='modal-body'><div class='progress progress-striped active'> @@ -163,6 +163,7 @@ confirmExperimentControllerAction(evt.target, model, function(confirmed) { if (confirmed) { console.debug("advancing to next round, notify all participants"); + sendUpdateEvent(); } }); }; diff -r f51624f9cb1b3b6e07b2e47a3915fde1da36ae34 -r a1dd1c200888f982753d36439d02942166088b96 vcweb/core/templates/includes/experimenter.events.html --- a/vcweb/core/templates/includes/experimenter.events.html +++ b/vcweb/core/templates/includes/experimenter.events.html @@ -1,4 +1,7 @@ <script type="text/javascript"> +function createUpdateEvent() { + return createMessageEvent("Update all participants", "update_participants"); +} function createRefreshEvent() { return createMessageEvent("Refresh all clients", "refresh"); } @@ -29,6 +32,9 @@ function createChatEvent(message) { return createMessageEvent(message); } +function sendUpdateEvent() { + getWebSocket().send(createUpdateEvent()); +} function sendRefreshEvent() { var webSocket = getWebSocket(); if (webSocket) { diff -r f51624f9cb1b3b6e07b2e47a3915fde1da36ae34 -r a1dd1c200888f982753d36439d02942166088b96 vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -96,9 +96,10 @@ # FIXME: could also use collections.defaultdict or regroup template tag to # accomplish this.. experiment_dict = {} - for experiment in user.participant.experiments.exclude(status__in=(Experiment.INACTIVE, Experiment.PAUSED, Experiment.COMPLETED)): +# FIXME: this needs to be refactored + for experiment in user.participant.experiments.exclude(status__in=(Experiment.Status.INACTIVE, Experiment.Status.PAUSED, Experiment.Status.COMPLETED)): 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] = 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 diff -r f51624f9cb1b3b6e07b2e47a3915fde1da36ae34 -r a1dd1c200888f982753d36439d02942166088b96 vcweb/vcweb-sockjs.py --- a/vcweb/vcweb-sockjs.py +++ b/vcweb/vcweb-sockjs.py @@ -188,6 +188,9 @@ connection.send(REFRESH_EVENT) return participant_connections + def send_update(self, experimenter, experiment): + pass + def send_goto(self, experimenter, experiment, url): notified_participants = [] message = json.dumps({'event_type': 'goto', 'url': url}) @@ -359,6 +362,10 @@ notified_participants = connection_manager.send_refresh(experimenter, experiment) self.send(create_message_event("Refreshed all connected participant pgr_ids=%s)" % notified_participants)) + def handle_update_participants(self, event, experiment, experimenter): + notified_participants = connection_manager.send_update(experimenter, experiment) + self.send(create_message_event("Updating all connected participants pgr_ids=%s)" % notified_participants)) + def on_close(self): #self.client.unsubscribe(self.default_channel) pass 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-20 07:51:15
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/f51624f9cb1b/ changeset: f51624f9cb1b user: alllee date: 2013-03-20 08:50:59 summary: fixing confirm-experiment-action click handler and reorganizing view model logic to query data appropriately based on the round configuration context affected #: 3 files diff -r 5dcd5787d4b75e8f1baa595d7ec2ed1d107856b9 -r f51624f9cb1b3b6e07b2e47a3915fde1da36ae34 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -388,11 +388,11 @@ model.harvestDecision = ko.observable(0); model.numberOfTreesPerRow = ko.observable(10); model.isResourceEmpty = ko.computed(function() { - return model.resourceLevel() == 0; + return model.resourceLevel == 0; }) model.resourcesToDisplay = ko.computed(function() { - if (model.resourceLevel() > 0) { - return Math.min(model.resourceLevel(), model.maximumResourcesToDisplay()); + if (model.resourceLevel > 0) { + return Math.min(model.resourceLevel, model.maximumResourcesToDisplay()); } return 0; }); diff -r 5dcd5787d4b75e8f1baa595d7ec2ed1d107856b9 -r f51624f9cb1b3b6e07b2e47a3915fde1da36ae34 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -61,40 +61,11 @@ current_round_data = experiment.current_round_data previous_round = experiment.previous_round previous_round_data = experiment.get_round_data(round_configuration=previous_round) + experiment_model_dict = experiment.to_dict(include_round_data=False, attrs={}) - experiment_model_dict = experiment.as_dict(include_round_data=False, attrs={}) +# round / experiment configuration data regrowth_rate = get_regrowth_rate(current_round) cost_of_living = get_cost_of_living(current_round) - own_group = participant_group_relationship.group - own_resource_level = get_resource_level(own_group) - last_harvest_decision = get_last_harvest_decision(participant_group_relationship, round_data=previous_round_data) - experiment_model_dict['playerData'] = [{ - 'id': pgr.participant_number, - 'lastHarvestDecision': last_harvest_decision, - 'storage': get_storage(pgr, current_round_data), - } for pgr in own_group.participant_group_relationship_set.all()] - experiment_model_dict['chatMessages'] = [{ - 'pk': cm.pk, - 'participant_number': cm.participant_group_relationship.participant_number, - 'message': cm.string_value, - 'date_created': cm.date_created.strftime("%I:%M:%S") - } for cm in ChatMessage.objects.for_group(own_group)] - experiment_model_dict['initialResourceLevel'] = get_initial_resource_level(current_round) - if not current_round.is_practice_round and can_observe_other_group(current_round): - gr = GroupRelationship.objects.select_related('cluster').get(group=own_group) - group_data = [] - for group in gr.cluster.group_set.all(): - if group != own_group: - group_data.append({ - 'groupId': unicode(group), - 'resourceLevel': get_resource_level(group), - 'totalStorage': get_total_storage(group), - 'regrowthRate': regrowth_rate, - 'costOfLiving': cost_of_living, - }) - experiment_model_dict['groupData'] = group_data - -# round / experiment configuration data experiment_model_dict['readyParticipants'] = experiment.ready_participants experiment_model_dict['participantsPerGroup'] = ec.max_group_size experiment_model_dict['regrowthRate'] = regrowth_rate @@ -113,15 +84,43 @@ else: experiment_model_dict['templateName'] = current_round.round_type +# participant group data parameters are only needed if this round is a data round or the previous round was a data round + if previous_round.is_playable_round or current_round.is_playable_round: + own_group = participant_group_relationship.group + own_resource_level = get_resource_level(own_group) + last_harvest_decision = get_last_harvest_decision(participant_group_relationship, round_data=previous_round_data) + experiment_model_dict['playerData'] = [{ + 'id': pgr.participant_number, + 'lastHarvestDecision': last_harvest_decision, + 'storage': get_storage(pgr, current_round_data), + } for pgr in own_group.participant_group_relationship_set.all()] + experiment_model_dict['chatMessages'] = [{ + 'pk': cm.pk, + 'participant_number': cm.participant_group_relationship.participant_number, + 'message': cm.string_value, + 'date_created': cm.date_created.strftime("%I:%M:%S") + } for cm in ChatMessage.objects.for_group(own_group)] + experiment_model_dict['initialResourceLevel'] = get_initial_resource_level(current_round) + experiment_model_dict['lastHarvestDecision'] = last_harvest_decision + experiment_model_dict['storage'] = get_storage(participant_group_relationship, current_round_data) + experiment_model_dict['resourceLevel'] = own_resource_level + if not current_round.is_practice_round and can_observe_other_group(current_round): + gr = GroupRelationship.objects.select_related('cluster').get(group=own_group) + group_data = [] + for group in gr.cluster.group_set.all(): + if group != own_group: + group_data.append({ + 'groupId': unicode(group), + 'resourceLevel': get_resource_level(group), + 'totalStorage': get_total_storage(group), + 'regrowthRate': regrowth_rate, + 'costOfLiving': cost_of_living, + }) + experiment_model_dict['groupData'] = group_data # FIXME: defaults hard coded in for now experiment_model_dict['maxEarnings'] = 20.00 experiment_model_dict['warningCountdownTime'] = 10 - - experiment_model_dict['lastHarvestDecision'] = last_harvest_decision - experiment_model_dict['storage'] = get_storage(participant_group_relationship, current_round_data) - experiment_model_dict['resourceLevel'] = own_resource_level -# FIXME: these need to be looked up experiment_model_dict['maxHarvestDecision'] = 10 experiment_model_dict['hasSubmit'] = False experiment_model_dict['instructions'] = current_round.get_custom_instructions() diff -r 5dcd5787d4b75e8f1baa595d7ec2ed1d107856b9 -r f51624f9cb1b3b6e07b2e47a3915fde1da36ae34 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -12,7 +12,7 @@ <li><div class='btn-toolbar'><div class='btn-group'> - <a class='btn btn-success' data-bind="css: { disabled: isRoundInProgress }" data-action='start_round' data-content='Starts the round.'><i class='icon-play'></i> start</a> + <a class='btn btn-success confirm-experiment-action' data-bind="css: { disabled: isRoundInProgress }" data-action='start_round' data-content='Starts the round.'><i class='icon-play'></i> start</a><a class='btn btn-success' data-bind='click: advanceToNextRound' data-action='advance_to_next_round' data-content='Advances to and starts the next round.'><i class='icon-step-forward'></i> next round</a><a class='btn btn-success' data-bind='click: refreshAllParticipants' data-content='Sends a page refresh to all connected participants.' ><i class='icon-refresh'></i> refresh participants</a></div> @@ -44,7 +44,7 @@ </div><div class='btn-toolbar'><div class='btn-group'> - <a data-content='Activate this experiment after all participants have been registered and you are ready to collect data.' + <a data-content='Activate to begin collecting data for this experiment.' class='btn btn-success confirm-experiment-action' data-action='activate'><i class='icon-off'></i> activate</a></div></div> @@ -186,7 +186,9 @@ confirmExperimentAction(element, function(confirmed, action) { $('#progress-modal').modal('show'); Dajaxice.vcweb.core.experiment_controller(update(experimentModel), {'pk': {{experiment.pk}}, 'action':action}); - callback(confirmed, action); + if (callback) { + callback(confirmed, action); + } }); } function confirmExperimentAction(element, callback) { @@ -221,7 +223,7 @@ }; $('a.confirm-experiment-action').on("click", function(evt) { evt.preventDefault(); - confirmExperimentAction(this); + confirmExperimentControllerAction(this, experimentModel); return false; }); return experimentModel; 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-20 07:32:54
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/5dcd5787d4b7/ changeset: 5dcd5787d4b7 user: alllee date: 2013-03-20 08:32:40 summary: adding migration to delete Experiment.ready_participants field affected #: 1 file diff -r 6c842fff9424c02add62faa19bc4b98921086628 -r 5dcd5787d4b75e8f1baa595d7ec2ed1d107856b9 vcweb/core/migrations/0028_auto__del_field_experiment_ready_participants.py --- /dev/null +++ b/vcweb/core/migrations/0028_auto__del_field_experiment_ready_participants.py @@ -0,0 +1,401 @@ +# -*- 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 field 'Experiment.ready_participants' + db.delete_column(u'core_experiment', 'ready_participants') + + + def backwards(self, orm): + # Adding field 'Experiment.ready_participants' + db.add_column(u'core_experiment', 'ready_participants', + self.gf('django.db.models.fields.PositiveIntegerField')(default=0), + keep_default=False) + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'core.activitylog': { + 'Meta': {'object_name': 'ActivityLog'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'log_message': ('django.db.models.fields.TextField', [], {}) + }, + u'core.address': { + 'Meta': {'object_name': 'Address'}, + 'city': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'state': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), + 'street1': ('django.db.models.fields.CharField', [], {'max_length': '256'}), + 'street2': ('django.db.models.fields.CharField', [], {'max_length': '256'}), + 'zipcode': ('django.db.models.fields.CharField', [], {'max_length': '8', 'blank': 'True'}) + }, + u'core.chatmessage': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'ChatMessage', '_ormbases': [u'core.ParticipantRoundDataValue']}, + u'participantrounddatavalue_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ParticipantRoundDataValue']", 'unique': 'True', 'primary_key': 'True'}), + 'target_participant': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'target_participant_chat_message_set'", 'null': 'True', 'to': u"orm['core.ParticipantGroupRelationship']"}) + }, + u'core.comment': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'Comment', '_ormbases': [u'core.ParticipantRoundDataValue']}, + u'participantrounddatavalue_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ParticipantRoundDataValue']", 'unique': 'True', 'primary_key': 'True'}) + }, + u'core.experiment': { + 'Meta': {'ordering': "['date_created', 'status']", 'object_name': 'Experiment'}, + 'amqp_exchange_name': ('django.db.models.fields.CharField', [], {'default': "'vcweb.default.exchange'", 'max_length': '64'}), + 'authentication_code': ('django.db.models.fields.CharField', [], {'default': "'vcweb.auth.code'", 'max_length': '32'}), + 'current_repeated_round_sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'current_round_elapsed_time': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'current_round_sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'current_round_start_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentConfiguration']"}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentMetadata']"}), + 'experimenter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experimenter']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'start_date_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'INACTIVE'", 'max_length': '32'}), + 'tick_duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'total_elapsed_time': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + }, + u'core.experimentactivitylog': { + 'Meta': {'object_name': 'ExperimentActivityLog', '_ormbases': [u'core.ActivityLog']}, + u'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': u"orm['core.Experiment']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.experimentconfiguration': { + 'Meta': {'ordering': "['experiment_metadata', 'creator', 'date_created']", 'object_name': 'ExperimentConfiguration'}, + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': u"orm['core.Experimenter']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'exchange_rate': ('django.db.models.fields.DecimalField', [], {'default': '0.2', 'null': 'True', 'max_digits': '6', 'decimal_places': '2', 'blank': 'True'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': u"orm['core.ExperimentMetadata']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation_subject': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'is_experimenter_driven': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'max_group_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), + 'max_number_of_participants': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'treatment_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}) + }, + u'core.experimenter': { + 'Meta': {'ordering': "['user']", 'object_name': 'Experimenter'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'authentication_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'failed_password_attempts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'institution': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Institution']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'experimenter'", 'unique': 'True', 'to': u"orm['auth.User']"}) + }, + u'core.experimenterrequest': { + 'Meta': {'object_name': 'ExperimenterRequest'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'}) + }, + u'core.experimentmetadata': { + 'Meta': {'ordering': "['namespace', 'date_created']", 'object_name': 'ExperimentMetadata'}, + 'about_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'default_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentConfiguration']", 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'namespace': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'short_name': ('django.db.models.fields.SlugField', [], {'max_length': '32', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'core.experimentparametervalue': { + 'Meta': {'object_name': 'ExperimentParameterValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_parameter_value_set'", 'to': u"orm['core.ExperimentConfiguration']"}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.experimentsession': { + 'Meta': {'object_name': 'ExperimentSession'}, + 'capacity': ('django.db.models.fields.PositiveIntegerField', [], {'default': '20'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_session_set'", 'to': u"orm['auth.User']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_session_set'", 'to': u"orm['core.ExperimentMetadata']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'scheduled_date': ('django.db.models.fields.DateTimeField', [], {}), + 'scheduled_end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.group': { + 'Meta': {'ordering': "['experiment', 'number']", 'object_name': 'Group'}, + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'max_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), + 'number': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.groupactivitylog': { + 'Meta': {'object_name': 'GroupActivityLog', '_ormbases': [u'core.ActivityLog']}, + u'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': u"orm['core.Group']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.groupcluster': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'GroupCluster'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.groupclusterdatavalue': { + 'Meta': {'object_name': 'GroupClusterDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'group_cluster': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.GroupCluster']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'round_data': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_cluster_data_value_set'", 'to': u"orm['core.RoundData']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.grouprelationship': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'GroupRelationship'}, + 'cluster': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_set'", 'to': u"orm['core.GroupCluster']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'core.grouprounddatavalue': { + 'Meta': {'ordering': "['round_data', 'group', 'parameter']", 'object_name': 'GroupRoundDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'data_value_set'", 'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'round_data': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_data_value_set'", 'to': u"orm['core.RoundData']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.institution': { + 'Meta': {'object_name': 'Institution'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}) + }, + u'core.invitation': { + 'Meta': {'object_name': 'Invitation'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment_session': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentSession']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'participant': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Participant']"}), + 'sender': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + }, + u'core.like': { + 'Meta': {'ordering': "['-date_created', 'round_data', 'participant_group_relationship', 'parameter']", 'object_name': 'Like', '_ormbases': [u'core.ParticipantRoundDataValue']}, + u'participantrounddatavalue_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ParticipantRoundDataValue']", 'unique': 'True', 'primary_key': 'True'}) + }, + u'core.parameter': { + 'Meta': {'ordering': "['name']", 'unique_together': "(('name', 'experiment_metadata', 'scope'),)", 'object_name': 'Parameter'}, + 'class_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experimenter']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'default_value_string': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '512', 'null': 'True', 'blank': 'True'}), + 'display_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'enum_choices': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentMetadata']", 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_required': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'scope': ('django.db.models.fields.CharField', [], {'default': "'round'", 'max_length': '32'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + u'core.participant': { + 'Meta': {'ordering': "['user']", 'object_name': 'Participant'}, + 'address': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Address']", 'null': 'True', 'blank': 'True'}), + 'authentication_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'birthdate': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'can_receive_invitations': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'experiments': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'participant_set'", 'symmetrical': 'False', 'through': u"orm['core.ParticipantExperimentRelationship']", 'to': u"orm['core.Experiment']"}), + 'failed_password_attempts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'gender': ('django.db.models.fields.CharField', [], {'max_length': '1', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'participant_set'", 'symmetrical': 'False', 'through': u"orm['core.ParticipantGroupRelationship']", 'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'institution': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Institution']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'participant'", 'unique': 'True', 'to': u"orm['auth.User']"}) + }, + u'core.participantexperimentrelationship': { + 'Meta': {'object_name': 'ParticipantExperimentRelationship'}, + 'additional_data': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'current_location': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_relationship_set'", 'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_completed_round_sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'participant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_relationship_set'", 'to': u"orm['core.Participant']"}), + 'participant_identifier': ('django.db.models.fields.CharField', [], {'max_length': '32'}), + 'sequential_participant_identifier': ('django.db.models.fields.PositiveIntegerField', [], {}) + }, + u'core.participantgrouprelationship': { + 'Meta': {'ordering': "['group', 'participant_number']", 'object_name': 'ParticipantGroupRelationship'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'first_visit': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_group_relationship_set'", 'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'notifications_since': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'null': 'True', 'blank': 'True'}), + 'participant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_group_relationship_set'", 'to': u"orm['core.Participant']"}), + 'participant_number': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'round_joined': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.participantrounddatavalue': { + 'Meta': {'ordering': "['-date_created', 'round_data', 'participant_group_relationship', 'parameter']", 'object_name': 'ParticipantRoundDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'participant_group_relationship': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_data_value_set'", 'to': u"orm['core.ParticipantGroupRelationship']"}), + 'round_data': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_data_value_set'", 'to': u"orm['core.RoundData']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'submitted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'target_data_value': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'target_data_value_set'", 'null': 'True', 'to': u"orm['core.ParticipantRoundDataValue']"}) + }, + u'core.participantsignup': { + 'Meta': {'object_name': 'ParticipantSignup'}, + 'attendance': ('django.db.models.fields.PositiveIntegerField', [], {'max_length': '1', 'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'signup_set'", 'to': u"orm['core.Invitation']"}), + 'participant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'signup_set'", 'to': u"orm['core.Participant']"}) + }, + u'core.quizquestion': { + 'Meta': {'object_name': 'QuizQuestion'}, + 'answer': ('django.db.models.fields.CharField', [], {'max_length': '64'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'default_quiz_question_set'", 'null': 'True', 'to': u"orm['core.Experiment']"}), + 'explanation': ('django.db.models.fields.CharField', [], {'max_length': '512'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'input_type': ('django.db.models.fields.CharField', [], {'max_length': '32'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '512'}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'quiz_question_set'", 'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.roundconfiguration': { + 'Meta': {'ordering': "['experiment_configuration', 'sequence_number', 'date_created']", 'object_name': 'RoundConfiguration'}, + 'chat_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'create_group_clusters': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'debriefing': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'display_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'duration': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_configuration_set'", 'to': u"orm['core.ExperimentConfiguration']"}), + 'group_cluster_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '2'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'instructions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'preserve_existing_groups': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'randomize_groups': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'repeat': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'round_type': ('django.db.models.fields.CharField', [], {'default': "'REGULAR'", 'max_length': '32'}), + 'sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'survey_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'template_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.rounddata': { + 'Meta': {'ordering': "['round_configuration']", 'unique_together': "(('round_configuration', 'experiment'),)", 'object_name': 'RoundData'}, + 'elapsed_time': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_data_set'", 'to': u"orm['core.Experiment']"}), + 'experimenter_notes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_data_set'", 'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.roundparametervalue': { + 'Meta': {'object_name': 'RoundParameterValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_parameter_value_set'", 'to': u"orm['core.RoundConfiguration']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.spoolparticipantstatistics': { + 'Meta': {'object_name': 'SpoolParticipantStatistics'}, + 'absences': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'discharges': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitations': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'participant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'spool_statistics_set'", 'to': u"orm['core.Participant']"}), + 'participations': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + } + } + + complete_apps = ['core'] \ No newline at end of file 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-20 07:32:31
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/6c842fff9424/ changeset: 6c842fff9424 user: alllee date: 2013-03-20 08:32:16 summary: fixing session_id check in Experiment.participant_group_relationships and no longer creating data value parameters for non-data rounds affected #: 2 files diff -r d542e23263d13375508d2d69e904e4e3739acb96 -r 6c842fff9424c02add62faa19bc4b98921086628 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -99,10 +99,11 @@ round_configuration = experiment.current_round logger.debug("setting up round %s", round_configuration) # initialize group and participant data values - experiment.initialize_data_values( - group_parameters=(get_regrowth_parameter(), get_group_harvest_parameter(), get_resource_level_parameter()), - participant_parameters=[get_harvest_decision_parameter(), get_storage_parameter(), get_player_status_parameter()] - ) + if round_configuration.is_playable_round: + experiment.initialize_data_values( + group_parameters=(get_regrowth_parameter(), get_group_harvest_parameter(), get_resource_level_parameter()), + participant_parameters=[get_harvest_decision_parameter(), get_storage_parameter(), get_player_status_parameter()] + ) ''' during a practice or regular round, set up resource levels and participant harvest decision parameters diff -r d542e23263d13375508d2d69e904e4e3739acb96 -r 6c842fff9424c02add62faa19bc4b98921086628 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -366,7 +366,7 @@ Generator function for all participant group relationships in this experiment ''' session_id = self.current_round.session_id - if session_id is not None: + if session_id: groups = self.group_set.filter(session_id=session_id) else: groups = self.group_set.all() @@ -759,6 +759,7 @@ round_data, created = self.round_data_set.get_or_create(round_configuration=self.current_round) if self.experiment_configuration.is_experimenter_driven: # create participant ready data values for every round in experimenter driven experiments + logger.debug("creating participant ready participant round data values") for pgr in self.participant_group_relationships: ParticipantRoundDataValue.objects.create(participant_group_relationship=pgr, boolean_value=False, parameter=get_participant_ready_parameter(), round_data=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-20 07:05:32
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/d542e23263d1/ changeset: d542e23263d1 user: alllee date: 2013-03-20 08:05:17 summary: removing ready_participants integer field on Experiment, too easily corrupted since we can't verify when duplicate increments occur replacing with stored participant_ready data values and count calculations affected #: 5 files diff -r d6622ad4c638f361b16509f918c415a23475ff5b -r d542e23263d13375508d2d69e904e4e3739acb96 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -95,6 +95,7 @@ experiment_model_dict['groupData'] = group_data # round / experiment configuration data + experiment_model_dict['readyParticipants'] = experiment.ready_participants experiment_model_dict['participantsPerGroup'] = ec.max_group_size experiment_model_dict['regrowthRate'] = regrowth_rate experiment_model_dict['costOfLiving'] = cost_of_living diff -r d6622ad4c638f361b16509f918c415a23475ff5b -r d542e23263d13375508d2d69e904e4e3739acb96 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -316,8 +316,6 @@ """ elapsed time in seconds for the current round. """ amqp_exchange_name = models.CharField(max_length=64, default="vcweb.default.exchange") - ready_participants = models.PositiveIntegerField(default=0, help_text=_("The number of participants ready to move on to the next round.")) - cached_round_sequence_number = None ''' used to cache the round configuration ''' @@ -520,11 +518,15 @@ return self.current_round.instructions @property + def ready_participants(self): + return ParticipantRoundDataValue.objects.filter(parameter=get_participant_ready_parameter(), round_data=self.current_round_data, boolean_value=True).count() + + @property def all_participants_ready(self): - return self.ready_participants >= self.participant_set.count() + return self.ready_participants == self.participant_set.count() def get_participant_experiment_relationship(self, participant): - return self.participant_relationship_set.get(participant=participant) + return self.participant_relationship_set.select_related('participant__user').get(participant=participant) def get_participant_group_relationship(self, participant): session_id = self.current_round.session_id @@ -770,7 +772,6 @@ self.create_round_data() self.current_round_elapsed_time = 0 self.current_round_start_time = datetime.now() - self.ready_participants = 0 self.save() self.log('Starting round') current_round_configuration = self.current_round diff -r d6622ad4c638f361b16509f918c415a23475ff5b -r d542e23263d13375508d2d69e904e4e3739acb96 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -13,7 +13,7 @@ <div class='btn-toolbar'><div class='btn-group'><a class='btn btn-success' data-bind="css: { disabled: isRoundInProgress }" data-action='start_round' data-content='Starts the round.'><i class='icon-play'></i> start</a> - <a class='btn btn-success' data-bind='click: advanceToNextRound' data-action='advance_to_next_round' data-content='Advances to the next round and starts it.'><i class='icon-step-forward'></i> next round</a> + <a class='btn btn-success' data-bind='click: advanceToNextRound' data-action='advance_to_next_round' data-content='Advances to and starts the next round.'><i class='icon-step-forward'></i> next round</a><a class='btn btn-success' data-bind='click: refreshAllParticipants' data-content='Sends a page refresh to all connected participants.' ><i class='icon-refresh'></i> refresh participants</a></div></div> @@ -69,7 +69,7 @@ <li><a href='export/configuration.xml'><i class='icon-cog'></i>xml</a></li><li><a href='export/configuration.json'><i class='icon-pencil'></i>json</a></li></ul> - <a class='btn btn-info confirm-experiment-action' data-action='complete' data-content='Mark this experiment as completed and archive it.'><i class='icon-save'></i> archive</a> + <a class='btn btn-danger confirm-experiment-action' data-action='complete' data-content='Mark this experiment as completed and archive it.'><i class='icon-save'></i> archive</a></div></div><div class='span6'> diff -r d6622ad4c638f361b16509f918c415a23475ff5b -r d542e23263d13375508d2d69e904e4e3739acb96 vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -522,13 +522,11 @@ if valid_form: pgr = get_object_or_404(ParticipantGroupRelationship.objects.select_related('group__experiment'), pk=form.cleaned_data['participant_group_id']) experiment = pgr.group.experiment - prdv, created = ParticipantRoundDataValue.objects.get_or_create(participant_group_relationship=pgr, + prdv = ParticipantRoundDataValue.objects.get(participant_group_relationship=pgr, round_data=experiment.get_round_data(), parameter=get_participant_ready_parameter()) prdv.submitted = True prdv.boolean_value = True prdv.save() - experiment.ready_participants += 1 - experiment.save() return JsonResponse(dumps({'success': valid_form})) def handler500(request): diff -r d6622ad4c638f361b16509f918c415a23475ff5b -r d542e23263d13375508d2d69e904e4e3739acb96 vcweb/forestry/tests.py --- a/vcweb/forestry/tests.py +++ b/vcweb/forestry/tests.py @@ -246,7 +246,7 @@ participant_data_values = round_data.participant_data_value_set.filter(participant_group_relationship__participant=p) logger.debug("XXX: participant data values: %s", participant_data_values) self.assertEqual(participant_data_values.count(), 2) - pexpr = p.get_participant_experiment_relationship(e) + pexpr = e.get_participant_experiment_relationship(p) logger.debug("relationship %s" % pexpr) for dv in participant_data_values.filter(parameter__type='int'): logger.debug("verifying data value %s" % dv) 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-20 06:24:41
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/d6622ad4c638/ changeset: d6622ad4c638 user: alllee date: 2013-03-20 07:24:28 summary: wiring up progress bar modal for updating experiment status affected #: 1 file diff -r 06d00ea1c772b471ac29498952004f21e2549798 -r d6622ad4c638f361b16509f918c415a23475ff5b vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -144,7 +144,7 @@ </div><div class='modal-body'><div class='progress progress-striped active'> - <div id='progress-bar' class='bar' style='width: 50%'></div> + <div id='progress-bar' class='bar' style='width: 100%'></div></div></div></div> @@ -183,10 +183,11 @@ return model; } function confirmExperimentControllerAction(element, experimentModel, callback) { - confirmExperimentAction(element, - function(confirmed, action) { - Dajaxice.vcweb.core.experiment_controller(update(experimentModel), {'pk': {{experiment.pk}}, 'action':action}); - }); + confirmExperimentAction(element, function(confirmed, action) { + $('#progress-modal').modal('show'); + Dajaxice.vcweb.core.experiment_controller(update(experimentModel), {'pk': {{experiment.pk}}, 'action':action}); + callback(confirmed, action); + }); } function confirmExperimentAction(element, callback) { var self = $(element); @@ -204,10 +205,8 @@ } function update(experimentModel) { return function(data) { - console.debug("updating experiment model with data:"); - console.debug(data); ko.mapping.fromJS(data, experimentModel); - console.debug("done"); + $('#progress-modal').modal('hide'); } } function initialize(experimentModelJson) { 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-20 06:16:43
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/06d00ea1c772/ changeset: 06d00ea1c772 user: alllee date: 2013-03-20 07:16:28 summary: fixing bootbox confirmation dialogs, needed to get rid of the last "return false" in the confirmation logic to allow cancel to work properly affected #: 1 file diff -r 47f9363dbc643868caf31ca521c44a24a21e1d2d -r 06d00ea1c772b471ac29498952004f21e2549798 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -12,8 +12,8 @@ <li><div class='btn-toolbar'><div class='btn-group'> - <a class='btn btn-success confirm-experiment-action' data-bind="css: { disabled: isRoundInProgress }" name='start_round' data-content='Starts the round.'><i class='icon-play'></i> start</a> - <a class='btn btn-success confirm-experiment-action' data-bind='click: advanceToNextRound' name='advance_to_next_round' data-content='Advances to the next round and starts it.'><i class='icon-step-forward'></i> next round</a> + <a class='btn btn-success' data-bind="css: { disabled: isRoundInProgress }" data-action='start_round' data-content='Starts the round.'><i class='icon-play'></i> start</a> + <a class='btn btn-success' data-bind='click: advanceToNextRound' data-action='advance_to_next_round' data-content='Advances to the next round and starts it.'><i class='icon-step-forward'></i> next round</a><a class='btn btn-success' data-bind='click: refreshAllParticipants' data-content='Sends a page refresh to all connected participants.' ><i class='icon-refresh'></i> refresh participants</a></div></div> @@ -42,10 +42,12 @@ existing data). </p></div> - <ul class='nav nav-list'> - <li><a data-content='Activate this experiment after all participants have been registered and you are ready to collect data.' - class='confirm-experiment-action' name='activate' href='activate'><i class='icon-off'></i>activate</a></li> - </ul> + <div class='btn-toolbar'> + <div class='btn-group'> + <a data-content='Activate this experiment after all participants have been registered and you are ready to collect data.' + class='btn btn-success confirm-experiment-action' data-action='activate'><i class='icon-off'></i> activate</a> + </div> + </div></div></div><ul class='nav nav-list'> @@ -67,7 +69,7 @@ <li><a href='export/configuration.xml'><i class='icon-cog'></i>xml</a></li><li><a href='export/configuration.json'><i class='icon-pencil'></i>json</a></li></ul> - <a class='btn btn-info confirm-experiment-action' name='complete' data-content='Mark this experiment as completed and archive it.'><i class='icon-save'></i> archive</a> + <a class='btn btn-info confirm-experiment-action' data-action='complete' data-content='Mark this experiment as completed and archive it.'><i class='icon-save'></i> archive</a></div></div><div class='span6'> @@ -157,14 +159,21 @@ function ExperimentModel(experimentModelJson) { var self = this; var model = ko.mapping.fromJS(experimentModelJson); - model.advanceToNextRound = function(model, evt) { - - return false; + model.advanceToNextRound = function(localModel, evt) { + confirmExperimentControllerAction(evt.target, model, function(confirmed) { + if (confirmed) { + console.debug("advancing to next round, notify all participants"); + } + }); }; model.refreshAllParticipants = function(model, evt) { - sendRefreshEvent(); - return false; - }; + confirmExperimentAction(evt.target, function(confirmed, action) { + if (confirmed) { + console.debug("sending refresh event"); + sendRefreshEvent(); + } + }); + } model.addMessage = function(data) { model.messages.unshift(data.message); }; @@ -173,6 +182,26 @@ }); return model; } + function confirmExperimentControllerAction(element, experimentModel, callback) { + confirmExperimentAction(element, + function(confirmed, action) { + Dajaxice.vcweb.core.experiment_controller(update(experimentModel), {'pk': {{experiment.pk}}, 'action':action}); + }); + } + function confirmExperimentAction(element, callback) { + var self = $(element); + var description = self.attr("data-content"); + var action = self.attr("data-action"); + if (self.hasClass('disabled')) { + console.debug("disabled action " + action + " - ignoring"); + return false; + } + bootbox.confirm(description + " Continue?", function(confirmed) { + if (confirmed && callback) { + callback(confirmed, action); + } + }); + } function update(experimentModel) { return function(data) { console.debug("updating experiment model with data:"); @@ -193,19 +222,7 @@ }; $('a.confirm-experiment-action').on("click", function(evt) { evt.preventDefault(); - var self = $(this); - var description = self.attr("data-content"); - var action = self.attr("name"); - if (self.hasClass('disabled')) { - console.debug("disabled action " + action + " - ignoring"); - return false; - } - bootbox.confirm(description + " Continue?", function(confirmed) { - if (confirmed) { - Dajaxice.vcweb.core.experiment_controller(update(experimentModel), {'pk': {{experiment.pk}}, 'action':action}); - } - return false; - }); + confirmExperimentAction(this); return false; }); return experimentModel; 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-20 00:29:03
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/47f9363dbc64/ changeset: 47f9363dbc64 user: alllee date: 2013-03-20 01:29:02 summary: bootbox confirmation dialogs are hanging, going to need to switch to manual bootstrap modals for more control affected #: 5 files diff -r 42abc273052667a4bb840d3ff8b20856f0f5bcd4 -r 47f9363dbc643868caf31ca521c44a24a21e1d2d vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -30,15 +30,22 @@ </div></div></div> - {% endblock sidebar %} - {% block javascript %} {{ block.super }} <!-- ko templates --><script type='text/html' id='CHAT'> {% include "forms/chat-template.html" %} </script> +<script type='text/html' id='WAITING_ROOM'> +<h3>Waiting Room</h3> +<div> +Please wait. The experiment will continue shortly once all the participants are ready. +</div> +<div class='progress progress-success progress-striped active'> +<div class='bar' data-bind='style: { width: readyParticipantsPercentage() + "%" }'></div> +</div> +</script><script type='text/html' id='WELCOME'><h3>Welcome</h3><p class='lead'> @@ -352,6 +359,12 @@ model.activateInstructionsPageThree = function() { model.templateName('GENERAL_INSTRUCTIONS3'); }; + model.activateWaitingRoomPage = function() { + model.templateName('WAITING_ROOM'); + } + model.readyParticipantsPercentage = ko.computed(function() { + return (model.readyParticipants() / model.totalNumberOfParticipants()) * 100; + }); model.activatePracticeRoundInstructions = function() { model.templateName("PRACTICE_ROUND_INSTRUCTIONS"); } @@ -363,6 +376,9 @@ $.post('/experiment/participant-ready', { participant_group_id: {{ participant_group_relationship.pk }} }, function(response) { console.debug("successfully posted to server, notifying sockjs: " + response); getWebSocket().send(createMessageEvent("Instructions completed", "client_ready")); + // FIXME: transition to a waiting screen + model.readyParticipant(); + model.activateWaitingRoomPage(); }); } model.showOtherGroup = function() { diff -r 42abc273052667a4bb840d3ff8b20856f0f5bcd4 -r 47f9363dbc643868caf31ca521c44a24a21e1d2d vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -98,6 +98,7 @@ experiment_model_dict['participantsPerGroup'] = ec.max_group_size experiment_model_dict['regrowthRate'] = regrowth_rate experiment_model_dict['costOfLiving'] = cost_of_living + experiment_model_dict['totalNumberOfParticipants'] = experiment.participant_set.count() experiment_model_dict['participantNumber'] = participant_group_relationship.participant_number experiment_model_dict['participantGroupId'] = participant_group_relationship.pk experiment_model_dict['dollarsPerToken'] = float(ec.exchange_rate) diff -r 42abc273052667a4bb840d3ff8b20856f0f5bcd4 -r 47f9363dbc643868caf31ca521c44a24a21e1d2d vcweb/core/templates/experimenter/base.html --- a/vcweb/core/templates/experimenter/base.html +++ b/vcweb/core/templates/experimenter/base.html @@ -6,7 +6,6 @@ {% url 'core:logout' as logout %} {% url 'core:profile' as profile %} {% block title %}Virtual Commons Web Experimenter Interface{% endblock %} - {% block javascript %} {{ block.super }} <script type='text/javascript' src='{{STATIC_URL}}/js/bootbox.min.js'></script> diff -r 42abc273052667a4bb840d3ff8b20856f0f5bcd4 -r 47f9363dbc643868caf31ca521c44a24a21e1d2d vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -13,8 +13,8 @@ <div class='btn-toolbar'><div class='btn-group'><a class='btn btn-success confirm-experiment-action' data-bind="css: { disabled: isRoundInProgress }" name='start_round' data-content='Starts the round.'><i class='icon-play'></i> start</a> - <a class='btn btn-success confirm-experiment-action' name='advance_to_next_round' data-content='Advances to the next round and starts it.'><i class='icon-step-forward'></i> next round</a> - <!-- FIXME: disabled for the time being<a class='btn btn-primary' id='refreshAllParticipants' data-content='Sends a page refresh to all connected participants.' ><i class='icon-refresh'></i> refresh participants</a> --> + <a class='btn btn-success confirm-experiment-action' data-bind='click: advanceToNextRound' name='advance_to_next_round' data-content='Advances to the next round and starts it.'><i class='icon-step-forward'></i> next round</a> + <a class='btn btn-success' data-bind='click: refreshAllParticipants' data-content='Sends a page refresh to all connected participants.' ><i class='icon-refresh'></i> refresh participants</a></div></div></li> @@ -74,7 +74,6 @@ <h4>Experiment Log</h4><div id='experiment-messages' class='alert' data-bind='foreach: messages'><div> - <button class='close' data-dismiss='alert'>×</button><span data-bind='text: $data'></span></div></div> @@ -155,12 +154,20 @@ <script type='text/javascript'> var experimentModelJson = $.parseJSON("{{ experiment.to_json|escapejs }}"); $(function() { - function ExperimentModel (experimentModelJson) { + function ExperimentModel(experimentModelJson) { var self = this; var model = ko.mapping.fromJS(experimentModelJson); - model.addMessage = function (evt) { - model.messages.unshift(evt.message); - } + model.advanceToNextRound = function(model, evt) { + + return false; + }; + model.refreshAllParticipants = function(model, evt) { + sendRefreshEvent(); + return false; + }; + model.addMessage = function(data) { + model.messages.unshift(data.message); + }; model.hasParticipants = ko.computed(function() { return model.participantCount() > 0; }); @@ -168,8 +175,10 @@ } function update(experimentModel) { return function(data) { + console.debug("updating experiment model with data:"); + console.debug(data); ko.mapping.fromJS(data, experimentModel); - $('#progress-modal').modal('hide'); + console.debug("done"); } } function initialize(experimentModelJson) { @@ -194,15 +203,9 @@ bootbox.confirm(description + " Continue?", function(confirmed) { if (confirmed) { Dajaxice.vcweb.core.experiment_controller(update(experimentModel), {'pk': {{experiment.pk}}, 'action':action}); - $('#progress-modal').modal({keyboard: false}); } return false; }); - }); - // FIXME: replace these with click data-binding - $('#refreshAllParticipants').click(function(evt) { - evt.preventDefault(); - sendRefreshEvent(); return false; }); return experimentModel; diff -r 42abc273052667a4bb840d3ff8b20856f0f5bcd4 -r 47f9363dbc643868caf31ca521c44a24a21e1d2d vcweb/vcweb-sockjs.py --- a/vcweb/vcweb-sockjs.py +++ b/vcweb/vcweb-sockjs.py @@ -8,7 +8,6 @@ from raven.contrib.tornado import AsyncSentryClient from sockjs.tornado import SockJSRouter, SockJSConnection from tornado import web, ioloop -from tornado.escape import xhtml_escape import tornadoredis sys.path.append( path.abspath(path.join(path.dirname(path.abspath(__file__)), '..')) ) @@ -358,7 +357,7 @@ def handle_refresh(self, event, experiment, experimenter): notified_participants = connection_manager.send_refresh(experimenter, experiment) - self.send(create_message_event("Refreshed %s participants" % notified_participants)) + self.send(create_message_event("Refreshed all connected participant pgr_ids=%s)" % notified_participants)) def on_close(self): #self.client.unsubscribe(self.default_channel) 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-19 23:06:19
|
2 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/a975b53ad569/ changeset: a975b53ad569 user: alllee date: 2013-03-19 21:47:10 summary: version bump bootbox affected #: 1 file diff -r 4dbb0ffe297cfd0e71a9ef19d20d0dbf97ddaf9d -r a975b53ad5697269d712da8d2ed0b7e05eddfdc4 vcweb/static/js/bootbox.min.js --- a/vcweb/static/js/bootbox.min.js +++ b/vcweb/static/js/bootbox.min.js @@ -1,16 +1,17 @@ /** - * bootbox.js v3.0.0 + * bootbox.js v3.2.0 * * http://bootboxjs.com/license.txt */ -var bootbox=window.bootbox||function(v,n){function h(b,a){null==a&&(a=r);return"string"===typeof l[a][b]?l[a][b]:a!=s?h(b,s):b}var r="en",s="en",t=!0,q="static",u="",g={},m={setLocale:function(b){for(var a in l)if(a==b){r=b;return}throw Error("Invalid locale: "+b);},addLocale:function(b,a){"undefined"===typeof l[b]&&(l[b]={});for(var c in a)l[b][c]=a[c]},setIcons:function(b){g=b;if("object"!==typeof g||null==g)g={}},alert:function(){var b="",a=h("OK"),c=null;switch(arguments.length){case 1:b=arguments[0]; -break;case 2:b=arguments[0];"function"==typeof arguments[1]?c=arguments[1]:a=arguments[1];break;case 3:b=arguments[0];a=arguments[1];c=arguments[2];break;default:throw Error("Incorrect number of arguments: expected 1-3");}return m.dialog(b,{label:a,icon:g.OK,callback:c},{onEscape:c||!0})},confirm:function(){var b="",a=h("CANCEL"),c=h("CONFIRM"),e=null;switch(arguments.length){case 1:b=arguments[0];break;case 2:b=arguments[0];"function"==typeof arguments[1]?e=arguments[1]:a=arguments[1];break;case 3:b= -arguments[0];a=arguments[1];"function"==typeof arguments[2]?e=arguments[2]:c=arguments[2];break;case 4:b=arguments[0];a=arguments[1];c=arguments[2];e=arguments[3];break;default:throw Error("Incorrect number of arguments: expected 1-4");}var j=function(){"function"===typeof e&&e(!1)};return m.dialog(b,[{label:a,icon:g.CANCEL,callback:j},{label:c,icon:g.CONFIRM,callback:function(){"function"===typeof e&&e(!0)}}],{onEscape:j})},prompt:function(){var b="",a=h("CANCEL"),c=h("CONFIRM"),e=null,j="";switch(arguments.length){case 1:b= -arguments[0];break;case 2:b=arguments[0];"function"==typeof arguments[1]?e=arguments[1]:a=arguments[1];break;case 3:b=arguments[0];a=arguments[1];"function"==typeof arguments[2]?e=arguments[2]:c=arguments[2];break;case 4:b=arguments[0];a=arguments[1];c=arguments[2];e=arguments[3];break;case 5:b=arguments[0];a=arguments[1];c=arguments[2];e=arguments[3];j=arguments[4];break;default:throw Error("Incorrect number of arguments: expected 1-5");}var d=n("<form></form>");d.append("<input autocomplete=off type=text value='"+ -j+"' />");var j=function(){"function"===typeof e&&e(null)},k=m.dialog(d,[{label:a,icon:g.CANCEL,callback:j},{label:c,icon:g.CONFIRM,callback:function(){"function"===typeof e&&e(d.find("input[type=text]").val())}}],{header:b,show:!1,onEscape:j});k.on("shown",function(){d.find("input[type=text]").focus();d.on("submit",function(a){a.preventDefault();k.find(".btn-primary").click()})});k.modal("show");return k},dialog:function(b,a,c){var e="",j=[];c=c||{};null==a?a=[]:"undefined"==typeof a.length&&(a= -[a]);for(var d=a.length;d--;){var k=null,g=null,h=null,l="",m=null;if("undefined"==typeof a[d].label&&"undefined"==typeof a[d]["class"]&&"undefined"==typeof a[d].callback){var k=0,g=null,p;for(p in a[d])if(g=p,1<++k)break;1==k&&"function"==typeof a[d][p]&&(a[d].label=g,a[d].callback=a[d][p])}"function"==typeof a[d].callback&&(m=a[d].callback);a[d]["class"]?h=a[d]["class"]:d==a.length-1&&2>=a.length&&(h="btn-primary");k=a[d].label?a[d].label:"Option "+(d+1);a[d].icon&&(l="<i class='"+a[d].icon+"'></i> "); -g=a[d].href?a[d].href:"javascript:;";e="<a data-handler='"+d+"' class='btn "+h+"' href='"+g+"'>"+l+""+k+"</a>"+e;j[d]=m}d=["<div class='bootbox modal' tabindex='-1' style='overflow:hidden;'>"];if(c.header){h="";if("undefined"==typeof c.headerCloseButton||c.headerCloseButton)h="<a href='javascript:;' class='close'>×</a>";d.push("<div class='modal-header'>"+h+"<h3>"+c.header+"</h3></div>")}d.push("<div class='modal-body'></div>");e&&d.push("<div class='modal-footer'>"+e+"</div>");d.push("</div>"); -var f=n(d.join("\n"));("undefined"===typeof c.animate?t:c.animate)&&f.addClass("fade");(e="undefined"===typeof c.classes?u:c.classes)&&f.addClass(e);f.find(".modal-body").html(b);f.on("hidden",function(){f.remove()});f.on("keyup.dismiss.modal",function(a){if(27==a.which&&c.onEscape){if("function"===typeof c.onEscape)c.onEscape();f.modal("hide")}});f.on("shown",function(){f.find("a.btn-primary:first").focus()});f.on("click",".modal-footer a, a.close",function(b){var c=n(this).data("handler"),d=j[c], -e=null;"undefined"!==typeof c&&"undefined"!==typeof a[c].href||(b.preventDefault(),"function"==typeof d&&(e=d()),!1!==e&&f.modal("hide"))});n("body").append(f);f.modal({backdrop:"undefined"===typeof c.backdrop?q:c.backdrop,keyboard:!1,show:!1});f.on("show",function(){n(v).off("focusin.modal")});("undefined"===typeof c.show||!0===c.show)&&f.modal("show");return f},modal:function(){var b,a,c,e={onEscape:null,keyboard:!0,backdrop:q};switch(arguments.length){case 1:b=arguments[0];break;case 2:b=arguments[0]; -"object"==typeof arguments[1]?c=arguments[1]:a=arguments[1];break;case 3:b=arguments[0];a=arguments[1];c=arguments[2];break;default:throw Error("Incorrect number of arguments: expected 1-3");}e.header=a;c="object"==typeof c?n.extend(e,c):e;return m.dialog(b,[],c)},hideAll:function(){n(".bootbox").modal("hide")},animate:function(b){t=b},backdrop:function(b){q=b},classes:function(b){u=b}},l={en:{OK:"OK",CANCEL:"Cancel",CONFIRM:"OK"},fr:{OK:"OK",CANCEL:"Annuler",CONFIRM:"D'accord"},de:{OK:"OK",CANCEL:"Abbrechen", -CONFIRM:"Akzeptieren"},es:{OK:"OK",CANCEL:"Cancelar",CONFIRM:"Aceptar"},br:{OK:"OK",CANCEL:"Cancelar",CONFIRM:"Sim"},nl:{OK:"OK",CANCEL:"Annuleren",CONFIRM:"Accepteren"},ru:{OK:"OK",CANCEL:"\u041e\u0442\u043c\u0435\u043d\u0430",CONFIRM:"\u041f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c"},it:{OK:"OK",CANCEL:"Annulla",CONFIRM:"Conferma"}};return m}(document,window.jQuery);window.bootbox=bootbox; +var bootbox=window.bootbox||function(w,n){function k(b,a){"undefined"===typeof a&&(a=p);return"string"===typeof j[a][b]?j[a][b]:a!=t?k(b,t):b}var p="en",t="en",u=!0,s="static",v="",l={},g={},m={setLocale:function(b){for(var a in j)if(a==b){p=b;return}throw Error("Invalid locale: "+b);},addLocale:function(b,a){"undefined"===typeof j[b]&&(j[b]={});for(var c in a)j[b][c]=a[c]},setIcons:function(b){g=b;if("object"!==typeof g||null===g)g={}},setBtnClasses:function(b){l=b;if("object"!==typeof l||null=== +l)l={}},alert:function(){var b="",a=k("OK"),c=null;switch(arguments.length){case 1:b=arguments[0];break;case 2:b=arguments[0];"function"==typeof arguments[1]?c=arguments[1]:a=arguments[1];break;case 3:b=arguments[0];a=arguments[1];c=arguments[2];break;default:throw Error("Incorrect number of arguments: expected 1-3");}return m.dialog(b,{label:a,icon:g.OK,"class":l.OK,callback:c},{onEscape:c||!0})},confirm:function(){var b="",a=k("CANCEL"),c=k("CONFIRM"),e=null;switch(arguments.length){case 1:b=arguments[0]; +break;case 2:b=arguments[0];"function"==typeof arguments[1]?e=arguments[1]:a=arguments[1];break;case 3:b=arguments[0];a=arguments[1];"function"==typeof arguments[2]?e=arguments[2]:c=arguments[2];break;case 4:b=arguments[0];a=arguments[1];c=arguments[2];e=arguments[3];break;default:throw Error("Incorrect number of arguments: expected 1-4");}var h=function(){if("function"===typeof e)return e(!1)};return m.dialog(b,[{label:a,icon:g.CANCEL,"class":l.CANCEL,callback:h},{label:c,icon:g.CONFIRM,"class":l.CONFIRM, +callback:function(){if("function"===typeof e)return e(!0)}}],{onEscape:h})},prompt:function(){var b="",a=k("CANCEL"),c=k("CONFIRM"),e=null,h="";switch(arguments.length){case 1:b=arguments[0];break;case 2:b=arguments[0];"function"==typeof arguments[1]?e=arguments[1]:a=arguments[1];break;case 3:b=arguments[0];a=arguments[1];"function"==typeof arguments[2]?e=arguments[2]:c=arguments[2];break;case 4:b=arguments[0];a=arguments[1];c=arguments[2];e=arguments[3];break;case 5:b=arguments[0];a=arguments[1]; +c=arguments[2];e=arguments[3];h=arguments[4];break;default:throw Error("Incorrect number of arguments: expected 1-5");}var q=n("<form></form>");q.append("<input autocomplete=off type=text value='"+h+"' />");var h=function(){if("function"===typeof e)return e(null)},d=m.dialog(q,[{label:a,icon:g.CANCEL,"class":l.CANCEL,callback:h},{label:c,icon:g.CONFIRM,"class":l.CONFIRM,callback:function(){if("function"===typeof e)return e(q.find("input[type=text]").val())}}],{header:b,show:!1,onEscape:h});d.on("shown", +function(){q.find("input[type=text]").focus();q.on("submit",function(a){a.preventDefault();d.find(".btn-primary").click()})});d.modal("show");return d},dialog:function(b,a,c){function e(){var a=null;"function"===typeof c.onEscape&&(a=c.onEscape());!1!==a&&f.modal("hide")}var h="",l=[];c||(c={});"undefined"===typeof a?a=[]:"undefined"==typeof a.length&&(a=[a]);for(var d=a.length;d--;){var g=null,k=null,j=null,m="",p=null;if("undefined"==typeof a[d].label&&"undefined"==typeof a[d]["class"]&&"undefined"== +typeof a[d].callback){var g=0,k=null,r;for(r in a[d])if(k=r,1<++g)break;1==g&&"function"==typeof a[d][r]&&(a[d].label=k,a[d].callback=a[d][r])}"function"==typeof a[d].callback&&(p=a[d].callback);a[d]["class"]?j=a[d]["class"]:d==a.length-1&&2>=a.length&&(j="btn-primary");g=a[d].label?a[d].label:"Option "+(d+1);a[d].icon&&(m="<i class='"+a[d].icon+"'></i> ");k=a[d].href?a[d].href:"javascript:;";h="<a data-handler='"+d+"' class='btn "+j+"' href='"+k+"'>"+m+""+g+"</a>"+h;l[d]=p}d=["<div class='bootbox modal' tabindex='-1' style='overflow:hidden;'>"]; +if(c.header){j="";if("undefined"==typeof c.headerCloseButton||c.headerCloseButton)j="<a href='javascript:;' class='close'>×</a>";d.push("<div class='modal-header'>"+j+"<h3>"+c.header+"</h3></div>")}d.push("<div class='modal-body'></div>");h&&d.push("<div class='modal-footer'>"+h+"</div>");d.push("</div>");var f=n(d.join("\n"));("undefined"===typeof c.animate?u:c.animate)&&f.addClass("fade");(h="undefined"===typeof c.classes?v:c.classes)&&f.addClass(h);f.find(".modal-body").html(b);f.on("keyup.dismiss.modal", +function(a){27===a.which&&c.onEscape&&e("escape")});f.on("click","a.close",function(a){a.preventDefault();e("close")});f.on("shown",function(){f.find("a.btn-primary:first").focus()});f.on("hidden",function(){f.remove()});f.on("click",".modal-footer a",function(b){var c=n(this).data("handler"),d=l[c],e=null;"undefined"!==typeof c&&"undefined"!==typeof a[c].href||(b.preventDefault(),"function"===typeof d&&(e=d()),!1!==e&&f.modal("hide"))});n("body").append(f);f.modal({backdrop:"undefined"===typeof c.backdrop? +s:c.backdrop,keyboard:!1,show:!1});f.on("show",function(){n(w).off("focusin.modal")});("undefined"===typeof c.show||!0===c.show)&&f.modal("show");return f},modal:function(){var b,a,c,e={onEscape:null,keyboard:!0,backdrop:s};switch(arguments.length){case 1:b=arguments[0];break;case 2:b=arguments[0];"object"==typeof arguments[1]?c=arguments[1]:a=arguments[1];break;case 3:b=arguments[0];a=arguments[1];c=arguments[2];break;default:throw Error("Incorrect number of arguments: expected 1-3");}e.header=a; +c="object"==typeof c?n.extend(e,c):e;return m.dialog(b,[],c)},hideAll:function(){n(".bootbox").modal("hide")},animate:function(b){u=b},backdrop:function(b){s=b},classes:function(b){v=b}},j={en:{OK:"OK",CANCEL:"Cancel",CONFIRM:"OK"},fr:{OK:"OK",CANCEL:"Annuler",CONFIRM:"D'accord"},de:{OK:"OK",CANCEL:"Abbrechen",CONFIRM:"Akzeptieren"},es:{OK:"OK",CANCEL:"Cancelar",CONFIRM:"Aceptar"},br:{OK:"OK",CANCEL:"Cancelar",CONFIRM:"Sim"},nl:{OK:"OK",CANCEL:"Annuleren",CONFIRM:"Accepteren"},ru:{OK:"OK",CANCEL:"\u041e\u0442\u043c\u0435\u043d\u0430", +CONFIRM:"\u041f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c"},it:{OK:"OK",CANCEL:"Annulla",CONFIRM:"Conferma"}};return m}(document,window.jQuery);window.bootbox=bootbox; https://bitbucket.org/virtualcommons/vcweb/commits/42abc2730526/ changeset: 42abc2730526 user: alllee date: 2013-03-20 00:06:12 summary: fixing transition from welcome -> general instructions round for boundaries experiment affected #: 8 files diff -r a975b53ad5697269d712da8d2ed0b7e05eddfdc4 -r 42abc273052667a4bb840d3ff8b20856f0f5bcd4 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -342,7 +342,6 @@ model.isTimerRunning = ko.computed(function() { return model.secondsLeft() > 0; }); - model.templateName = ko.observable("WELCOME"); // activate instructions click bindings model.activateInstructionsPageOne = function() { model.templateName('GENERAL_INSTRUCTIONS'); @@ -477,19 +476,6 @@ $('#harvestDecision').keyup(function() { $('#harvestDecision').val(this.value.match(/\d+/)); }); - $('#pick-template').change(function() { - var templateName = $(this).val(); - console.debug("switching to template: " + templateName); - if (templateName === "PRACTICE") { - templateName = "REGULAR"; - experimentModel.practiceRound(true); - } - else if (templateName === "REGULAR") { - experimentModel.practiceRound(false); - } - experimentModel.templateName(templateName); - }); - } //send the message when submit is clicked var experimentModelJson = $.parseJSON("{{ experimentModelJson|escapejs }}"); diff -r a975b53ad5697269d712da8d2ed0b7e05eddfdc4 -r 42abc273052667a4bb840d3ff8b20856f0f5bcd4 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -5,7 +5,7 @@ from vcweb.core.decorators import participant_required from vcweb.core.http import JsonResponse from vcweb.core.models import (is_participant, is_experimenter, Experiment, ParticipantGroupRelationship, - ParticipantExperimentRelationship, ChatMessage, ParticipantRoundDataValue) + ParticipantExperimentRelationship, ChatMessage, ParticipantRoundDataValue, GroupRelationship) from vcweb.boundaries.forms import HarvestDecisionForm from vcweb.boundaries.models import (get_experiment_metadata, get_regrowth_rate, get_harvest_decision_parameter, get_cost_of_living, get_resource_level, get_initial_resource_level, get_total_storage, get_storage, @@ -54,6 +54,7 @@ return JsonResponse(dumps({'success': False })) +# FIXME: need to distinguish between instructions / welcome rounds and practice/regular rounds def get_view_model_json(experiment, participant_group_relationship, **kwargs): ec = experiment.experiment_configuration current_round = experiment.current_round @@ -65,7 +66,7 @@ regrowth_rate = get_regrowth_rate(current_round) cost_of_living = get_cost_of_living(current_round) own_group = participant_group_relationship.group - own_resource_level = 0 + own_resource_level = get_resource_level(own_group) last_harvest_decision = get_last_harvest_decision(participant_group_relationship, round_data=previous_round_data) experiment_model_dict['playerData'] = [{ 'id': pgr.participant_number, @@ -86,7 +87,7 @@ if group != own_group: group_data.append({ 'groupId': unicode(group), - 'resourceLevel': resource_level, + 'resourceLevel': get_resource_level(group), 'totalStorage': get_total_storage(group), 'regrowthRate': regrowth_rate, 'costOfLiving': cost_of_living, @@ -95,13 +96,22 @@ # round / experiment configuration data experiment_model_dict['participantsPerGroup'] = ec.max_group_size - experiment_model_dict['roundType'] = current_round.round_type experiment_model_dict['regrowthRate'] = regrowth_rate experiment_model_dict['costOfLiving'] = cost_of_living experiment_model_dict['participantNumber'] = participant_group_relationship.participant_number experiment_model_dict['participantGroupId'] = participant_group_relationship.pk - experiment_model_dict['dollarsPerToken'] = ec.exchange_rate - experiment_model_dict['chatEnabled'] = current_round.chat_enabled + experiment_model_dict['dollarsPerToken'] = float(ec.exchange_rate) + experiment_model_dict['roundType'] = current_round.round_type + experiment_model_dict['practiceRound'] = current_round.is_practice_round + experiment_model_dict['chatEnabled'] = False + if current_round.is_regular_round: + experiment_model_dict['chatEnabled'] = current_round.chat_enabled + if current_round.is_practice_round: + experiment_model_dict['templateName'] = 'REGULAR' + else: + experiment_model_dict['templateName'] = current_round.round_type + + # FIXME: defaults hard coded in for now experiment_model_dict['maxEarnings'] = 20.00 experiment_model_dict['warningCountdownTime'] = 10 @@ -112,7 +122,6 @@ # FIXME: these need to be looked up experiment_model_dict['maxHarvestDecision'] = 10 experiment_model_dict['hasSubmit'] = False - experiment_model_dict['practiceRound'] = current_round.is_practice_round experiment_model_dict['instructions'] = current_round.get_custom_instructions() experiment_model_dict.update(**kwargs) return dumps(experiment_model_dict) diff -r a975b53ad5697269d712da8d2ed0b7e05eddfdc4 -r 42abc273052667a4bb840d3ff8b20856f0f5bcd4 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -528,11 +528,11 @@ def get_participant_group_relationship(self, participant): session_id = self.current_round.session_id - if session_id is None: - return ParticipantGroupRelationship.objects.get(group__experiment=self, participant=participant) - else: + if session_id: return ParticipantGroupRelationship.objects.get(group__experiment=self, participant=participant, group__session_id=session_id) + else: + return ParticipantGroupRelationship.objects.get(group__experiment=self, participant=participant) def all_participants_have_submitted(self): return ParticipantRoundDataValue.objects.filter(submitted=False, round_data=self.current_round_data).count() == 0 @@ -888,13 +888,14 @@ # maps round type name to (description, default_template_name) ROUND_TYPES_DICT = dict( WELCOME=('Initial welcome round', 'welcome.html'), + GENERAL_INSTRUCTIONS=('General instructions round (introduction)', 'general-instructions.html'), REGULAR=('Regular experiment round', 'participate.html'), CHAT=('Chat round', 'chat.html'), DEBRIEFING=('Debriefing round', 'debriefing.html'), INSTRUCTIONS=('Instructions round', 'instructions.html'), PRACTICE=('Practice round', 'practice.html'), QUIZ=('Quiz round', 'quiz.html')) - ROUND_TYPES = (CHAT, DEBRIEFING, INSTRUCTIONS, PRACTICE, QUIZ, REGULAR, WELCOME) = sorted(ROUND_TYPES_DICT.keys()) + ROUND_TYPES = (CHAT, DEBRIEFING, GENERAL_INSTRUCTIONS, INSTRUCTIONS, PRACTICE, QUIZ, REGULAR, WELCOME) = sorted(ROUND_TYPES_DICT.keys()) ROUND_TYPE_CHOICES = Choices(*[(round_type, ROUND_TYPES_DICT[round_type][0]) for round_type in ROUND_TYPES]) PLAYABLE_ROUND_CONFIGURATIONS = (PRACTICE, REGULAR) @@ -958,12 +959,16 @@ if not self.is_instructions_round: logger.warning("tried to get custom instructions for a non-instructions round %s", self) return None - instructions_template = select_template([self.template_path]) - if context_dict is None: - context_dict = {} - context_dict.update(kwargs, session_number=self.session_id) - c = Context(context_dict) - return instructions_template.render(c) + try: + instructions_template = select_template([self.template_path]) + if context_dict is None: + context_dict = {} + context_dict.update(kwargs, session_number=self.session_id) + c = Context(context_dict) + return instructions_template.render(c) + except: + logger.warning("no template found for custom instructions: %s", self.template_path) + return None @property def template_path(self): diff -r a975b53ad5697269d712da8d2ed0b7e05eddfdc4 -r 42abc273052667a4bb840d3ff8b20856f0f5bcd4 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -137,6 +137,16 @@ </div></div></div> +<div id='progress-modal' class='modal hide fade'> + <div class='model-header'> + <h3>Updating experiment status</h3> + </div> + <div class='modal-body'> + <div class='progress progress-striped active'> + <div id='progress-bar' class='bar' style='width: 50%'></div> + </div> + </div> +</div> {% endblock page %} {% block javascript %} {{ block.super }} @@ -159,6 +169,7 @@ function update(experimentModel) { return function(data) { ko.mapping.fromJS(data, experimentModel); + $('#progress-modal').modal('hide'); } } function initialize(experimentModelJson) { @@ -183,6 +194,7 @@ bootbox.confirm(description + " Continue?", function(confirmed) { if (confirmed) { Dajaxice.vcweb.core.experiment_controller(update(experimentModel), {'pk': {{experiment.pk}}, 'action':action}); + $('#progress-modal').modal({keyboard: false}); } return false; }); Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
|
From: <com...@bi...> - 2013-03-19 19:57:57
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/4dbb0ffe297c/ changeset: 4dbb0ffe297c user: alllee date: 2013-03-19 20:57:54 summary: version bump on jquery.cookie plugin affected #: 1 file diff -r b077379cb082b25c8092b234d0669da7ef8ac189 -r 4dbb0ffe297cfd0e71a9ef19d20d0dbf97ddaf9d vcweb/static/js/jquery.cookie.js --- a/vcweb/static/js/jquery.cookie.js +++ b/vcweb/static/js/jquery.cookie.js @@ -1,72 +1,90 @@ /*! - * jQuery Cookie Plugin v1.3 + * jQuery Cookie Plugin v1.3.1 * https://github.com/carhartl/jquery-cookie * - * Copyright 2011, Klaus Hartl - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://www.opensource.org/licenses/mit-license.php - * http://www.opensource.org/licenses/GPL-2.0 + * Copyright 2013 Klaus Hartl + * Released under the MIT license */ (function ($, document, undefined) { - var pluses = /\+/g; + var pluses = /\+/g; - function raw(s) { - return s; - } + function raw(s) { + return s; + } - function decoded(s) { - return decodeURIComponent(s.replace(pluses, ' ')); - } + function decoded(s) { + return unRfc2068(decodeURIComponent(s.replace(pluses, ' '))); + } - var config = $.cookie = function (key, value, options) { + function unRfc2068(value) { + if (value.indexOf('"') === 0) { + // This is a quoted cookie as according to RFC2068, unescape + value = value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); + } + return value; + } - // write - if (value !== undefined) { - options = $.extend({}, config.defaults, options); + function fromJSON(value) { + return config.json ? JSON.parse(value) : value; + } - if (value === null) { - options.expires = -1; - } + var config = $.cookie = function (key, value, options) { - if (typeof options.expires === 'number') { - var days = options.expires, t = options.expires = new Date(); - t.setDate(t.getDate() + days); - } + // write + if (value !== undefined) { + options = $.extend({}, config.defaults, options); - value = config.json ? JSON.stringify(value) : String(value); + if (value === null) { + options.expires = -1; + } - return (document.cookie = [ - encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value), - options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE - options.path ? '; path=' + options.path : '', - options.domain ? '; domain=' + options.domain : '', - options.secure ? '; secure' : '' - ].join('')); - } + if (typeof options.expires === 'number') { + var days = options.expires, t = options.expires = new Date(); + t.setDate(t.getDate() + days); + } - // read - var decode = config.raw ? raw : decoded; - var cookies = document.cookie.split('; '); - for (var i = 0, l = cookies.length; i < l; i++) { - var parts = cookies[i].split('='); - if (decode(parts.shift()) === key) { - var cookie = decode(parts.join('=')); - return config.json ? JSON.parse(cookie) : cookie; - } - } + value = config.json ? JSON.stringify(value) : String(value); - return null; - }; + return (document.cookie = [ + encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value), + options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE + options.path ? '; path=' + options.path : '', + options.domain ? '; domain=' + options.domain : '', + options.secure ? '; secure' : '' + ].join('')); + } - config.defaults = {}; + // read + var decode = config.raw ? raw : decoded; + var cookies = document.cookie.split('; '); + var result = key ? null : {}; + for (var i = 0, l = cookies.length; i < l; i++) { + var parts = cookies[i].split('='); + var name = decode(parts.shift()); + var cookie = decode(parts.join('=')); - $.removeCookie = function (key, options) { - if ($.cookie(key) !== null) { - $.cookie(key, null, options); - return true; - } - return false; - }; + if (key && key === name) { + result = fromJSON(cookie); + break; + } -})(jQuery, document); + if (!key) { + result[name] = fromJSON(cookie); + } + } + + return result; + }; + + config.defaults = {}; + + $.removeCookie = function (key, options) { + if ($.cookie(key) !== null) { + $.cookie(key, null, options); + return true; + } + return false; + }; + +})(jQuery, document); \ No newline at end of file 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-19 19:42:15
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/b077379cb082/ changeset: b077379cb082 user: alllee date: 2013-03-19 20:42:13 summary: refining experimenter monitor view a bit, replacing navlist with button groups affected #: 2 files diff -r 20d7401e0ff852fe5becdbee8d9cd8d792610972 -r b077379cb082b25c8092b234d0669da7ef8ac189 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -28,7 +28,7 @@ return render_to_response('boundaries/participate.html', { 'auth_token': participant.authentication_token, 'experiment': experiment, - 'participant_experiment_relationship': experiment.get_participant_experiment_relationship(participant) + 'participant_experiment_relationship': experiment.get_participant_experiment_relationship(participant), 'participant_group_relationship': pgr, 'experimentModelJson': get_view_model_json(experiment, pgr), }, diff -r 20d7401e0ff852fe5becdbee8d9cd8d792610972 -r b077379cb082b25c8092b234d0669da7ef8ac189 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -9,11 +9,15 @@ <div class='span6'><ul class='nav nav-list' data-bind="if: isActive"><li class='nav-header'>round management</li> - <li><a class='confirm-experiment-action' name='advance_to_next_round' href='javascript:void()' data-content='Stops the current round if necessary and advances to the next round.'><i class='icon-step-forward'></i>advance to next round</a></li> - <li data-bind="ifnot: isRoundInProgress"><a class='confirm-experiment-action' name='start_round' href='start-round' data-content='Starts the round.'><i class='icon-play'></i>start round</a></li> - <li data-bind="if: isRoundInProgress"><a class='confirm-experiment-action' name='end_round' href='end-round' data-content='Stops the current round.'><i class='icon-stop'></i>end round</a></li> - <li><a href='javascript:void();' id='refreshAllParticipants' data-content='Sends a page refresh to all connected participants.' ><i class='icon-refresh'></i>refresh all participants</a></li> - <li class='divider'></li> + <li> + <div class='btn-toolbar'> + <div class='btn-group'> + <a class='btn btn-success confirm-experiment-action' data-bind="css: { disabled: isRoundInProgress }" name='start_round' data-content='Starts the round.'><i class='icon-play'></i> start</a> + <a class='btn btn-success confirm-experiment-action' name='advance_to_next_round' data-content='Advances to the next round and starts it.'><i class='icon-step-forward'></i> next round</a> + <!-- FIXME: disabled for the time being<a class='btn btn-primary' id='refreshAllParticipants' data-content='Sends a page refresh to all connected participants.' ><i class='icon-refresh'></i> refresh participants</a> --> + </div> + </div> + </li></ul> {% comment %} should offer different actions (start + reset) to experiments that has already been activated / started {% endcomment %} <div data-bind='if: isArchived()'> @@ -53,18 +57,17 @@ <li>Registered participants: <span data-bind='text:participantCount' class='badge badge-info'></span></li></ul><div class='alert alert-message alert-block'> - <h4><i class='icon-download'></i>Download Data</h4> + <h4><i class='icon-download'></i> Download Data</h4><ul class='inline'><li><a href='download/csv'><img src='{{STATIC_URL}}images/famfamfam/page_white_text.png' alt='csv' />csv</a></li><li><a href='download/xls'><img src='{{STATIC_URL}}images/famfamfam/page_white_excel.png' alt='xls'/>xls</a></li></ul> - </div> - <div class='alert alert-message'><h4><i class='icon-download-alt'></i>Download Configuration Files</h4><ul class='inline'><li><a href='export/configuration.xml'><i class='icon-cog'></i>xml</a></li><li><a href='export/configuration.json'><i class='icon-pencil'></i>json</a></li></ul> + <a class='btn btn-info confirm-experiment-action' name='complete' data-content='Mark this experiment as completed and archive it.'><i class='icon-save'></i> archive</a></div></div><div class='span6'> @@ -173,6 +176,10 @@ var self = $(this); var description = self.attr("data-content"); var action = self.attr("name"); + if (self.hasClass('disabled')) { + console.debug("disabled action " + action + " - ignoring"); + return false; + } bootbox.confirm(description + " Continue?", function(confirmed) { if (confirmed) { Dajaxice.vcweb.core.experiment_controller(update(experimentModel), {'pk': {{experiment.pk}}, 'action':action}); @@ -188,7 +195,7 @@ }); return experimentModel; } - $('[data-content]').popover(); + $('[data-content]').popover({placement: 'top', trigger: 'hover'}); // initialize experiment model JSON from experiment model initialize(experimentModelJson); }); 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-19 07:10:17
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/20d7401e0ff8/ changeset: 20d7401e0ff8 user: alllee date: 2013-03-19 08:09:57 summary: adding participant experiment relationship back for sockjs connectivity affected #: 3 files diff -r 69282ad0b5f9fb3882ed224cd6c15106ab0f8875 -r 20d7401e0ff852fe5becdbee8d9cd8d792610972 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -28,6 +28,7 @@ return render_to_response('boundaries/participate.html', { 'auth_token': participant.authentication_token, 'experiment': experiment, + 'participant_experiment_relationship': experiment.get_participant_experiment_relationship(participant) 'participant_group_relationship': pgr, 'experimentModelJson': get_view_model_json(experiment, pgr), }, diff -r 69282ad0b5f9fb3882ed224cd6c15106ab0f8875 -r 20d7401e0ff852fe5becdbee8d9cd8d792610972 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -450,7 +450,7 @@ @property def playable_round_data(self): - return self.round_data_set.select_related(depth=1).filter(round_configuration__round_type__in=RoundConfiguration.PLAYABLE_ROUND_CONFIGURATIONS, + return self.round_data_set.select_related('experiment', 'round_configuration').filter(round_configuration__round_type__in=RoundConfiguration.PLAYABLE_ROUND_CONFIGURATIONS, round_configuration__sequence_number__lte=self.current_round_sequence_number) @property @@ -523,6 +523,9 @@ def all_participants_ready(self): return self.ready_participants >= self.participant_set.count() + def get_participant_experiment_relationship(self, participant): + return self.participant_relationship_set.get(participant=participant) + def get_participant_group_relationship(self, participant): session_id = self.current_round.session_id if session_id is None: @@ -1592,6 +1595,8 @@ birthdate = models.DateField(null=True, blank=True) address = models.ForeignKey(Address, null=True, blank=True) + ''' + FIXME: move these into a ParticipantQuerySet with PassThroughManager if needed @property def active_experiments(self): return self.experiment_relationship_set.filter(experiment__status=Experiment.Status.ACTIVE) @@ -1604,14 +1609,9 @@ def completed_experiments(self): return self.experiments_with_status(Experiment.Status.COMPLETED) - def get_participant_experiment_relationship(self, experiment): - return ParticipantExperimentRelationship.objects.select_related(depth=1).get(participant=self, experiment=experiment) - - def get_participant_group_relationship(self, experiment): - return ParticipantGroupRelationship.objects.get_relationship(self, experiment) - def experiments_with_status(self, status=Experiment.Status.ACTIVE): return self.experiment_relationship_set.filter(experiment__status=status) + ''' class Meta: ordering = ['user'] diff -r 69282ad0b5f9fb3882ed224cd6c15106ab0f8875 -r 20d7401e0ff852fe5becdbee8d9cd8d792610972 vcweb/vcweb-sockjs.py --- a/vcweb/vcweb-sockjs.py +++ b/vcweb/vcweb-sockjs.py @@ -163,7 +163,7 @@ ''' def connections(self, group): experiment = group.experiment - for participant_group_relationship in group.participant_group_relationship_set.select_related(depth=1).all(): + for participant_group_relationship in group.participant_group_relationship_set.select_related('participant').all(): ''' only return currently connected connections in this group ''' participant = participant_group_relationship.participant participant_tuple = (participant.pk, experiment.pk) 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-19 07:01:17
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/69282ad0b5f9/ changeset: 69282ad0b5f9 user: alllee date: 2013-03-19 08:01:00 summary: session ids should be embedded in the round configurations themselves affected #: 2 files diff -r 7f44c1cbedbc8a556647b7dbf3ebca272897ff92 -r 69282ad0b5f9fb3882ed224cd6c15106ab0f8875 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -111,14 +111,7 @@ # FIXME: these need to be looked up experiment_model_dict['maxHarvestDecision'] = 10 experiment_model_dict['hasSubmit'] = False - experiment_model_dict['practiceRound'] = round_configuration.is_practice_round - experiment_model_dict['instructions'] = current_round.get_custom_instructions(session_number=get_session_number(current_round)) + experiment_model_dict['practiceRound'] = current_round.is_practice_round + experiment_model_dict['instructions'] = current_round.get_custom_instructions() experiment_model_dict.update(**kwargs) return dumps(experiment_model_dict) - -def get_session_number(round_configuration): - # FIXME: brittle but alternatives are messy and time consuming, refactor later - if round_configuration.sequence_number > 22: - return 2 - else: - return 1 diff -r 7f44c1cbedbc8a556647b7dbf3ebca272897ff92 -r 69282ad0b5f9fb3882ed224cd6c15106ab0f8875 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -958,7 +958,7 @@ instructions_template = select_template([self.template_path]) if context_dict is None: context_dict = {} - context_dict.update(kwargs) + context_dict.update(kwargs, session_number=self.session_id) c = Context(context_dict) return instructions_template.render(c) 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. |