def get(self): """Handles GET requests.""" # TODO(sll): Get the 50 most recent failed shards, not all of them. failed_jobs = jobs.get_stuck_jobs(TWENTY_FIVE_HOURS_IN_MSECS) if failed_jobs: email_subject = 'MapReduce failure alert' email_message = ( '%s jobs have failed in the past 25 hours. More information ' '(about at most %s jobs; to see more, please check the logs):' ) % (len(failed_jobs), MAX_JOBS_TO_REPORT_ON) for job in failed_jobs[:MAX_JOBS_TO_REPORT_ON]: email_message += '\n' email_message += '-----------------------------------' email_message += '\n' email_message += ( 'Job with mapreduce ID %s (key name %s) failed. ' 'More info:\n\n' ' counters_map: %s\n' ' shard_retries: %s\n' ' slice_retries: %s\n' ' last_update_time: %s\n' ' last_work_item: %s\n' ) % ( job.mapreduce_id, job.key().name(), job.counters_map, job.retries, job.slice_retries, job.update_time, job.last_work_item ) else: email_subject = 'MapReduce status report' email_message = 'All MapReduce jobs are running fine.' email_manager.send_mail_to_admin(email_subject, email_message)
def put(self, topic_id): """Returns the TopicRights object of a topic.""" topic_url = feconf.TOPIC_EDITOR_URL_PREFIX + '/' + topic_id if feconf.CAN_SEND_EMAILS: email_manager.send_mail_to_admin( 'Request to review and publish a topic', '%s wants to publish topic: %s at URL %s, please review' ' and publish if it looks good.' % (self.username, self.payload.get('topic_name'), topic_url)) self.render_json(self.values)
def get(self, topic_id): """Populates the data on the individual topic page.""" topic = topic_fetchers.get_topic_by_id(topic_id, strict=False) if topic is None: raise self.PageNotFoundException( Exception('The topic with the given id doesn\'t exist.')) skill_id_to_description_dict, deleted_skill_ids = ( skill_services.get_descriptions_of_skills( topic.get_all_skill_ids())) topics = topic_fetchers.get_all_topics() grouped_skill_summary_dicts = {} skill_id_to_rubrics_dict = {} for topic_object in topics: skill_id_to_rubrics_dict_local, deleted_skill_ids = ( skill_services.get_rubrics_of_skills( topic_object.get_all_skill_ids())) skill_id_to_rubrics_dict.update(skill_id_to_rubrics_dict_local) if deleted_skill_ids: deleted_skills_string = ', '.join(deleted_skill_ids) logging.error( 'The deleted skills: %s are still present in topic with ' 'id %s' % (deleted_skills_string, topic_id)) if feconf.CAN_SEND_EMAILS: email_manager.send_mail_to_admin( 'Deleted skills present in topic', 'The deleted skills: %s are still present in ' 'topic with id %s' % (deleted_skills_string, topic_id)) skill_summaries = skill_services.get_multi_skill_summaries( topic_object.get_all_skill_ids()) skill_summary_dicts = [ summary.to_dict() for summary in skill_summaries ] grouped_skill_summary_dicts[ topic_object.name] = skill_summary_dicts self.values.update({ 'topic_dict': topic.to_dict(), 'grouped_skill_summary_dicts': grouped_skill_summary_dicts, 'skill_id_to_description_dict': skill_id_to_description_dict, 'skill_id_to_rubrics_dict': skill_id_to_rubrics_dict }) self.render_json(self.values)
def handle_exception(self, exception, unused_debug_mode): """Overwrite the default exception handler. Args: exception: Exception. The exception that was thrown. unused_debug_mode: bool. True if the web application is running in debug mode. """ email_subject = 'Oppia Foundation website exception stacktrace' stacktrace_contents = ''.join( traceback.format_exception(*sys.exc_info())) logging.info(stacktrace_contents) logging.error('Exception raised: %s', exception) email_manager.send_mail_to_admin(email_subject, stacktrace_contents, config.NO_REPLY_EMAIL_ADDRESS) self.error(500)
def post(self): """Handle POST requests.""" payload = json.loads(self.request.body) if 'email_type' not in payload: email_type = config.EMAIL_TYPE_DEFAULT else: email_type = payload['email_type'] email_subject = ForwardToAdminEmailHandler.write_email_subject( email_type) if 'organization' not in payload: user_organization = None else: user_organization = payload['organization'] email_contents = ForwardToAdminEmailHandler.write_email_contents( payload['comment'], user_organization) email_manager.send_mail_to_admin( email_subject, email_contents, payload['email']) self.render_json({})
def get_skill_descriptions_by_ids(topic_id, skill_ids): """Returns a list of skill descriptions corresponding to given skill ids. Args: topic_id: str. The id of the topic that these skills are a part of. skill_ids: list(str). The list of skill ids. Returns: dict. The skill descriptions of skills keyed by their corresponding ids. """ skill_summary_models = skill_models.SkillSummaryModel.get_multi(skill_ids) skill_id_to_description_dict = {} for skill_summary_model in skill_summary_models: if skill_summary_model is not None: skill_id_to_description_dict[skill_summary_model.id] = ( skill_summary_model.description) deleted_skill_ids = [] for skill_id in skill_ids: if skill_id not in skill_id_to_description_dict: skill_id_to_description_dict[skill_id] = None deleted_skill_ids.append(skill_id) if deleted_skill_ids: deleted_skills_string = ', '.join(deleted_skill_ids) logging.error( 'The deleted skills: %s are still present in topic with id %s' % (deleted_skills_string, topic_id) ) if feconf.CAN_SEND_EMAILS: email_manager.send_mail_to_admin( 'Deleted skills present in topic', 'The deleted skills: %s are still present in topic with id %s' % (deleted_skills_string, topic_id)) return skill_id_to_description_dict
def put(self, topic_id): """Updates properties of the given topic. Also, each change_dict given for editing should have an additional property called is_topic_change, which would be a boolean. If True, it means that change is for a topic (includes adding and removing subtopics), while False would mean it is for a Subtopic Page (this includes editing its html data as of now). """ topic = topic_fetchers.get_topic_by_id(topic_id, strict=False) version = self.payload.get('version') self._require_valid_version(version, topic.version) commit_message = self.payload.get('commit_message') if (commit_message is not None and len(commit_message) > constants.MAX_COMMIT_MESSAGE_LENGTH): raise self.InvalidInputException( 'Commit messages must be at most %s characters long.' % constants.MAX_COMMIT_MESSAGE_LENGTH) topic_and_subtopic_page_change_dicts = self.payload.get( 'topic_and_subtopic_page_change_dicts') topic_and_subtopic_page_change_list = [] for change in topic_and_subtopic_page_change_dicts: if change['cmd'] == ( subtopic_page_domain.CMD_UPDATE_SUBTOPIC_PAGE_PROPERTY): topic_and_subtopic_page_change_list.append( subtopic_page_domain.SubtopicPageChange(change)) else: topic_and_subtopic_page_change_list.append( topic_domain.TopicChange(change)) try: topic_services.update_topic_and_subtopic_pages( self.user_id, topic_id, topic_and_subtopic_page_change_list, commit_message) except utils.ValidationError as e: raise self.InvalidInputException(e) topic = topic_fetchers.get_topic_by_id(topic_id, strict=False) skill_id_to_description_dict, deleted_skill_ids = ( skill_services.get_descriptions_of_skills( topic.get_all_skill_ids())) skill_id_to_rubrics_dict, deleted_skill_ids = ( skill_services.get_rubrics_of_skills(topic.get_all_skill_ids()) ) if deleted_skill_ids: deleted_skills_string = ', '.join(deleted_skill_ids) logging.error( 'The deleted skills: %s are still present in topic with id %s' % (deleted_skills_string, topic_id) ) if feconf.CAN_SEND_EMAILS: email_manager.send_mail_to_admin( 'Deleted skills present in topic', 'The deleted skills: %s are still present in topic with ' 'id %s' % (deleted_skills_string, topic_id)) self.values.update({ 'topic_dict': topic.to_dict(), 'skill_id_to_description_dict': skill_id_to_description_dict, 'skill_id_to_rubrics_dict': skill_id_to_rubrics_dict }) self.render_json(self.values)
def get(self, topic_id): """Populates the data on the individual topic page.""" topic = topic_fetchers.get_topic_by_id(topic_id, strict=False) if topic is None: raise self.PageNotFoundException( Exception('The topic with the given id doesn\'t exist.')) skill_id_to_description_dict, deleted_skill_ids = ( skill_services.get_descriptions_of_skills( topic.get_all_skill_ids())) topics = topic_fetchers.get_all_topics() grouped_skill_summary_dicts = {} skill_id_to_rubrics_dict = {} for topic_object in topics: skill_id_to_rubrics_dict_local, deleted_skill_ids = ( skill_services.get_rubrics_of_skills( topic_object.get_all_skill_ids()) ) skill_id_to_rubrics_dict.update(skill_id_to_rubrics_dict_local) if deleted_skill_ids: deleted_skills_string = ', '.join(deleted_skill_ids) logging.error( 'The deleted skills: %s are still present in topic with ' 'id %s' % (deleted_skills_string, topic_id) ) if feconf.CAN_SEND_EMAILS: email_manager.send_mail_to_admin( 'Deleted skills present in topic', 'The deleted skills: %s are still present in ' 'topic with id %s' % (deleted_skills_string, topic_id)) skill_summaries = skill_services.get_multi_skill_summaries( topic_object.get_all_skill_ids()) skill_summary_dicts = [ summary.to_dict() for summary in skill_summaries] grouped_skill_summary_dicts[topic_object.name] = skill_summary_dicts classroom_url_fragment = ( classroom_services.get_classroom_url_fragment_for_topic_id( topic_id)) skill_question_count_dict = {} for skill_id in topic.get_all_skill_ids(): skill_question_count_dict[skill_id] = ( question_services.get_total_question_count_for_skill_ids( [skill_id])) skill_creation_is_allowed = ( role_services.ACTION_CREATE_NEW_SKILL in self.user.actions) self.values.update({ 'classroom_url_fragment': classroom_url_fragment, 'topic_dict': topic.to_dict(), 'grouped_skill_summary_dicts': grouped_skill_summary_dicts, 'skill_question_count_dict': skill_question_count_dict, 'skill_id_to_description_dict': skill_id_to_description_dict, 'skill_id_to_rubrics_dict': skill_id_to_rubrics_dict, 'skill_creation_is_allowed': skill_creation_is_allowed }) self.render_json(self.values)
def get(self, topic_name): """Handles GET requests.""" topic = topic_fetchers.get_topic_by_name(topic_name) canonical_story_ids = topic.get_canonical_story_ids( include_only_published=True) additional_story_ids = topic.get_additional_story_ids( include_only_published=True) canonical_story_summaries = [ story_fetchers.get_story_summary_by_id( canonical_story_id) for canonical_story_id in canonical_story_ids] additional_story_summaries = [ story_fetchers.get_story_summary_by_id( additional_story_id) for additional_story_id in additional_story_ids] canonical_story_dicts = [] for story_summary in canonical_story_summaries: completed_node_titles = [ completed_node.title for completed_node in story_fetchers.get_completed_nodes_in_story( self.user_id, story_summary.id)] story_summary_dict = story_summary.to_human_readable_dict() story_summary_dict['story_is_published'] = True story_summary_dict['completed_node_titles'] = completed_node_titles canonical_story_dicts.append(story_summary_dict) additional_story_dicts = [] for story_summary in additional_story_summaries: completed_node_titles = [ completed_node.title for completed_node in story_fetchers.get_completed_nodes_in_story( self.user_id, story_summary.id)] story_summary_dict = story_summary.to_human_readable_dict() story_summary_dict['story_is_published'] = True story_summary_dict['completed_node_titles'] = completed_node_titles additional_story_dicts.append(story_summary_dict) uncategorized_skill_ids = topic.get_all_uncategorized_skill_ids() subtopics = topic.get_all_subtopics() all_skill_ids = topic.get_all_skill_ids() skill_descriptions, deleted_skill_ids = ( skill_services.get_descriptions_of_skills( all_skill_ids)) if deleted_skill_ids: deleted_skills_string = ', '.join(deleted_skill_ids) logging.error( 'The deleted skills: %s are still present in topic with id %s' % (deleted_skills_string, topic.id) ) if feconf.CAN_SEND_EMAILS: email_manager.send_mail_to_admin( 'Deleted skills present in topic', 'The deleted skills: %s are still present in topic with ' 'id %s' % (deleted_skills_string, topic.id)) if self.user_id: degrees_of_mastery = skill_services.get_multi_user_skill_mastery( self.user_id, all_skill_ids) else: degrees_of_mastery = {} for skill_id in all_skill_ids: degrees_of_mastery[skill_id] = None self.values.update({ 'topic_id': topic.id, 'topic_name': topic.name, 'topic_description': topic.description, 'canonical_story_dicts': canonical_story_dicts, 'additional_story_dicts': additional_story_dicts, 'uncategorized_skill_ids': uncategorized_skill_ids, 'subtopics': subtopics, 'degrees_of_mastery': degrees_of_mastery, 'skill_descriptions': skill_descriptions, 'practice_tab_is_displayed': topic.practice_tab_is_displayed }) self.render_json(self.values)
def get(self, topic_name): """Handles GET requests.""" if not constants.ENABLE_NEW_STRUCTURE_PLAYERS: raise self.PageNotFoundException topic = topic_fetchers.get_topic_by_name(topic_name) canonical_story_ids = topic.get_canonical_story_ids( include_only_published=True) additional_story_ids = topic.get_additional_story_ids( include_only_published=True) canonical_story_summaries = [ story_fetchers.get_story_summary_by_id(canonical_story_id) for canonical_story_id in canonical_story_ids ] additional_story_summaries = [ story_fetchers.get_story_summary_by_id(additional_story_id) for additional_story_id in additional_story_ids ] canonical_story_dicts = [ summary.to_human_readable_dict() for summary in canonical_story_summaries ] additional_story_dicts = [ summary.to_human_readable_dict() for summary in additional_story_summaries ] uncategorized_skill_ids = topic.get_all_uncategorized_skill_ids() subtopics = topic.get_all_subtopics() assigned_skill_ids = topic.get_all_skill_ids() skill_descriptions, deleted_skill_ids = ( skill_services.get_descriptions_of_skills(assigned_skill_ids)) if deleted_skill_ids: deleted_skills_string = ', '.join(deleted_skill_ids) logging.error( 'The deleted skills: %s are still present in topic with id %s' % (deleted_skills_string, topic.id)) if feconf.CAN_SEND_EMAILS: email_manager.send_mail_to_admin( 'Deleted skills present in topic', 'The deleted skills: %s are still present in topic with ' 'id %s' % (deleted_skills_string, topic.id)) if self.user_id: degrees_of_mastery = skill_services.get_multi_user_skill_mastery( self.user_id, assigned_skill_ids) else: degrees_of_mastery = {} for skill_id in assigned_skill_ids: degrees_of_mastery[skill_id] = None self.values.update({ 'topic_id': topic.id, 'topic_name': topic.name, 'canonical_story_dicts': canonical_story_dicts, 'additional_story_dicts': additional_story_dicts, 'uncategorized_skill_ids': uncategorized_skill_ids, 'subtopics': subtopics, 'degrees_of_mastery': degrees_of_mastery, 'skill_descriptions': skill_descriptions }) self.render_json(self.values)