def post(self): """ HTTP POST method to add the student. """ # First, check that the logged in user is an instructor instructor = utils.check_privilege(model.Role.instructor) if not instructor: # Send them home and short circuit all other logic return self.redirect('/') # end # So first we need to get at the course and section course, section = utils.get_course_and_section_objs(self.request, instructor) # And grab the action from the page action = self.request.get('action') # Check that the action was actually supplied if not action: # Error if not utils.error('Invalid arguments: course_name or section_name or actoin is null', handler=self) else: # Now switch on the action if action == 'add': # Grab a list of the emails from the page emails = json.loads(self.request.get('emails')) # And create new students from that list self.add_students(section, emails) elif action == 'remove': # Grab the email from the page to remove email = self.request.get('email').lower() # And remove it self.remove_student(section, email) else: # Send an error if any other action is supplied utils.error('Unexpected action: ' + action, handler=self)
def post(self): """ HTTP POST method to create groups. """ # First, check that the logged in user is an instructor instructor = utils.check_privilege(model.Role.instructor) if not instructor: # Send them home and short circuit all other logic return self.redirect('/') # end # So first we need to get at the course and section course, section = utils.get_course_and_section_objs(self.request, instructor) # Grab the action from the page action = self.request.get('action') # Check that the action was actually supplied if not action: # Error if not utils.error('Invalid argument: action is null', handler=self) else: # Switch on the action utils.log('action = ' + action) if action == 'add': # If add, grab the number of groups from the page group_count = int(self.request.get('groups')) # And modify the database self.modify_group_count(section, group_count) elif action == 'update': # For update, grab the group settings from the page groups = json.loads(self.request.get('groups')) # And modify the database self.update_groups(section, groups) else: # Send an error if a different action is supplied utils.error('Unknown action' + action if action else 'None', handler=self)
def start_rounds(self, instructor): # So first we need to get at the course and section course, section = utils.get_course_and_section_objs( self.request, instructor) # And grab all of the rounds for this section rounds = model.Round.query(ancestor=section.key).fetch() # The view requires at least a initial question to add rounds, but check if not rounds: # Send an error if no rounds exist for this section utils.error('Error! No initial question exists; cannot start yet.', handler=self) # And redirect return self.redirect('/') # end # Now simply turn on the first round section.current_round = 1 section.put() # Add the dummy read only round if it's a rounds based discussion if section.has_rounds: self.add_rounds(num_of_rounds=1, duration=0, instructor=instructor, type=model.Round.get_round_type('readonly'), buffer_bw_rounds=0, quiet=True) # And send a success message utils.log('Successfully started the first round.', type='Success!', handler=self)
def toggle_anonymity(self, instructor): # So first we need to get at the course and section course, section = utils.get_course_and_section_objs( self.request, instructor) if section: section.is_anonymous = not section.is_anonymous section.put() utils.log('Anonymity toggled to: ' + str(section.is_anonymous)) else: utils.error('Section not found')
def toggle_round_structure(self, instructor): # So first we need to get at the course and section course, section = utils.get_course_and_section_objs( self.request, instructor) if section: section.has_rounds = not section.has_rounds section.put() utils.log('Rounds Structure toggled to: ' + str(section.has_rounds)) else: utils.error('Section not found')
def add_rounds(self, num_of_rounds, duration, instructor, buffer_bw_rounds, type=2, quiet=False): # So first we need to get at the course and section course, section = utils.get_course_and_section_objs( self.request, instructor) # And grab all of the rounds for this section rounds = model.Round.query(ancestor=section.key).fetch() # The view requires at least a initial question to add rounds, but check if not rounds: # Send an error if no rounds exist for this section utils.error( 'Error! No initial question exists; cannot add new rounds yet.', handler=self) # And redirect return self.redirect('/') # end # We'll need this later on when doing the buffer stuff # if rounds_buffer < 0 # # Make sure the buffer value is positive # utils.error('Error! Buffer value must be greater than 0.', handler=self) # # And redirect # return self.redirect('/') # #end # Copy the summary round if it exists summary = copy_summary(section, rounds, num_of_rounds) # If it exists, pop it off the list if summary: rounds.pop() # end # Now create all the new rounds new_rounds = create_new_rounds(section, rounds, num_of_rounds, duration, buffer_bw_rounds, type) # And update the summary round update_summary(summary, new_rounds) # Now update the number of rounds attribute of the section update_section_rounds(new_rounds[-1].number, section) # Now send a success message if not quiet: utils.log( 'Successfully added {0} new rounds.'.format(num_of_rounds), type='Success!', handler=self) utils.log('Added Rounds = ' + str(new_rounds))
def end_current_round(self, instructor): utils.log("trying to end the current round") course, section = utils.get_course_and_section_objs( self.request, instructor) current_round = utils.get_current_round_object(section) next_round = utils.get_next_round_object(section) if not current_round: utils.log("current round is empty!") return utils.log("current round is number " + str(current_round.number)) # if/else is to support both legacy (string) and new (datetime) data types current_round.deadline = datetime.datetime.now() current_round.put() if next_round: next_round.starttime = datetime.datetime.now() next_round.put() section.current_round = next_round.number section.put()
def delete_round(self, instructor, round_id): # So first we need to get at the course and section course, section = utils.get_course_and_section_objs( self.request, instructor) # And grab all of the rounds for this section rounds = model.Round.query(ancestor=section.key).fetch() # The view requires at least a initial question to add rounds, but check if not rounds: # Send an error if no rounds exist for this section utils.error( 'Error! No initial question exists; cannot add new rounds yet.', handler=self) # And redirect return self.redirect('/') # end # Now shift all the rounds and remove the round with the input id shift_rounds(rounds, round_id) # Now let's check if we need to copy a summary question over or not if rounds[-1].description == 'summary': # Delete the next to last round and remove from the list rounds[-2].put().delete() rounds.pop(-2) # And copy the summary round and update the times summary = copy_summary(section, rounds, -1) # Remove the old summary from the list rounds.pop() update_summary(summary, rounds) else: # Finally, remove the very last round from the list rounds[-1].put().delete() # end # Since we shifted rounds forward, remove the last round from the list rounds.pop() # And update the section update_section_rounds(rounds[-1].number, section) # And send a success message utils.log('Successfully deleted round {0}'.format(round_id), type='Success!', handler=self)
def edit_round(self, instructor, round_id): # So first we need to get at the course and section course, section = utils.get_course_and_section_objs( self.request, instructor) # And grab all of the rounds for this section rounds = model.Round.query(ancestor=section.key).fetch() # The view requires at least a initial question to add rounds, but check if not rounds: # Send an error if no rounds exist for this section utils.error( 'Error! No initial question exists; cannot add new rounds yet.', handler=self) # And redirect return self.redirect('/') # end # TODO allow editing the _deadline_ even after the round has started # Now grab the inputs from the page description = self.request.get('description') # and get the start and end times for the round start_time = utils.to_utc(self.request.get('start_time')) deadline = utils.to_utc(self.request.get('deadline')) # Loop over the rounds to find the one we're trying to edit for i in range(len(rounds)): if rounds[i].number == round_id: # First, let's set the description rounds[i].description = description # Now, let's grab the deadline of the previous round previous_end = rounds[i - 1].deadline # Check if the new start time is BEFORE the previous round's # end time if start_time < previous_end: # Send an error if so utils.error( 'Error! Cannot set new start time earlier than \ deadline of round {0}.'.format(i - 1), handler=self) # And exit break # end # Otherwise, the new start time doesn't overlap; we can set it rounds[i].starttime = start_time # And now set the new deadline for this round rounds[i].deadline = deadline # Now, check to see if there's a rounds we need to propagate to if i != len(rounds) - 1: # Grab the start time of the next round next_start = rounds[i + 1].starttime # If the new deadline isn't the same as the next start time if deadline != next_start: # We need to move the start and end times of the rest # of the rounds, so loop over them for j in range(i + 1, len(rounds)): # First, get the duration of the round duration = get_duration(rounds[j].starttime, rounds[j].deadline) # Now set the new start time to be the # deadline of the previous round rounds[j].starttime = rounds[j - 1].deadline # And calculate and set the new end time rounds[j].deadline = rounds[j].starttime + duration # And save it back to the database rounds[j].put() # end # end # end # And commit the changes to the database rounds[i].put() # Since we've done our updating, break the loop utils.log('Successfully updated round {0}.'.format(round_id), type='S', handler=self) break
def add_leadin_summary(self, instructor): # So first we need to get at the course and section course, section = utils.get_course_and_section_objs( self.request, instructor) # Before anything, we need to check that the deadline is in the future if datetime.datetime.now() > utils.to_utc(self.request.get('time')): # Send an error if so and exit utils.error('Error! Cannot create deadline in the past.', handler=self) return # end # Build the round object round_obj = self.build_round_obj(section) # Now grab all of the rounds rounds = model.Round.query(ancestor=section.key).fetch() # And switch on the type to create our start time if round_obj.description == 'initial': round_obj.type = model.Round.get_round_type('initial') add_lead_in(round_obj, rounds) else: # If not a lead-in question, we know it's a summary # And check that we're not trying to add a summary as the first if not rounds: # Send an error if so and return utils.error( 'Error! Summary question cannot be first round added.', handler=self) return # end # First check if we're editing the summary if rounds[-1].description == 'summary': # And if so, grab the deadline of the round before the summary last_time = rounds[-2].deadline # And remove the old summary from the database rounds[-1].put().delete() else: # Otherwise, grab the deadline of the previous round last_time = rounds[-1].deadline # end # Assign the proper type round_obj.type = model.Round.get_round_type('final') # Let's check that the deadline doesn't conflict with the last round if round_obj.deadline <= last_time: # Send an error if so and return utils.error( 'Error! Cannot set end time of final before end of last discussion.', handler=self) return # end # Set start time of summary as the deadline of the last round round_obj.starttime = utils.str_to_datetime(last_time) # end # Now save the round to the database round_obj.put() # And grab all the rounds one last time rounds = model.Round.query(ancestor=section.key).fetch() # And update the section rounds attribute if necessary update_section_rounds(rounds[-1].number, section) # And send our success message # utils.log('Success, round added.', type='Success!', handler=self) utils.log('Success! Round added.', type='S', handler=self)
def post(self): # First, check that the logged in user is an instructor instructor = utils.check_privilege(model.Role.instructor) if not instructor: # Send them home and short circuit all other logic return self.redirect('/') # end # Now let's grab the action from the page action = self.request.get('action') # And check that it was actually passed if not action: # Error if not utils.error('Error! Invalid arguments: action is null', handler=self) else: # Now switch on the action if action == 'add': # Only the lead-in or summary are listed as an 'add' action self.add_leadin_summary(instructor) elif action == 'end-current-round': self.end_current_round(instructor) elif action == 'add_disc': # Now, let's grab the number of rounds and duration from page num_of_rounds = int(self.request.get('total_discussions')) duration_of_round = int(self.request.get('duration')) # And grab the buffer time between rounds buffer_bw_rounds = 0 # int(self.request.get('buffer_time')) # Get the type based on whether it's a rounds based discussion or sequential course, section = utils.get_course_and_section_objs( self.request, instructor) # round_type = model.Round.get_round_type( # 'discussion') if section.has_rounds else model.Round.get_round_type('sequential') round_type = 2 if section.has_rounds else 3 # Send the number and duration to the add rounds function self.add_rounds(num_of_rounds=num_of_rounds, duration=duration_of_round, instructor=instructor, type=round_type, buffer_bw_rounds=buffer_bw_rounds) elif action == 'delete': # Send the id of the round to be deleted round_id = int(self.request.get('round_id')) self.delete_round(instructor, round_id) elif action == 'change': # Send the id of the round to be edited round_id = int(self.request.get('round_id')) self.edit_round(instructor, round_id) elif action == 'start': # Simply kick off the first round self.start_rounds(instructor) # Send mail to students # Grab section object and instructor email to pass to email function email_course, email_section = utils.get_course_and_section_objs( self.request, instructor) # Grab the message of the email message = self.request.get('message') # Grab the subject of the email subject = self.request.get('subject') to_emails = [s.email for s in email_section.students] utils.send_mails(to_emails, subject, message) email_course.recent_section = email_section.name email_course.put() elif action == 'toggle_anon': self.toggle_anonymity(instructor) elif action == 'toggle_round_structure': self.toggle_round_structure(instructor) else: # Send an error if any other action is supplied utils.error('Error! Unexpected action: ' + action, handler=self)