def get_podcast_episode(db: DatabaseHandler, stories_id: int) -> PodcastEpisode: """ Get podcast episode object for story ID. :param db: Database handler. :param stories_id: Story ID. :return: Podcast episode object. """ try: podcast_episodes = db.select( table='podcast_episodes', what_to_select='*', condition_hash={ 'stories_id': stories_id }, ).hashes() except Exception as ex: raise McPodcastDatabaseErrorException( f"Unable to fetch story's {stories_id} podcast episodes: {ex}") if not podcast_episodes: raise McPodcastNoEpisodesException( f"There are no podcast episodes for story {stories_id}") if len(podcast_episodes) > 1: # That's very weird, there should be only one episode per story raise McPodcastDatabaseErrorException( f"There's more than one podcast episode for story {stories_id}") try: episode = PodcastEpisode(stories_id=stories_id, db_row=podcast_episodes[0]) except Exception as ex: raise McPodcastInvalidInputException( f"Invalid episode for story {stories_id}: {ex}") if episode.duration > MAX_DURATION: raise McPodcastEpisodeTooLongException( f"Story's {stories_id} podcast episode is too long ({episode.duration} seconds)." ) return episode
def update_tags_for_story(self, db: DatabaseHandler, stories_id: int) -> None: """Add version, country and story tags for story.""" # MC_REWRITE_TO_PYTHON: remove after rewrite to Python if isinstance(stories_id, bytes): stories_id = decode_object_from_bytes_if_needed(stories_id) stories_id = int(stories_id) annotation = self.__annotation_store.fetch_annotation_for_story( db=db, stories_id=stories_id) if annotation is None: raise McJSONAnnotationTaggerException( "Unable to fetch annotation for story %d" % stories_id) tags = None try: tags = self._tags_for_annotation(annotation) except Exception as ex: # Programming error (should at least return an empty list) fatal_error("Unable to fetch tags for story %d: %s" % ( stories_id, str(ex), )) if tags is None: raise McJSONAnnotationTaggerException( "Returned tags is None for story %d." % stories_id) log.debug("Tags for story %d: %s" % ( stories_id, str(tags), )) db.begin() unique_tag_sets_names = set() for tag in tags: tag_sets_name = self.__strip_linebreaks_and_whitespace( tag.tag_sets_name) unique_tag_sets_names.add(tag_sets_name) # Delete old tags the story might have under a given tag set db.query( """ DELETE FROM stories_tags_map WHERE stories_id = %(stories_id)s AND tags_id IN ( SELECT tags_id FROM tags WHERE tag_sets_id IN ( SELECT tag_sets_id FROM tag_sets WHERE name = ANY(%(tag_sets_names)s) ) ) """, { 'stories_id': stories_id, 'tag_sets_names': list(unique_tag_sets_names) }) for tag in tags: tag_sets_name = self.__strip_linebreaks_and_whitespace( tag.tag_sets_name) tags_name = self.__strip_linebreaks_and_whitespace(tag.tags_name) # Not using find_or_create() because tag set / tag might already exist # with slightly different label / description # Find or create a tag set db_tag_set = db.select(table='tag_sets', what_to_select='*', condition_hash={ 'name': tag_sets_name }).hash() if db_tag_set is None: db.query( """ INSERT INTO tag_sets (name, label, description) VALUES (%(name)s, %(label)s, %(description)s) ON CONFLICT (name) DO NOTHING """, { 'name': tag_sets_name, 'label': tag.tag_sets_label, 'description': tag.tag_sets_description }) db_tag_set = db.select(table='tag_sets', what_to_select='*', condition_hash={ 'name': tag_sets_name }).hash() tag_sets_id = int(db_tag_set['tag_sets_id']) # Find or create tag db_tag = db.select(table='tags', what_to_select='*', condition_hash={ 'tag_sets_id': tag_sets_id, 'tag': tags_name, }).hash() if db_tag is None: db.query( """ INSERT INTO tags (tag_sets_id, tag, label, description) VALUES (%(tag_sets_id)s, %(tag)s, %(label)s, %(description)s) ON CONFLICT (tag, tag_sets_id) DO NOTHING """, { 'tag_sets_id': tag_sets_id, 'tag': tags_name, 'label': tag.tags_label, 'description': tag.tags_description, }) db_tag = db.select(table='tags', what_to_select='*', condition_hash={ 'tag_sets_id': tag_sets_id, 'tag': tags_name, }).hash() tags_id = int(db_tag['tags_id']) # Assign story to tag (if no such mapping exists yet) # # (partitioned table's INSERT trigger will take care of conflicts) # # Not using db.create() because it tests last_inserted_id, and on duplicates there would be no such # "last_inserted_id" set. db.query( """ INSERT INTO stories_tags_map (stories_id, tags_id) VALUES (%(stories_id)s, %(tags_id)s) """, { 'stories_id': stories_id, 'tags_id': tags_id, }) db.commit()
def update_tags_for_story(self, db: DatabaseHandler, stories_id: int) -> None: """Add version, country and story tags for story.""" if not self.annotator_is_enabled(): fatal_error("Annotator is not enabled in the configuration.") # MC_REWRITE_TO_PYTHON: remove after rewrite to Python if isinstance(stories_id, bytes): stories_id = decode_object_from_bytes_if_needed(stories_id) stories_id = int(stories_id) annotation = self.fetch_annotation_for_story(db=db, stories_id=stories_id) if annotation is None: raise McJSONAnnotatorException("Unable to fetch annotation for story %d" % stories_id) tags = None try: tags = self._tags_for_annotation(annotation) except Exception as ex: # Programming error (should at least return an empty list) fatal_error("Unable to fetch tags for story %d: %s" % (stories_id, str(ex),)) if tags is None: raise McJSONAnnotatorException("Returned tags is None for story %d." % stories_id) log.debug("Tags for story %d: %s" % (stories_id, str(tags),)) db.begin() unique_tag_sets_names = set() for tag in tags: tag_sets_name = self.__strip_linebreaks_and_whitespace(tag.tag_sets_name) unique_tag_sets_names.add(tag_sets_name) # Delete old tags the story might have under a given tag set db.query(""" DELETE FROM stories_tags_map WHERE stories_id = %(stories_id)s AND tags_id IN ( SELECT tags_id FROM tags WHERE tag_sets_id IN ( SELECT tag_sets_id FROM tag_sets WHERE name = ANY(%(tag_sets_names)s) ) ) """, {'stories_id': stories_id, 'tag_sets_names': list(unique_tag_sets_names)}) for tag in tags: tag_sets_name = self.__strip_linebreaks_and_whitespace(tag.tag_sets_name) tags_name = self.__strip_linebreaks_and_whitespace(tag.tags_name) # Not using find_or_create() because tag set / tag might already exist # with slightly different label / description # Find or create a tag set db_tag_set = db.select(table='tag_sets', what_to_select='*', condition_hash={'name': tag_sets_name}).hash() if db_tag_set is None: db.query(""" INSERT INTO tag_sets (name, label, description) VALUES (%(name)s, %(label)s, %(description)s) ON CONFLICT (name) DO NOTHING """, { 'name': tag_sets_name, 'label': tag.tag_sets_label, 'description': tag.tag_sets_description }) db_tag_set = db.select(table='tag_sets', what_to_select='*', condition_hash={'name': tag_sets_name}).hash() tag_sets_id = int(db_tag_set['tag_sets_id']) # Find or create tag db_tag = db.select(table='tags', what_to_select='*', condition_hash={ 'tag_sets_id': tag_sets_id, 'tag': tags_name, }).hash() if db_tag is None: db.query(""" INSERT INTO tags (tag_sets_id, tag, label, description) VALUES (%(tag_sets_id)s, %(tag)s, %(label)s, %(description)s) ON CONFLICT (tag, tag_sets_id) DO NOTHING """, { 'tag_sets_id': tag_sets_id, 'tag': tags_name, 'label': tag.tags_label, 'description': tag.tags_description, }) db_tag = db.select(table='tags', what_to_select='*', condition_hash={ 'tag_sets_id': tag_sets_id, 'tag': tags_name, }).hash() tags_id = int(db_tag['tags_id']) # Assign story to tag (if no such mapping exists yet) # (partitioned table's INSERT trigger will take care of conflicts) # # db.create() can't be used here because: # # 1) Master table for partitioned table might not have a primary key itself, only the partitions do -- # FIXME maybe master tables should have primary keys? Or let's wait for when we move to PostgreSQL 10+. # # 2) Partitioned table's INSERT trigger doesn't return last_inserted_id which db.create() requires # FIXME there might be a way for it to return the inserted row # db.query(""" INSERT INTO stories_tags_map (stories_id, tags_id) VALUES (%(stories_id)s, %(tags_id)s) """, { 'stories_id': stories_id, 'tags_id': tags_id, }) db.commit()
def update_tags_for_story(self, db: DatabaseHandler, stories_id: int) -> None: """Add version, country and story tags for story.""" if not self.annotator_is_enabled(): fatal_error("Annotator is not enabled in the configuration.") # MC_REWRITE_TO_PYTHON: remove after rewrite to Python if isinstance(stories_id, bytes): stories_id = decode_object_from_bytes_if_needed(stories_id) stories_id = int(stories_id) annotation = self.fetch_annotation_for_story(db=db, stories_id=stories_id) if annotation is None: raise McJSONAnnotatorException( "Unable to fetch annotation for story %d" % stories_id) tags = None try: tags = self._tags_for_annotation(annotation) except Exception as ex: # Programming error (should at least return an empty list) fatal_error("Unable to fetch tags for story %d: %s" % ( stories_id, str(ex), )) if tags is None: raise McJSONAnnotatorException( "Returned tags is None for story %d." % stories_id) log.debug("Tags for story %d: %s" % ( stories_id, str(tags), )) db.begin() # Delete old tags the story might have under a given tag set for tag in tags: tag_sets_name = self.__strip_linebreaks_and_whitespace( tag.tag_sets_name) db.query( """ DELETE FROM stories_tags_map USING tags, tag_sets WHERE stories_tags_map.tags_id = tags.tags_id AND tags.tag_sets_id = tag_sets.tag_sets_id AND stories_tags_map.stories_id = %(stories_id)s AND tag_sets.name = %(tag_sets_name)s """, { 'stories_id': stories_id, 'tag_sets_name': tag_sets_name }) for tag in tags: tag_sets_name = self.__strip_linebreaks_and_whitespace( tag.tag_sets_name) tags_name = self.__strip_linebreaks_and_whitespace(tag.tags_name) # Not using find_or_create() because tag set / tag might already exist # with slightly different label / description # Create tag set db_tag_set = db.select(table='tag_sets', what_to_select='*', condition_hash={ 'name': tag_sets_name }).hash() if db_tag_set is None: db.query( """ INSERT INTO tag_sets (name, label, description) VALUES (%(name)s, %(label)s, %(description)s) ON CONFLICT (name) DO NOTHING """, { 'name': tag_sets_name, 'label': tag.tag_sets_label, 'description': tag.tag_sets_description }) db_tag_set = db.select(table='tag_sets', what_to_select='*', condition_hash={ 'name': tag_sets_name }).hash() tag_sets_id = int(db_tag_set['tag_sets_id']) # Create tag db_tag = db.select(table='tags', what_to_select='*', condition_hash={ 'tag_sets_id': tag_sets_id, 'tag': tags_name, }).hash() if db_tag is None: db.query( """ INSERT INTO tags (tag_sets_id, tag, label, description) VALUES (%(tag_sets_id)s, %(tag)s, %(label)s, %(description)s) ON CONFLICT (tag, tag_sets_id) DO NOTHING """, { 'tag_sets_id': tag_sets_id, 'tag': tags_name, 'label': tag.tags_label, 'description': tag.tags_description, }) db_tag = db.select(table='tags', what_to_select='*', condition_hash={ 'tag_sets_id': tag_sets_id, 'tag': tags_name, }).hash() tags_id = int(db_tag['tags_id']) # Assign story to tag (if no such mapping exists yet) db.query( """ INSERT INTO stories_tags_map (stories_id, tags_id) VALUES (%(stories_id)s, %(tags_id)s) ON CONFLICT (stories_id, tags_id) DO NOTHING """, { 'stories_id': stories_id, 'tags_id': tags_id, }) db.commit()