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)