virtualcommons-developer Mailing List for Virtual Commons Experiment Software
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-28 03:45:34
|
4 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/55fc8fda20b5/ Changeset: 55fc8fda20b5 User: alllee Date: 2013-03-28 03:30:52 Summary: replacing activateXXX methods with a single parameterized activateTemplate method that takes the template to activate. Affected #: 1 file diff -r 63c8882e10ecc82ef2d8ac613210ce555db6ebea -r 55fc8fda20b5cd89a805cac1b7e74ad8d6a5c71a vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -50,6 +50,20 @@ {% block javascript %} {{ block.super }} <!-- ko templates --> +<script type='text/html' id='PRACTICE_ROUND_RESULTS'> + <h3>Practice Round Results</h3> + <p> + If this had been been a paid session, you would have earned <span class='text-gold' data-bind='text: formatCurrency(totalEarnings)'></span>. + </p> + <p> + We will now move on to the <strong>paid rounds.</strong> + </p> + <ul class='pager'> + <li class='next'> + <a data-bind='click: activateTemplate.bind($data, "PAID_EXPERIMENT_INSTRUCTIONS")'>Ok, continue</a> + </li> + </ul> +</script><script type='text/html' id='WAITING_ROOM'><h3>Waiting for other participants</h3><div> @@ -108,7 +122,7 @@ </p><ul class='pager'><li class='next'> -<a href='javascript: void();' data-bind='click: activateInstructionsPageTwo'>OK, I understand</a> +<a href='javascript: void();' data-bind='click: activateTemplate.bind($data, "GENERAL_INSTRUCTIONS2")'>OK, I understand</a></li></ul></div> @@ -137,10 +151,10 @@ </p><ul class='pager'><li class='previous'> -<a href='javascript: void();' data-bind='click: activateInstructionsPageOne' >Back</a> +<a href='javascript: void();' data-bind='click: activateTemplate.bind($data, "GENERAL_INSTRUCTIONS")' >Back</a></li><li class='next'> -<a href='javascript: void();' data-bind='click: activateInstructionsPageThree' >OK, I understand</a> +<a href='javascript: void();' data-bind='click: activateTemplate.bind($data, "GENERAL_INSTRUCTIONS3")' >OK, I understand</a></li></ul></div> @@ -161,10 +175,10 @@ </p><ul class='pager'><li class='previous'> -<a href='javascript: void();' data-bind='click: activateInstructionsPageTwo' >Back</a> +<a href='javascript: void();' data-bind='click: activateTemplate.bind($data, "GENERAL_INSTRUCTIONS2")' >Back</a></li><li class='next'> -<a href='javascript: void();' data-bind='click: activatePracticeRoundInstructions'>OK, Continue to practice rounds</a> +<a href='javascript: void();' data-bind='click: activateTemplate.bind($data, "PRACTICE_ROUND_INSTRUCTIONS")'>OK, Continue to practice rounds</a></li></ul></div> @@ -194,7 +208,7 @@ </p><ul class='pager'><li class='previous'> -<a href='javascript:void();' data-bind='click: activateInstructionsPageThree'>Back</a> +<a href='javascript:void();' data-bind='click: activateTemplate.bind($data, "GENERAL_INSTRUCTIONS3")'>Back</a></li><li class='next'><a href='javascript: void();' data-bind='click: participantReady'>I have fully read and understand these instructions</a> @@ -368,6 +382,8 @@ model.secondsLeft = ko.observable(0); model.currentInterval = ko.observable(); model.templateName = ko.computed(function() { + // FIXME: not sure about this style of template name manipulation, maybe it's still more straightforward + // to just have a templateName observable instead of a computed.. switch ( model.roundType() ) { case 'PRACTICE': return 'REGULAR'; @@ -393,34 +409,19 @@ return model.secondsLeft() > 0; }); // activate instructions click bindings - model.activateInstructionsPageOne = function() { - model.roundType('GENERAL_INSTRUCTIONS'); - }; - model.activateInstructionsPageTwo = function() { - model.roundType('GENERAL_INSTRUCTIONS2'); - }; - model.activateInstructionsPageThree = function() { - model.roundType('GENERAL_INSTRUCTIONS3'); - }; - model.activateWaitingRoomPage = function() { - model.roundType('WAITING_ROOM'); + model.activateTemplate = function(templateName) { + model.roundType(templateName); } model.readyParticipantsPercentage = ko.computed(function() { return (model.readyParticipants() / model.totalNumberOfParticipants()) * 100; }); - model.activatePracticeRoundInstructions = function() { - model.roundType("PRACTICE_ROUND_INSTRUCTIONS"); - } - model.activateTreatmentInstructions = function() { - model.roundType("TREATMENT_INSTRUCTIONS"); - } model.participantReady = function() { $.post('/experiment/participant-ready', { participant_group_id: model.participantGroupId() }, function(response) { console.debug("successfully posted to server, notifying sockjs"); console.debug(response); getWebSocket().send(createMessageEvent("Participant finished reading instructions", "client_ready")); model.readyParticipants(response.number_of_ready_participants); - model.activateWaitingRoomPage(); + model.activateTemplate("WAITING_ROOM"); }); } model.showOtherGroup = function() { https://bitbucket.org/virtualcommons/vcweb/commits/f46602ee6c9d/ Changeset: f46602ee6c9d User: alllee Date: 2013-03-28 03:42:17 Summary: adding template_id field to RoundConfiguration to specify an in-page HTML template to render as part of a round configuration Affected #: 4 files diff -r 55fc8fda20b5cd89a805cac1b7e74ad8d6a5c71a -r f46602ee6c9dcf52d269adf129a70b96ce29f48f vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -382,13 +382,11 @@ model.secondsLeft = ko.observable(0); model.currentInterval = ko.observable(); model.templateName = ko.computed(function() { - // FIXME: not sure about this style of template name manipulation, maybe it's still more straightforward - // to just have a templateName observable instead of a computed.. - switch ( model.roundType() ) { + switch ( model.templateId() ) { case 'PRACTICE': return 'REGULAR'; default: - return model.roundType(); + return model.templateId(); } }); model.setCurrentInterval = function(intervalId) { @@ -409,8 +407,8 @@ return model.secondsLeft() > 0; }); // activate instructions click bindings - model.activateTemplate = function(templateName) { - model.roundType(templateName); + model.activateTemplate = function(templateId) { + model.templateId(templateId); } model.readyParticipantsPercentage = ko.computed(function() { return (model.readyParticipants() / model.totalNumberOfParticipants()) * 100; diff -r 55fc8fda20b5cd89a805cac1b7e74ad8d6a5c71a -r f46602ee6c9dcf52d269adf129a70b96ce29f48f vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -91,7 +91,7 @@ experiment_model_dict['participantNumber'] = participant_group_relationship.participant_number experiment_model_dict['participantGroupId'] = participant_group_relationship.pk - experiment_model_dict['roundType'] = current_round.round_type + experiment_model_dict['templateId'] = current_round.round_type experiment_model_dict['practiceRound'] = current_round.is_practice_round if current_round.is_regular_round: diff -r 55fc8fda20b5cd89a805cac1b7e74ad8d6a5c71a -r f46602ee6c9dcf52d269adf129a70b96ce29f48f vcweb/core/migrations/0004_auto__add_field_roundconfiguration_template_id.py --- /dev/null +++ b/vcweb/core/migrations/0004_auto__add_field_roundconfiguration_template_id.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): + # Adding field 'RoundConfiguration.template_id' + db.add_column(u'core_roundconfiguration', 'template_id', + self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'RoundConfiguration.template_id' + db.delete_column(u'core_roundconfiguration', 'template_id') + + + 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_sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'current_round_start_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentConfiguration']"}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentMetadata']"}), + 'experimenter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experimenter']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'start_date_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'INACTIVE'", 'max_length': '32'}), + 'tick_duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'total_elapsed_time': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + }, + u'core.experimentactivitylog': { + 'Meta': {'object_name': 'ExperimentActivityLog', '_ormbases': [u'core.ActivityLog']}, + u'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': u"orm['core.Experiment']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.experimentconfiguration': { + 'Meta': {'ordering': "['experiment_metadata', 'creator', 'date_created']", 'object_name': 'ExperimentConfiguration'}, + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': u"orm['core.Experimenter']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'exchange_rate': ('django.db.models.fields.DecimalField', [], {'default': '0.2', 'null': 'True', 'max_digits': '6', 'decimal_places': '2', 'blank': 'True'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': u"orm['core.ExperimentMetadata']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation_subject': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'is_experimenter_driven': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'max_group_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), + 'max_number_of_participants': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'treatment_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}) + }, + u'core.experimenter': { + 'Meta': {'ordering': "['user']", 'object_name': 'Experimenter'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'authentication_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'failed_password_attempts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'institution': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Institution']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'experimenter'", 'unique': 'True', 'to': u"orm['auth.User']"}) + }, + u'core.experimenterrequest': { + 'Meta': {'object_name': 'ExperimenterRequest'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'}) + }, + u'core.experimentmetadata': { + 'Meta': {'ordering': "['namespace', 'date_created']", 'object_name': 'ExperimentMetadata'}, + 'about_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'default_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentConfiguration']", 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'namespace': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'short_name': ('django.db.models.fields.SlugField', [], {'max_length': '32', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'core.experimentparametervalue': { + 'Meta': {'object_name': 'ExperimentParameterValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_parameter_value_set'", 'to': u"orm['core.ExperimentConfiguration']"}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.experimentsession': { + 'Meta': {'object_name': 'ExperimentSession'}, + 'capacity': ('django.db.models.fields.PositiveIntegerField', [], {'default': '20'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_session_set'", 'to': u"orm['auth.User']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_session_set'", 'to': u"orm['core.ExperimentMetadata']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'scheduled_date': ('django.db.models.fields.DateTimeField', [], {}), + 'scheduled_end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.group': { + 'Meta': {'ordering': "['experiment', 'number']", 'object_name': 'Group'}, + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'max_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), + 'number': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.groupactivitylog': { + 'Meta': {'object_name': 'GroupActivityLog', '_ormbases': [u'core.ActivityLog']}, + u'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': u"orm['core.Group']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.groupcluster': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'GroupCluster'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_cluster_set'", 'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.groupclusterdatavalue': { + 'Meta': {'object_name': 'GroupClusterDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'group_cluster': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.GroupCluster']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'round_data': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_cluster_data_value_set'", 'to': u"orm['core.RoundData']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.grouprelationship': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'GroupRelationship'}, + 'cluster': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_relationship_set'", 'to': u"orm['core.GroupCluster']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'core.grouprounddatavalue': { + 'Meta': {'ordering': "['round_data', 'group', 'parameter']", 'object_name': 'GroupRoundDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'data_value_set'", 'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.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', 'null': 'True', 'blank': 'True'}), + 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_id': ('django.db.models.fields.CharField', [], {'max_length': '128', '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 diff -r 55fc8fda20b5cd89a805cac1b7e74ad8d6a5c71a -r f46602ee6c9dcf52d269adf129a70b96ce29f48f vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -1015,6 +1015,8 @@ help_text=_('''The name of the template to use to render when executing this round. This file should exist in your templates directory as your-experiment-namespace/template-name.html, e.g., if set to foo.html, vcweb will look for templates/forestry/foo.html''')) + template_id = models.CharField(max_length=128, null=True, blank=True, + help_text=_('A HTML template ID to use in a single page app, e.g., KO template')) survey_url = models.URLField(null=True, blank=True) """ external survey url """ chat_enabled = models.BooleanField(default=False, help_text=_("Is chat enabled in this round?")) https://bitbucket.org/virtualcommons/vcweb/commits/39518ecd3789/ Changeset: 39518ecd3789 User: alllee Date: 2013-03-28 04:32:20 Summary: schema updates, changing RoundConfiguration.template_name to RoundConfiguration.template_filename to make room for a template_name property that looks up template_id or defaults to round_type Affected #: 11 files diff -r f46602ee6c9dcf52d269adf129a70b96ce29f48f -r 39518ecd37898188f47840d665e8ee70b0ae5cba vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -6,7 +6,7 @@ <link rel='stylesheet' href='{% static "css/boundaries/style.css" %}'/> {% endblock %} {% block content %} -<div data-bind='template: { name: templateName(), afterRender: afterRenderTemplate }'> +<div data-bind='template: { name: templateId(), afterRender: afterRenderTemplate }'></div><div id='progress-modal' class='modal hide fade'><div class='model-header'> @@ -381,12 +381,12 @@ var model = ko.mapping.fromJS(experimentModelJson); model.secondsLeft = ko.observable(0); model.currentInterval = ko.observable(); - model.templateName = ko.computed(function() { - switch ( model.templateId() ) { + model.templateId = ko.computed(function() { + switch ( model.templateName() ) { case 'PRACTICE': return 'REGULAR'; default: - return model.templateId(); + return model.templateName(); } }); model.setCurrentInterval = function(intervalId) { @@ -407,8 +407,8 @@ return model.secondsLeft() > 0; }); // activate instructions click bindings - model.activateTemplate = function(templateId) { - model.templateId(templateId); + model.activateTemplate = function(name) { + model.templateName(name); } model.readyParticipantsPercentage = ko.computed(function() { return (model.readyParticipants() / model.totalNumberOfParticipants()) * 100; @@ -527,7 +527,7 @@ } } model.afterRenderTemplate = function(elements) { - if (model.templateName() === "REGULAR") { + if (model.templateId() === "REGULAR") { model.startRound() } } diff -r f46602ee6c9dcf52d269adf129a70b96ce29f48f -r 39518ecd37898188f47840d665e8ee70b0ae5cba vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -91,7 +91,7 @@ experiment_model_dict['participantNumber'] = participant_group_relationship.participant_number experiment_model_dict['participantGroupId'] = participant_group_relationship.pk - experiment_model_dict['templateId'] = current_round.round_type + experiment_model_dict['templateName'] = current_round.template_name experiment_model_dict['practiceRound'] = current_round.is_practice_round if current_round.is_regular_round: diff -r f46602ee6c9dcf52d269adf129a70b96ce29f48f -r 39518ecd37898188f47840d665e8ee70b0ae5cba vcweb/broker/fixtures/broker_experiment_metadata.json --- a/vcweb/broker/fixtures/broker_experiment_metadata.json +++ b/vcweb/broker/fixtures/broker_experiment_metadata.json @@ -67,10 +67,9 @@ "fields": { "experiment_metadata": 7, "status": "INACTIVE", - "start_date_time": null, + "date_activated": null, "tick_duration": "", "authentication_code": "broker_test", - "total_elapsed_time": 0, "current_round_start_time": null, "last_modified": "2013-02-13T15:53:45.902", "experimenter": 7, diff -r f46602ee6c9dcf52d269adf129a70b96ce29f48f -r 39518ecd37898188f47840d665e8ee70b0ae5cba vcweb/core/migrations/0004_auto__add_field_roundconfiguration_template_id.py --- a/vcweb/core/migrations/0004_auto__add_field_roundconfiguration_template_id.py +++ b/vcweb/core/migrations/0004_auto__add_field_roundconfiguration_template_id.py @@ -8,16 +8,37 @@ class Migration(SchemaMigration): def forwards(self, orm): + # rename field 'RoundConfiguration.template_name' to 'RoundConfiguration.template_filename' + db.rename_column(u'core_roundconfiguration', 'template_name', 'template_filename') + # Adding field 'RoundConfiguration.template_id' db.add_column(u'core_roundconfiguration', 'template_id', self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True), keep_default=False) + # Renaming field 'Experiment.start_date_time' to 'Experiment.date_activated' + db.rename_column(u'core_experiment', 'start_date_time', 'date_activated') + + # Deleting field 'Experiment.total_elapsed_time' + db.delete_column(u'core_experiment', 'total_elapsed_time') + def backwards(self, orm): + # Rename field 'RoundConfiguration.template_filename' + db.rename_column(u'core_roundconfiguration', 'template_filename', 'template_name') + # Deleting field 'RoundConfiguration.template_id' db.delete_column(u'core_roundconfiguration', 'template_id') + # Renaming field 'Experiment.date_activated' to 'Experiment.start_date_time' + db.rename_column(u'core_experiment', 'date_activated', 'start_date_time') + + # Adding field 'Experiment.total_elapsed_time' + db.add_column(u'core_experiment', 'total_elapsed_time', + self.gf('django.db.models.fields.PositiveIntegerField')(default=0), + keep_default=False) + + models = { u'auth.group': { @@ -87,6 +108,7 @@ 'current_repeated_round_sequence_number': ('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_activated': ('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']"}), @@ -94,10 +116,8 @@ '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'}) + 'tick_duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}) }, u'core.experimentactivitylog': { 'Meta': {'object_name': 'ExperimentActivityLog', '_ormbases': [u'core.ActivityLog']}, @@ -363,8 +383,8 @@ '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_id': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), - 'template_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + 'template_filename': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'template_id': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}) }, u'core.rounddata': { 'Meta': {'ordering': "['round_configuration']", 'unique_together': "(('round_configuration', 'experiment'),)", 'object_name': 'RoundData'}, @@ -398,4 +418,4 @@ } } - complete_apps = ['core'] \ No newline at end of file + complete_apps = ['core'] diff -r f46602ee6c9dcf52d269adf129a70b96ce29f48f -r 39518ecd37898188f47840d665e8ee70b0ae5cba vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -312,18 +312,13 @@ date_created = models.DateTimeField(default=datetime.now) last_modified = AutoDateTimeField(default=datetime.now) # FIXME: inherit from TimeFramedModel instead? - start_date_time = models.DateTimeField(null=True, blank=True) + date_activated = models.DateTimeField(null=True, blank=True) # how long this experiment should run in a date format # 1w2d = 1 week 2 days = 9d duration = models.CharField(max_length=32, null=True, blank=True) tick_duration = models.CharField(max_length=32, null=True, blank=True) """ how often the experiment_metadata server should tick. """ - total_elapsed_time = models.PositiveIntegerField(default=0) - """ - total elapsed time in seconds since this experiment_metadata was - started, incremented by the heartbeat monitor. - """ current_round_start_time = models.DateTimeField(null=True, blank=True) """ elapsed time in seconds for the current round. """ amqp_exchange_name = models.CharField(max_length=64, default="vcweb.default.exchange") @@ -346,6 +341,12 @@ return self.is_round_in_progress and self.current_round.is_playable_round @property + def total_elapsed_time(self): + if self.date_activated: + return datetime.now() - self.date_activated + return timedelta(0) + + @property def current_round_elapsed_time(self): if self.current_round_start_time: return datetime.now() - self.current_round_start_time @@ -864,7 +865,7 @@ elif not self.is_active: self.allocate_groups() self.status = Experiment.Status.ACTIVE - self.start_date_time = datetime.now() + self.date_activated = datetime.now() self.save() return self @@ -1011,8 +1012,8 @@ quiz_2.html in the forestry experiment app, this would be loaded from forestry/templates/forestry/quiz_2.html """ - template_name = models.CharField(max_length=64, null=True, blank=True, - help_text=_('''The name of the template to use to render when executing this round. + template_filename = models.CharField(max_length=64, null=True, blank=True, + help_text=_('''The filename of the template to use to render when executing this round. This file should exist in your templates directory as your-experiment-namespace/template-name.html, e.g., if set to foo.html, vcweb will look for templates/forestry/foo.html''')) template_id = models.CharField(max_length=128, null=True, blank=True, @@ -1037,11 +1038,11 @@ repeat = models.PositiveIntegerField(default=0, help_text=_('If set to a positive integer n, this round will repeat itself n times with the same configuration and parameter values.')) @property - def custom_template_name(self): - return self.template_name if self.template_name else self.default_template_name + def custom_template_filename(self): + return self.template_filename if self.template_filename else self.default_template_filename @property - def default_template_name(self): + def default_template_filename(self): return RoundConfiguration.ROUND_TYPES_DICT[self.round_type][1] def get_custom_instructions(self, context_dict=None, **kwargs): @@ -1060,8 +1061,12 @@ return None @property + def template_name(self): + return self.template_id if self.template_id else self.round_type + + @property def template_path(self): - return "%s/%s" % (self.experiment_configuration.namespace, self.custom_template_name) + return "%s/%s" % (self.experiment_configuration.namespace, self.custom_template_filename) @property def round_number(self): diff -r f46602ee6c9dcf52d269adf129a70b96ce29f48f -r 39518ecd37898188f47840d665e8ee70b0ae5cba vcweb/core/tests.py --- a/vcweb/core/tests.py +++ b/vcweb/core/tests.py @@ -16,7 +16,7 @@ forestry_test_data, and a number of participants, experiments, etc., based on the forestry experiment """ - fixtures = ['test_users_participants', 'forestry_test_data'] + fixtures = ['forestry_experiment_metadata'] def load_experiment(self, experiment_metadata=None, **kwargs): if experiment_metadata is None: @@ -210,18 +210,11 @@ experiment.advance_to_next_round() self.assertTrue(experiment.current_round_sequence_number == round_number) - def test_increment_elapsed_time(self): + def test_elapsed_ti... [truncated message content] |
From: <com...@bi...> - 2013-03-28 01:28:18
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/63c8882e10ec/ Changeset: 63c8882e10ec User: alllee Date: 2013-03-28 02:28:04 Summary: fixing broker tour, element names needed a hash in front of them to be addressed properly by jQuery Affected #: 2 files diff -r 23749c5b2471a37184240038ba2dccd91ecfad02 -r 63c8882e10ecc82ef2d8ac613210ce555db6ebea vcweb/broker/templates/broker/participate.html --- a/vcweb/broker/templates/broker/participate.html +++ b/vcweb/broker/templates/broker/participate.html @@ -493,26 +493,21 @@ }); model.setupFirstPracticeRoundTour = function () { // set up first bootstrap tour - var tourFirst = new Tour({ - useLocalStorage: true, - onShow: function(tour) { - alert("showing tour"); - } - }); + var tourFirst = new Tour(); tourFirst.addStep({ - element: "harvestDecisionId", + element: "#harvestDecisionId", title: "Here's where you insert your harvesting decision", content: "For this practice round, go ahead and put 6 hours into harvesting. Each round you will have a maximum of 6 minute to make a harvest decision.", /* content of the popover */ placement: "right" }); tourFirst.addStep({ - element: "conservationDecision", + element: "#conservationDecision", title: "Your conservation decision", content: "Note that the rest of your available hours will be put into conservation.", placement: "right" }); tourFirst.addStep({ - element: "submitDecision", + element: "#submitDecision", title: "Submit your decision", content: "Now click here to submit your harvest choice. Your choice will be submitted automatically when time is up. A countdown will alert you when there are 10 seconds remaining to make a harvest. The default harvest is zero.", /* content of the popover */ placement: "right" @@ -525,43 +520,43 @@ model.setupSecondPracticeRoundTour = function () { var tourSecond = new Tour(); tourSecond.addStep({ - element: "lastRoundHarvestPayOff", + element: "#lastRoundHarvestPayOff", title: "Your round earnings", content: "Here you will see how much you earned in each round. You receive 0.6 from harvesting. Because everyone contributed 4 hours to conservation, resulting in 8 hours for group A and 8 hours for group B.", placement: "right" }); tourSecond.addStep({ - element: "lastRoundGroupLocalBonus", + element: "#lastRoundGroupLocalBonus", title: "Bonus", content: "So the standard revenue of $0.10/hour has been increased by 50% you receive an extra $0.30 and your total is $0.90. If the sum within your group was less than 5 hours you would not receive benefits. ", placement: "right" }); tourSecond.addStep({ - element: "lastRoundMyGroupConservation", + element: "#lastRoundMyGroupConservation", title: "Bonus", content: "If the sum of conservation time of all players were more than 22 hours you would get a further increase of 50% in the revenues.", placement: "right" }); tourSecond.addStep({ - element: "totalEarning", + element: "#totalEarning", title: "Total Earning", content: "Here you can your total earning throughout the game", placement: "right" }); tourSecond.addStep({ - element: "totalEarning", + element: "#totalEarning", title: "Communication", content: "At some point during the game you will have the option of communicating to other players. Communication to the other player within your group is FREE. Communication with the other group costs 2 hours.", }); tourSecond.addStep({ - element: "totalEarning", + element: "#totalEarning", title: "", content: "For this practice, go ahead and choose 'Communication within Group' and 'Communication with other Group'", }); tourSecond.addStep({ - element: "totalEarning", + element: "#totalEarning", title: "Chat rooms", content: "Communication will happen through these chat windows. Communications is time bound. Each message you send will be targeted a single player. Go ahead and send a message. It will not be seen by others for this practice.", onHide: function (tourSecond) { @@ -570,7 +565,7 @@ }); tourSecond.addStep({ - element: "totalEarning", + element: "#totalEarning", title: "Chat rooms", content: "Remember that all your choices are independent and none will see what your decisions are.", }); diff -r 23749c5b2471a37184240038ba2dccd91ecfad02 -r 63c8882e10ecc82ef2d8ac613210ce555db6ebea vcweb/core/templates/base.html --- a/vcweb/core/templates/base.html +++ b/vcweb/core/templates/base.html @@ -133,14 +133,16 @@ </div> {% endblock footer %} {% with jquery_version="1.9.1" %} - <script type='text/javascript' src='//ajax.googleapis.com/ajax/libs/jquery/{{jquery_version}}/jquery.min.js'></script> + <script src='//ajax.googleapis.com/ajax/libs/jquery/{{jquery_version}}/jquery.min.js'></script> {% endwith %} - <script type='text/javascript' src='{{STATIC_URL}}bootstrap/js/bootstrap.min.js'></script> - <script type='text/javascript' src='{{STATIC_URL}}js/jquery.cookie.js'></script> - <script type='text/javascript' src='{{STATIC_URL}}js/ko/knockout.min.js'></script> - <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> + <script src='{{STATIC_URL}}bootstrap/js/bootstrap.min.js'></script> + <script src='{{STATIC_URL}}js/jquery.cookie.js'></script> + <script src='{{STATIC_URL}}js/ko/knockout.min.js'></script> + <script src='{{STATIC_URL}}js/ko/knockout.mapping.min.js'></script> + <script src='{{STATIC_URL}}js/common.js'></script> + {% comment %} + <script src='//cdnjs.cloudflare.com/ajax/libs/d3/3.0.1/d3.v3.min.js'></script> + {% endcomment %} {% dajaxice_js_import %} {% block javascript %} {% endblock %} Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-28 01:20:55
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/23749c5b2471/ Changeset: 23749c5b2471 User: alllee Date: 2013-03-28 02:20:36 Summary: updating bootstrap tour and setup tour functions Affected #: 2 files diff -r 692ba46bcd6e5764dbf51180b04029fa8d5b04f6 -r 23749c5b2471a37184240038ba2dccd91ecfad02 vcweb/broker/templates/broker/participate.html --- a/vcweb/broker/templates/broker/participate.html +++ b/vcweb/broker/templates/broker/participate.html @@ -22,8 +22,7 @@ <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> + <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> @@ -288,6 +287,7 @@ This is a practice round. The decisions you make in this round will <b>NOT</b> contribute to your earnings. <span data-bind="if: isFirstPracticeRound"> + <button class='btn btn-primary' data-bind='click: setupFirstPracticeRoundTour'>Tour</button><a href="#" data-bind="">Show me 1st Instructions again</a></span> @@ -493,26 +493,102 @@ }); model.setupFirstPracticeRoundTour = function () { // set up first bootstrap tour - alert("setting up first practice round tour"); - + var tourFirst = new Tour({ + useLocalStorage: true, + onShow: function(tour) { + alert("showing tour"); + } + }); + tourFirst.addStep({ + element: "harvestDecisionId", + title: "Here's where you insert your harvesting decision", + content: "For this practice round, go ahead and put 6 hours into harvesting. Each round you will have a maximum of 6 minute to make a harvest decision.", /* content of the popover */ + placement: "right" + }); + tourFirst.addStep({ + element: "conservationDecision", + title: "Your conservation decision", + content: "Note that the rest of your available hours will be put into conservation.", + placement: "right" + }); + tourFirst.addStep({ + element: "submitDecision", + title: "Submit your decision", + content: "Now click here to submit your harvest choice. Your choice will be submitted automatically when time is up. A countdown will alert you when there are 10 seconds remaining to make a harvest. The default harvest is zero.", /* content of the popover */ + placement: "right" + }); + tourFirst.start(true); + tour = tourFirst; + console.debug("set up tour"); + console.debug(tour); }; model.setupSecondPracticeRoundTour = function () { - alert("setting up second practice round tour"); + var tourSecond = new Tour(); + tourSecond.addStep({ + element: "lastRoundHarvestPayOff", + title: "Your round earnings", + content: "Here you will see how much you earned in each round. You receive 0.6 from harvesting. Because everyone contributed 4 hours to conservation, resulting in 8 hours for group A and 8 hours for group B.", + placement: "right" + }); + tourSecond.addStep({ + element: "lastRoundGroupLocalBonus", + title: "Bonus", + content: "So the standard revenue of $0.10/hour has been increased by 50% you receive an extra $0.30 and your total is $0.90. If the sum within your group was less than 5 hours you would not receive benefits. ", + placement: "right" + }); + tourSecond.addStep({ + element: "lastRoundMyGroupConservation", + title: "Bonus", + content: "If the sum of conservation time of all players were more than 22 hours you would get a further increase of 50% in the revenues.", + placement: "right" + }); + tourSecond.addStep({ + element: "totalEarning", + title: "Total Earning", + content: "Here you can your total earning throughout the game", + placement: "right" + }); + tourSecond.addStep({ + element: "totalEarning", + title: "Communication", + content: "At some point during the game you will have the option of communicating to other players. Communication to the other player within your group is FREE. Communication with the other group costs 2 hours.", + }); + tourSecond.addStep({ + element: "totalEarning", + title: "", + content: "For this practice, go ahead and choose 'Communication within Group' and 'Communication with other Group'", + + }); + tourSecond.addStep({ + element: "totalEarning", + title: "Chat rooms", + content: "Communication will happen through these chat windows. Communications is time bound. Each message you send will be targeted a single player. Go ahead and send a message. It will not be seen by others for this practice.", + onHide: function (tourSecond) { + // post a dummy message to the chat... "Here's an example of a reply message" + } + + }); + tourSecond.addStep({ + element: "totalEarning", + title: "Chat rooms", + content: "Remember that all your choices are independent and none will see what your decisions are.", + }); + tourSecond.start(); }; model.update = function () { $.get('view-model', { participant_group_id: model.participantGroupId(), }, - function (response) { - console.debug("updating with response: "); - console.debug(response); - ko.mapping.fromJS(response, model); - if (model.isFirstPracticeRound()) { - model.setupFirstPracticeRoundTour(); - } - else if (model.isSecondPracticeRound()) { - model.setupSecondPracticeRoundTour(); - } - }); + function (response) { + console.debug("updating with response: "); + console.debug(response); + ko.mapping.fromJS(response, model); + if (model.isFirstPracticeRound()) { + model.setupFirstPracticeRoundTour(); + } + else if (model.isSecondPracticeRound()) { + model.setupSecondPracticeRoundTour(); + } + }); }; // activate instructions click bindings model.activateInstructionsPageOne = function () { @@ -555,54 +631,54 @@ model.conservationDecision = ko.computed(function () { return model.maxHarvestDecision() - model.harvestDecision(); }); -// model.numberOfTreesPerRow = ko.observable(10); -// model.isResourceEmpty = ko.computed(function() { -// return model.resourceLevel() == 0; -// }); -// model.resourcesToDisplay = ko.computed(function() { -// if (model.resourceLevel() > 0) { -// return Math.min(model.resourceLevel(), 20); -// } -// return 0; -// }); + // model.numberOfTreesPerRow = ko.observable(10); + // model.isResourceEmpty = ko.computed(function() { + // return model.resourceLevel() == 0; + // }); + // model.resourcesToDisplay = ko.computed(function() { + // if (model.resourceLevel() > 0) { + // return Math.min(model.resourceLevel(), 20); + // } + // return 0; + // }); -// + // model.startChatTimer = function () { model.enableChat(); model.secondsLeft(60); model.setCurrentInterval( - setInterval(function () { - model.tick(); - if (!model.isTimerRunning()) { - model.disableChat(); - model.clearCurrentInterval(); - } - }, - 1000)); + setInterval(function () { + model.tick(); + if (!model.isTimerRunning()) { + model.disableChat(); + model.clearCurrentInterval(); + } + }, + 1000)); }; model.startHarvestDecisionTimer = function () { model.secondsLeft(10); model.setCurrentInterval(setInterval(function () { - model.tick(); - if (!model.isTimerRunning()) { - model.submitDecision(); - model.clearCurrentInterval(); - } - }, - 1000)); + model.tick(); + if (!model.isTimerRunning()) { + model.submitDecision(); + model.clearCurrentInterval(); + } + }, + 1000)); }; model.startChatOptionTimer = function () { model.enableChatOption(); model.secondsLeft(10); model.setCurrentInterval( - setInterval(function () { - model.tick(); - if (!model.isTimerRunning()) { - model.disableChatOption(); - model.clearCurrentInterval(); - } - }, - 1000)); + setInterval(function () { + model.tick(); + if (!model.isTimerRunning()) { + model.disableChatOption(); + model.clearCurrentInterval(); + } + }, + 1000)); }; model.submitDecision = function (data, evt) { var formData = $('#vcweb-form').serialize(); @@ -618,36 +694,6 @@ // model.clearCurrentInterval(); }); }; -// model.submitChatMessage = function(data, evt) { -// evt.preventDefault(); -// console.log("clicking chat message"); -// var message = $('#chatText').val(); -// if (message) { -// $('#chatText').val(''); -// getWebSocket().send(createMessageEvent(message)); -// $('#chatText').focus(); -// } -// } -// model.disableChat = function() { -// $('#content').removeClass('span6').addClass('span9'); -// $('#sidebar').removeClass('span6').addClass('span3'); -// $('.chat-action').addClass('disabled').attr('disabled', true); -// model.chatEnabled(false); -// } -// model.enableChat = function() { -// $('#content').removeClass('span9').addClass('span6'); -// $('#sidebar').removeClass('span3').addClass('span6'); -// $('.chat-action').removeClass('disabled').attr('disabled', false); -// model.chatEnabled(true); -// } -// -// model.disableChatOption = function() { -// model.chatOptionEnabled(false); -// } -// model.enableChatOption = function() { -// model.chatOptionEnabled(true); -// } -// return model; } @@ -663,129 +709,22 @@ switch (data.event_type) { case 'chat': experimentModel.withinGroupChatMessages.unshift(data); - break; + break; case 'update': console.debug("updating view model"); experimentModel.update(); break; case 'participant_ready': experimentModel.readyParticipants(Math.min(experimentModel.totalNumberOfParticipants(), experimentModel.readyParticipants() + 1)); - // FIXME: replace with this later - // experimentModel.checkReadyParticipants(); - break; + // FIXME: replace with this later + // experimentModel.checkReadyParticipants(); + break; default: console.debug("unhandled json message:" + json); - break; + break; } }; -// $('#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); - if (experimentModel.isFirstPracticeRound) { - console.debug("starting first practice round tour"); - - var tourFirst = new Tour({ - useLocalStorage: true - }); - tourFirst.addStep({ - element: "harvestDecisionId", - title: "Here's where you insert your harvesting decision", - content: "For this practice round, go ahead and put 6 hours into harvesting. Each round you will have a maximum of 6 minute to make a harvest decision.", /* content of the popover */ - placement: "right" - }); - tourFirst.addStep({ - element: "conservationDecision", - title: "Your conservation decision", - content: "Note that the rest of your available hours will be put into conservation.", - placement: "right" - }); - tourFirst.addStep({ - element: "submitDecision", - title: "Submit your decision", - content: "Now click here to submit your harvest choice. Your choice will be submitted automatically when time is up. A countdown will alert you when there are 10 seconds remaining to make a harvest. The default harvest is zero.", /* content of the popover */ - placement: "right" - }); - tourFirst.start(true); - tour = tourFirst; - console.debug("tour started"); - - - } else if (experimentModel.isSecondPracticeRound) { - var tourSecond = new Tour(); - alert("second tour"); - tourSecond.addStep({ - element: "lastRoundHarvestPayOff", - title: "Your round earnings", - content: "Here you will see how much you earned in each round. You receive 0.6 from harvesting. Because everyone contributed 4 hours to conservation, resulting in 8 hours for group A and 8 hours for group B.", - placement: "right" - }); - tourSecond.addStep({ - element: "lastRoundGroupLocalBonus", - title: "Bonus", - content: "So the standard revenue of $0.10/hour has been increased by 50% you receive an extra $0.30 and your total is $0.90. If the sum within your group was less than 5 hours you would not receive benefits. ", - placement: "right" - }); - tourSecond.addStep({ - element: "lastRoundMyGroupConservation", - title: "Bonus", - content: "If the sum of conservation time of all players were more than 22 hours you would get a further increase of 50% in the revenues.", - placement: "right" - }); - tourSecond.addStep({ - element: "totalEarning", - title: "Total Earning", - content: "Here you can your total earning throughout the game", - placement: "right" - }); - - tourSecond.addStep({ - element: "totalEarning", - title: "Communication", - content: "At some point during the game you will have the option of communicating to other players. Communication to the other player within your group is FREE. Communication with the other group costs 2 hours.", - }); - tourSecond.addStep({ - element: "totalEarning", - title: "", - content: "For this practice, go ahead and choose 'Communication within Group' and 'Communication with other Group'", - - }); - tourSecond.addStep({ - element: "totalEarning", - title: "Chat rooms", - content: "Communication will happen through these chat windows. Communications is time bound. Each message you send will be targeted a single player. Go ahead and send a message. It will not be seen by others for this practice.", - onHide: function (tourSecond) { - // post a dummy message to the chat... "Here's an example of a reply message" - } - - }); - tourSecond.addStep({ - element: "totalEarning", - title: "Chat rooms", - content: "Remember that all your choices are independent and none will see what your decisions are.", - }); - tourSecond.start(); - - - } - } - else if (templateName === "REGULAR") { - experimentModel.practiceRound(false); - } - experimentModel.templateName(templateName); - }); -// $('#pick-network-structure').change(function() { -// var networkStructure = $(this).val(); -// console.debug("choosing network structure: " + networkStructure); -// experimentModel.networkStructure(networkStructure); -// }); - } var experimentModelJson = $.parseJSON("{{ experimentModelJson|escapejs }}"); @@ -793,4 +732,4 @@ }); </script> -{% endblock %} + {% endblock %} diff -r 692ba46bcd6e5764dbf51180b04029fa8d5b04f6 -r 23749c5b2471a37184240038ba2dccd91ecfad02 vcweb/static/js/bootstrap-tour.js --- a/vcweb/static/js/bootstrap-tour.js +++ b/vcweb/static/js/bootstrap-tour.js @@ -1,10 +1,9 @@ -// Generated by CoffeeScript 1.6.1 - +// Generated by CoffeeScript 1.6.2 /* ============================================================ -# bootstrap-tour.js v0.1 -# http://pushly.github.com/bootstrap-tour/ +# bootstrap-tour.js v0.3.0 +# http://bootstraptour.com/ # ============================================================== -# Copyright 2012 Push.ly +# Copyright 2012-2013 Ulrich Sossou # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -21,12 +20,11 @@ (function() { - (function($, window) { var Tour, document; + document = window.document; Tour = (function() { - function Tour(options) { this._options = $.extend({ name: 'tour', @@ -35,19 +33,29 @@ next: 'Next »', prev: '« Prev' }, + template: "<div class='popover tour'><div class='arrow'></div><h3 class='popover-title'></h3><div class='popover-content'></div></div>", + container: 'body', keyboard: true, useLocalStorage: false, + debug: false, + backdrop: false, afterSetState: function(key, value) {}, afterGetState: function(key, value) {}, afterRemoveState: function(key) {}, onStart: function(tour) {}, onEnd: function(tour) {}, onShow: function(tour) {}, + onShown: function(tour) {}, onHide: function(tour) {}, - onShown: function(tour) {} + onHidden: function(tour) {} }, options); this._steps = []; this.setCurrentStep(); + this.backdrop = { + overlay: null, + step: null, + background: null + }; } Tour.prototype.setState = function(key, value) { @@ -77,6 +85,7 @@ Tour.prototype.getState = function(key) { var value; + if (this._options.useLocalStorage) { value = window.localStorage.getItem("" + this._options.name + "_" + key); } else { @@ -100,12 +109,16 @@ placement: "right", title: "", content: "", + id: "step-" + i, next: i === this._steps.length - 1 ? -1 : i + 1, prev: i - 1, animation: true, onShow: this._options.onShow, + onShown: this._options.onShown, onHide: this._options.onHide, - onShown: this._options.onShown + onHidden: this._options.onHidden, + template: this._options.template, + container: this._options.container }, this._steps[i]); } }; @@ -113,11 +126,12 @@ Tour.prototype.start = function(force) { var promise, _this = this; + if (force == null) { force = false; } if (this.ended() && !force) { - return; + return this._debug("Tour ended, start prevented."); } $(document).off("click.bootstrap-tour", ".popover .next").on("click.bootstrap-tour", ".popover .next", function(e) { e.preventDefault(); @@ -141,23 +155,28 @@ Tour.prototype.next = function() { var promise; + promise = this.hideStep(this._current); return this._callOnPromiseDone(promise, this.showNextStep); }; Tour.prototype.prev = function() { var promise; - return promise = this.hideStep(this._current); + + promise = this.hideStep(this._current); + return this._callOnPromiseDone(promise, this.showPrevStep); }; Tour.prototype.end = function() { var endHelper, hidePromise, _this = this; + endHelper = function(e) { $(document).off("click.bootstrap-tour"); $(document).off("keyup.bootstrap-tour"); $(window).off("resize.bootstrap-tour"); _this.setState("end", "yes"); + _this._hideBackdrop(); if (_this._options.onEnd != null) { return _this._options.onEnd(_this); } @@ -180,13 +199,21 @@ Tour.prototype.hideStep = function(i) { var hideStepHelper, promise, step, _this = this; + step = this.getStep(i); promise = this._makePromise((step.onHide != null ? step.onHide(this) : void 0)); hideStepHelper = function(e) { var $element; + $element = $(step.element).popover("hide"); if (step.reflex) { - return $element.css("cursor", "").off("click.boostrap-tour"); + $element.css("cursor", "").off("click.boostrap-tour"); + } + if (step.backdrop) { + _this._hideBackdrop(); + } + if (step.onHidden != null) { + return step.onHidden(_this); } }; this._callOnPromiseDone(promise, hideStepHelper); @@ -196,27 +223,36 @@ Tour.prototype.showStep = function(i) { var promise, showStepHelper, step, _this = this; + step = this.getStep(i); if (!step) { return; } promise = this._makePromise((step.onShow != null ? step.onShow(this) : void 0)); showStepHelper = function(e) { - var path; + var current_path, path; + _this.setCurrentStep(i); path = typeof step.path === "function" ? step.path.call() : step.path; - if (_this._redirect(path, document.location.pathname)) { + current_path = [document.location.pathname, document.location.hash].join(''); + if (_this._redirect(path, current_path)) { + _this._debug("Redirect to " + path); document.location.href = path; return; } if (!((step.element != null) && $(step.element).length !== 0 && $(step.element).is(":visible"))) { + _this._debug("Skip the step " + (_this._current + 1) + ". The element does not exist or is not visible."); _this.showNextStep(); return; } + if (step.backdrop) { + _this._showBackdrop(step.element); + } _this._showPopover(step, i); if (step.onShown != null) { - return step.onShown(_this); + step.onShown(_this); } + return _this._debug("Step " + (_this._current + 1) + " of " + _this._steps.length); }; return this._callOnPromiseDone(promise, showStepHelper); }; @@ -237,23 +273,32 @@ Tour.prototype.showNextStep = function() { var step; + step = this.getStep(this._current); return this.showStep(step.next); }; Tour.prototype.showPrevStep = function() { var step; + step = this.getStep(this._current); return this.showStep(step.prev); }; + Tour.prototype._debug = function(text) { + if (this._options.debug) { + return window.console.log("Bootstrap Tour '" + this._options.name + "' | " + text); + } + }; + Tour.prototype._redirect = function(path, currentPath) { return (path != null) && path !== "" && path.replace(/\?.*$/, "").replace(/\/?$/, "") !== currentPath.replace(/\/?$/, ""); }; Tour.prototype._showPopover = function(step, i) { - var content, nav, options, tip, + var $tip, content, nav, options, _this = this; + content = "" + step.content + "<br /><p>"; options = $.extend({}, this._options); if (step.options) { @@ -266,10 +311,10 @@ } nav = []; if (step.prev >= 0) { - nav.push("<a href='#" + step.prev + "' class='prev'>" + options.labels.prev + "</a>"); + nav.push("<a href='#' class='prev'>" + options.labels.prev + "</a>"); } if (step.next >= 0) { - nav.push("<a href='#" + step.next + "' class='next'>" + options.labels.next + "</a>"); + nav.push("<a href='#' class='next'>" + options.labels.next + "</a>"); } content += nav.join(" | "); content += "<a href='#' class='pull-right end'>" + options.labels.end + "</a>"; @@ -280,15 +325,18 @@ content: content, html: true, animation: step.animation, - container: "body" + container: step.container, + template: step.template }).popover("show"); - tip = $(step.element).data("popover").tip(); - this._reposition(tip, step); - return this._scrollIntoView(tip); + $tip = $(step.element).data("popover").tip(); + $tip.attr("id", step.id); + this._reposition($tip, step); + return this._scrollIntoView($tip); }; Tour.prototype._reposition = function(tip, step) { var offsetBottom, offsetRight, original_left, original_offsetHeight, original_offsetWidth, original_top, tipOffset; + original_offsetWidth = tip[0].offsetWidth; original_offsetHeight = tip[0].offsetHeight; tipOffset = tip.offset(); @@ -326,6 +374,7 @@ Tour.prototype._scrollIntoView = function(tip) { var tipRect; + tipRect = tip.get(0).getBoundingClientRect(); if (!(tipRect.top >= 0 && tipRect.bottom < $(window).height() && tipRect.left >= 0 && tipRect.right < $(window).width())) { return tip.get(0).scrollIntoView(true); @@ -341,6 +390,7 @@ Tour.prototype._setupKeyboardNavigation = function() { var _this = this; + if (this._options.keyboard) { return $(document).on("keyup.bootstrap-tour", function(e) { if (!e.which) { @@ -351,6 +401,8 @@ e.preventDefault(); if (_this._current < _this._steps.length - 1) { return _this.next(); + } else { + return _this.end(); } break; case 37: @@ -373,6 +425,7 @@ Tour.prototype._callOnPromiseDone = function(promise, cb, arg) { var _this = this; + if (promise) { return promise.then(function(e) { return cb.call(_this, arg); @@ -382,6 +435,57 @@ } }; + Tour.prototype._showBackdrop = function(el) { + if (this.backdrop.overlay !== null) { + return; + } + this._showOverlay(); + return this._showOverlayElement(el); + }; + + Tour.prototype._hideBackdrop = function() { + if (this.backdrop.overlay === null) { + return; + } + this._hideOverlayElement(); + return this._hideOverlay(); + }; + + Tour.prototype._showOverlay = function() { + this.backdrop = $('<div/>'); + this.backdrop.addClass('tour-backdrop'); + this.backdrop.height($(document).innerHeight()); + return $('body').append(this.backdrop); + }; + + Tour.prototype._hideOverlay = function() { + this.backdrop.remove(); + return this.backdrop.overlay = null; + }; + + Tour.prototype._showOverlayElement = function(el) { + var background, offset, padding, step; + + step = $(el); + padding = 5; + offset = step.offset(); + offset.top = offset.top - padding; + offset.left = offset.left - padding; + background = $('<div/>'); + background.width(step.innerWidth() + padding).height(step.innerHeight() + padding).addClass('tour-step-background').offset(offset); + step.addClass('tour-step-backdrop'); + $('body').append(background); + this.backdrop.step = step; + return this.backdrop.background = background; + }; + + Tour.prototype._hideOverlayElement = function() { + this.backdrop.step.removeClass('tour-step-backdrop'); + this.backdrop.background.remove(); + this.backdrop.step = null; + return this.backdrop.background = null; + }; + return Tour; })(); Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-28 01:06:35
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/692ba46bcd6e/ Changeset: 692ba46bcd6e User: alllee Date: 2013-03-28 02:06:17 Summary: some basic setting up of participant linkages based on chat preferences Affected #: 11 files diff -r ef739932a1be5788d8a47a793b3699460df31756 -r 692ba46bcd6e5764dbf51180b04029fa8d5b04f6 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -89,12 +89,10 @@ experiment_model_dict['regrowthRate'] = regrowth_rate experiment_model_dict['initialResourceLevel'] = get_initial_resource_level(current_round) - 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['roundType'] = current_round.round_type experiment_model_dict['practiceRound'] = current_round.is_practice_round - experiment_model_dict['showChatRooms'] = True if current_round.is_regular_round: experiment_model_dict['chatEnabled'] = current_round.chat_enabled diff -r ef739932a1be5788d8a47a793b3699460df31756 -r 692ba46bcd6e5764dbf51180b04029fa8d5b04f6 vcweb/broker/forms.py --- a/vcweb/broker/forms.py +++ b/vcweb/broker/forms.py @@ -3,6 +3,6 @@ __author__ = 'diegogalafassi' class ChatPreferenceForm (forms.Form): - participant_group_id = forms.IntegerField() - chat_within_group = forms.BooleanField(default=False) - chat_between_group = forms.BooleanField(default=False) + participant_group_id = forms.IntegerField(widget=forms.widgets.HiddenInput) + chat_within_group = forms.BooleanField(initial=False, required=False) + chat_between_group = forms.BooleanField(initial=False, required=False) diff -r ef739932a1be5788d8a47a793b3699460df31756 -r 692ba46bcd6e5764dbf51180b04029fa8d5b04f6 vcweb/broker/migrations/0002_add_broker_parameters.py --- a/vcweb/broker/migrations/0002_add_broker_parameters.py +++ b/vcweb/broker/migrations/0002_add_broker_parameters.py @@ -39,7 +39,7 @@ Parameter.objects.create( name='participant_link', scope='participant', - type='int', + type='foreignkey', class_name='core.ParticipantGroupRelationship', description='Linkage between two participant group relationships (e.g., an edge)', creator=experimenter) diff -r ef739932a1be5788d8a47a793b3699460df31756 -r 692ba46bcd6e5764dbf51180b04029fa8d5b04f6 vcweb/broker/migrations/0004_add_chat_preferences_parameters.py --- /dev/null +++ b/vcweb/broker/migrations/0004_add_chat_preferences_parameters.py @@ -0,0 +1,415 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + + def forwards(self, orm): + "Write your forwards methods here." + # Note: Remember to use orm['appname.ModelName'] rather than "from appname.models..." + Parameter = orm['core.Parameter'] + Experimenter = orm['core.Experimenter'] + experimenter = Experimenter.objects.get(pk=1) + Parameter.objects.create( + name='chat_within_group', + scope='participant', + type='boolean', + description='Does this participant want to chat within their own group?', + creator=experimenter) + Parameter.objects.create( + name='chat_between_group', + scope='participant', + type='foreignkey', + class_name='core.Group', + description='Does this participant want to chat with another group?', + creator=experimenter) + + def backwards(self, orm): + "Write your backwards methods here." + Parameter = orm['core.Parameter'] + Parameter.objects.get(name='chat_within_group').delete() + Parameter.objects.get(name='chat_between_group').delete() + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'core.activitylog': { + 'Meta': {'object_name': 'ActivityLog'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'log_message': ('django.db.models.fields.TextField', [], {}) + }, + u'core.address': { + 'Meta': {'object_name': 'Address'}, + 'city': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'state': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), + 'street1': ('django.db.models.fields.CharField', [], {'max_length': '256'}), + 'street2': ('django.db.models.fields.CharField', [], {'max_length': '256'}), + 'zipcode': ('django.db.models.fields.CharField', [], {'max_length': '8', 'blank': 'True'}) + }, + u'core.chatmessage': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'ChatMessage', '_ormbases': [u'core.ParticipantRoundDataValue']}, + u'participantrounddatavalue_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ParticipantRoundDataValue']", 'unique': 'True', 'primary_key': 'True'}), + 'target_participant': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'target_participant_chat_message_set'", 'null': 'True', 'to': u"orm['core.ParticipantGroupRelationship']"}) + }, + u'core.comment': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'Comment', '_ormbases': [u'core.ParticipantRoundDataValue']}, + u'participantrounddatavalue_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ParticipantRoundDataValue']", 'unique': 'True', 'primary_key': 'True'}) + }, + u'core.experiment': { + 'Meta': {'ordering': "['date_created', 'status']", 'object_name': 'Experiment'}, + 'amqp_exchange_name': ('django.db.models.fields.CharField', [], {'default': "'vcweb.default.exchange'", 'max_length': '64'}), + 'authentication_code': ('django.db.models.fields.CharField', [], {'default': "'vcweb.auth.code'", 'max_length': '32'}), + 'current_repeated_round_sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'current_round_sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'current_round_start_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentConfiguration']"}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentMetadata']"}), + 'experimenter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experimenter']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'start_date_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'INACTIVE'", 'max_length': '32'}), + 'tick_duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'total_elapsed_time': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + }, + u'core.experimentactivitylog': { + 'Meta': {'object_name': 'ExperimentActivityLog', '_ormbases': [u'core.ActivityLog']}, + u'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': u"orm['core.Experiment']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.experimentconfiguration': { + 'Meta': {'ordering': "['experiment_metadata', 'creator', 'date_created']", 'object_name': 'ExperimentConfiguration'}, + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': u"orm['core.Experimenter']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'exchange_rate': ('django.db.models.fields.DecimalField', [], {'default': '0.2', 'null': 'True', 'max_digits': '6', 'decimal_places': '2', 'blank': 'True'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': u"orm['core.ExperimentMetadata']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation_subject': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'is_experimenter_driven': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'max_group_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), + 'max_number_of_participants': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'treatment_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}) + }, + u'core.experimenter': { + 'Meta': {'ordering': "['user']", 'object_name': 'Experimenter'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'authentication_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'failed_password_attempts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'institution': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Institution']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'experimenter'", 'unique': 'True', 'to': u"orm['auth.User']"}) + }, + u'core.experimenterrequest': { + 'Meta': {'object_name': 'ExperimenterRequest'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'}) + }, + u'core.experimentmetadata': { + 'Meta': {'ordering': "['namespace', 'date_created']", 'object_name': 'ExperimentMetadata'}, + 'about_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'default_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentConfiguration']", 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'namespace': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'short_name': ('django.db.models.fields.SlugField', [], {'max_length': '32', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'core.experimentparametervalue': { + 'Meta': {'object_name': 'ExperimentParameterValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_parameter_value_set'", 'to': u"orm['core.ExperimentConfiguration']"}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.experimentsession': { + 'Meta': {'object_name': 'ExperimentSession'}, + 'capacity': ('django.db.models.fields.PositiveIntegerField', [], {'default': '20'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_session_set'", 'to': u"orm['auth.User']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_session_set'", 'to': u"orm['core.ExperimentMetadata']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'scheduled_date': ('django.db.models.fields.DateTimeField', [], {}), + 'scheduled_end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.group': { + 'Meta': {'ordering': "['experiment', 'number']", 'object_name': 'Group'}, + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'max_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), + 'number': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.groupactivitylog': { + 'Meta': {'object_name': 'GroupActivityLog', '_ormbases': [u'core.ActivityLog']}, + u'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': u"orm['core.Group']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.groupcluster': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'GroupCluster'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_cluster_set'", 'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.groupclusterdatavalue': { + 'Meta': {'object_name': 'GroupClusterDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'group_cluster': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.GroupCluster']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'round_data': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_cluster_data_value_set'", 'to': u"orm['core.RoundData']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.grouprelationship': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'GroupRelationship'}, + 'cluster': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_relationship_set'", 'to': u"orm['core.GroupCluster']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'core.grouprounddatavalue': { + 'Meta': {'ordering': "['round_data', 'group', 'parameter']", 'object_name': 'GroupRoundDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'data_value_set'", 'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.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', 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'instructions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'preserve_existing_groups': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'randomize_groups': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'repeat': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'round_type': ('django.db.models.fields.CharField', [], {'default': "'REGULAR'", 'max_length': '32'}), + 'sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'survey_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'template_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.rounddata': { + 'Meta': {'ordering': "['round_configuration']", 'unique_together': "(('round_configuration', 'experiment'),)", 'object_name': 'RoundData'}, + 'elapsed_time': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_data_set'", 'to': u"orm['core.Experiment']"}), + 'experimenter_notes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_data_set'", 'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.roundparametervalue': { + 'Meta': {'object_name': 'RoundParameterValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_parameter_value_set'", 'to': u"orm['core.RoundConfiguration']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.spoolparticipantstatistics': { + 'Meta': {'object_name': 'SpoolParticipantStatistics'}, + 'absences': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'discharges': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitations': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'participant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'spool_statistics_set'", 'to': u"orm['core.Participant']"}), + 'participations': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + } + } + + complete_apps = ['core', 'broker'] + symmetrical = True diff -r ef739932a1be5788d8a47a793b3699460df31756 -r 692ba46bcd6e5764dbf51180b04029fa8d5b04f6 vcweb/broker/models.py --- a/vcweb/broker/models.py +++ b/vcweb/broker/models.py @@ -14,6 +14,14 @@ ''' participant parameters ''' @simplecache +def get_chat_between_group_parameter(): + return Parameter.objects.get(name="chat_between_group") + +@simplecache +def get_chat_within_group_parameter(): + return Parameter.objects.get(name="chat_within_group") + +@simplecache def get_participant_link_parameter(): return Parameter.objects.get(name='participant_link') @@ -21,7 +29,6 @@ def get_participant_payoff_parameter(): return Parameter.objects.get(name='payoff') - @simplecache def get_conservation_decision_parameter(): return Parameter.objects.get(name='conservation_decision') @@ -85,7 +92,10 @@ experiment.initialize_data_values( group_cluster_parameters=(get_group_cluster_bonus_parameter(),), group_parameters=(get_group_local_bonus_parameter(),), - participant_parameters=[get_harvest_decision_parameter(), get_conservation_decision_parameter(), get_participant_link_parameter(), get_participant_payoff_parameter()] + participant_parameters=(get_harvest_decision_parameter(), get_conservation_decision_parameter(), + get_participant_link_parameter(), get_participant_payoff_parameter(), + get_chat_between_group_parameter(), get_chat_within_group_parameter(), + ) ) def calculate_group_local_bonus(group_conservation_hours, local_threshold): diff -r ef739932a1be5788d8a47a793b3699460df31756 -r 692ba46bcd6e5764dbf51180b04029fa8d5b04f6 vcweb/broker/templates/broker/participate.html --- a/vcweb/broker/templates/broker/participate.html +++ b/vcweb/broker/templates/broker/participate.html @@ -6,66 +6,7 @@ {% endblock %} {% block page %} <div class="container"> - <div class="hero-unit"> - <form class='form-inline'> - <div class="row"> - - <div class='control-group'> - <div class='controls'> - <label class='control-label' for='pick-template'>Round template</label> - <select id='pick-template' data-bind='value: templateName()'> - <option value='WELCOME'>Welcome</option> - <option value='GENERAL_INSTRUCTIONS'>Instructions</option> - <option value='GENERAL_INSTRUCTIONS2'>Instructions page 2</option> - <option value='PRACTICE_ROUND_INSTRUCTIONS'>Practice Round Instructions</option> - <option value='PRACTICE'>Practice round</option> - <option value='REGULAR'>Actual round</option> - </select> - </div> - - - <div class='controls'> - <label class='control-label' for='pick-network-structure'>Network structure</label> - <select id='pick-network-structure' data-bind='value: networkStructure()'> - <option value='SES.jpg'>Whole System</option> - <option value='WITHIN_AB.jpg'>Within Group Communication A-B</option> - <option value='WITHIN_CD.jpg'>Within Group Communication C-D</option> - <option value='BETWEEN_AC.jpg'>Within Group Communication A-C</option> - <option value='BETWEEN_AD.jpg'>Within Group Communication A-D</option> - <option value='BETWEEN_BC.jpg'>Within Group Communication B-C</option> - <option value='BETWEEN_BD.jpg'>Within Group Communication B-D</option> - </select> - </div> - - </div> - </div> - <div class="row"> - <h3>Timers</h3> - - <div class='control-group'> - <div class='controls'> - <button data-bind='click: startHarvestDecisionTimer' type='button' class='btn btn-primary'> - Start harvest decision timer - </button> - <button data-bind='click: startChatTimer' type='button' class='btn btn-primary'>Start chat - timer - </button> - <button data-bind='click: startChatOptionTimer' type='button' class='btn btn-primary'>Start - chat option timer - </button> - <button data-bind='click: update' type='button' class='btn btn-primary' - data-bind='click: update'>Update - </button> - </div> - </div> - </div> - </div> - </form> - </div> - <div class="row"> - <div class="span9"> - <div data-bind='template: { name: templateName() }'> - </div> + <div data-bind='template: { name: templateName() }'></div></div> {% endblock page %} @@ -75,39 +16,24 @@ {{ block.super }} <script src='{% static "js/bootstrap-tour.js" %}'></script><!-- ko templates --> - <script type='text/html' id='CHAT'> - {% include "forms/chat-template.html" %} - <div data-bind='if: chatEnabled'> - <h3>Chat</h3> + <script type='text/html' id='WAITING_ROOM'> + <h3>Waiting for other participants</h3> - <div class='chat-sidebar well'> - <form id="chatform" class='form-inline'> - <div class='input-prepend input-append'> - <span class='add-on'><i class='text-info icon-comment'></i></span> - <input style='width: 100%;' class='chat-action' id='chatText' type="text" - placeholder="Enter a chat message"> - <button class='btn' data-bind='click: submitChatMessage'>Send</button> - </div> - </form> - <div id='chat-div'> - <div data-bind='foreach: chatMessages'> - <i class='icon-user muted'></i><strong>Participant <span - data-bind='text: participant_number'></span></strong><b class='pull-right muted' - data-bind='text: date_created'></b> - - <p> - <small><i class='icon-double-angle-right'></i></small> - <span data-bind='text: message'></span> - </p> - </div> - </div> - </div> + <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></div></script> - - <script type='text/html' id='WELCOME'> - <h3>Welcome</h3><p class='lead'> @@ -134,8 +60,6 @@ </div></script> - - <script type='text/html' id='GENERAL_INSTRUCTIONS'><div id='instructions1'><h4>Harvesting and Profit</h4> @@ -262,251 +186,251 @@ <a href='javascript:void();' data-bind='click: activateInstructionsPageTwo'>Back</a></li><li class='next'> - <a href='javascript: void();' data-bind='click: finishedInstructions'>I have fully read and understand + <a href='javascript: void();' data-bind='click: participantReady'>I have fully read and understand these instructions</a></li></ul></script> - <script type='text/html' id='PRACTICE'></script> - - <script type='text/html' id='REGULAR'><div data-bind='if: showChatRooms'><h3>Chat</h3> + <div data-bind='ifnot: chatEnabled'><div class='alert alert-info'><i class='icon-warning-sign'></i> Chat is currently disabled. </div></div> - <form id="chat-form" class='form-inline'> - <div class='input-prepend input-append'> - <span class='add-on'><i class='text-info icon-comment'></i></span> - <input id='chatMessage' type="text" placeholder="Enter a chat message"> - <button class='btn btn-primary' data-bind='click: submitChatMessage'>Send</button> + <div data-bind='if: chatEnabled'> + <div class='row'> + <div class='span3'> + <form id="within-group-chat-form" class='form-inline'> + <div class='input-prepend input-append'> + <span class='add-on'><i class='text-info icon-comment'></i></span> + <input name='participant_group_id' type='hidden' data-bind='value: participantGroupId'> + <input id='withinGroupChatMessage' name='message' type="text" placeholder="Message your group"> + <button class='btn btn-primary' data-bind='click: submitWithinGroupChatMessage'>Send</button> + </div> + </form> + <div class='chat-window'> + <div class='chat-messages' data-bind='foreach: withinGroupChatMessages'> + <i class='icon-user muted'></i> + <strong>Participant <span data-bind='text: participant_number'></strong><b class='pull-right muted' data-bind='text: date_created'></b> + <p> + <small><i class='icon-double-angle-right'></i></small> + <span data-bind='text: message'></span> + </p> + </div> + </div> + </div> + <div class='span1'> + </div> + <div class='span3'> + <form id="between-group-chat-form" class='form-inline'> + <div class='input-prepend input-append'> + <span class='add-on'><i class='text-info icon-comment'></i></span> + <input id='participant_group_id' type='hidden' data-bind='value: participantGroupId'> + <input id='betweenGroupChatMessage' type="text" placeholder="Message the other group"> + <button class='btn btn-primary' data-bind='click: submitBetweenGroupChatMessage'>Send</button> + </div> + </form> + <div class='chat-window'> + <div class='chat-messages' data-bind='foreach: betweenGroupChatMessages'> + <i class='icon-user muted'></i><strong>Participant <span + data-bind='text: participant_number'></strong><b class='pull-right muted' + data-bind='text: date_created'></b> + + <p> + <small><i class='icon-double-angle-right'></i></small> + <span data-bind='text: message'></span> + </p> + </div> + </div> + </div></div> + </div> + </div> + <div data-bind='if: chatEnabled'> + <form id='chatPreferencesForm' class='form-horizontal'> + <input type='hidden' name='participant_group_id' data-bind='value:participantGroupId'> + <label class='checkbox'> + <input type='checkbox' name='chat_within_group'> + <strong>Talk within group FREE</strong> + </label> + <label class='checkbox'> + <input type='checkbox' name='chat_between_group'> + <strong>Talk with other group (costs 2h)</strong> + </label> + <button class='btn btn-primary' data-bind='click: submitChatPreferences'>Submit Chat Preferences</button></form> - <div class='chat-sidebar'> - <div id='chat-div'> - <div class='chat-messages' data-bind='foreach: chatMessages'> - <i class='icon-user muted'></i><strong>Participant <span data-bind='text: participant_number'></strong><b class='pull-right muted' data-bind='text: date_created'></b> - <p> - <small><i class='icon-double-angle-right'></i></small><span data-bind='text: message'></span> - </p> + </div> + + <div class='row'> + <div class='span4'> + <h3>My Current Earnings</h3> + <div> + <span id="totalEarning" data-bind='text: totalEarning'></span> + </div> + <div data-bind='if: isTimerRunning'> + <div class='alert alert-error'> + <b><i class='icon-time'></i> Time left:</b> + <span data-bind='text: secondsLeft'></span></div></div></div></div> - - <form> - <div class="span1" > - <a href="#" class="btn btn-primary" data-bind="submitChatOptionLocal"> - <i class="icon-home icon-white"></i> - <span><strong>Talk within group FREE</strong> - <input id="chat_within_group" hidden="True"> - </span> - </a> - </div> - <div class="span1"> - <a href="#" class="btn btn-primary" data-bind="submitChatOptionGlobal"> - <i class="icon-globe icon-white"></i> - <span><strong>Talk with other group $$ 2h</strong></span> - <input id="chat_between_group" hidden="True"> - </a> - </div> - </form> - - - <div class='row'> - <div class='span4'> - <h3>My Current Earnings</h3> - - <div> - <span id="totalEarning" data-bind='text: totalEarning'></span> - </div> - - <div data-bind='if: isTimerRunning'> - <div class='alert alert-error'> - <b><i class='icon-time'></i> Time left:</b> - <span data-bind='text: secondsLeft'></span> - </div> - </div> - </div> - </div> - - <!-- only show when chatOption enabled --> - <div class="span6" data-bind="if: chatOptionEnabled"> - <div data-bind='if: isTimerRunning'> - <div class='alert alert-error'> - <b><i class='icon-time'></i> Time left:</b> - <span data-bind='text: secondsLeft'></span>s - </div> - </div> - <div class="span1"> - <a href="#" class="btn btn-primary" data-bind="submitChatOptionLocal()"> - <i class="icon-home icon-white"></i> - <span><strong>Talk within group FREE</strong></span> - </a> - </div> - <div class="span1"> - <a href="#" class="btn btn-primary" data-bind="submitChatOptionGlobal()"> - <i class="icon-globe icon-white"></i> - <span><strong>Talk with other group $$ 2h</strong></span> - </a> - </div> - </div> - - <div data-bind='if: practiceRound'> - <div class='alert alert-error alert-block'> - <h4>PRACTICE ROUND</h4> - This is a practice round. The decisions you make in this round will <b>NOT</b> contribute to your - earnings. + <div data-bind='if: practiceRound'> + <div class='alert alert-error alert-block'> + <h4>PRACTICE ROUND</h4> + This is a practice round. The decisions you make in this round will <b>NOT</b> contribute to your + earnings. <span data-bind="if: isFirstPracticeRound"><a href="#" data-bind="">Show me 1st Instructions again</a></span> - </div> - <div> - Insert system image here - </div> + </div> + <div> + Insert system image here + </div> - <div data-bind="ifnot: isTimeOut" id='resourceDisplay'> - <div class='alert alert-info'>You have <strong class='badge badge-success' - data-bind='text:maxHarvestDecision'></strong> hours - left to use - today. - </div> + <div data-bind="ifnot: isTimeOut" id='resourceDisplay'> + <div class='alert alert-info'>You have <strong class='badge badge-success' + data-bind='text:maxHarvestDecision'></strong> hours + left to use + today. + </div> - </div> - <div data-bind="if: isTimeOut"> - <div style='padding: 8px; margin: auto; border: solid 1px; background: url("{{ STATIC_URL }}images/broker/SES.jpg") no-repeat center; height: 282px; width:425px;'> - - </div> - <div class='alert alert-error'>You have no time left today. Please wait until the next round begins. - </div> - </div> - <div data-bind='if: hasSubmit'> - <div class='alert alert-error'> - You have invested <span class='badge badge-important' data-bind='text: harvestDecision'></span> - hours in - harvesting today. - You have invested <span class='badge badge-important' - data-bind='text: conservationDecision'></span> - hours in conservation today. - </div> - </div> + </div> + <div data-bind="if: isTimeOut"> + <div style='padding: 8px; margin: auto; border: solid 1px; background: url("{{ STATIC_URL }}images/broker/SES.jpg") no-repeat center; height: 282px; width:425px;'> + + </div> + <div class='alert alert-error'>You have no time left today. Please wait until the next round begins. + </div> + </div> + <div data-bind='if: hasSubmit'> + <div class='alert alert-error'> + You have invested <span class='badge badge-important' data-bind='text: harvestDecision'></span> + hours in + harvesting today. + You have invested <span class='badge badge-important' + ... [truncated message content] |
From: <com...@bi...> - 2013-03-27 22:56:20
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/ef739932a1be/ Changeset: ef739932a1be User: dieg...@gmail.com Date: 2013-03-27 23:56:02 Summary: chat form, fixed tour Affected #: 2 files diff -r 7fef6cff071c3301e6a3b05d4f4b39f497c36fb5 -r ef739932a1be5788d8a47a793b3699460df31756 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -94,6 +94,8 @@ experiment_model_dict['participantGroupId'] = participant_group_relationship.pk experiment_model_dict['roundType'] = current_round.round_type experiment_model_dict['practiceRound'] = current_round.is_practice_round + experiment_model_dict['showChatRooms'] = True + if current_round.is_regular_round: experiment_model_dict['chatEnabled'] = current_round.chat_enabled diff -r 7fef6cff071c3301e6a3b05d4f4b39f497c36fb5 -r ef739932a1be5788d8a47a793b3699460df31756 vcweb/broker/templates/broker/participate.html --- a/vcweb/broker/templates/broker/participate.html +++ b/vcweb/broker/templates/broker/participate.html @@ -274,6 +274,33 @@ <script type='text/html' id='REGULAR'> + <div data-bind='if: showChatRooms'> + <h3>Chat</h3> + <div data-bind='ifnot: chatEnabled'> + <div class='alert alert-info'> + <i class='icon-warning-sign'></i> Chat is currently disabled. + </div> + </div> + <form id="chat-form" class='form-inline'> + <div class='input-prepend input-append'> + <span class='add-on'><i class='text-info icon-comment'></i></span> + <input id='chatMessage' type="text" placeholder="Enter a chat message"> + <button class='btn btn-primary' data-bind='click: submitChatMessage'>Send</button> + </div> + </form> + <div class='chat-sidebar'> + <div id='chat-div'> + <div class='chat-messages' data-bind='foreach: chatMessages'> + <i class='icon-user muted'></i><strong>Participant <span data-bind='text: participant_number'></strong><b class='pull-right muted' data-bind='text: date_created'></b> + <p> + <small><i class='icon-double-angle-right'></i></small><span data-bind='text: message'></span> + </p> + </div> + </div> + </div> + </div> + + <form><div class="span1" ><a href="#" class="btn btn-primary" data-bind="submitChatOptionLocal"> @@ -568,6 +595,7 @@ }); }; model.chatEnabled = ko.observable(false); // round configurations + model.showChatRooms = ko.observable(false); model.chatOptionEnabled = ko.observable(false); // round configurations model.harvestDecision = ko.observable(0); model.conservationDecision = ko.computed(function () { @@ -669,6 +697,92 @@ return model; } + function set_first_tour(){ + var tourFirst = new Tour({ + useLocalStorage: true + }); + tourFirst.addStep({ + element: "harvestDecisionId", + title: "Here's where you insert your harvesting decision", + content: "For this practice round, go ahead and put 6 hours into harvesting. Each round you will have a maximum of 6 minute to make a harvest decision.", /* content of the popover */ + placement: "right" + }); + tourFirst.addStep({ + element: "conservationDecision", + title: "Your conservation decision", + content: "Note that the rest of your available hours will be put into conservation.", + placement: "right" + }); + tourFirst.addStep({ + element: "submitDecision", + title: "Submit your decision", + content: "Now click here to submit your harvest choice. Your choice will be submitted automatically when time is up. A countdown will alert you when there are 10 seconds remaining to make a harvest. The default harvest is zero.", /* content of the popover */ + placement: "right" + }); + tourFirst.start(true); + tour = tourFirst; + console.debug("tour started"); + + + } + + function set_second_tour(){ + var tourSecond = new Tour(); + alert("second tour"); + tourSecond.addStep({ + element: "lastRoundHarvestPayOff", + title: "Your round earnings", + content: "Here you will see how much you earned in each round. You receive 0.6 from harvesting. Because everyone contributed 4 hours to conservation, resulting in 8 hours for group A and 8 hours for group B.", + placement: "right" + }); + tourSecond.addStep({ + element: "lastRoundGroupLocalBonus", + title: "Bonus", + content: "So the standard revenue of $0.10/hour has been increased by 50% you receive an extra $0.30 and your total is $0.90. If the sum within your group was less than 5 hours you would not receive benefits. ", + placement: "right" + }); + tourSecond.addStep({ + element: "lastRoundMyGroupConservation", + title: "Bonus", + content: "If the sum of conservation time of all players were more than 22 hours you would get a further increase of 50% in the revenues.", + placement: "right" + }); + tourSecond.addStep({ + element: "totalEarning", + title: "Total Earning", + content: "Here you can your total earning throughout the game", + placement: "right" + }); + + tourSecond.addStep({ + element: "totalEarning", + title: "Communication", + content: "At some point during the game you will have the option of communicating to other players. Communication to the other player within your group is FREE. Communication with the other group costs 2 hours.", + }); + tourSecond.addStep({ + element: "totalEarning", + title: "", + content: "For this practice, go ahead and choose 'Communication within Group' and 'Communication with other Group'", + + }); + tourSecond.addStep({ + element: "totalEarning", + title: "Chat rooms", + content: "Communication will happen through these chat windows. Communications is time bound. Each message you send will be targeted a single player. Go ahead and send a message. It will not be seen by others for this practice.", + onHide: function (tourSecond) { + // post a dummy message to the chat... "Here's an example of a reply message" + } + + }); + tourSecond.addStep({ + element: "totalEarning", + title: "Chat rooms", + content: "Remember that all your choices are independent and none will see what your decisions are.", + }); + tourSecond.start(); + + } + function initialize(experimentModelJson) { var experimentModel = new ExperimentModel(experimentModelJson); ko.applyBindings(experimentModel); @@ -695,97 +809,18 @@ // $('#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); - if (experimentModel.isFirstPracticeRound) { + if (experimentModel.isFirstPracticeRound()) { console.debug("starting first practice round tour"); - - var tourFirst = new Tour({ - useLocalStorage: true - }); - tourFirst.addStep({ - element: "harvestDecisionId", - title: "Here's where you insert your harvesting decision", - content: "For this practice round, go ahead and put 6 hours into harvesting. Each round you will have a maximum of 6 minute to make a harvest decision.", /* content of the popover */ - placement: "right" - }); - tourFirst.addStep({ - element: "conservationDecision", - title: "Your conservation decision", - content: "Note that the rest of your available hours will be put into conservation.", - placement: "right" - }); - tourFirst.addStep({ - element: "submitDecision", - title: "Submit your decision", - content: "Now click here to submit your harvest choice. Your choice will be submitted automatically when time is up. A countdown will alert you when there are 10 seconds remaining to make a harvest. The default harvest is zero.", /* content of the popover */ - placement: "right" - }); - tourFirst.start(true); - tour = tourFirst; - console.debug("tour started"); - - - } else if (experimentModel.isSecondPracticeRound) { - var tourSecond = new Tour(); - alert("second tour"); - tourSecond.addStep({ - element: "lastRoundHarvestPayOff", - title: "Your round earnings", - content: "Here you will see how much you earned in each round. You receive 0.6 from harvesting. Because everyone contributed 4 hours to conservation, resulting in 8 hours for group A and 8 hours for group B.", - placement: "right" - }); - tourSecond.addStep({ - element: "lastRoundGroupLocalBonus", - title: "Bonus", - content: "So the standard revenue of $0.10/hour has been increased by 50% you receive an extra $0.30 and your total is $0.90. If the sum within your group was less than 5 hours you would not receive benefits. ", - placement: "right" - }); - tourSecond.addStep({ - element: "lastRoundMyGroupConservation", - title: "Bonus", - content: "If the sum of conservation time of all players were more than 22 hours you would get a further increase of 50% in the revenues.", - placement: "right" - }); - tourSecond.addStep({ - element: "totalEarning", - title: "Total Earning", - content: "Here you can your total earning throughout the game", - placement: "right" - }); - - tourSecond.addStep({ - element: "totalEarning", - title: "Communication", - content: "At some point during the game you will have the option of communicating to other players. Communication to the other player within your group is FREE. Communication with the other group costs 2 hours.", - }); - tourSecond.addStep({ - element: "totalEarning", - title: "", - content: "For this practice, go ahead and choose 'Communication within Group' and 'Communication with other Group'", - - }); - tourSecond.addStep({ - element: "totalEarning", - title: "Chat rooms", - content: "Communication will happen through these chat windows. Communications is time bound. Each message you send will be targeted a single player. Go ahead and send a message. It will not be seen by others for this practice.", - onHide: function (tourSecond) { - // post a dummy message to the chat... "Here's an example of a reply message" - } - - }); - tourSecond.addStep({ - element: "totalEarning", - title: "Chat rooms", - content: "Remember that all your choices are independent and none will see what your decisions are.", - }); - tourSecond.start(); - - + set_first_tour(); + } else if (experimentModel.isSecondPracticeRound()) { + set_second_tour(); } } else if (templateName === "REGULAR") { 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-27 21:45:51
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/7fef6cff071c/ Changeset: 7fef6cff071c User: alllee Date: 2013-03-27 22:45:38 Summary: removing deleted field Affected #: 1 file diff -r 4a51b1e2c2ada637e97f641bcb52d59c9a5989be -r 7fef6cff071c3301e6a3b05d4f4b39f497c36fb5 vcweb/broker/fixtures/broker_experiment_metadata.json --- a/vcweb/broker/fixtures/broker_experiment_metadata.json +++ b/vcweb/broker/fixtures/broker_experiment_metadata.json @@ -68,7 +68,6 @@ "experiment_metadata": 7, "status": "INACTIVE", "start_date_time": null, - "current_round_elapsed_time": 0, "tick_duration": "", "authentication_code": "broker_test", "total_elapsed_time": 0, 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-27 21:37:03
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/4a51b1e2c2ad/ Changeset: 4a51b1e2c2ad User: dieg...@gmail.com Date: 2013-03-27 22:36:51 Summary: chat form sketch Affected #: 1 file diff -r d6f1de14bbcb0eda4c678329b03a7b2ed6dca41b -r 4a51b1e2c2ada637e97f641bcb52d59c9a5989be vcweb/broker/templates/broker/participate.html --- a/vcweb/broker/templates/broker/participate.html +++ b/vcweb/broker/templates/broker/participate.html @@ -274,6 +274,25 @@ <script type='text/html' id='REGULAR'> + <form> + <div class="span1" > + <a href="#" class="btn btn-primary" data-bind="submitChatOptionLocal"> + <i class="icon-home icon-white"></i> + <span><strong>Talk within group FREE</strong> + <input id="chat_within_group" hidden="True"> + </span> + </a> + </div> + <div class="span1"> + <a href="#" class="btn btn-primary" data-bind="submitChatOptionGlobal"> + <i class="icon-globe icon-white"></i> + <span><strong>Talk with other group $$ 2h</strong></span> + <input id="chat_between_group" hidden="True"> + </a> + </div> + </form> + + <div class='row'><div class='span4'><h3>My Current Earnings</h3> 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-27 21:31:58
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/d6f1de14bbcb/ Changeset: d6f1de14bbcb User: dieg...@gmail.com Date: 2013-03-27 22:31:44 Summary: creating form for chat within and between group Affected #: 3 files diff -r 0d78692980a78f5136533fffb68a7f67ba900faa -r d6f1de14bbcb0eda4c678329b03a7b2ed6dca41b vcweb/broker/forms.py --- /dev/null +++ b/vcweb/broker/forms.py @@ -0,0 +1,8 @@ +from django import forms + +__author__ = 'diegogalafassi' + +class ChatPreferenceForm (forms.Form): + participant_group_id = forms.IntegerField() + chat_within_group = forms.BooleanField(default=False) + chat_between_group = forms.BooleanField(default=False) diff -r 0d78692980a78f5136533fffb68a7f67ba900faa -r d6f1de14bbcb0eda4c678329b03a7b2ed6dca41b vcweb/broker/models.py --- a/vcweb/broker/models.py +++ b/vcweb/broker/models.py @@ -19,7 +19,7 @@ @simplecache def get_participant_payoff_parameter(): - return Parameter.objects.get(name='participant_payoff') + return Parameter.objects.get(name='payoff') @simplecache diff -r 0d78692980a78f5136533fffb68a7f67ba900faa -r d6f1de14bbcb0eda4c678329b03a7b2ed6dca41b vcweb/broker/views.py --- a/vcweb/broker/views.py +++ b/vcweb/broker/views.py @@ -5,7 +5,7 @@ from vcweb.core.forms import ParticipantGroupIdForm, SingleIntegerDecisionForm from vcweb.core.http import JsonResponse from vcweb.core.models import (is_participant, is_experimenter, Experiment, ParticipantGroupRelationship, - ParticipantExperimentRelationship, RoundConfiguration, ChatMessage, ParticipantRoundDataValue) + ParticipantExperimentRelationship, RoundConfiguration, ChatMessage, ParticipantRoundDataValue, Parameter) from vcweb.broker.models import (get_max_harvest_hours, get_harvest_decision_parameter, get_conservation_decision_parameter, set_harvest_decision, set_conservation_decision, get_harvest_decision, @@ -14,9 +14,44 @@ import random import logging +from vcweb.broker.forms import ChatPreferenceForm logger = logging.getLogger(__name__) + +def get_chat_between_group_parameter(): + return Parameter.objects.get(Name="chat_between_group") + +def get_chat_within_group_parameter(): + return Parameter.objects.get(Name="chat_within_group") + +@participant_required +def submit_chat_preference (request, experiment_id=None,): + form = ChatPreferenceForm(request.POST or None) + experiment = get_object_or_404(Experiment, pk=experiment_id) + if form.is_valid(): + logger.debug("handing POST request, cleaned data: %s", form.cleaned_data) + participant_group_id = form.cleaned_data['participant_group_id'] + pgr = get_object_or_404(ParticipantGroupRelationship, pk=participant_group_id) + round_data = experiment.current_round_data + chat_within_group = form.cleaned_data['chat_within_group'] + chat_between_group = form.cleaned_data['chat_between_group'] + pgr.set_data_value(parameter=get_chat_within_group_parameter(), value=chat_within_group, round_data=round_data) + pgr.set_data_value(parameter=get_chat_between_group_parameter(), value=chat_between_group, round_data=round_data) + ncwg = ParticipantRoundDataValue.objects.filter(parameter=get_chat_within_group_parameter(), round_data=round_data, submitted=True).count() + ncbg = ParticipantRoundDataValue.objects.filter(parameter=get_chat_between_group_parameter(), round_data=round_data, submitted=True).count() + np = experiment.participant_set.count() + response_dict = { + 'success': True, + 'all_participants_submitted': False, + } + if ncwg == np and ncbg == np: + # everyone submitted a chat preference decision, create participant linkages + + response_dict['all_participants_submitted'] = True + return JsonResponse(dumps(response_dict)) + return JsonResponse(dumps({'success': False})) + @participant_required def submit_decision(request, experiment_id=None): form = SingleIntegerDecisionForm(request.POST or None) Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-27 20:21:29
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/0d78692980a7/ Changeset: 0d78692980a7 User: alllee Date: 2013-03-27 21:21:14 Summary: removing typo from broker views Affected #: 1 file diff -r 22db62968915818d9db0a72df997de7010387bf6 -r 0d78692980a78f5136533fffb68a7f67ba900faa vcweb/broker/views.py --- a/vcweb/broker/views.py +++ b/vcweb/broker/views.py @@ -16,7 +16,6 @@ import logging logger = logging.getLogger(__name__) -totalEarning = @participant_required def submit_decision(request, experiment_id=None): Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-27 20:15:12
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/22db62968915/ Changeset: 22db62968915 User: alllee Date: 2013-03-27 21:14:19 Summary: minor hygiene on boundaries participant interface and starting to work on round configurations, need to implement debriefing instructions for practice rounds and regular rounds Affected #: 7 files diff -r ea01e7b153a264aefe8f002de660457b999226d2 -r 22db62968915818d9db0a72df997de7010387bf6 vcweb/boundaries/templates/bound --- /dev/null +++ b/vcweb/boundaries/templates/bound @@ -0,0 +1,1 @@ +boundaries \ No newline at end of file diff -r ea01e7b153a264aefe8f002de660457b999226d2 -r 22db62968915818d9db0a72df997de7010387bf6 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -444,20 +444,21 @@ }); model.resourceImageHeight = ko.observable("79px"); model.startRound = function() { + if (model.submitted() || ! model.alive()) { + model.disableHarvestForm(); + model.disableChatForm(); + return; + } console.debug("starting round"); - model.enableChat(); - var intRegex = /^\d+$/; - if (intRegex.test(model.timeRemaining()) && model.timeRemaining() > 0) { + if (isInt(model.timeRemaining()) && model.timeRemaining() > 0) { + model.setupChat(); model.secondsLeft(model.timeRemaining()); model.setCurrentInterval( setInterval(function() { model.tick(); - if (model.secondsLeft() == 30 && !model.submitted()) { - model.setFormDisabled("#vcweb-form", false); - } + model.setFormDisabled("#vcweb-form", model.secondsLeft() > 30); if (! model.isTimerRunning()) { model.submitDecision(); - model.disableChat(); model.clearCurrentInterval(); } }, @@ -468,6 +469,7 @@ model.setFormDisabled("#vcweb-form", false); var formData = $('#vcweb-form').serialize(); model.setFormDisabled("#vcweb-form", true); + model.disableChat(); model.setFormDisabled("#chat-form", true); console.debug(formData); $.post('submit-harvest-decision', formData, function(response) { @@ -506,29 +508,26 @@ } $(formId + " :input").prop("disabled", disabled); } - model.disableChat = function() { - // $('#content').removeClass('span6').addClass('span9'); - // $('#sidebar').removeClass('span6').addClass('span3'); + model.enableHarvestForm = function() { + model.setFormDisabled("#vcweb-form", false); + } + model.disableHarvestForm = function() { + model.setFormDisabled("#vcweb-form", true); + } + model.enableChatForm = function() { + model.setFormDisabled("#chat-form", false); + } + model.disableChatForm = function() { model.setFormDisabled("#chat-form", true); } - model.enableChat = function() { - if (! model.chatEnabled()) { - return; + model.setupChat = function() { + chatEnabled = model.chatEnabled(); + model.setFormDisabled("#chat-form", ! chatEnabled); + if (chatEnabled) { + model.disableHarvestForm(); } - // $('#content').removeClass('span9').addClass('span6'); - // $('#sidebar').removeClass('span3').addClass('span6'); - model.setFormDisabled("#vcweb-form", true); - model.setFormDisabled("#chat-form", false); } model.afterRenderTemplate = function(elements) { - model.setFormDisabled("#chat-form", ! model.chatEnabled()); - if (model.submitted() || ! model.alive()) { - model.setFormDisabled("#vcweb-form", true); - model.setFormDisabled("#chat-form", true); - } - else { - model.setFormDisabled("#vcweb-form", false); - } if (model.templateName() === "REGULAR") { model.startRound() } diff -r ea01e7b153a264aefe8f002de660457b999226d2 -r 22db62968915818d9db0a72df997de7010387bf6 vcweb/core/migrations/0003_auto__chg_field_roundconfiguration_group_cluster_size.py --- /dev/null +++ b/vcweb/core/migrations/0003_auto__chg_field_roundconfiguration_group_cluster_size.py @@ -0,0 +1,398 @@ +# -*- 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): + + # Changing field 'RoundConfiguration.group_cluster_size' + db.alter_column(u'core_roundconfiguration', 'group_cluster_size', self.gf('django.db.models.fields.PositiveIntegerField')(null=True)) + + def backwards(self, orm): + + # Changing field 'RoundConfiguration.group_cluster_size' + db.alter_column(u'core_roundconfiguration', 'group_cluster_size', self.gf('django.db.models.fields.PositiveIntegerField')()) + + 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_sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'current_round_start_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentConfiguration']"}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentMetadata']"}), + 'experimenter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experimenter']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'start_date_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'INACTIVE'", 'max_length': '32'}), + 'tick_duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'total_elapsed_time': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + }, + u'core.experimentactivitylog': { + 'Meta': {'object_name': 'ExperimentActivityLog', '_ormbases': [u'core.ActivityLog']}, + u'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': u"orm['core.Experiment']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.experimentconfiguration': { + 'Meta': {'ordering': "['experiment_metadata', 'creator', 'date_created']", 'object_name': 'ExperimentConfiguration'}, + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': u"orm['core.Experimenter']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'exchange_rate': ('django.db.models.fields.DecimalField', [], {'default': '0.2', 'null': 'True', 'max_digits': '6', 'decimal_places': '2', 'blank': 'True'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': u"orm['core.ExperimentMetadata']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation_subject': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'is_experimenter_driven': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'max_group_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), + 'max_number_of_participants': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'treatment_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}) + }, + u'core.experimenter': { + 'Meta': {'ordering': "['user']", 'object_name': 'Experimenter'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'authentication_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'failed_password_attempts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'institution': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Institution']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'experimenter'", 'unique': 'True', 'to': u"orm['auth.User']"}) + }, + u'core.experimenterrequest': { + 'Meta': {'object_name': 'ExperimenterRequest'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'}) + }, + u'core.experimentmetadata': { + 'Meta': {'ordering': "['namespace', 'date_created']", 'object_name': 'ExperimentMetadata'}, + 'about_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'default_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentConfiguration']", 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'namespace': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'short_name': ('django.db.models.fields.SlugField', [], {'max_length': '32', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'core.experimentparametervalue': { + 'Meta': {'object_name': 'ExperimentParameterValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_parameter_value_set'", 'to': u"orm['core.ExperimentConfiguration']"}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.experimentsession': { + 'Meta': {'object_name': 'ExperimentSession'}, + 'capacity': ('django.db.models.fields.PositiveIntegerField', [], {'default': '20'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_session_set'", 'to': u"orm['auth.User']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_session_set'", 'to': u"orm['core.ExperimentMetadata']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'scheduled_date': ('django.db.models.fields.DateTimeField', [], {}), + 'scheduled_end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.group': { + 'Meta': {'ordering': "['experiment', 'number']", 'object_name': 'Group'}, + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'max_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), + 'number': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.groupactivitylog': { + 'Meta': {'object_name': 'GroupActivityLog', '_ormbases': [u'core.ActivityLog']}, + u'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': u"orm['core.Group']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.groupcluster': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'GroupCluster'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_cluster_set'", 'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.groupclusterdatavalue': { + 'Meta': {'object_name': 'GroupClusterDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'group_cluster': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.GroupCluster']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'round_data': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_cluster_data_value_set'", 'to': u"orm['core.RoundData']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.grouprelationship': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'GroupRelationship'}, + 'cluster': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_relationship_set'", 'to': u"orm['core.GroupCluster']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'core.grouprounddatavalue': { + 'Meta': {'ordering': "['round_data', 'group', 'parameter']", 'object_name': 'GroupRoundDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'data_value_set'", 'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.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', 'null': 'True', 'blank': 'True'}), + 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 diff -r ea01e7b153a264aefe8f002de660457b999226d2 -r 22db62968915818d9db0a72df997de7010387bf6 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -1009,7 +1009,7 @@ """ external survey url """ chat_enabled = models.BooleanField(default=False, help_text=_("Is chat enabled in this round?")) create_group_clusters = models.BooleanField(default=False, help_text=_("Create relationships (clusters) of groups that can share group cluster data values")) - group_cluster_size = models.PositiveIntegerField(default=2, help_text=_("How many groups should be clustered together at a time?")) + group_cluster_size = models.PositiveIntegerField(null=True, blank=True, default=2, help_text=_("How many groups should form a cluster?")) randomize_groups = models.BooleanField(default=False, help_text=_("Shuffle participants into new groups when the round begins?")) """ Should groups be randomized at the start of the round? """ preserve_existing_groups = models.BooleanField(default=True, help_text=_("This option is only useful if randomize_groups is set to true. If we are randomizing groups, should existing groups (if any) be preserved?")) diff -r ea01e7b153a264aefe8f002de660457b999226d2 -r 22db62968915818d9db0a72df997de7010387bf6 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -293,8 +293,8 @@ } }); } - model.addMessage = function(data) { - model.messages.unshift(data.message); + model.addMessage = function(message) { + model.messages.unshift(message); }; model.hasParticipants = ko.computed(function() { return model.participantCount() > 0; @@ -317,7 +317,6 @@ } function initialize(experimentModelJson) { var experimentModel = new ExperimentModel(experimentModelJson); - // var experimentModel = new ExperimentModel(); ko.applyBindings(experimentModel); // establish sockjs websocket connection var s = connect("/experimenter"); @@ -325,9 +324,10 @@ console.log("Received event: " + evt); experiment_event = $.parseJSON(evt.data); switch (experiment_event.event_type) { + case 'update': + console.debug("FIXME: ignoring update requests, patch sockjs broadcast to not send certain messages"); + break; case 'chat': - experimentModel.addMessage("Participant " + experiment_event.participant_number + ": " + experiment_event.message); - break; case 'info': default: experimentModel.addMessage(experiment_event.message); diff -r ea01e7b153a264aefe8f002de660457b999226d2 -r 22db62968915818d9db0a72df997de7010387bf6 vcweb/static/js/common.js --- a/vcweb/static/js/common.js +++ b/vcweb/static/js/common.js @@ -10,6 +10,10 @@ function formatCurrency(floatValue) { return "$" + floatValue.toFixed(2); } +var INT_REGEX = /^\d+$/; +function isInt(value) { + return INT_REGEX.test(value); +} function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); diff -r ea01e7b153a264aefe8f002de660457b999226d2 -r 22db62968915818d9db0a72df997de7010387bf6 vcweb/vcweb-sockjs.py --- a/vcweb/vcweb-sockjs.py +++ b/vcweb/vcweb-sockjs.py @@ -208,7 +208,7 @@ logger.debug("no experimenter found with pk %s in experimenters set %s", experimenter_tuple, self.experimenter_to_connection) - def broadcast(self, experiment=None, message=None, experimenter=None): + def broadcast(self, experiment=None, message=None, experimenter=None, notify_experimenter=True): if experimenter is None: experimenter = experiment.experimenter if message is None: @@ -219,7 +219,8 @@ participant_connections.append(participant_group_id) connection.send(message) logger.debug("sent message %s to %s", message, participant_connections) - self.send_to_experimenter(message, experiment=experiment) + if notify_experimenter: + self.send_to_experimenter(message, experiment=experiment) return participant_connections def send_to_group(self, group, json): @@ -229,7 +230,6 @@ connection_manager = ConnectionManager() - # replace with namedtuple class Struct: def __init__(self, **attributes): 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-27 19:26:00
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/ea01e7b153a2/ Changeset: ea01e7b153a2 User: dieg...@gmail.com Date: 2013-03-27 20:25:44 Summary: displaying payoff on the view Affected #: 2 files diff -r ac8883ef68fd2650fcf5004feb132b277e4eb4c5 -r ea01e7b153a264aefe8f002de660457b999226d2 vcweb/broker/models.py --- a/vcweb/broker/models.py +++ b/vcweb/broker/models.py @@ -61,6 +61,12 @@ prdv.int_value = value prdv.save() +def get_payoff_dv(participant_group_relationship, round_data=None, default=0): + return participant_group_relationship.get_data_value(round_data=round_data, parameter=get_payoff_parameter(), default=default) + +def get_payoff(participant_group_relationship, round_data=None, default=0): + return get_payoff_dv(participant_group_relationship, round_data, default).int_value + def get_group_local_bonus_threshold(round_configuration): return round_configuration.get_parameter_value(parameter=get_group_local_bonus_parameter(), default=5).int_value diff -r ac8883ef68fd2650fcf5004feb132b277e4eb4c5 -r ea01e7b153a264aefe8f002de660457b999226d2 vcweb/broker/views.py --- a/vcweb/broker/views.py +++ b/vcweb/broker/views.py @@ -9,13 +9,14 @@ from vcweb.broker.models import (get_max_harvest_hours, get_harvest_decision_parameter, get_conservation_decision_parameter, set_harvest_decision, set_conservation_decision, get_harvest_decision, - get_conservation_decision) + get_conservation_decision, get_payoff) import random import logging logger = logging.getLogger(__name__) +totalEarning = @participant_required def submit_decision(request, experiment_id=None): @@ -105,7 +106,7 @@ experiment_model_dict['lastRoundGlobalConservation'] = 10 experiment_model_dict['lastRoundGroupLocalBonus'] = 10 experiment_model_dict['lastRoundGroupGlobalBonus'] = 10 - experiment_model_dict['lastRoundHarvestPayOff'] = 5 + experiment_model_dict['lastRoundHarvestPayOff'] = get_payoff(participant_group_relationship, round_data=previous_round_data) experiment_model_dict['totalEarning'] = 100 number_of_connected_groups = round_configuration.get_parameter_value(name='number_of_connected_groups', default=2).int_value experiment_model_dict['participantsPerSubGroup'] = group.max_size 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-27 10:44:19
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/ac8883ef68fd/ Changeset: ac8883ef68fd User: alllee Date: 2013-03-27 11:44:01 Summary: tuning message for experimenter / participants Affected #: 1 file diff -r 6fed7a80dc3ef56617679869a3c9f5d788908745 -r ac8883ef68fd2650fcf5004feb132b277e4eb4c5 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -37,10 +37,10 @@ pgr = get_object_or_404(ParticipantGroupRelationship, pk=participant_group_id) harvest_decision = form.cleaned_data['integer_decision'] set_harvest_decision(pgr, harvest_decision, experiment.current_round_data, submitted=True) - message = "%s harvested %s trees" % (pgr.participant, harvest_decision) - experiment.log(message) + message = "%s harvested %s trees" + experiment.log(message % (pgr.participant, harvest_decision)) return JsonResponse(dumps({ 'success': True, 'experimentModelJson': get_view_model_json(experiment, pgr), - 'message': message})) + 'message': message % (pgr.participant_handle, harvest_decision)})) else: logger.debug("form was invalid: %s", form) for field in form: 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-27 10:14:56
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/6fed7a80dc3e/ Changeset: 6fed7a80dc3e User: alllee Date: 2013-03-27 11:14:34 Summary: setting logs properly Affected #: 5 files diff -r dafca79ec5983354784a555c021a739fd07d17de -r 6fed7a80dc3ef56617679869a3c9f5d788908745 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -204,7 +204,6 @@ # reset all player statuses to True ParticipantRoundDataValue.objects.for_group(group, parameter=get_player_status_parameter(), round_data=round_data).update(boolean_value=True) - # FIXME: start server side timer def get_total_harvest(group, round_data): diff -r dafca79ec5983354784a555c021a739fd07d17de -r 6fed7a80dc3ef56617679869a3c9f5d788908745 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -446,11 +446,13 @@ model.startRound = function() { console.debug("starting round"); model.enableChat(); - model.secondsLeft(model.timeRemaining()); - model.setCurrentInterval( + var intRegex = /^\d+$/; + if (intRegex.test(model.timeRemaining()) && model.timeRemaining() > 0) { + model.secondsLeft(model.timeRemaining()); + model.setCurrentInterval( setInterval(function() { model.tick(); - if (model.secondsLeft() == 30) { + if (model.secondsLeft() == 30 && !model.submitted()) { model.setFormDisabled("#vcweb-form", false); } if (! model.isTimerRunning()) { @@ -460,8 +462,10 @@ } }, 1000)); + } }; model.submitDecision = function(data, evt) { + model.setFormDisabled("#vcweb-form", false); var formData = $('#vcweb-form').serialize(); model.setFormDisabled("#vcweb-form", true); model.setFormDisabled("#chat-form", true); diff -r dafca79ec5983354784a555c021a739fd07d17de -r 6fed7a80dc3ef56617679869a3c9f5d788908745 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -37,7 +37,7 @@ pgr = get_object_or_404(ParticipantGroupRelationship, pk=participant_group_id) harvest_decision = form.cleaned_data['integer_decision'] set_harvest_decision(pgr, harvest_decision, experiment.current_round_data, submitted=True) - message = "harvested %s trees" % harvest_decision + message = "%s harvested %s trees" % (pgr.participant, harvest_decision) experiment.log(message) return JsonResponse(dumps({ 'success': True, 'experimentModelJson': get_view_model_json(experiment, pgr), 'message': message})) diff -r dafca79ec5983354784a555c021a739fd07d17de -r 6fed7a80dc3ef56617679869a3c9f5d788908745 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -111,10 +111,12 @@ </div></div><div class='span6'> - <h4>Experiment Log</h4> - <div id='experiment-messages' class='alert' data-bind='foreach: messages'> - <div> - <span data-bind='text: $data'></span> + <div style='padding-right: 8px;' class='alert alert-messages'> + <h4>EXPERIMENT LOG</h4> + <div id='experiment-messages' data-bind='foreach: messages'> + <div> + <span data-bind='text: $data'></span> + </div></div></div> {% comment %} @@ -321,7 +323,16 @@ var s = connect("/experimenter"); s.onmessage = function(evt) { console.log("Received event: " + evt); - experimentModel.addMessage(jQuery.parseJSON(evt.data)); + experiment_event = $.parseJSON(evt.data); + switch (experiment_event.event_type) { + case 'chat': + experimentModel.addMessage("Participant " + experiment_event.participant_number + ": " + experiment_event.message); + break; + case 'info': + default: + experimentModel.addMessage(experiment_event.message); + break; + } }; return experimentModel; // FIXME: this won't quite work diff -r dafca79ec5983354784a555c021a739fd07d17de -r 6fed7a80dc3ef56617679869a3c9f5d788908745 vcweb/static/css/style.css --- a/vcweb/static/css/style.css +++ b/vcweb/static/css/style.css @@ -82,7 +82,10 @@ margin-bottom: 10px; } #experiment-messages { - height: 230px; + height: 280px; + width: auto; + padding: 5px 0px 5px 0px; + margin: 5px 0px 5px 0px; overflow: auto; } .left-divider { 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-27 09:52:59
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/dafca79ec598/ Changeset: dafca79ec598 User: alllee Date: 2013-03-27 10:52:43 Summary: setting up experimenter timers Affected #: 2 files diff -r f00a49bdfa9113b2eb5da37ca32d405a5013ae25 -r dafca79ec5983354784a555c021a739fd07d17de vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -27,9 +27,9 @@ <div class='btn-group'><a class='btn btn-danger' data-bind="click: confirmExperimentControllerAction.bind($data, true)" data-action='restart_round' data-content='Restart the round. This will reset timers and perform any additional round started setup logic.'> - <i class='icon-circle-arrow-left'></i> restart round</a> + <i class='icon-repeat'></i> restart round</a><a class='btn btn-danger' data-bind="click: confirmExperimentControllerAction.bind($data, true)" - data-action='restart_round' data-content='Restart the round. This will reset timers and perform any additional round started setup logic.'> + data-action='restart' data-content='Restart the entire experiment. This will reset all data and start the experiment over at round 1.'><i class='icon-circle-arrow-up'></i> restart experiment</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> @@ -78,21 +78,21 @@ </div><div id='registeredParticipants' class='accordion-body collapse'><div class='accordion-inner'> + {% regroup registeredParticipants by group as group_list %} + {% for group in group_list %} <table class='table table-compact table-striped table-bordered'> - <thead><tr><th>Group</th><th>PGR PK</th><th>Participant</th></tr></thead> + <caption class='text-info'><b>{{ group.grouper }} (PK: {{group.grouper.pk}})</b></caption> + <thead><tr><th>PGR PK</th><th>Participant</th></tr></thead><tbody> - {% regroup registeredParticipants by group as group_list %} - {% for group in group_list %} {% for item in group.list %} <tr> - <td>{{ item.group }}</td><td>{{ item.participant_group_relationship.pk }}</td> - <td>{{ item.participant_group_relationship.participant.email }}, {{ item.participant_group_relationship.participant_handle}} </td> + <td>{{ item.participant_group_relationship.participant_handle}} <i class='icon-resize-horizontal'></i> {{ item.participant_group_relationship.participant }}</td></tr> {% endfor %} - {% endfor %} </tbody></table> + {% endfor %} </div></div></div> @@ -212,6 +212,25 @@ function ExperimentModel(experimentModelJson) { var self = this; var model = ko.mapping.fromJS(experimentModelJson); + model.currentInterval = ko.observable(); + model.setCurrentInterval = function(intervalId) { + model.clearCurrentInterval(); + model.currentInterval(intervalId); + } + model.clearCurrentInterval = function() { + console.debug("clearing current interval: " + model.currentInterval()); + if (model.currentInterval()) { + clearInterval(model.currentInterval()); + model.currentInterval(undefined); + } + } + model.tick = function() { + model.timeRemaining(model.timeRemaining() - 1); + if (model.timeRemaining() < 0) { + model.addMessage("Round time has expired!"); + model.clearCurrentInterval(); + } + } model.saveExperimenterNotes = function(localModel, evt) { var notes = $('#experimenterNotesText').val(); Dajaxice.vcweb.core.save_experimenter_notes(function(data) { @@ -225,9 +244,21 @@ // 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}}}); + Dajaxice.vcweb.core.get_experiment_model(function(data) { + console.debug("model has time remaining: " + model.timeRemaining()); + ko.mapping.fromJS(data, model); + model.startTimer(); + $('#progress-modal').modal('hide'); + + }, + {pk: {{experiment.pk}}}); } - model.confirmExperimentControllerAction = function(updateParticipants, localModel, evt) { + model.startTimer = function() { + if (model.timeRemaining() > 0) { + model.setCurrentInterval( setInterval( model.tick, 1000 ) ); + } + }; + model.confirmExperimentControllerAction = function(shouldUpdateParticipants, localModel, evt) { element = evt.target; console.debug(element); if ($(element).hasClass('disabled')) { @@ -238,7 +269,8 @@ $('#progress-modal').modal('show'); Dajaxice.vcweb.core.experiment_controller(function(data) { ko.mapping.fromJS(data, model); - if (updateParticipants) { + model.startTimer(); + if (shouldUpdateParticipants) { sendUpdateEvent(); } $('#progress-modal').modal('hide'); diff -r f00a49bdfa9113b2eb5da37ca32d405a5013ae25 -r dafca79ec5983354784a555c021a739fd07d17de vcweb/core/views.py --- a/vcweb/core/views.py +++ b/vcweb/core/views.py @@ -272,7 +272,7 @@ experiment = get_object_or_404(Experiment.objects.select_related('experiment_configuration', 'experimenter'), pk=pk) user = request.user if is_experimenter(user, experiment.experimenter): - registered_participants = [ { "group": unicode(pgr.group), "participant_group_relationship": pgr } for pgr in experiment.participant_group_relationships ] + registered_participants = [ { "group": pgr.group, "participant_group_relationship": pgr } for pgr in experiment.participant_group_relationships ] return render(request, 'experimenter/monitor.html', { 'experiment': experiment, 'registeredParticipants': registered_participants, 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-27 08:51:34
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/f00a49bdfa91/ Changeset: f00a49bdfa91 User: alllee Date: 2013-03-27 09:51:18 Summary: removing current_round_elapsed_time from forestry fixture Affected #: 1 file diff -r 6853702867f4cdf88ca84e36c5372366c0437783 -r f00a49bdfa9113b2eb5da37ca32d405a5013ae25 vcweb/forestry/fixtures/initial_data.json --- a/vcweb/forestry/fixtures/initial_data.json +++ b/vcweb/forestry/fixtures/initial_data.json @@ -33,7 +33,6 @@ { "fields": { "authentication_code": "TEST_FORESTRY", - "current_round_elapsed_time": 0, "current_round_sequence_number": 1, "duration": "1h", "experiment_configuration": 1, 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-27 08:44:13
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/6853702867f4/ Changeset: 6853702867f4 User: alllee Date: 2013-03-27 09:43:56 Summary: convertin e.current_round_elapsed_time into a calculated field and refining experiment monitor interface Affected #: 8 files diff -r be61831f5354003e211ca1bec17819b94e61c97a -r 6853702867f4cdf88ca84e36c5372366c0437783 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -204,6 +204,7 @@ # reset all player statuses to True ParticipantRoundDataValue.objects.for_group(group, parameter=get_player_status_parameter(), round_data=round_data).update(boolean_value=True) + # FIXME: start server side timer def get_total_harvest(group, round_data): diff -r be61831f5354003e211ca1bec17819b94e61c97a -r 6853702867f4cdf88ca84e36c5372366c0437783 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -21,10 +21,11 @@ {% endblock content %} {% block sidebar %} +<div data-bind='ifnot: instructionsRound'><h3>Chat</h3><div data-bind='ifnot: chatEnabled'><div class='alert alert-info'> - <i class='icon-info-sign'></i> Chat is disabled until the next round begins. + <i class='icon-warning-sign'></i> Chat is currently disabled. </div></div><form id="chat-form" class='form-inline'> @@ -44,6 +45,7 @@ </div></div></div> +</div> {% endblock sidebar %} {% block javascript %} {{ block.super }} @@ -233,25 +235,27 @@ <div class='row'><div class='span5'><h3>My Status</h3> - <div data-bind='if: isTimerRunning'> - <div class='alert alert-error'> - <b><i class='icon-time'></i> Time left:</b> - <span data-bind='text: secondsLeft'></span>s - </div> - </div><div class='row'> - <div class='alert boundaries-status-dashboard span2'> - <h4>Last harvest <i class='icon-info-sign' data-content="The number of trees you harvested last round."></i></h4> - <p> - <strong class='text-success'><span data-bind='text:lastHarvestDecision'></span><i class='icon-leaf'></i></strong> - </p> - </div> - <div class='alert boundaries-status-dashboard span2'> - <h4>Storage <i class='icon-info-sign' data-bind='attr: {"data-content": "You need at least " + costOfLiving() + " trees to survive each round."}'></i></h4> - <p> - <strong data-bind='css: { "text-error": storage() < costOfLiving(), "text-success": storage() > costOfLiving()}'><span data-bind='text: storage'></span><i class='icon-leaf'></i></strong> - </p> - </div> + <div class='alert boundaries-status-dashboard span2'> + <h4>Last harvest <i class='icon-info-sign' data-content="The number of trees you harvested last round."></i></h4> + <p> + <strong class='text-success'><span data-bind='text:lastHarvestDecision'></span><i class='icon-leaf'></i></strong> + </p> + </div> + <div class='alert boundaries-status-dashboard span1'> + <h4>Storage <i class='icon-info-sign' data-bind='attr: {"data-content": "You need at least " + costOfLiving() + " trees to survive each round."}'></i></h4> + <p> + <strong data-bind='css: { "text-error": storage() < costOfLiving(), "text-success": storage() > costOfLiving()}'><span data-bind='text: storage'></span><i class='icon-leaf'></i></strong> + </p> + </div> + <div class='alert boundaries-status-dashboard span1'> + <h4><i class='icon-time'></i> Time</h4> + <p> + <strong data-bind='css: { "text-error": secondsLeft() < warningCountdownTime(), "text-info": secondsLeft() > warningCountdownTime()}'> + <span data-bind='text: secondsLeft'></span> s + </strong> + </p> + </div></div></div><div class='span4'> @@ -303,7 +307,7 @@ </div><div data-bind='if: submitted'><div class='alert alert-error'> - You have already submitted a harvest decision for <span class='badge badge-success' data-bind='text: harvestDecision'></span> trees. + You have submitted a harvest decision for <span class='badge badge-success' data-bind='text: harvestDecision'></span> trees. </div></div> @@ -440,8 +444,9 @@ }); model.resourceImageHeight = ko.observable("79px"); model.startRound = function() { + console.debug("starting round"); model.enableChat(); - model.secondsLeft(model.roundDuration()); + model.secondsLeft(model.timeRemaining()); model.setCurrentInterval( setInterval(function() { model.tick(); @@ -503,12 +508,16 @@ model.setFormDisabled("#chat-form", true); } model.enableChat = function() { + if (! model.chatEnabled()) { + return; + } // $('#content').removeClass('span9').addClass('span6'); // $('#sidebar').removeClass('span3').addClass('span6'); model.setFormDisabled("#vcweb-form", true); model.setFormDisabled("#chat-form", false); } model.afterRenderTemplate = function(elements) { + model.setFormDisabled("#chat-form", ! model.chatEnabled()); if (model.submitted() || ! model.alive()) { model.setFormDisabled("#vcweb-form", true); model.setFormDisabled("#chat-form", true); @@ -516,7 +525,7 @@ else { model.setFormDisabled("#vcweb-form", false); } - if (model.roundType() === "REGULAR") { + if (model.templateName() === "REGULAR") { model.startRound() } } diff -r be61831f5354003e211ca1bec17819b94e61c97a -r 6853702867f4cdf88ca84e36c5372366c0437783 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -64,6 +64,7 @@ 'warningCountdownTime': 10, 'harvestDecision': 0, 'chatMessages': [], + 'instructionsRound': False, } # FIXME: need to distinguish between instructions / welcome rounds and practice/regular rounds def get_view_model_json(experiment, participant_group_relationship, **kwargs): @@ -76,12 +77,14 @@ # round / experiment configuration data experiment_model_dict['roundDuration'] = current_round.duration + experiment_model_dict['timeRemaining'] = experiment.time_remaining regrowth_rate = get_regrowth_rate(current_round) cost_of_living = get_cost_of_living(current_round) experiment_model_dict['costOfLiving'] = cost_of_living experiment_model_dict['maxHarvestDecision'] = get_max_allowed_harvest_decision(participant_group_relationship, current_round_data, ec) # instructions round parameters if current_round.is_instructions_round: + experiment_model_dict['instructionsRound'] = True experiment_model_dict['participantsPerGroup'] = ec.max_group_size experiment_model_dict['regrowthRate'] = regrowth_rate experiment_model_dict['initialResourceLevel'] = get_initial_resource_level(current_round) @@ -116,8 +119,8 @@ experiment_model_dict['submitted'] = harvest_decision.submitted if harvest_decision.submitted: # user has already submit a harvest decision this round - logger.debug("already submitted, setting harvest decision to %s", harvest_decision.int_value) experiment_model_dict['harvestDecision'] = harvest_decision.int_value + logger.debug("already submitted, setting harvest decision to %s", experiment_model_dict['harvestDecision']) experiment_model_dict['chatMessages'] = [{ 'pk': cm.pk, @@ -125,7 +128,6 @@ 'message': cm.string_value, 'date_created': cm.date_created.strftime("%I:%M:%S") } for cm in ChatMessage.objects.for_group(own_group)] - logger.debug("chat messages: %s", experiment_model_dict['chatMessages']) 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) @@ -143,5 +145,4 @@ # FIXME: defaults hard coded in for now experiment_model_dict['instructions'] = current_round.get_custom_instructions() - experiment_model_dict.update(**kwargs) return dumps(experiment_model_dict) diff -r be61831f5354003e211ca1bec17819b94e61c97a -r 6853702867f4cdf88ca84e36c5372366c0437783 vcweb/core/cron.py --- a/vcweb/core/cron.py +++ b/vcweb/core/cron.py @@ -3,6 +3,10 @@ from vcweb.core import signals from vcweb.core.services import fetch_foursquare_categories +@register('@minute') +def every_minute(): + signals.minute_tick.send(sender=None, time=datetime.now()) + @register('@hourly') def every_hour(): signals.hour_tick.send(sender=None, time=datetime.now()) diff -r be61831f5354003e211ca1bec17819b94e61c97a -r 6853702867f4cdf88ca84e36c5372366c0437783 vcweb/core/migrations/0002_auto__del_field_experiment_current_round_elapsed_time.py --- /dev/null +++ b/vcweb/core/migrations/0002_auto__del_field_experiment_current_round_elapsed_time.py @@ -0,0 +1,400 @@ +# -*- 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.current_round_elapsed_time' + db.delete_column(u'core_experiment', 'current_round_elapsed_time') + + + def backwards(self, orm): + # Adding field 'Experiment.current_round_elapsed_time' + db.add_column(u'core_experiment', 'current_round_elapsed_time', + 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_sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'current_round_start_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentConfiguration']"}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentMetadata']"}), + 'experimenter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experimenter']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'start_date_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'INACTIVE'", 'max_length': '32'}), + 'tick_duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'total_elapsed_time': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + }, + u'core.experimentactivitylog': { + 'Meta': {'object_name': 'ExperimentActivityLog', '_ormbases': [u'core.ActivityLog']}, + u'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': u"orm['core.Experiment']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.experimentconfiguration': { + 'Meta': {'ordering': "['experiment_metadata', 'creator', 'date_created']", 'object_name': 'ExperimentConfiguration'}, + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': u"orm['core.Experimenter']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'exchange_rate': ('django.db.models.fields.DecimalField', [], {'default': '0.2', 'null': 'True', 'max_digits': '6', 'decimal_places': '2', 'blank': 'True'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': u"orm['core.ExperimentMetadata']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation_subject': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'is_experimenter_driven': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'max_group_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), + 'max_number_of_participants': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'treatment_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}) + }, + u'core.experimenter': { + 'Meta': {'ordering': "['user']", 'object_name': 'Experimenter'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'authentication_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'failed_password_attempts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'institution': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Institution']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'experimenter'", 'unique': 'True', 'to': u"orm['auth.User']"}) + }, + u'core.experimenterrequest': { + 'Meta': {'object_name': 'ExperimenterRequest'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'}) + }, + u'core.experimentmetadata': { + 'Meta': {'ordering': "['namespace', 'date_created']", 'object_name': 'ExperimentMetadata'}, + 'about_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'default_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentConfiguration']", 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'namespace': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'short_name': ('django.db.models.fields.SlugField', [], {'max_length': '32', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'core.experimentparametervalue': { + 'Meta': {'object_name': 'ExperimentParameterValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_parameter_value_set'", 'to': u"orm['core.ExperimentConfiguration']"}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.experimentsession': { + 'Meta': {'object_name': 'ExperimentSession'}, + 'capacity': ('django.db.models.fields.PositiveIntegerField', [], {'default': '20'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_session_set'", 'to': u"orm['auth.User']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_session_set'", 'to': u"orm['core.ExperimentMetadata']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'scheduled_date': ('django.db.models.fields.DateTimeField', [], {}), + 'scheduled_end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.group': { + 'Meta': {'ordering': "['experiment', 'number']", 'object_name': 'Group'}, + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'max_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), + 'number': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.groupactivitylog': { + 'Meta': {'object_name': 'GroupActivityLog', '_ormbases': [u'core.ActivityLog']}, + u'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': u"orm['core.Group']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.groupcluster': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'GroupCluster'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_cluster_set'", 'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.groupclusterdatavalue': { + 'Meta': {'object_name': 'GroupClusterDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'group_cluster': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.GroupCluster']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'round_data': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_cluster_data_value_set'", 'to': u"orm['core.RoundData']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.grouprelationship': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'GroupRelationship'}, + 'cluster': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_relationship_set'", 'to': u"orm['core.GroupCluster']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'core.grouprounddatavalue': { + 'Meta': {'ordering': "['round_data', 'group', 'parameter']", 'object_name': 'GroupRoundDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'data_value_set'", 'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.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 diff -r be61831f5354003e211ca1bec17819b94e61c97a -r 6853702867f4cdf88ca84e36c5372366c0437783 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -274,17 +274,6 @@ return self.filter(status='COMPLETED', **kwargs) def active(self, **kwargs): return self.filter(status__in=('ACTIVE', 'ROUND_IN_PROGRESS'), **kwargs) - def increment_elapsed_time(self, status='ROUND_IN_PROGRESS', amount=60): - logger.debug("filtering on status %s", status) - if status is not None: - es = self.filter(status=status) - es.update(current_round_elapsed_time=models.F('current_round_elapsed_time') + amount, - total_elapsed_time=models.F('total_elapsed_time') + amount) - # check each experiment's total_elapsed_time against the total allotted time and - # issue round_stopped signals to experiments that need to be stopped. - for experiment in es.all(): - logger.debug("checking elapsed time on experiment %s", experiment) - experiment.check_elapsed_time() class Experiment(models.Model): """ @@ -336,8 +325,6 @@ started, incremented by the heartbeat monitor. """ current_round_start_time = models.DateTimeField(null=True, blank=True) - """ current round start time """ - current_round_elapsed_time = models.PositiveIntegerField(default=0) """ elapsed time in seconds for the current round. """ amqp_exchange_name = models.CharField(max_length=64, default="vcweb.default.exchange") @@ -359,8 +346,17 @@ return self.is_round_in_progress and self.current_round.is_playable_round @property + def current_round_elapsed_time(self): + if self.current_round_start_time: + return datetime.now() - self.current_round_start_time + return timedelta(0) + + @property def time_remaining(self): - return self.current_round.duration - self.current_round_elapsed_time + tr = self.current_round.duration - self.current_round_elapsed_time.seconds + if tr < 0: + return u"Expired %s seconds ago" % abs(tr) + return tr @property def is_timed_round(self): @@ -795,8 +791,10 @@ self.current_round_sequence_number = max(self.current_round_sequence_number - 1, 1) self.save() + ACCEPTABLE_ACTIONS = ('advance_to_next_round', 'end_round', 'start_round', 'move_to_previous_round', 'activate', + 'deactivate', 'complete', 'restart_round', 'restart') def invoke(self, action_name): - if action_name in ('advance_to_next_round', 'end_round', 'start_round', 'move_to_previous_round', 'activate', 'deactivate', 'complete'): + if action_name in Experiment.ACCEPTABLE_ACTIONS: getattr(self, action_name)() else: raise AttributeError("Invalid experiment action %s requested of experiment %s" % (action_name, self)) @@ -805,7 +803,6 @@ if self.is_round_in_progress: self.end_round() if self.has_next_round: - self.current_round_elapsed_time = 0 self.current_round_sequence_number += 1 self.start_round() else: @@ -827,7 +824,6 @@ logger.debug("%s STARTING ROUND (sender: %s)", self, sender) self.status = Experiment.Status.ROUND_IN_PROGRESS self.create_round_data() - self.current_round_elapsed_time = 0 self.current_round_start_time = datetime.now() self.save() self.log('Starting round') @@ -841,9 +837,11 @@ logger.debug("About to send round started signal with sender %s", sender) return signals.round_started.send_robust(sender, experiment=self, time=datetime.now(), round_configuration=current_round_configuration) + def stop_round(self, sender=None, **kwargs): + self.end_round() + def end_round(self, sender=None): self.status = Experiment.Status.ACTIVE - self.current_round_elapsed_time = max(self.current_round_elapsed_time, self.current_round.duration) self.save() self.log('Ending round with elapsed time %s' % self.current_round_elapsed_time) sender = intern(self.experiment_metadata.namespace.encode('utf8')) if sender is None else sender @@ -861,6 +859,17 @@ self.save() return self + def restart(self): + self.log("Restarting experiment entirely from the first round.") + self.deactivate() + self.current_round_sequence_number = 1 + self.activate() + self.start_round() + + def restart_round(self): + self.stop_round() + self.start_round() + def complete(self): self.log("Marking as COMPLETED") self.status = Experiment.Status.COMPLETED diff -r be61831f5354003e211ca1bec17819b94e61c97a -r 6853702867f4cdf88ca84e36c5372366c0437783 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -7,28 +7,34 @@ <h3>{{experiment}}</h3><div class='row-fluid'><div class='span6'> - <ul class='nav nav-list' data-bind="if: isActive"> - <li class='nav-header'>round management</li> - <li> + <div class='alert alert-white' data-bind='if: isActive'> + <h4>ROUND MANAGEMENT</h4><div class='btn-toolbar'><div class='btn-group'> - {% if DEBUG %} <a class='btn btn-success' data-bind="click: confirmExperimentControllerAction.bind($data, true)" data-action='move_to_previous_round' data-content='Go back to the previous round.'><i class='icon-step-backward'></i> back</a> - {% endif %} - <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="visible: isRoundInProgress, click: confirmExperimentControllerAction.bind($data, true)" data-action='end_round' data-content='Ends the round.'><i class='icon-stop'></i> end round</a> + <a class='btn btn-success' data-bind="visible: ! isRoundInProgress(), click: confirmExperimentControllerAction.bind($data, true)" 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-primary' 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='Updates this pagedata.' ><i class='icon-refresh'></i> refresh this page</a> + </div> + </div> + <div class='btn-toolbar'> + <div class='btn-group'> + <a class='btn btn-danger' data-bind="click: confirmExperimentControllerAction.bind($data, true)" + data-action='restart_round' data-content='Restart the round. This will reset timers and perform any additional round started setup logic.'> + <i class='icon-circle-arrow-left'></i> restart round</a> + <a class='btn btn-danger' data-bind="click: confirmExperimentControllerAction.bind($data, true)" + data-action='restart_round' data-content='Restart the round. This will reset timers and perform any additional round started setup logic.'> + <i class='icon-circle-arrow-up'></i> restart experiment</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> - </ul> - {% comment %} should offer different actions (start + reset) to experiments that has already been activated / started {% endcomment %} + </div><div data-bind='if: isArchived()'><div class='alert alert-success'><i class='icon-save'></i> This experiment has been archived. @@ -47,23 +53,49 @@ <h4>Inactive Experiment</h4><p> There are <span data-bind='text:participantCount' class='badge badge-info'></span> registered participants. - You can activate the experiment whenever you are ready to collect data. + Activate the experiment whenever you are ready to collect data. </p> - <p class='text-error'>NOTE: activating an experiment <b>will delete all existing data</b> + <p class='text-error'>NOTE: activating an experiment <b>deletes all existing data</b></p><a data-content='Starts this experiment, assigns participants to groups, etc.' class='btn btn-success' data-bind='click: confirmExperimentControllerAction.bind($data, false)' 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><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> - <li>Registered participants: <span data-bind='text:participantCount' class='badge badge-info'></span></li> - </ul> + <div class='well' style='padding-top: 5px; padding-bottom: 5px; margin-bottom: 0px;'> + <h5>ROUND STATUS</h5> + <div><b class='text-info' data-bind='text:roundSequenceLabel'></b></div> + <div><span data-bind='text:roundStatusLabel'></span></div> + <div>Round started on: <span data-bind='text:currentRoundStartTime'></span></div> + <div>Time remaining: <span data-bind='text:timeRemaining'></span></div> + </div> + <div class='accordion-group'> + <div class='accordion-heading'> + <a class='accordion-toggle' data-toggle='collapse' + data-parent='#registeredParticipantsAccordion' href='#registeredParticipants'> + Registered participants: <span id='participantCountId' data-bind='text:participantCount' class='badge badge-info'></span> + </a> + </div> + <div id='registeredParticipants' class='accordion-body collapse'> + <div class='accordion-inner'> + <table class='table table-compact table-striped table-bordered'> + <thead><tr><th>Group</th><th>PGR PK</th><th>Participant</th></tr></thead> + <tbody> + {% regroup registeredParticipants by group as group_list %} + {% for group in group_list %} + {% for item in group.list %} + <tr> + <td>{{ item.group }}</td> + <td>{{ item.participant_group_relationship.pk }}</td> + <td>{{ item.participant_group_relationship.participant.email }}, {{ item.participant_group_relationship.participant_handle}} </td> + </tr> + {% endfor %} + {% endfor %} + </tbody> + </table> + </div> + </div> + </div><div class='alert alert-message alert-block'><h4><i class='icon-download'></i> Download Data</h4><ul class='inline'> @@ -213,6 +245,12 @@ }, {pk: {{experiment.pk}}, 'action':action}); }); } + model.startOrStopExperimentAction = ko.computed(function() { + return model.isRoundInProgress() ? "stop_round" : "start_round"; + }); + model.startOrStopExperimentActionText = ko.computed(function() { + return model.isRoundInProgress() ? "stop" : "start"; + }); model.updateParticipants = function(m, evt) { confirmAction(evt.target, function(confirmed, action) { if (confirmed) { @@ -254,6 +292,8 @@ experimentModel.addMessage(jQuery.parseJSON(evt.data)); }; return experimentModel; + // FIXME: this won't quite work + // $('#participan... [truncated message content] |
From: <com...@bi...> - 2013-03-27 04:53:20
|
2 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/5cb16c9dbc4f/ Changeset: 5cb16c9dbc4f User: alllee Date: 2013-03-27 05:01:02 Summary: styling chat sidebar Affected #: 4 files diff -r 65cdbed51c4e01ece5079179a5a58fad5c27c07c -r 5cb16c9dbc4ff9758c1ac7cc88415442d4ac48b9 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -294,6 +294,7 @@ player_status_dv = get_player_status_dv(pgr, round_data) player_alive = player_status_dv.boolean_value if not player_alive: + logger.debug("Skipping deceased participant %s", pgr) continue harvest_decision = get_harvest_decision(pgr, round_data) storage_dv = get_storage_dv(pgr, round_data) diff -r 65cdbed51c4e01ece5079179a5a58fad5c27c07c -r 5cb16c9dbc4ff9758c1ac7cc88415442d4ac48b9 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -21,17 +21,16 @@ {% endblock content %} {% block sidebar %} -<h3>Chat</h3> -<div class='chat-sidebar well'> - <form id="chat-form" class='form-inline'> - <div class='input-prepend input-append'> - <span class='add-on'><i class='text-info icon-comment'></i></span> - <input class='chat-action input-block-level' id='chatText' type="text" placeholder="Enter a chat message"> - <button class='btn' data-bind='click: submitChatMessage'>Send</button> - </div> - </form> +<form id="chat-form" class='form-inline'> + <div class='input-prepend input-append'> + <span class='add-on'><i class='text-info icon-comment'></i></span> + <input id='chatMessage' type="text" placeholder="Enter a chat message"> + <button class='btn btn-primary' data-bind='click: submitChatMessage'>Send</button> + </div> +</form> +<div class='chat-sidebar'><div id='chat-div'> - <div data-bind='foreach: chatMessages'> + <div class='chat-messages' data-bind='foreach: chatMessages'><i class='icon-user muted'></i><strong>Participant <span data-bind='text: participant_number'></strong><b class='pull-right muted' data-bind='text: date_created'></b><p><small><i class='icon-double-angle-right'></i></small><span data-bind='text: message'></span> @@ -436,7 +435,6 @@ model.resourceImageHeight = ko.observable("79px"); model.startRound = function() { model.enableChat(); - model.setFormDisabled("#vcweb-form", true); model.secondsLeft(model.roundDuration()); model.setCurrentInterval( setInterval(function() { @@ -457,21 +455,24 @@ model.setFormDisabled("#vcweb-form", true); model.setFormDisabled("#chat-form", true); console.debug(formData); - $.post('submit-harvest-decision', formData, function(jsonString) { - console.log(jsonString); - //update($.parseJSON(jsonString.experimentModelJson)); - model.secondsLeft(0); + $.post('submit-harvest-decision', formData, function(response) { + console.log(response); + model.update($.parseJSON(response.experimentModelJson)); + // FIXME: forward the response message to the chat window should be handled completely on the server + // side instead of ping-ponging to the client side back to the real time server back out to all + // clients in this group + getWebSocket().send(createMessageEvent(response.message)); model.clearCurrentInterval(); }); } model.submitChatMessage = function(data, evt) { evt.preventDefault(); console.log("clicking chat message"); - var message = $('#chatText').val(); + var message = $('#chatMessage').val(); if (message) { - $('#chatText').val(''); + $('#chatMessage').val(''); getWebSocket().send(createMessageEvent(message)); - $('#chatText').focus(); + $('#chatMessage').focus(); } } model.update = function() { @@ -494,19 +495,21 @@ // $('#content').removeClass('span6').addClass('span9'); // $('#sidebar').removeClass('span6').addClass('span3'); model.setFormDisabled("#chat-form", true); - model.chatEnabled(false); } model.enableChat = function() { // $('#content').removeClass('span9').addClass('span6'); // $('#sidebar').removeClass('span3').addClass('span6'); + model.setFormDisabled("#vcweb-form", true); model.setFormDisabled("#chat-form", false); - model.chatEnabled(true); } model.afterRenderTemplate = function(elements) { - if (model.submitted()) { + if (model.submitted() || ! model.alive()) { model.setFormDisabled("#vcweb-form", true); model.setFormDisabled("#chat-form", true); } + else { + model.setFormDisabled("#vcweb-form", false); + } if (model.roundType() === "REGULAR") { model.startRound() } diff -r 65cdbed51c4e01ece5079179a5a58fad5c27c07c -r 5cb16c9dbc4ff9758c1ac7cc88415442d4ac48b9 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -40,7 +40,10 @@ pgr = get_object_or_404(ParticipantGroupRelationship, pk=participant_group_id) harvest_decision = form.cleaned_data['integer_decision'] set_harvest_decision(pgr, harvest_decision, experiment.current_round_data, submitted=True) - return JsonResponse(dumps({ 'success': True, 'experimentModelJson': get_view_model_json(experiment, pgr)})) + message = "harvested %s trees" % harvest_decision + experiment.log(message) + return JsonResponse(dumps({ 'success': True, 'experimentModelJson': get_view_model_json(experiment, pgr), + 'message': message})) else: logger.debug("form was invalid: %s", form) for field in form: @@ -64,6 +67,7 @@ 'warningCountdownTime': 10, 'maxHarvestDecision': 10, 'harvestDecision': 0, + 'chatMessages': [], } # FIXME: need to distinguish between instructions / welcome rounds and practice/regular rounds def get_view_model_json(experiment, participant_group_relationship, **kwargs): @@ -124,6 +128,7 @@ 'message': cm.string_value, 'date_created': cm.date_created.strftime("%I:%M:%S") } for cm in ChatMessage.objects.for_group(own_group)] + logger.debug("chat messages: %s", experiment_model_dict['chatMessages']) experiment_model_dict['canObserveOtherGroup'] = can_observe_other_group(current_round) if not current_round.is_practice_round and experiment_model_dict['canObserveOtherGroup']: gr = GroupRelationship.objects.select_related('cluster').get(group=own_group) diff -r 65cdbed51c4e01ece5079179a5a58fad5c27c07c -r 5cb16c9dbc4ff9758c1ac7cc88415442d4ac48b9 vcweb/static/css/boundaries/style.css --- a/vcweb/static/css/boundaries/style.css +++ b/vcweb/static/css/boundaries/style.css @@ -1,6 +1,19 @@ .chat-sidebar { - height: 600px; - padding: 10px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + padding: 0px 0px 0px 0px; + margin: 0px; + height: 520px; +} +.chat-messages { + padding: 5px; +} +#chat-div { + overflow: auto; + height: inherit; +} +#chatMessage { + width: auto; } .boundaries-status-dashboard p { padding-top: 15px; https://bitbucket.org/virtualcommons/vcweb/commits/be61831f5354/ Changeset: be61831f5354 User: alllee Date: 2013-03-27 05:53:02 Summary: switching to get_max_allowed_harvest_decision and using KO to render the select options instead of django Affected #: 3 files diff -r 5cb16c9dbc4ff9758c1ac7cc88415442d4ac48b9 -r be61831f5354003e211ca1bec17819b94e61c97a vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -90,8 +90,13 @@ return round_configuration.get_parameter_value(get_cost_of_living_parameter(), default=5).int_value -def get_max_harvest(experiment): - return experiment.experiment_configuration.get_parameter_value(parameter=get_max_harvest_decision_parameter(), default=10).int_value +def get_max_harvest_decision(experiment_configuration): + return experiment_configuration.get_parameter_value(parameter=get_max_harvest_decision_parameter(), default=10).int_value + +def get_max_allowed_harvest_decision(participant_group_relationship, round_data=None, experiment_configuration=None): + group = participant_group_relationship.group + resource_level = get_resource_level(group, round_data) + return min(get_max_harvest_decision(experiment_configuration), resource_level / group.size) ''' group data accessors ''' diff -r 5cb16c9dbc4ff9758c1ac7cc88415442d4ac48b9 -r be61831f5354003e211ca1bec17819b94e61c97a vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -21,6 +21,12 @@ {% endblock content %} {% block sidebar %} +<h3>Chat</h3> +<div data-bind='ifnot: chatEnabled'> + <div class='alert alert-info'> + <i class='icon-info-sign'></i> Chat is disabled until the next round begins. + </div> +</div><form id="chat-form" class='form-inline'><div class='input-prepend input-append'><span class='add-on'><i class='text-info icon-comment'></i></span> @@ -339,9 +345,9 @@ <input id='participantGroupId' type='hidden' name='participant_group_id' data-bind='value: participantGroupId'/><input id='harvestDecisionTextInput' type='hidden' name='integer_decision' data-bind='value: harvestDecision'><select id='harvestDecisionSelect' required="required" form="vcweb-form" data-bind='value: harvestDecision'> - {% for i in harvest_decision_choices %} - <option>{{i}}</option> - {% endfor %} + <!-- ko foreach: ko.utils.range(0, maxHarvestDecision()) --> + <option data-bind='value: $data, text: $data'></option> + <!-- /ko --></select></div> diff -r 5cb16c9dbc4ff9758c1ac7cc88415442d4ac48b9 -r be61831f5354003e211ca1bec17819b94e61c97a vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -5,7 +5,7 @@ from vcweb.core.http import JsonResponse from vcweb.core.models import (Experiment, ParticipantGroupRelationship, ChatMessage, GroupRelationship) from vcweb.boundaries.forms import SingleIntegerDecisionForm -from vcweb.boundaries.models import (get_experiment_metadata, get_regrowth_rate, get_max_harvest, +from vcweb.boundaries.models import (get_experiment_metadata, get_regrowth_rate, get_max_allowed_harvest_decision, get_cost_of_living, get_resource_level, get_initial_resource_level, get_total_storage, get_storage, get_last_harvest_decision, get_harvest_decision_dv, set_harvest_decision, can_observe_other_group, get_player_status) @@ -20,12 +20,9 @@ pgr = experiment.get_participant_group_relationship(participant) if experiment.experiment_metadata != get_experiment_metadata() or pgr.participant != request.user.participant: raise Http404 - -# FIXME: should limit harvest_decision_choices by min(max_harvest, resource_level / group.size) return render(request, 'boundaries/participate.html', { 'auth_token': participant.authentication_token, 'experiment': experiment, - 'harvest_decision_choices': range(get_max_harvest(experiment) + 1), 'participant_experiment_relationship': experiment.get_participant_experiment_relationship(participant), 'participant_group_relationship': pgr, 'experimentModelJson': get_view_model_json(experiment, pgr), @@ -65,7 +62,6 @@ 'maxEarnings': 20.00, 'maximumResourcesToDisplay': 20, 'warningCountdownTime': 10, - 'maxHarvestDecision': 10, 'harvestDecision': 0, 'chatMessages': [], } @@ -83,6 +79,7 @@ regrowth_rate = get_regrowth_rate(current_round) cost_of_living = get_cost_of_living(current_round) experiment_model_dict['costOfLiving'] = cost_of_living + experiment_model_dict['maxHarvestDecision'] = get_max_allowed_harvest_decision(participant_group_relationship, current_round_data, ec) # instructions round parameters if current_round.is_instructions_round: experiment_model_dict['participantsPerGroup'] = ec.max_group_size 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-27 01:53:02
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/65cdbed51c4e/ Changeset: 65cdbed51c4e User: alllee Date: 2013-03-27 02:52:41 Summary: adding chat interface back and providing defaults to experiment model dict Affected #: 4 files diff -r ad15bcef5e4f8ec53ac052b0cc5f752e9406f93d -r 65cdbed51c4e01ece5079179a5a58fad5c27c07c vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -21,13 +21,12 @@ {% endblock content %} {% block sidebar %} -<div data-bind='if: chatEnabled'><h3>Chat</h3><div class='chat-sidebar well'><form id="chat-form" class='form-inline'><div class='input-prepend input-append'><span class='add-on'><i class='text-info icon-comment'></i></span> - <input style='width: 100%;' class='chat-action' id='chatText' type="text" placeholder="Enter a chat message"> + <input class='chat-action input-block-level' id='chatText' type="text" placeholder="Enter a chat message"><button class='btn' data-bind='click: submitChatMessage'>Send</button></div></form> @@ -40,7 +39,6 @@ </div></div></div> -</div> {% endblock sidebar %} {% block javascript %} {{ block.super }} @@ -439,7 +437,7 @@ model.startRound = function() { model.enableChat(); model.setFormDisabled("#vcweb-form", true); - model.secondsLeft(60); + model.secondsLeft(model.roundDuration()); model.setCurrentInterval( setInterval(function() { model.tick(); @@ -509,6 +507,9 @@ model.setFormDisabled("#vcweb-form", true); model.setFormDisabled("#chat-form", true); } + if (model.roundType() === "REGULAR") { + model.startRound() + } } return model; } diff -r ad15bcef5e4f8ec53ac052b0cc5f752e9406f93d -r 65cdbed51c4e01ece5079179a5a58fad5c27c07c vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -55,6 +55,16 @@ logger.debug("getting view model for participant: %s", pgr) return JsonResponse(get_view_model_json(experiment, pgr)) +experiment_model_defaults = { + 'submitted': False, + 'chatEnabled': False, + 'resourceLevel': 0, + 'maxEarnings': 20.00, + 'maximumResourcesToDisplay': 20, + 'warningCountdownTime': 10, + 'maxHarvestDecision': 10, + 'harvestDecision': 0, + } # 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 @@ -62,10 +72,10 @@ 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['submitted'] = False + experiment_model_dict = experiment.to_dict(include_round_data=False, default_value_dict=experiment_model_defaults) # round / experiment configuration data + experiment_model_dict['roundDuration'] = current_round.duration regrowth_rate = get_regrowth_rate(current_round) cost_of_living = get_cost_of_living(current_round) experiment_model_dict['costOfLiving'] = cost_of_living @@ -74,15 +84,12 @@ 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['resourceLevel'] = 0 experiment_model_dict['totalNumberOfParticipants'] = experiment.participant_set.count() experiment_model_dict['participantNumber'] = participant_group_relationship.participant_number experiment_model_dict['participantGroupId'] = participant_group_relationship.pk 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 @@ -133,11 +140,6 @@ experiment_model_dict['groupData'] = group_data # FIXME: defaults hard coded in for now - experiment_model_dict['maxEarnings'] = 20.00 - experiment_model_dict['maximumResourcesToDisplay'] = 20 - experiment_model_dict['warningCountdownTime'] = 10 - experiment_model_dict['maxHarvestDecision'] = 10 - experiment_model_dict['hasSubmit'] = False experiment_model_dict['instructions'] = current_round.get_custom_instructions() experiment_model_dict.update(**kwargs) return dumps(experiment_model_dict) diff -r ad15bcef5e4f8ec53ac052b0cc5f752e9406f93d -r 65cdbed51c4e01ece5079179a5a58fad5c27c07c vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -893,7 +893,7 @@ }) return all_round_data - def to_dict(self, include_round_data=True, *args, **kwargs): + def to_dict(self, include_round_data=True, default_value_dict=None, attrs=None, *args, **kwargs): ec = self.experiment_configuration experiment_dict = { 'roundStatusLabel': self.status_label, @@ -912,6 +912,10 @@ 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 else '' + if default_value_dict: + experiment_dict.update(default_value_dict, **kwargs) + if attrs: + experiment_dict.update([(attr, getattr(self, attr, None)) for attr in attrs]) return experiment_dict def as_dict(self, *args, **kwargs): diff -r ad15bcef5e4f8ec53ac052b0cc5f752e9406f93d -r 65cdbed51c4e01ece5079179a5a58fad5c27c07c vcweb/static/css/boundaries/style.css --- a/vcweb/static/css/boundaries/style.css +++ b/vcweb/static/css/boundaries/style.css @@ -1,6 +1,6 @@ .chat-sidebar { height: 600px; - padding: 20px; + padding: 10px; } .boundaries-status-dashboard p { padding-top: 15px; 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-27 00:10:51
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/ad15bcef5e4f/ Changeset: ad15bcef5e4f User: alllee Date: 2013-03-27 01:10:31 Summary: updating boundaries participant interface a bit more, next up is to move on to chat / harvest timing Affected #: 3 files diff -r 8e7949599709276940715f12b8fddb02f7360ade -r ad15bcef5e4f8ec53ac052b0cc5f752e9406f93d vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -6,7 +6,7 @@ <link rel='stylesheet' href='{% static "css/boundaries/style.css" %}'/> {% endblock %} {% block content %} -<div data-bind='template: { name: templateName() }'> +<div data-bind='template: { name: templateName(), afterRender: afterRenderTemplate }'></div><div id='progress-modal' class='modal hide fade'><div class='model-header'> @@ -228,7 +228,7 @@ </script><script type='text/html' id='REGULAR'><div class='row'> - <div class='span4'> + <div class='span5'><h3>My Status</h3><div data-bind='if: isTimerRunning'><div class='alert alert-error'> @@ -236,17 +236,22 @@ <span data-bind='text: secondsLeft'></span>s </div></div> - <div class='alert alert-message'> - You harvested <strong class='text-success'><span data-bind='text:lastHarvestDecision'></span><i class='icon-leaf'></i></strong> trees last round. + <div class='row'> + <div class='alert boundaries-status-dashboard span2'> + <h4>Last harvest <i class='icon-info-sign' data-content="The number of trees you harvested last round."></i></h4> + <p> + <strong class='text-success'><span data-bind='text:lastHarvestDecision'></span><i class='icon-leaf'></i></strong> + </p></div> - <div class='alert alert-message'> - You have <strong class='text-success'><span data-bind='text: storage'></span><i class='icon-leaf'></i></strong> trees stored. + <div class='alert boundaries-status-dashboard span2'> + <h4>Storage <i class='icon-info-sign' data-bind='attr: {"data-content": "You need at least " + costOfLiving() + " trees to survive each round."}'></i></h4> + <p> + <strong data-bind='css: { "text-error": storage() < costOfLiving(), "text-success": storage() > costOfLiving()}'><span data-bind='text: storage'></span><i class='icon-leaf'></i></strong> + </p></div> - <div class='alert alert-error'> - <i class='icon-warning-sign'></i> You need at least <strong class='text-success'><span data-bind='text: costOfLiving'></span><i class='icon-leaf'></i></strong> trees to survive each round. </div></div> - <div class='span5'> + <div class='span4'><h3>Group Status</h3><table class='table table-bordered table-condensed'><thead> @@ -291,11 +296,11 @@ <div style='padding: 8px; margin: auto; border: solid 1px; background: url("{{STATIC_URL}}images/forestry/deforestation.jpg") no-repeat center; height: 282px; width:425px;'> </div> - <div class='alert alert-error'>There are no more resources to harvest. Please wait until the next round begins.</div> + <div class='alert alert-error'>There are no more trees to harvest. Please wait until the next round begins.</div></div><div data-bind='if: submitted'><div class='alert alert-error'> - You have submitted a decision to harvest <span class='badge badge-important' data-bind='text: harvestDecision'></span> resources. + You have already submitted a harvest decision for <span class='badge badge-success' data-bind='text: harvestDecision'></span> trees. </div></div> @@ -327,7 +332,7 @@ </div></div></div> -<br> +<h3>Harvest</h3><div data-bind='ifnot: isResourceEmpty'><form id='vcweb-form' action='' method='post' class='form-horizontal' > {% csrf_token %} @@ -476,6 +481,7 @@ console.debug("retrieved view model successfully"); console.debug(data); ko.mapping.fromJS(data, model); + model.afterRenderTemplate(); $('#progress-modal').modal('hide'); }); } @@ -498,16 +504,17 @@ model.setFormDisabled("#chat-form", false); model.chatEnabled(true); } + model.afterRenderTemplate = function(elements) { + if (model.submitted()) { + model.setFormDisabled("#vcweb-form", true); + model.setFormDisabled("#chat-form", true); + } + } return model; } function initialize(experimentModelJson) { var experimentModel = new ExperimentModel(experimentModelJson); ko.applyBindings(experimentModel); - if (experimentModel.submitted()) { - experimentModel.setFormDisabled("#vcweb-form", true); - experimentModel.setFormDisabled("#chat-form", true); - } - var s = connect(); s.onmessage = function(json) { console.debug(json); @@ -537,6 +544,7 @@ } var experimentModelJson = $.parseJSON("{{ experimentModelJson|escapejs }}"); initialize(experimentModelJson); + $('[data-content]').popover({placement: 'top', trigger: 'hover'}); }); </script> {% endblock %} diff -r 8e7949599709276940715f12b8fddb02f7360ade -r ad15bcef5e4f8ec53ac052b0cc5f752e9406f93d vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -63,6 +63,7 @@ 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['submitted'] = False # round / experiment configuration data regrowth_rate = get_regrowth_rate(current_round) diff -r 8e7949599709276940715f12b8fddb02f7360ade -r ad15bcef5e4f8ec53ac052b0cc5f752e9406f93d vcweb/static/css/boundaries/style.css --- a/vcweb/static/css/boundaries/style.css +++ b/vcweb/static/css/boundaries/style.css @@ -2,3 +2,14 @@ height: 600px; padding: 20px; } +.boundaries-status-dashboard p { + padding-top: 15px; + font-size: 2em; +} +.boundaries-status-dashboard h4 { + border-bottom: 1px solid #ccc; +} +.boundaries-status-dashboard { + height: 80px; + padding: 8px 8px 8px 8px; +} Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-26 22:31:45
|
3 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/27196b54d85c/ Changeset: 27196b54d85c User: alllee Date: 2013-03-26 23:21:47 Summary: adding migrate target to fabfile Affected #: 1 file diff -r c3e6e9c956a734fb1ebef8760a2dec9e44fd0238 -r 27196b54d85c928ffc073aa93be4f86bf7b8da73 fabfile.py --- a/fabfile.py +++ b/fabfile.py @@ -39,6 +39,9 @@ '%(python)s manage.py migrate' % env, ] +def migrate(): + local("{python} manage.py migrate".format(python=env.python), capture=False) + def psh(): local("{python} manage.py shell_plus".format(python=env.python), capture=False) https://bitbucket.org/virtualcommons/vcweb/commits/765ed0482bff/ Changeset: 765ed0482bff User: alllee Date: 2013-03-26 23:22:15 Summary: adding move_to_previous_round in DEBUG mode, might make it more widely available if needed Affected #: 2 files diff -r 27196b54d85c928ffc073aa93be4f86bf7b8da73 -r 765ed0482bffba1e5bc2c072a2e6752645010ed0 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -796,7 +796,7 @@ self.save() def invoke(self, action_name): - if action_name in ('advance_to_next_round', 'end_round', 'start_round', 'activate', 'deactivate', 'complete'): + if action_name in ('advance_to_next_round', 'end_round', 'start_round', 'move_to_previous_round', 'activate', 'deactivate', 'complete'): getattr(self, action_name)() else: raise AttributeError("Invalid experiment action %s requested of experiment %s" % (action_name, self)) diff -r 27196b54d85c928ffc073aa93be4f86bf7b8da73 -r 765ed0482bffba1e5bc2c072a2e6752645010ed0 vcweb/core/templates/experimenter/monitor.html --- a/vcweb/core/templates/experimenter/monitor.html +++ b/vcweb/core/templates/experimenter/monitor.html @@ -12,6 +12,9 @@ <li><div class='btn-toolbar'><div class='btn-group'> + {% if DEBUG %} + <a class='btn btn-success' data-bind="click: confirmExperimentControllerAction.bind($data, true)" data-action='move_to_previous_round' data-content='Go back to the previous round.'><i class='icon-step-backward'></i> back</a> + {% endif %} <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> https://bitbucket.org/virtualcommons/vcweb/commits/8e7949599709/ Changeset: 8e7949599709 User: alllee Date: 2013-03-26 23:31:28 Summary: adding survival cost to status display Affected #: 1 file diff -r 765ed0482bffba1e5bc2c072a2e6752645010ed0 -r 8e7949599709276940715f12b8fddb02f7360ade vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -240,7 +240,10 @@ You harvested <strong class='text-success'><span data-bind='text:lastHarvestDecision'></span><i class='icon-leaf'></i></strong> trees last round. </div><div class='alert alert-message'> - You have <strong class='text-success'><span data-bind='text: storage'></span><i class='icon-leaf'></i></strong> trees stored. + You have <strong class='text-success'><span data-bind='text: storage'></span><i class='icon-leaf'></i></strong> trees stored. + </div> + <div class='alert alert-error'> + <i class='icon-warning-sign'></i> You need at least <strong class='text-success'><span data-bind='text: costOfLiving'></span><i class='icon-leaf'></i></strong> trees to survive each round. </div></div><div class='span5'> Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-26 22:08:53
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/c3e6e9c956a7/ Changeset: c3e6e9c956a7 User: dieg...@gmail.com Date: 2013-03-26 23:08:23 Summary: accidentally committed conflicted migration Affected #: 1 file diff -r 5d4558cd408b897968aea2dca076e8427cf0673d -r c3e6e9c956a734fb1ebef8760a2dec9e44fd0238 vcweb/broker/migrations/0003_add_broker_parameters_payoff.py --- a/vcweb/broker/migrations/0003_add_broker_parameters_payoff.py +++ b/vcweb/broker/migrations/0003_add_broker_parameters_payoff.py @@ -13,40 +13,18 @@ Parameter = orm['core.Parameter'] experimenter = Experimenter.objects.get(pk=1) Parameter.objects.create( -<<<<<<< local name='payoff', -======= - name='participant_payoff', ->>>>>>> other scope='participant', -<<<<<<< local type='float', description='earning each participant gets at each round', -======= - type='int', - description='the earning each participant gets at each round', ->>>>>>> other creator=experimenter) -<<<<<<< local -======= ->>>>>>> other def backwards(self, orm): "Write your backwards methods here." Parameter = orm['core.Parameter'] -<<<<<<< local Parameter.objects.get(name='payoff').delete() -======= - Parameter.objects.get(name='conservation_decision').delete() - Parameter.objects.get(name='max_hours').delete() - Parameter.objects.get(name='group_local_bonus').delete() - Parameter.objects.get(name='group_cluster_bonus').delete() - Parameter.objects.get(name='participant_link').delete() - Parameter.objects.get(name='group_local_bonus_threshold').delete() - Parameter.objects.get(name='group_cluster_bonus_threshold').delete() ->>>>>>> other models = { u'auth.group': { Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-26 22:07:00
|
3 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/50e1649421eb/ Changeset: 50e1649421eb User: dieg...@gmail.com Date: 2013-03-26 22:57:45 Summary: adding payoff participant parameter and refining round_ended method to calculate and assign participant payoffs Affected #: 2 files diff -r 3ae6b5d1ea094304cc9b7c9b099d4ace25c8c092 -r 50e1649421eb08645e1caf5fe3de267828b123e1 vcweb/broker/migrations/0003_add_broker_parameters_payoff.py --- /dev/null +++ b/vcweb/broker/migrations/0003_add_broker_parameters_payoff.py @@ -0,0 +1,409 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + + def forwards(self, orm): + "Write your forwards methods here." + # Note: Remember to use orm['appname.ModelName'] rather than "from appname.models..." + Experimenter = orm['core.Experimenter'] + Parameter = orm['core.Parameter'] + experimenter = Experimenter.objects.get(pk=1) + Parameter.objects.create( + name='payoff', + scope='participant', + type='float', + description='earning each participant gets at each round', + creator=experimenter) + + + def backwards(self, orm): + "Write your backwards methods here." + Parameter = orm['core.Parameter'] + Parameter.objects.get(name='payoff').delete() + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'core.activitylog': { + 'Meta': {'object_name': 'ActivityLog'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'log_message': ('django.db.models.fields.TextField', [], {}) + }, + u'core.address': { + 'Meta': {'object_name': 'Address'}, + 'city': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'state': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), + 'street1': ('django.db.models.fields.CharField', [], {'max_length': '256'}), + 'street2': ('django.db.models.fields.CharField', [], {'max_length': '256'}), + 'zipcode': ('django.db.models.fields.CharField', [], {'max_length': '8', 'blank': 'True'}) + }, + u'core.chatmessage': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'ChatMessage', '_ormbases': [u'core.ParticipantRoundDataValue']}, + u'participantrounddatavalue_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ParticipantRoundDataValue']", 'unique': 'True', 'primary_key': 'True'}), + 'target_participant': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'target_participant_chat_message_set'", 'null': 'True', 'to': u"orm['core.ParticipantGroupRelationship']"}) + }, + u'core.comment': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'Comment', '_ormbases': [u'core.ParticipantRoundDataValue']}, + u'participantrounddatavalue_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ParticipantRoundDataValue']", 'unique': 'True', 'primary_key': 'True'}) + }, + u'core.experiment': { + 'Meta': {'ordering': "['date_created', 'status']", 'object_name': 'Experiment'}, + 'amqp_exchange_name': ('django.db.models.fields.CharField', [], {'default': "'vcweb.default.exchange'", 'max_length': '64'}), + 'authentication_code': ('django.db.models.fields.CharField', [], {'default': "'vcweb.auth.code'", 'max_length': '32'}), + 'current_repeated_round_sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'current_round_elapsed_time': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'current_round_sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'current_round_start_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentConfiguration']"}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentMetadata']"}), + 'experimenter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experimenter']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'start_date_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'INACTIVE'", 'max_length': '32'}), + 'tick_duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'total_elapsed_time': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + }, + u'core.experimentactivitylog': { + 'Meta': {'object_name': 'ExperimentActivityLog', '_ormbases': [u'core.ActivityLog']}, + u'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': u"orm['core.Experiment']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.experimentconfiguration': { + 'Meta': {'ordering': "['experiment_metadata', 'creator', 'date_created']", 'object_name': 'ExperimentConfiguration'}, + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': u"orm['core.Experimenter']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'exchange_rate': ('django.db.models.fields.DecimalField', [], {'default': '0.2', 'null': 'True', 'max_digits': '6', 'decimal_places': '2', 'blank': 'True'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': u"orm['core.ExperimentMetadata']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation_subject': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'is_experimenter_driven': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'max_group_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), + 'max_number_of_participants': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'treatment_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}) + }, + u'core.experimenter': { + 'Meta': {'ordering': "['user']", 'object_name': 'Experimenter'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'authentication_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'failed_password_attempts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'institution': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Institution']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'experimenter'", 'unique': 'True', 'to': u"orm['auth.User']"}) + }, + u'core.experimenterrequest': { + 'Meta': {'object_name': 'ExperimenterRequest'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'}) + }, + u'core.experimentmetadata': { + 'Meta': {'ordering': "['namespace', 'date_created']", 'object_name': 'ExperimentMetadata'}, + 'about_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'default_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentConfiguration']", 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'namespace': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'short_name': ('django.db.models.fields.SlugField', [], {'max_length': '32', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'core.experimentparametervalue': { + 'Meta': {'object_name': 'ExperimentParameterValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_parameter_value_set'", 'to': u"orm['core.ExperimentConfiguration']"}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.experimentsession': { + 'Meta': {'object_name': 'ExperimentSession'}, + 'capacity': ('django.db.models.fields.PositiveIntegerField', [], {'default': '20'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_session_set'", 'to': u"orm['auth.User']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_session_set'", 'to': u"orm['core.ExperimentMetadata']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'scheduled_date': ('django.db.models.fields.DateTimeField', [], {}), + 'scheduled_end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.group': { + 'Meta': {'ordering': "['experiment', 'number']", 'object_name': 'Group'}, + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'max_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), + 'number': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.groupactivitylog': { + 'Meta': {'object_name': 'GroupActivityLog', '_ormbases': [u'core.ActivityLog']}, + u'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': u"orm['core.Group']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.groupcluster': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'GroupCluster'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'max_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.groupclusterdatavalue': { + 'Meta': {'object_name': 'GroupClusterDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'group_cluster': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.GroupCluster']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'round_data': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_cluster_data_value_set'", 'to': u"orm['core.RoundData']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.grouprelationship': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'GroupRelationship'}, + 'cluster': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_set'", 'to': u"orm['core.GroupCluster']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'core.grouprounddatavalue': { + 'Meta': {'ordering': "['round_data', 'group', 'parameter']", 'object_name': 'GroupRoundDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'data_value_set'", 'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'round_data': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_data_value_set'", 'to': u"orm['core.RoundData']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.institution': { + 'Meta': {'object_name': 'Institution'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}) + }, + u'core.invitation': { + 'Meta': {'object_name': 'Invitation'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment_session': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentSession']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'participant': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Participant']"}), + 'sender': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + }, + u'core.like': { + 'Meta': {'ordering': "['-date_created', 'round_data', 'participant_group_relationship', 'parameter']", 'object_name': 'Like', '_ormbases': [u'core.ParticipantRoundDataValue']}, + u'participantrounddatavalue_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ParticipantRoundDataValue']", 'unique': 'True', 'primary_key': 'True'}) + }, + u'core.parameter': { + 'Meta': {'ordering': "['name']", 'unique_together': "(('name', 'experiment_metadata', 'scope'),)", 'object_name': 'Parameter'}, + 'class_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experimenter']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'default_value_string': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '512', 'null': 'True', 'blank': 'True'}), + 'display_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'enum_choices': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentMetadata']", 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_required': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'scope': ('django.db.models.fields.CharField', [], {'default': "'round'", 'max_length': '32'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + u'core.participant': { + 'Meta': {'ordering': "['user']", 'object_name': 'Participant'}, + 'address': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Address']", 'null': 'True', 'blank': 'True'}), + 'authentication_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'birthdate': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'can_receive_invitations': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'experiments': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'participant_set'", 'symmetrical': 'False', 'through': u"orm['core.ParticipantExperimentRelationship']", 'to': u"orm['core.Experiment']"}), + 'failed_password_attempts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'gender': ('django.db.models.fields.CharField', [], {'max_length': '1', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'participant_set'", 'symmetrical': 'False', 'through': u"orm['core.ParticipantGroupRelationship']", 'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'institution': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Institution']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'participant'", 'unique': 'True', 'to': u"orm['auth.User']"}) + }, + u'core.participantexperimentrelationship': { + 'Meta': {'object_name': 'ParticipantExperimentRelationship'}, + 'additional_data': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'current_location': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_relationship_set'", 'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_completed_round_sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'participant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_relationship_set'", 'to': u"orm['core.Participant']"}), + 'participant_identifier': ('django.db.models.fields.CharField', [], {'max_length': '32'}), + 'sequential_participant_identifier': ('django.db.models.fields.PositiveIntegerField', [], {}) + }, + u'core.participantgrouprelationship': { + 'Meta': {'ordering': "['group', 'participant_number']", 'object_name': 'ParticipantGroupRelationship'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'first_visit': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_group_relationship_set'", 'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'notifications_since': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'null': 'True', 'blank': 'True'}), + 'participant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_group_relationship_set'", 'to': u"orm['core.Participant']"}), + 'participant_number': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'round_joined': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.participantrounddatavalue': { + 'Meta': {'ordering': "['-date_created', 'round_data', 'participant_group_relationship', 'parameter']", 'object_name': 'ParticipantRoundDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'participant_group_relationship': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_data_value_set'", 'to': u"orm['core.ParticipantGroupRelationship']"}), + 'round_data': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'participant_data_value_set'", 'to': u"orm['core.RoundData']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'submitted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'target_data_value': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'target_data_value_set'", 'null': 'True', 'to': u"orm['core.ParticipantRoundDataValue']"}) + }, + u'core.participantsignup': { + 'Meta': {'object_name': 'ParticipantSignup'}, + 'attendance': ('django.db.models.fields.PositiveIntegerField', [], {'max_length': '1', 'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'signup_set'", 'to': u"orm['core.Invitation']"}), + 'participant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'signup_set'", 'to': u"orm['core.Participant']"}) + }, + u'core.quizquestion': { + 'Meta': {'object_name': 'QuizQuestion'}, + 'answer': ('django.db.models.fields.CharField', [], {'max_length': '64'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'default_quiz_question_set'", 'null': 'True', 'to': u"orm['core.Experiment']"}), + 'explanation': ('django.db.models.fields.CharField', [], {'max_length': '512'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'input_type': ('django.db.models.fields.CharField', [], {'max_length': '32'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '512'}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'quiz_question_set'", 'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.roundconfiguration': { + 'Meta': {'ordering': "['experiment_configuration', 'sequence_number', 'date_created']", 'object_name': 'RoundConfiguration'}, + 'chat_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'create_group_clusters': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'debriefing': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'display_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'duration': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_configuration_set'", 'to': u"orm['core.ExperimentConfiguration']"}), + 'group_cluster_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '2'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'instructions': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'preserve_existing_groups': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'randomize_groups': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'repeat': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'round_type': ('django.db.models.fields.CharField', [], {'default': "'REGULAR'", 'max_length': '32'}), + 'sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'survey_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'template_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.rounddata': { + 'Meta': {'ordering': "['round_configuration']", 'unique_together': "(('round_configuration', 'experiment'),)", 'object_name': 'RoundData'}, + 'elapsed_time': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_data_set'", 'to': u"orm['core.Experiment']"}), + 'experimenter_notes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_data_set'", 'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.roundparametervalue': { + 'Meta': {'object_name': 'RoundParameterValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'round_parameter_value_set'", 'to': u"orm['core.RoundConfiguration']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.spoolparticipantstatistics': { + 'Meta': {'object_name': 'SpoolParticipantStatistics'}, + 'absences': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'discharges': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitations': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'participant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'spool_statistics_set'", 'to': u"orm['core.Participant']"}), + 'participations': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + } + } + + complete_apps = ['core', 'broker'] + symmetrical = True diff -r 3ae6b5d1ea094304cc9b7c9b099d4ace25c8c092 -r 50e1649421eb08645e1caf5fe3de267828b123e1 vcweb/broker/models.py --- a/vcweb/broker/models.py +++ b/vcweb/broker/models.py @@ -21,6 +21,11 @@ def get_conservation_decision_parameter(): return Parameter.objects.get(name='conservation_decision') +@simplecache +def get_payoff_parameter(): + return Parameter.objects.get(name='payoff') + + ''' group round parameters ''' @simplecache def get_group_local_bonus_parameter(): @@ -73,6 +78,25 @@ participant_parameters=[get_harvest_decision_parameter(), get_conservation_decision_parameter(), get_participant_link_parameter()] ) + +def calculate_group_local_bonus(group_conservation_hours, local_threshold): + if group_conservation_hours > local_threshold: + return () + else: + return () + +def calculate_group_local_bonus(group_conservation_hours, local_threshold): + if group_conservation_hours > local_threshold: + return (1.5) + else: + return (1) + +def calculate_group_cluster_bonus(group_conservation_hours, local_threshold): + if group_conservation_hours > local_threshold: + return (2) + else: + return (1) + @receiver(signals.round_ended, sender=EXPERIMENT_METADATA_NAME) def round_ended_handler(sender, experiment=None, **kwargs): ''' @@ -80,8 +104,11 @@ also responsible for transferring those parameters to the next round as needed. ''' current_round_configuration = experiment.current_round - logger.debug("ending boundaries round: %s", current_round_configuration) + logger.debug("ending broker round: %s", current_round_configuration) round_data = experiment.current_round_data + group_local_bonus_dict = {} + group_cluster_bonus_dict = {} + participant_conservation_dict = {} if current_round_configuration.is_playable_round: local_threshold = get_group_local_bonus_threshold(current_round_configuration) group_cluster_threshold = get_group_cluster_bonus_threshold(current_round_configuration) @@ -92,11 +119,24 @@ group = group_relationship.group for pgr in group.participant_group_relationship_set.all(): conservation_hours = get_conservation_decision(pgr, round_data=round_data) + participant_conservation_dict[pgr] = conservation_hours group_conservation_hours += conservation_hours - # calculate local group conservation bonus - local_bonus = calculate_group_local_bonus(group_conservation_hours, local_threshold) + local_bonus = calculate_group_local_bonus(group_conservation_hours, get_group_local_bonus_parameter()) + group_local_bonus_dict[group] = local_bonus group.set_data_value(parameter=get_group_local_bonus_parameter(), value=local_bonus) + group_cluster_conservation_hours += group_conservation_hours group_cluster_bonus = calculate_group_cluster_bonus(group_cluster_conservation_hours, group_cluster_threshold) + group_cluster_bonus_dict[group_cluster] = group_cluster_bonus group_cluster.set_data_value(parameter=get_group_cluster_bonus_parameter(), value=group_cluster_bonus) + ## needs revision: + for group_cluster in GroupCluster.objects.for_experiment(experiment): + for group_relationship in group_cluster.group_relationship_set.all(): + group = group_relationship.group + for pgr in group.participant_group_relationship_set.all(): + payoff = (participant_conservation_dict[pgr] * group_local_bonus_dict[group]) + \ + (get_harvest_decision(pgr, round_data) * group_cluster_bonus_dict[group_cluster]) + pgr.set_data_value(parameter=get_payoff_parameter(), round_data=round_data, value=payoff) + + https://bitbucket.org/virtualcommons/vcweb/commits/e2e82017e08d/ Changeset: e2e82017e08d User: dieg...@gmail.com Date: 2013-03-26 05:34:39 Summary: calculating cluster and group bonus, calculating payoff and recording. Creating the parameter participant_payoff Affected #: 2 files diff -r 50e1649421eb08645e1caf5fe3de267828b123e1 -r e2e82017e08d9271aaa1adda8b217eb64ac6abf5 vcweb/broker/migrations/0003_add_broker_parameters_payoff.py --- a/vcweb/broker/migrations/0003_add_broker_parameters_payoff.py +++ b/vcweb/broker/migrations/0003_add_broker_parameters_payoff.py @@ -13,17 +13,40 @@ Parameter = orm['core.Parameter'] experimenter = Experimenter.objects.get(pk=1) Parameter.objects.create( +<<<<<<< local name='payoff', +======= + name='participant_payoff', +>>>>>>> other scope='participant', +<<<<<<< local type='float', description='earning each participant gets at each round', +======= + type='int', + description='the earning each participant gets at each round', +>>>>>>> other creator=experimenter) +<<<<<<< local +======= + +>>>>>>> other def backwards(self, orm): "Write your backwards methods here." Parameter = orm['core.Parameter'] +<<<<<<< local Parameter.objects.get(name='payoff').delete() +======= + Parameter.objects.get(name='conservation_decision').delete() + Parameter.objects.get(name='max_hours').delete() + Parameter.objects.get(name='group_local_bonus').delete() + Parameter.objects.get(name='group_cluster_bonus').delete() + Parameter.objects.get(name='participant_link').delete() + Parameter.objects.get(name='group_local_bonus_threshold').delete() + Parameter.objects.get(name='group_cluster_bonus_threshold').delete() +>>>>>>> other models = { u'auth.group': { diff -r 50e1649421eb08645e1caf5fe3de267828b123e1 -r e2e82017e08d9271aaa1adda8b217eb64ac6abf5 vcweb/broker/models.py --- a/vcweb/broker/models.py +++ b/vcweb/broker/models.py @@ -18,6 +18,11 @@ return Parameter.objects.get(name='participant_link') @simplecache +def get_participant_payoff_parameter(): + return Parameter.objects.get(name='participant_payoff') + + +@simplecache def get_conservation_decision_parameter(): return Parameter.objects.get(name='conservation_decision') @@ -25,7 +30,6 @@ def get_payoff_parameter(): return Parameter.objects.get(name='payoff') - ''' group round parameters ''' @simplecache def get_group_local_bonus_parameter(): @@ -75,7 +79,7 @@ experiment.initialize_data_values( group_cluster_parameters=(get_group_cluster_bonus_parameter(),), group_parameters=(get_group_local_bonus_parameter(),), - participant_parameters=[get_harvest_decision_parameter(), get_conservation_decision_parameter(), get_participant_link_parameter()] + participant_parameters=[get_harvest_decision_parameter(), get_conservation_decision_parameter(), get_participant_link_parameter(), get_participant_payoff_parameter()] ) @@ -138,5 +142,3 @@ payoff = (participant_conservation_dict[pgr] * group_local_bonus_dict[group]) + \ (get_harvest_decision(pgr, round_data) * group_cluster_bonus_dict[group_cluster]) pgr.set_data_value(parameter=get_payoff_parameter(), round_data=round_data, value=payoff) - - https://bitbucket.org/virtualcommons/vcweb/commits/5d4558cd408b/ Changeset: 5d4558cd408b User: dieg...@gmail.com Date: 2013-03-26 23:04:35 Summary: fixing local bonus calculations and adding round_data to get data value calls Affected #: 1 file diff -r e2e82017e08d9271aaa1adda8b217eb64ac6abf5 -r 5d4558cd408b897968aea2dca076e8427cf0673d vcweb/broker/models.py --- a/vcweb/broker/models.py +++ b/vcweb/broker/models.py @@ -82,24 +82,17 @@ participant_parameters=[get_harvest_decision_parameter(), get_conservation_decision_parameter(), get_participant_link_parameter(), get_participant_payoff_parameter()] ) - def calculate_group_local_bonus(group_conservation_hours, local_threshold): if group_conservation_hours > local_threshold: - return () + return 1.5 else: - return () - -def calculate_group_local_bonus(group_conservation_hours, local_threshold): - if group_conservation_hours > local_threshold: - return (1.5) - else: - return (1) + return 1 def calculate_group_cluster_bonus(group_conservation_hours, local_threshold): if group_conservation_hours > local_threshold: - return (2) + return 2 else: - return (1) + return 1 @receiver(signals.round_ended, sender=EXPERIMENT_METADATA_NAME) def round_ended_handler(sender, experiment=None, **kwargs): @@ -125,15 +118,14 @@ conservation_hours = get_conservation_decision(pgr, round_data=round_data) participant_conservation_dict[pgr] = conservation_hours group_conservation_hours += conservation_hours - local_bonus = calculate_group_local_bonus(group_conservation_hours, get_group_local_bonus_parameter()) + local_bonus = calculate_group_local_bonus(group_conservation_hours, local_threshold) group_local_bonus_dict[group] = local_bonus - group.set_data_value(parameter=get_group_local_bonus_parameter(), value=local_bonus) + group.set_data_value(parameter=get_group_local_bonus_parameter(), round_data=round_data, value=local_bonus) group_cluster_conservation_hours += group_conservation_hours - group_cluster_bonus = calculate_group_cluster_bonus(group_cluster_conservation_hours, - group_cluster_threshold) + group_cluster_bonus = calculate_group_cluster_bonus(group_cluster_conservation_hours, group_cluster_threshold) group_cluster_bonus_dict[group_cluster] = group_cluster_bonus - group_cluster.set_data_value(parameter=get_group_cluster_bonus_parameter(), value=group_cluster_bonus) + group_cluster.set_data_value(parameter=get_group_cluster_bonus_parameter(), round_data=round_data, value=group_cluster_bonus) ## needs revision: for group_cluster in GroupCluster.objects.for_experiment(experiment): for group_relationship in group_cluster.group_relationship_set.all(): Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-26 21:18:27
|
2 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/bc1c86438575/ Changeset: bc1c86438575 User: alllee Date: 2013-03-26 22:02:06 Summary: converting harvest decision submission type from input type=number to select box Affected #: 8 files diff -r 53c6141a5e6c9752fa67a99b25206bb31e9353ae -r bc1c86438575b002b76db8cc7312b5f3fdfc6419 vcweb/boundaries/migrations/0001_initial.py --- /dev/null +++ b/vcweb/boundaries/migrations/0001_initial.py @@ -0,0 +1,21 @@ +# -*- 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): + from django.core.management import call_command + call_command("loaddata", "boundaries_experiment_metadata.json") + + def backwards(self, orm): + pass + + models = { + + } + + complete_apps = ['boundaries'] diff -r 53c6141a5e6c9752fa67a99b25206bb31e9353ae -r bc1c86438575b002b76db8cc7312b5f3fdfc6419 vcweb/boundaries/migrations/0002_max_harvest_decision.py --- /dev/null +++ b/vcweb/boundaries/migrations/0002_max_harvest_decision.py @@ -0,0 +1,405 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + + def forwards(self, orm): + "Write your forwards methods here." + # Note: Remember to use orm['appname.ModelName'] rather than "from appname.models..." + Parameter = orm['core.Parameter'] + Experimenter = orm['core.Experimenter'] + Parameter.objects.create(name='max_harvest_decision', + creator=Experimenter.objects.get(pk=1), + type='int', + scope='experiment', + default_value_string='10', + description='Maximum harvest decision a player can make in a typical harvesting experiment') + + + def backwards(self, orm): + "Write your backwards methods here." + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'core.activitylog': { + 'Meta': {'object_name': 'ActivityLog'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'log_message': ('django.db.models.fields.TextField', [], {}) + }, + u'core.address': { + 'Meta': {'object_name': 'Address'}, + 'city': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'state': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}), + 'street1': ('django.db.models.fields.CharField', [], {'max_length': '256'}), + 'street2': ('django.db.models.fields.CharField', [], {'max_length': '256'}), + 'zipcode': ('django.db.models.fields.CharField', [], {'max_length': '8', 'blank': 'True'}) + }, + u'core.chatmessage': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'ChatMessage', '_ormbases': [u'core.ParticipantRoundDataValue']}, + u'participantrounddatavalue_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ParticipantRoundDataValue']", 'unique': 'True', 'primary_key': 'True'}), + 'target_participant': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'target_participant_chat_message_set'", 'null': 'True', 'to': u"orm['core.ParticipantGroupRelationship']"}) + }, + u'core.comment': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'Comment', '_ormbases': [u'core.ParticipantRoundDataValue']}, + u'participantrounddatavalue_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ParticipantRoundDataValue']", 'unique': 'True', 'primary_key': 'True'}) + }, + u'core.experiment': { + 'Meta': {'ordering': "['date_created', 'status']", 'object_name': 'Experiment'}, + 'amqp_exchange_name': ('django.db.models.fields.CharField', [], {'default': "'vcweb.default.exchange'", 'max_length': '64'}), + 'authentication_code': ('django.db.models.fields.CharField', [], {'default': "'vcweb.auth.code'", 'max_length': '32'}), + 'current_repeated_round_sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'current_round_elapsed_time': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'current_round_sequence_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'current_round_start_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentConfiguration']"}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentMetadata']"}), + 'experimenter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experimenter']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'start_date_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'INACTIVE'", 'max_length': '32'}), + 'tick_duration': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'total_elapsed_time': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + }, + u'core.experimentactivitylog': { + 'Meta': {'object_name': 'ExperimentActivityLog', '_ormbases': [u'core.ActivityLog']}, + u'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': u"orm['core.Experiment']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.experimentconfiguration': { + 'Meta': {'ordering': "['experiment_metadata', 'creator', 'date_created']", 'object_name': 'ExperimentConfiguration'}, + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': u"orm['core.Experimenter']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'exchange_rate': ('django.db.models.fields.DecimalField', [], {'default': '0.2', 'null': 'True', 'max_digits': '6', 'decimal_places': '2', 'blank': 'True'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_configuration_set'", 'to': u"orm['core.ExperimentMetadata']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation_subject': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'is_experimenter_driven': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'max_group_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), + 'max_number_of_participants': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'treatment_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}) + }, + u'core.experimenter': { + 'Meta': {'ordering': "['user']", 'object_name': 'Experimenter'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'authentication_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'failed_password_attempts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'institution': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Institution']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'experimenter'", 'unique': 'True', 'to': u"orm['auth.User']"}) + }, + u'core.experimenterrequest': { + 'Meta': {'object_name': 'ExperimenterRequest'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'}) + }, + u'core.experimentmetadata': { + 'Meta': {'ordering': "['namespace', 'date_created']", 'object_name': 'ExperimentMetadata'}, + 'about_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'default_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.ExperimentConfiguration']", 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'namespace': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'short_name': ('django.db.models.fields.SlugField', [], {'max_length': '32', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'core.experimentparametervalue': { + 'Meta': {'object_name': 'ExperimentParameterValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'experiment_configuration': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_parameter_value_set'", 'to': u"orm['core.ExperimentConfiguration']"}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.experimentsession': { + 'Meta': {'object_name': 'ExperimentSession'}, + 'capacity': ('django.db.models.fields.PositiveIntegerField', [], {'default': '20'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_session_set'", 'to': u"orm['auth.User']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment_metadata': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'experiment_session_set'", 'to': u"orm['core.ExperimentMetadata']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invitation_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'scheduled_date': ('django.db.models.fields.DateTimeField', [], {}), + 'scheduled_end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.group': { + 'Meta': {'ordering': "['experiment', 'number']", 'object_name': 'Group'}, + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'max_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5'}), + 'number': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.groupactivitylog': { + 'Meta': {'object_name': 'GroupActivityLog', '_ormbases': [u'core.ActivityLog']}, + u'activitylog_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['core.ActivityLog']", 'unique': 'True', 'primary_key': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log_set'", 'to': u"orm['core.Group']"}), + 'round_configuration': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.RoundConfiguration']"}) + }, + u'core.groupcluster': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'GroupCluster'}, + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'experiment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_cluster_set'", 'to': u"orm['core.Experiment']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}), + 'session_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}) + }, + u'core.groupclusterdatavalue': { + 'Meta': {'object_name': 'GroupClusterDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'group_cluster': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.GroupCluster']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.models.AutoDateTimeField', [], {'default': 'datetime.datetime.now'}), + 'parameter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Parameter']"}), + 'round_data': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_cluster_data_value_set'", 'to': u"orm['core.RoundData']"}), + 'string_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + u'core.grouprelationship': { + 'Meta': {'ordering': "['date_created']", 'object_name': 'GroupRelationship'}, + 'cluster': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_relationship_set'", 'to': u"orm['core.GroupCluster']"}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'core.grouprounddatavalue': { + 'Meta': {'ordering': "['round_data', 'group', 'parameter']", 'object_name': 'GroupRoundDataValue'}, + 'boolean_value': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'float_value': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'data_value_set'", 'to': u"orm['core.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'int_value': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_modified': ('vcweb.core.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', 'boundaries'] + symmetrical = True diff -r 53c6141a5e6c9752fa67a99b25206bb31e9353ae -r bc1c86438575b002b76db8cc7312b5f3fdfc6419 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -2,10 +2,10 @@ from django.dispatch import receiver from vcweb.core import signals, simplecache from vcweb.core.models import (ExperimentMetadata, Parameter, ParticipantRoundDataValue, GroupRelationship, GroupCluster, GroupClusterDataValue) -from vcweb.forestry.models import (get_harvest_decision_parameter, get_harvest_decision, get_regrowth_rate_parameter, +from vcweb.forestry.models import (get_harvest_decision_parameter, get_harvest_decision, get_harvest_decision_dv, get_regrowth_rate_parameter, get_group_harvest_parameter, get_reset_resource_level_parameter, get_resource_level, - get_initial_resource_level as forestry_initial_resource_level, set_resource_level, get_regrowth_parameter, - get_resource_level_parameter, has_resource_level, get_resource_level_dv as get_unshared_resource_level_dv, + get_initial_resource_level as forestry_initial_resource_level, get_regrowth_parameter, + get_resource_level_parameter, get_resource_level_dv as get_unshared_resource_level_dv, set_group_harvest, set_regrowth, set_harvest_decision) import logging @@ -91,7 +91,7 @@ def get_max_harvest(experiment): - return experiment.get_parameter_value(parameter=get_max_harvest_decision_parameter(), default=10).int_value + return experiment.experiment_configuration.get_parameter_value(parameter=get_max_harvest_decision_parameter(), default=10).int_value ''' group data accessors ''' diff -r 53c6141a5e6c9752fa67a99b25206bb31e9353ae -r bc1c86438575b002b76db8cc7312b5f3fdfc6419 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -1,4 +1,5 @@ {% extends "participant/base.html" %} +{% load tags %} {% load static %} {% block head %} {{ block.super }} @@ -323,16 +324,21 @@ </div></div></div> -<h3>Harvest</h3> +<br><div data-bind='ifnot: isResourceEmpty'> - <form id='vcweb-form' action='' method='post' class='form-inline'> + <form id='vcweb-form' action='' method='post' class='form-horizontal' > {% csrf_token %} <div class='control-group'> - <div class='controls'> - <input id='participantGroupId' type='hidden' name='participant_group_id' data-bind='value: participantGroupId'/> - <input id='harvestDecision' type="number" size="1" maxlength="1" name='harvest_decision' class='required' min="0" data-bind="value: harvestDecision, attr: { max: maxHarvestDecision }" /> - <button id='submitDecision' data-bind='click: submitDecision' type='submit' class='btn'>Harvest</button> - </div> + <div class='input-prepend'> + <span class='add-on'><i class='icon-leaf'></i></span> + <input id='participantGroupId' type='hidden' name='participant_group_id' data-bind='value: participantGroupId'/> + <select name='harvest_decision' required="required" form="vcweb-form" data-bind='value: harvestDecision'> + {% for i in harvest_decision_choices %} + <option>{{i}}</option> + {% endfor %} + </select> + </div> + <button id='submitDecision' data-bind='click: submitDecision' type='submit' class='btn btn-primary'>Submit</button></div></form></div> @@ -440,9 +446,6 @@ 1000)); }; model.submitDecision = function(data, evt) { - if (evt) { - evt.preventDefault(); - } model.setFormDisabled("#vcweb-form", true); model.setFormDisabled("#chat-form", true); var formData = $('#vcweb-form').serialize(); @@ -496,6 +499,11 @@ function initialize(experimentModelJson) { var experimentModel = new ExperimentModel(experimentModelJson); ko.applyBindings(experimentModel); + if (experimentModel.submitted()) { + experimentModel.setFormDisabled("#vcweb-form", true); + experimentModel.setFormDisabled("#chat-form", true); + } + var s = connect(); s.onmessage = function(json) { console.debug(json); diff -r 53c6141a5e6c9752fa67a99b25206bb31e9353ae -r bc1c86438575b002b76db8cc7312b5f3fdfc6419 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -1,15 +1,13 @@ from django.http import Http404 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 from vcweb.core.http import JsonResponse -from vcweb.core.models import (is_participant, is_experimenter, Experiment, ParticipantGroupRelationship, - ParticipantExperimentRelationship, ChatMessage, ParticipantRoundDataValue, GroupRelationship) +from vcweb.core.models import (Experiment, ParticipantGroupRelationship, ChatMessage, GroupRelationship) from vcweb.boundaries.forms import HarvestDecisionForm -from vcweb.boundaries.models import (get_experiment_metadata, get_regrowth_rate, get_harvest_decision_parameter, +from vcweb.boundaries.models import (get_experiment_metadata, get_regrowth_rate, get_max_harvest, get_cost_of_living, get_resource_level, get_initial_resource_level, get_total_storage, get_storage, - get_last_harvest_decision, set_harvest_decision, can_observe_other_group, get_player_status) + get_last_harvest_decision, get_harvest_decision_dv, set_harvest_decision, can_observe_other_group, get_player_status) import logging logger = logging.getLogger(__name__) @@ -23,10 +21,11 @@ if experiment.experiment_metadata != get_experiment_metadata() or pgr.participant != request.user.participant: raise Http404 -# sends view model JSON to the template to be processed by knockout +# FIXME: should limit harvest_decision_choices by min(max_harvest, resource_level / group.size) return render(request, 'boundaries/participate.html', { 'auth_token': participant.authentication_token, 'experiment': experiment, + 'harvest_decision_choices': range(get_max_harvest(experiment) + 1), 'participant_experiment_relationship': experiment.get_participant_experiment_relationship(participant), 'participant_group_relationship': pgr, 'experimentModelJson': get_view_model_json(experiment, pgr), @@ -103,6 +102,12 @@ experiment_model_dict['alive'] = get_player_status(participant_group_relationship, current_round_data) # participant group data parameters are only needed if this round is a data round or the previous round was a data round if previous_round.is_playable_round or current_round.is_playable_round: + harvest_decision = get_harvest_decision_dv(participant_group_relationship, current_round_data) + experiment_model_dict['submitted'] = harvest_decision.submitted + if harvest_decision.submitted: + # user has already submit a harvest decision this round + experiment_model_dict['harvestDecision'] = harvest_decision.int_value + experiment_model_dict['chatMessages'] = [{ 'pk': cm.pk, 'participant_number': cm.participant_group_relationship.participant_number, diff -r 53c6141a5e6c9752fa67a99b25206bb31e9353ae -r bc1c86438575b002b76db8cc7312b5f3fdfc6419 vcweb/core/templatetags/tags.py --- a/vcweb/core/templatetags/tags.py +++ b/vcweb/core/templatetags/tags.py @@ -4,8 +4,6 @@ from django import template register = template.Library() -import logging -logger = logging.getLogger(__name__) @register.simple_tag def active(request, pattern): @@ -16,3 +14,6 @@ import re return 'active' if re.search(pattern, request.path) else 'inactive' +...@re...lter +def mkrange(value): + return range(value) diff -r 53c6141a5e6c9752fa67a99b25206bb31e9353ae -r bc1c86438575b002b76db8cc7312b5f3fdfc6419 vcweb/forestry/models.py --- a/vcweb/forestry/models.py +++ b/vcweb/forestry/models.py @@ -28,8 +28,11 @@ def has_resource_level(group=None): return group.has_data_parameter(parameter=get_resource_level_parameter()) -def get_harvest_decision(participant_group_relationship, round_data=None): - return participant_group_relationship.get_data_value(round_data=round_data, parameter=get_harvest_decision_parameter(), default=0).int_value +def get_harvest_decision_dv(participant_group_relationship, round_data=None, default=0): + return participant_group_relationship.get_data_value(round_data=round_data, parameter=get_harvest_decision_parameter(), default=default) + +def get_harvest_decision(participant_group_relationship, round_data=None, default=0): + return get_harvest_decision_dv(participant_group_relationship, round_data, default).int_value def get_harvest_decisions(group=None): return group.get_participant_data_values(parameter__name='harvest_decision') if group else [] https://bitbucket.org/virtualcommons/vcweb/commits/3ae6b5d1ea09/ Changeset: 3ae6b5d1ea09 User: alllee Date: 2013-03-26 22:18:10 Summary: wiring up persistent harvest decisions Affected #: 3 files diff -r bc1c86438575b002b76db8cc7312b5f3fdfc6419 -r 3ae6b5d1ea094304cc9b7c9b099d4ace25c8c092 vcweb/boundaries/forms.py --- a/vcweb/boundaries/forms.py +++ b/vcweb/boundaries/forms.py @@ -1,4 +1,4 @@ -from vcweb.core.forms import ParticipantGroupIdForm +from vcweb.core.forms import ParticipantGroupIdForm, SingleIntegerDecisionForm from vcweb.forestry import forms diff -r bc1c86438575b002b76db8cc7312b5f3fdfc6419 -r 3ae6b5d1ea094304cc9b7c9b099d4ace25c8c092 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -290,7 +290,7 @@ </div><div class='alert alert-error'>There are no more resources to harvest. Please wait until the next round begins.</div></div> -<div data-bind='if: hasSubmit'> +<div data-bind='if: submitted'><div class='alert alert-error'> You have submitted a decision to harvest <span class='badge badge-important' data-bind='text: harvestDecision'></span> resources. </div> @@ -332,11 +332,13 @@ <div class='input-prepend'><span class='add-on'><i class='icon-leaf'></i></span><input id='participantGroupId' type='hidden' name='participant_group_id' data-bind='value: participantGroupId'/> - <select name='harvest_decision' required="required" form="vcweb-form" data-bind='value: harvestDecision'> + <input id='harvestDecisionTextInput' type='hidden' name='integer_decision' data-bind='value: harvestDecision'> + <select id='harvestDecisionSelect' required="required" form="vcweb-form" data-bind='value: harvestDecision'> {% for i in harvest_decision_choices %} <option>{{i}}</option> {% endfor %} </select> + </div><button id='submitDecision' data-bind='click: submitDecision' type='submit' class='btn btn-primary'>Submit</button></div> @@ -410,7 +412,6 @@ model.shouldShowOtherGroup(true); } model.shouldShowOtherGroup = ko.observable(false); - model.harvestDecision = ko.observable(0); model.numberOfTreesPerRow = ko.observable(10); model.isResourceEmpty = ko.computed(function() { return model.resourceLevel() == 0; @@ -446,14 +447,14 @@ 1000)); }; model.submitDecision = function(data, evt) { + var formData = $('#vcweb-form').serialize(); model.setFormDisabled("#vcweb-form", true); model.setFormDisabled("#chat-form", true); - var formData = $('#vcweb-form').serialize(); + console.debug(formData); $.post('submit-harvest-decision', formData, function(jsonString) { console.log(jsonString); //update($.parseJSON(jsonString.experimentModelJson)); model.secondsLeft(0); - model.hasSubmit(true); model.clearCurrentInterval(); }); } @@ -530,9 +531,6 @@ break; } }; - $('#harvestDecision').keyup(function() { - $('#harvestDecision').val(this.value.match(/\d+/)); - }); } var experimentModelJson = $.parseJSON("{{ experimentModelJson|escapejs }}"); initialize(experimentModelJson); diff -r bc1c86438575b002b76db8cc7312b5f3fdfc6419 -r 3ae6b5d1ea094304cc9b7c9b099d4ace25c8c092 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -4,7 +4,7 @@ from vcweb.core.decorators import participant_required from vcweb.core.http import JsonResponse from vcweb.core.models import (Experiment, ParticipantGroupRelationship, ChatMessage, GroupRelationship) -from vcweb.boundaries.forms import HarvestDecisionForm +from vcweb.boundaries.forms import SingleIntegerDecisionForm from vcweb.boundaries.models import (get_experiment_metadata, get_regrowth_rate, get_max_harvest, get_cost_of_living, get_resource_level, get_initial_resource_level, get_total_storage, get_storage, get_last_harvest_decision, get_harvest_decision_dv, set_harvest_decision, can_observe_other_group, get_player_status) @@ -33,15 +33,16 @@ @participant_required def submit_harvest_decision(request, experiment_id=None): - form = HarvestDecisionForm(request.POST or None) + form = SingleIntegerDecisionForm(request.POST or None) experiment = get_object_or_404(Experiment, pk=experiment_id) if form.is_valid(): - logger.debug("handing POST request, cleaned data: %s", form.cleaned_data) participant_group_id = form.cleaned_data['participant_group_id'] pgr = get_object_or_404(ParticipantGroupRelationship, pk=participant_group_id) - harvest_decision = form.cleaned_data['harvest_decision'] + harvest_decision = form.cleaned_data['integer_decision'] set_harvest_decision(pgr, harvest_decision, experiment.current_round_data, submitted=True) return JsonResponse(dumps({ 'success': True, 'experimentModelJson': get_view_model_json(experiment, pgr)})) + else: + logger.debug("form was invalid: %s", form) for field in form: if field.errors: logger.debug("field %s had errors %s", field, field.errors) @@ -106,6 +107,7 @@ experiment_model_dict['submitted'] = harvest_decision.submitted if harvest_decision.submitted: # user has already submit a harvest decision this round + logger.debug("already submitted, setting harvest decision to %s", harvest_decision.int_value) experiment_model_dict['harvestDecision'] = harvest_decision.int_value experiment_model_dict['chatMessages'] = [{ Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-26 19:50:42
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/53c6141a5e6c/ Changeset: 53c6141a5e6c User: alllee Date: 2013-03-26 20:50:22 Summary: adding default to player status Affected #: 2 files diff -r a384ab7d24a0f431bff64eb1036ec8ca6c1700cf -r 53c6141a5e6c9752fa67a99b25206bb31e9353ae vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -144,12 +144,12 @@ storage_dv.save() return storage_dv -def get_player_status_dv(participant_group_relationship, round_data): +def get_player_status_dv(participant_group_relationship, round_data, default=True): return participant_group_relationship.get_data_value(parameter=get_player_status_parameter(), - round_data=round_data) + round_data=round_data, default=default) -def get_player_status(participant_group_relationship, round_data): - return get_player_status_dv(participant_group_relationship, round_data).boolean_value +def get_player_status(participant_group_relationship, round_data, default=True): + return get_player_status_dv(participant_group_relationship, round_data, default).boolean_value def set_player_status(participant_group_relationship, round_data, value): status_dv = get_player_status_dv(participant_group_relationship, round_data) diff -r a384ab7d24a0f431bff64eb1036ec8ca6c1700cf -r 53c6141a5e6c9752fa67a99b25206bb31e9353ae vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -23,7 +23,7 @@ <div data-bind='if: chatEnabled'><h3>Chat</h3><div class='chat-sidebar well'> - <form id="chatform" class='form-inline'> + <form id="chat-form" class='form-inline'><div class='input-prepend input-append'><span class='add-on'><i class='text-info icon-comment'></i></span><input style='width: 100%;' class='chat-action' id='chatText' type="text" placeholder="Enter a chat message"> @@ -44,9 +44,6 @@ {% 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 for other participants</h3><div> @@ -426,13 +423,13 @@ model.resourceImageHeight = ko.observable("79px"); model.startRound = function() { model.enableChat(); - model.setFormDisabled(true); + model.setFormDisabled("#vcweb-form", true); model.secondsLeft(60); model.setCurrentInterval( setInterval(function() { model.tick(); if (model.secondsLeft() == 30) { - model.setFormDisabled(false); + model.setFormDisabled("#vcweb-form", false); } if (! model.isTimerRunning()) { model.submitDecision(); @@ -442,15 +439,12 @@ }, 1000)); }; - model.setFormDisabled = function(toggle) { - // disable all form inputs - $('#vcweb-form :input').prop("disabled", toggle); - } model.submitDecision = function(data, evt) { if (evt) { evt.preventDefault(); } - model.setFormDisabled(true); + model.setFormDisabled("#vcweb-form", true); + model.setFormDisabled("#chat-form", true); var formData = $('#vcweb-form').serialize(); $.post('submit-harvest-decision', formData, function(jsonString) { console.log(jsonString); @@ -471,23 +465,30 @@ } } model.update = function() { - $.get('view-model', { participant_group_id: {{ participant_group_relationship.pk }} }, function(data) { + $.get('view-model', { participant_group_id: model.participantGroupId() }, function(data) { console.debug("retrieved view model successfully"); console.debug(data); ko.mapping.fromJS(data, model); $('#progress-modal').modal('hide'); }); } + model.setFormDisabled = function(formId, disabled) { + // disable all form inputs + if (formId.indexOf("#") != 0) { + formId = "#" + formId; + } + $(formId + " :input").prop("disabled", disabled); + } model.disableChat = function() { - $('#content').removeClass('span6').addClass('span9'); - $('#sidebar').removeClass('span6').addClass('span3'); - $('.chat-action').addClass('disabled').attr('disabled', true); + // $('#content').removeClass('span6').addClass('span9'); + // $('#sidebar').removeClass('span6').addClass('span3'); + model.setFormDisabled("#chat-form", true); model.chatEnabled(false); } model.enableChat = function() { - $('#content').removeClass('span9').addClass('span6'); - $('#sidebar').removeClass('span3').addClass('span6'); - $('.chat-action').removeClass('disabled').attr('disabled', false); + // $('#content').removeClass('span9').addClass('span6'); + // $('#sidebar').removeClass('span3').addClass('span6'); + model.setFormDisabled("#chat-form", false); model.chatEnabled(true); } return model; Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |
From: <com...@bi...> - 2013-03-26 08:44:39
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/a384ab7d24a0/ Changeset: a384ab7d24a0 User: alllee Date: 2013-03-26 09:44:24 Summary: s/attr/prop Affected #: 1 file diff -r e1c60488c39b6e7bbd4f6ff568e187ab863d7c32 -r a384ab7d24a0f431bff64eb1036ec8ca6c1700cf vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -444,7 +444,7 @@ }; model.setFormDisabled = function(toggle) { // disable all form inputs - $('#vcweb-form :input').attr("disabled", toggle); + $('#vcweb-form :input').prop("disabled", toggle); } model.submitDecision = function(data, evt) { if (evt) { 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. |