""" Manage the ASOP. """ import os from flask import jsonify, render_template_string, send_from_directory, url_for, abort from werkzeug.utils import safe_join from asl_rulebook2.webapp import app from asl_rulebook2.webapp.content import tag_ruleids from asl_rulebook2.webapp.utils import load_data_file _asop = None _asop_dir = None _asop_preambles = None _asop_section_content = None _footer = None user_css_url = None # --------------------------------------------------------------------- def init_asop( startup_msgs, logger ): """Initialize the ASOP.""" # initiailize global _asop, _asop_dir, _asop_preambles, _asop_section_content, _footer, user_css_url _asop, _asop_preambles, _asop_section_content, _footer = {}, {}, {}, "" # get the data directory data_dir = app.config.get( "DATA_DIR" ) if not data_dir: return None, None, None, None dname = os.path.join( data_dir, "asop/" ) if not os.path.isdir( dname ): return None, None, None, None # NOTE: We need to resolve symlinks, since we use send_from_directory() to serve files, and it doesn't allow # symlinks that point outside of the base directory (e.g. asop/ in the "full" fixtures data set). _asop_dir = os.path.realpath( dname ) fname = os.path.join( _asop_dir, "asop.css" ) if os.path.isfile( fname ): user_css_url = url_for( "get_asop_file", path="asop.css" ) # initialize asop_fnames = [] # load the ASOP index fname = os.path.join( _asop_dir, "index.json" ) _asop = load_data_file( fname, "ASOP index", "json", logger, startup_msgs.error ) if not _asop: return None, None, None, None asop_fnames.append( fname ) # load the ASOP content for chapter in _asop.get( "chapters", [] ): chapter_id = chapter[ "chapter_id" ] # load the chapter preamble fname, preamble = _render_template( chapter_id + "-0.html" ) if preamble: _asop_preambles[chapter_id] = preamble asop_fnames.append( fname ) # load the content for each section for section_no, section in enumerate( chapter.get( "sections", [] ) ): section_id = "{}-{}".format( chapter_id, 1+section_no ) section[ "section_id" ] = section_id fname, content = _render_template( section_id + ".html" ) if content: _asop_section_content[ section_id ] = content asop_fnames.append( fname ) # load the ASOP footer fname, footer = _render_template( "footer.html" ) _footer = tag_ruleids( footer, None ) if _footer: asop_fnames.append( fname ) return _asop, _asop_preambles, _asop_section_content, asop_fnames # --------------------------------------------------------------------- @app.route( "/asop" ) def get_asop(): """Return the ASOP.""" return jsonify( _asop ) @app.route( "/asop/intro" ) def get_asop_intro(): """Return the ASOP intro.""" _, resp = _render_template( "intro.html" ) if not resp: return "No ASOP intro." return resp @app.route( "/asop/footer" ) def get_asop_footer(): """Return the ASOP footer.""" if not _footer: abort( 404 ) return _footer @app.route( "/asop/preamble/" ) def get_asop_preamble( chapter_id ): """Return the specified ASOP chapter preamble.""" content = _asop_preambles.get( chapter_id ) if not content: abort( 404 ) return content @app.route( "/asop/section/" ) def get_asop_section( section_id ): """Return the specified ASOP section.""" content = _asop_section_content.get( section_id ) if not content: abort( 404 ) return content @app.route( "/asop/" ) def get_asop_file( path ): """Return a user-defined ASOP file.""" return send_from_directory( _asop_dir, path ) # --------------------------------------------------------------------- def _render_template( fname ): """Render an ASOP template.""" if not _asop_dir: return None, None fname = safe_join( _asop_dir, fname ) if not os.path.isfile( fname ): return None, None args = { "ASOP_BASE_URL": url_for( "get_asop_file", path="" ), } args.update( _asop.get( "template_args", {} ) ) with open( fname, "r", encoding="utf-8" ) as fp: return fname, render_template_string( fp.read(), **args )