@@ -695,3 +695,109 @@ def takeovers_healthcheck(self, metadata, topic_id, title=None):
695695 raise MarkdownError ((", " ).join (errors ))
696696
697697 pass
698+
699+
700+ class Category (Discourse ):
701+ """
702+ Given a category id and CategoryParser takes any data tables found in the
703+ index topic and stores the data in a dictionary.
704+ Builds a URL map of all topics in the category.
705+ Returns a Flask view function to serve a topics from a Discourse category
706+ depending on the path.
707+
708+ :param parser: A HTML parse class
709+ :param category_id: ID of a Discourse category
710+ :param url_prefix: URL prefix on project
711+ :param document_template: Path to a template to render page
712+ :param blueprint_name: Name of the Flask blueprint
713+ :param exclude_topics: Skip given posts from throwing errors
714+ """
715+
716+ def __init__ (
717+ self ,
718+ parser ,
719+ category_id ,
720+ url_prefix ,
721+ document_template ,
722+ blueprint_name ,
723+ exclude_topics = [],
724+ ):
725+ super ().__init__ (parser , document_template , url_prefix , blueprint_name )
726+ self .parser = parser
727+ self .category_id = category_id
728+ self .exclude_topics = exclude_topics
729+ self .category_topics = []
730+ self .parser .parse_index_topic ()
731+ pass
732+
733+ @self .blueprint .route ("/" )
734+ @self .blueprint .route ("/<path:path>" )
735+ def document_view (path = "" ):
736+ """
737+ A Flask view function to serve topics from a Discourse category
738+ """
739+ path = "/" + path
740+ if path == "/" :
741+ document = self .parser .parse_topic (self .parser .index_topic )
742+ else :
743+ try :
744+ topic_id = self ._get_topic_id_from_path (path )
745+ except PathNotFoundError :
746+ return flask .abort (404 )
747+
748+ if topic_id == self .parser .index_topic_id :
749+ return flask .redirect (self .url_prefix )
750+
751+ try :
752+ topic = self .parser .api .get_topic (topic_id )
753+ except HTTPError as http_error :
754+ return flask .abort (http_error .response .status_code )
755+
756+ document = self .parser .parse_topic (topic )
757+
758+ template = flask .render_template (
759+ document_template ,
760+ category_index_metadata = self .parser .category_index_metadata ,
761+ document = document ,
762+ )
763+ return flask .make_response (template )
764+
765+ def _get_topic_id_from_path (self , path ):
766+ path = path .lstrip ("/" )
767+ category_topics = self ._query_category_topics ()
768+ for topic in category_topics :
769+ if topic [2 ] == path :
770+ return topic [0 ]
771+ return None
772+
773+ def get_category_index_metadata (self , data_name ):
774+ """
775+ Exposes an API to query category metadata
776+
777+ :param data_name: Name of the data table
778+ """
779+ if data_name :
780+ return self .parser .category_index_metadata [data_name ]
781+ else :
782+ return self .parser .category_index_metadata
783+
784+ def get_topics_in_category (self ):
785+ """
786+ Exposes an API to query all topics in a category
787+ """
788+ topics_list = self ._query_category_topics ()
789+ topics_map = {str (topic [0 ]): topic [2 ] for topic in topics_list }
790+ return topics_map
791+
792+ def _query_category_topics (self ):
793+ """
794+ Retrieve the category topics list from the api and store it.
795+ On subsequent calls, return the stored list.
796+ """
797+ if self .category_topics :
798+ return self .category_topics
799+ else :
800+ self .category_topics = self .parser .api .get_topic_list_by_category (
801+ self .category_id
802+ )
803+ return self .category_topics
0 commit comments