Example #1
0
class PiazzaScanner:
  """
  Scans piazza and answers unanswered questions. Should be run in cron.
  """
  def __init__(self, username, password, course_id, es_metadata_host,
               es_metadata_index, es_metadata_type, es_question_host,
               es_question_index, es_question_type, query_function):
    self.piazza = PiazzaAPI(username, password)
    self.course_id = course_id
    self.es_metadata = Elasticsearch(es_metadata_host)
    self.es_metadata_index = es_metadata_index
    self.es_metadata_type = es_metadata_type
    self.es_question_host = es_question_host
    self.es_question_index = es_question_index
    self.es_question_type = es_question_type
    self.query_function = query_function

  def run(self):
    """
    Runs the Scanner from the last_id, answering all new questions in a
    followup post.
    """
    self.answer_questions(self.get_new_questions())

  def answer_questions(self, questions):
    """
    Answers questions given a list of question objects.
    """
    for question in questions:
      answers = get_answers(self.es_question_host, self.es_question_index,
                            self.es_question_type, question, 10,
                            self.query_function)
      response = self.generate_response_string(answers)
      if response:
        self.piazza.post_followup(self.course_id, response, cid=question['cid'])

  def generate_response_string(self, answers):
    """
    Generates a response string message with the answers object.
    """
    response = ''
    if len(answers) > 0:
      response += answers[0][1]
    if response:
      response += ('<p>\n</p>--This is an autogenerated message. If it\'s' +
                   ' helpful please comment a \'+1\'. Otherwise comment a ' +
                   ' \'-1\'. Thank you. <3.')
    return response

  def get_new_questions(self):
    """
    Returns list of all unanswered question objects from last_id.
    """
    last_id = self.get_last_id()
    failed_reads = 0
    curr_id = last_id
    new_questions = []

    while failed_reads < 5:
      curr_id += 1
      new_data = self.piazza.get_question_data(curr_id, self.course_id)
      if ('error' in new_data and
          new_data['error'] == 'Content_id out of range.'):
        failed_reads += 1
      elif 'error' not in new_data:
        failed_reads = 0
        last_id = curr_id
        new_questions.append(new_data)

    self.write_last_id(last_id)
    return new_questions

  def get_last_id(self):
    """
    Reads the last_id from the elasticsearch store.
    """
    return self.es_metadata.get(index=self.es_metadata_index,
                                doc_type=self.es_metadata_type,
                                id=1)['_source']['last_read']

  def write_last_id(self, last_id):
    """
    Writes the new value of last_id to elasticsearch store.
    """
    self.es_metadata.update(index=self.es_metadata_index,
                            doc_type=self.es_metadata_type, id=1,
                            body='{"doc":{"last_read": %s}}' % last_id)