[virtualcommons-developer] commit/vcweb: 2 new changesets
Status: Beta
Brought to you by:
alllee
|
From: <com...@bi...> - 2013-03-20 19:02:12
|
2 new commits in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/82148e9a0f1e/ changeset: 82148e9a0f1e user: alllee date: 2013-03-20 19:15:34 summary: refactoring sockjs server, adding broadcast method to send a parameterized message to everyone in the experiment affected #: 1 file diff -r a1dd1c200888f982753d36439d02942166088b96 -r 82148e9a0f1eb69c8cdce15cf38dcef9b97fb997 vcweb/vcweb-sockjs.py --- a/vcweb/vcweb-sockjs.py +++ b/vcweb/vcweb-sockjs.py @@ -71,6 +71,7 @@ return json.dumps({ 'message': message, 'event_type': event_type}) REFRESH_EVENT = json.dumps({ 'event_type': 'refresh' }) +UPDATE_EVENT = json.dumps({ 'event_type': 'update' }) DISCONNECTION_EVENT = create_message_event('Your session has expired and you have been disconnected. You can only have one window open to a vcweb page.') UNAUTHORIZED_EVENT = create_message_event("You do not appear to be authorized to perform this action. If this problem persists, please contact us.") @@ -169,6 +170,9 @@ if participant_tuple in self.participant_to_connection: yield (participant_group_relationship.pk, self.participant_to_connection[participant_tuple]) + ''' + generator function yielding all (participant group relationship id, connection) tuples for the given experiment + ''' def all_participants(self, experimenter, experiment): experimenter_key = (experimenter.pk, experiment.pk) if experimenter_key in self.experimenter_to_connection: @@ -181,23 +185,14 @@ experimenter functions ''' def send_refresh(self, experimenter, experiment): - participant_connections = [] - for (participant_group_pk, connection) in self.all_participants(experimenter, experiment): - logger.debug("sending refresh to %s, %s", participant_group_pk, connection) - participant_connections.append(participant_group_pk) - connection.send(REFRESH_EVENT) - return participant_connections + return self.broadcast(experimenter, experiment, REFRESH_EVENT) - def send_update(self, experimenter, experiment): - pass + def send_update_event(self, experimenter, experiment): + return self.broadcast(experimenter, experiment, UPDATE_EVENT) def send_goto(self, experimenter, experiment, url): - notified_participants = [] message = json.dumps({'event_type': 'goto', 'url': url}) - for (participant_group_pk, connection) in self.all_participants(experimenter, experiment): - connection.send(message) - notified_participants.append(participant_group_pk) - return notified_participants + return self.broadcast(experimenter, experiment, message) def send_to_experimenter(self, json, experiment_id=None, experimenter_id=None, experiment=None): if experimenter_id is None and experiment_id is None: @@ -213,8 +208,16 @@ logger.debug("no experimenter found with pk %s in experimenters set %s", experimenter_tuple, self.experimenter_to_connection) + def broadcast(self, experimenter, experiment, message): + participant_connections = [] + for (participant_group_id, connection) in self.all_participants(experimenter, experiment): + participant_connections.append(participant_group_id) + connection.send(message) + logger.debug("sent message %s to %s", message, participant_connections) + return participant_connections + def send_to_group(self, group, json): - for participant_group_pk, connection in self.connections(group): + for participant_group_id, connection in self.connections(group): connection.send(json) self.send_to_experimenter(json, experiment=group.experiment) @@ -363,7 +366,7 @@ self.send(create_message_event("Refreshed all connected participant pgr_ids=%s)" % notified_participants)) def handle_update_participants(self, event, experiment, experimenter): - notified_participants = connection_manager.send_update(experimenter, experiment) + notified_participants = connection_manager.send_update_event(experimenter, experiment) self.send(create_message_event("Updating all connected participants pgr_ids=%s)" % notified_participants)) def on_close(self): https://bitbucket.org/virtualcommons/vcweb/commits/3aa5801c8f2e/ changeset: 3aa5801c8f2e user: alllee date: 2013-03-20 20:02:06 summary: experimenter now triggering transitions / updates on the client properly, still need to set up timers and fix some issues with invalid data affected #: 5 files diff -r 82148e9a0f1eb69c8cdce15cf38dcef9b97fb997 -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 vcweb/boundaries/models.py --- a/vcweb/boundaries/models.py +++ b/vcweb/boundaries/models.py @@ -2,9 +2,9 @@ from vcweb.core import signals, simplecache from vcweb.core.models import ExperimentMetadata, Parameter, ParticipantRoundDataValue from vcweb.forestry.models import (get_harvest_decision_parameter, get_harvest_decision, get_regrowth_rate, - get_group_harvest_parameter, get_resource_level, get_initial_resource_level as forestry_initial_resource_level, - set_resource_level, get_regrowth_parameter, get_resource_level_parameter, has_resource_level, - get_resource_level_dv, get_harvest_decisions, set_group_harvest, set_regrowth) + get_group_harvest_parameter, get_reset_resource_level_parameter, get_resource_level, get_initial_resource_level + as forestry_initial_resource_level, set_resource_level, get_regrowth_parameter, get_resource_level_parameter, + has_resource_level, get_resource_level_dv, get_harvest_decisions, set_group_harvest, set_regrowth) import logging diff -r 82148e9a0f1eb69c8cdce15cf38dcef9b97fb997 -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 vcweb/boundaries/templates/boundaries/participate.html --- a/vcweb/boundaries/templates/boundaries/participate.html +++ b/vcweb/boundaries/templates/boundaries/participate.html @@ -48,9 +48,14 @@ {% include "forms/chat-template.html" %} </script><script type='text/html' id='WAITING_ROOM'> -<h3>Waiting Room</h3> +<h3>Waiting for other participants</h3><div> Please wait. The experiment will continue shortly once all the participants are ready. +<p> +<span class='badge' +data-bind='css: { "badge-important": readyParticipants() < (totalNumberOfParticipants() / 2), "badge-success": readyParticipants() > (totalNumberOfParticipants() / 2)}, text: readyParticipants'></span> of <span class='badge badge-success' data-bind='text: totalNumberOfParticipants'></span> participants are ready. +</p> +</div></div><div class='progress progress-success progress-striped active'><div class='bar' data-bind='style: { width: readyParticipantsPercentage() + "%" }'></div> @@ -386,8 +391,6 @@ $.post('/experiment/participant-ready', { participant_group_id: {{ participant_group_relationship.pk }} }, function(response) { console.debug("successfully posted to server, notifying sockjs: " + response); getWebSocket().send(createMessageEvent("Instructions completed", "client_ready")); - // FIXME: transition to a waiting screen - model.readyParticipant(); model.activateWaitingRoomPage(); }); } diff -r 82148e9a0f1eb69c8cdce15cf38dcef9b97fb997 -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 vcweb/boundaries/views.py --- a/vcweb/boundaries/views.py +++ b/vcweb/boundaries/views.py @@ -11,7 +11,6 @@ get_cost_of_living, get_resource_level, get_initial_resource_level, get_total_storage, get_storage, get_last_harvest_decision, can_observe_other_group) import logging -import random logger = logging.getLogger(__name__) @@ -55,7 +54,7 @@ @participant_required def get_view_model(request, experiment_id=None): - experiment = get_object_or_404(Experiment.select_related('experiment_metadata', 'experiment_configuration'), pk=experiment_id) + experiment = get_object_or_404(Experiment.objects.select_related('experiment_metadata', 'experiment_configuration'), pk=experiment_id) pgr = experiment.get_participant_group_relationship(request.user.participant) return JsonResponse(get_view_model_json(experiment, pgr)) @@ -72,13 +71,17 @@ regrowth_rate = get_regrowth_rate(current_round) cost_of_living = get_cost_of_living(current_round) experiment_model_dict['readyParticipants'] = experiment.ready_participants - experiment_model_dict['participantsPerGroup'] = ec.max_group_size - experiment_model_dict['regrowthRate'] = regrowth_rate experiment_model_dict['costOfLiving'] = cost_of_living +# instructions round parameters + if current_round.is_instructions_round: + experiment_model_dict['participantsPerGroup'] = ec.max_group_size + experiment_model_dict['regrowthRate'] = regrowth_rate + experiment_model_dict['initialResourceLevel'] = get_initial_resource_level(current_round) + experiment_model_dict['dollarsPerToken'] = float(ec.exchange_rate) + experiment_model_dict['totalNumberOfParticipants'] = experiment.participant_set.count() experiment_model_dict['participantNumber'] = participant_group_relationship.participant_number experiment_model_dict['participantGroupId'] = participant_group_relationship.pk - experiment_model_dict['dollarsPerToken'] = float(ec.exchange_rate) experiment_model_dict['roundType'] = current_round.round_type experiment_model_dict['practiceRound'] = current_round.is_practice_round experiment_model_dict['chatEnabled'] = False @@ -105,11 +108,12 @@ 'message': cm.string_value, 'date_created': cm.date_created.strftime("%I:%M:%S") } for cm in ChatMessage.objects.for_group(own_group)] - experiment_model_dict['initialResourceLevel'] = get_initial_resource_level(current_round) +# FIXME: this is redundant experiment_model_dict['lastHarvestDecision'] = last_harvest_decision experiment_model_dict['storage'] = get_storage(participant_group_relationship, current_round_data) experiment_model_dict['resourceLevel'] = own_resource_level - if not current_round.is_practice_round and can_observe_other_group(current_round): + experiment_model_dict['canObserveOtherGroup'] = can_observe_other_group(current_round) + if not current_round.is_practice_round and experiment_model_dict['canObserveOtherGroup']: gr = GroupRelationship.objects.select_related('cluster').get(group=own_group) group_data = [] for group in gr.cluster.group_set.all(): diff -r 82148e9a0f1eb69c8cdce15cf38dcef9b97fb997 -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 vcweb/core/models.py --- a/vcweb/core/models.py +++ b/vcweb/core/models.py @@ -887,7 +887,8 @@ ordering = ['date_created', 'status'] class RoundConfiguration(models.Model): -# maps round type name to (description, default_template_name) + # FIXME: refactor this into a single data structure + # maps round type name to (description, default_template_name) ROUND_TYPES_DICT = dict( WELCOME=('Initial welcome round', 'welcome.html'), GENERAL_INSTRUCTIONS=('General instructions round (introduction)', 'general-instructions.html'), @@ -899,8 +900,8 @@ QUIZ=('Quiz round', 'quiz.html')) ROUND_TYPES = (CHAT, DEBRIEFING, GENERAL_INSTRUCTIONS, INSTRUCTIONS, PRACTICE, QUIZ, REGULAR, WELCOME) = sorted(ROUND_TYPES_DICT.keys()) - ROUND_TYPE_CHOICES = Choices(*[(round_type, ROUND_TYPES_DICT[round_type][0]) for round_type in ROUND_TYPES]) - PLAYABLE_ROUND_CONFIGURATIONS = (PRACTICE, REGULAR) + RoundType = Choices(*[(round_type, ROUND_TYPES_DICT[round_type][0]) for round_type in ROUND_TYPES]) + PLAYABLE_ROUND_CONFIGURATIONS = (RoundType.PRACTICE, RoundType.REGULAR) experiment_configuration = models.ForeignKey(ExperimentConfiguration, related_name='round_configuration_set') sequence_number = models.PositiveIntegerField(help_text='Used internally to determine the ordering of the rounds in an experiment in ascending order, e.g., 1,2,3,4,5') @@ -919,8 +920,8 @@ debriefing = models.TextField(null=True, blank=True) """ debriefing, if any, to display after the round ends """ round_type = models.CharField(max_length=32, - choices=ROUND_TYPE_CHOICES, - default=REGULAR) + choices=RoundType, + default=RoundType.REGULAR) """ name of a custom template to be used this round. e.g., if set to quiz_2.html in the forestry experiment app, this would be loaded from @@ -982,27 +983,27 @@ @property def is_debriefing_round(self): - return self.round_type == RoundConfiguration.DEBRIEFING + return self.round_type == RoundConfiguration.RoundType.DEBRIEFING @property def is_chat_round(self): - return self.round_type == RoundConfiguration.CHAT + return self.round_type == RoundConfiguration.RoundType.CHAT @property def is_instructions_round(self): - return self.round_type == RoundConfiguration.INSTRUCTIONS + return self.round_type in (RoundConfiguration.RoundType.INSTRUCTIONS, RoundConfiguration.RoundType.GENERAL_INSTRUCTIONS) @property def is_quiz_round(self): - return self.round_type == RoundConfiguration.QUIZ + return self.round_type == RoundConfiguration.RoundType.QUIZ @property def is_practice_round(self): - return self.round_type == RoundConfiguration.PRACTICE + return self.round_type == RoundConfiguration.RoundType.PRACTICE @property def is_regular_round(self): - return self.round_type == RoundConfiguration.REGULAR + return self.round_type == RoundConfiguration.RoundType.REGULAR @property def is_playable_round(self): diff -r 82148e9a0f1eb69c8cdce15cf38dcef9b97fb997 -r 3aa5801c8f2ea252f88a43f2f8147f38e2b59fb2 vcweb/forestry/tests.py --- a/vcweb/forestry/tests.py +++ b/vcweb/forestry/tests.py @@ -59,11 +59,11 @@ def test_get_template(self): e = self.experiment - rc = self.create_new_round_configuration(round_type=RoundConfiguration.QUIZ, template_name='quiz_23.html') + rc = self.create_new_round_configuration(round_type=RoundConfiguration.RoundType.QUIZ, template_name='quiz_23.html') e.current_round_sequence_number = rc.sequence_number self.assertEqual(e.current_round_template, 'forestry/quiz_23.html', 'should return specified quiz_template') - rc = self.create_new_round_configuration(round_type=RoundConfiguration.QUIZ) + rc = self.create_new_round_configuration(round_type=RoundConfiguration.RoundType.QUIZ) e.current_round_sequence_number = rc.sequence_number self.assertEqual(e.current_round_template, 'forestry/quiz.html', 'should return default quiz.html') Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |