def __init__(self, config: Config): self.config = config self.cache: Cache = Cache.instance(self) self.exclusions: List[Pattern] = list( map(lambda e: re.compile(e), config.get('content', 'exclusions'))) self.root_path: Path = Path(config.get('content', 'root')).resolve() self.root: Directory = Directory(self) self.theme: Theme = Theme(self) self.auth_provider: AuthProvider = AuthProvider.instance(self)
def test_serve_non_markdown_file(): markdownup = MarkdownUp( Config.from_dict({ 'content': { 'root': str( Path(__file__).parent / '..' / '..' / 'test_resources' / 'dummy_docs') } })) response = markdownup.get('/dummy-asset.txt') assert response.status == '200 OK' assert next(response.body).decode('UTF-8') == 'Dummy asset content.'
def test_prevent_access_outside_root(): markdownup = MarkdownUp( Config.from_dict({ 'content': { 'root': str( Path(__file__).parent / '..' / '..' / 'test_resources' / 'dummy_docs' / 'subdir') } })) response = markdownup.get('../index.md') assert response.status == '400 Bad Request' assert response.body[0] == b'400 Bad Request'
def test_search(): markdownup = MarkdownUp( Config.from_dict({ 'content': { 'root': str( Path(__file__).parent / '..' / '..' / 'test_resources' / 'dummy_docs') } })) results = search(markdownup, {'auth': {}}, ["THIS"]) assert len(results) == 2 assert results[0].name == 'Hello, World!' assert results[1].name == 'Hello, nested World!'
def test_hidden_file_request_yields_404(): # 404 because we don't want to expose the fact it exists markdownup = MarkdownUp( Config.from_dict({ 'content': { 'root': str( Path(__file__).parent / '..' / '..' / 'test_resources' / 'dummy_docs') } })) response = markdownup.get('/.hidden.md') assert response.status == '404 Not Found'
def test_get(): markdownup = MarkdownUp( Config.from_dict({ 'theme': 'bare', 'content': { 'root': str( Path(__file__).parent / '..' / '..' / 'test_resources' / 'dummy_docs'), 'indices': [] } })) response = markdownup.get('/index.md') assert response.status == '200 OK' assert response.body[ 0] == b'<h1>Hello, World!</h1>\n<p>This is a markdown file.</p>'
def test_get_hidden_file_with_proper_config(): markdownup = MarkdownUp( Config.from_dict({ 'theme': 'bare', 'content': { 'root': str( Path(__file__).parent / '..' / '..' / 'test_resources' / 'dummy_docs'), 'exclusions': [] } })) response = markdownup.get('/.hidden.md') assert response.status == '200 OK' assert response.body[ 0] == b'<p>This file must not be served with the default configuration.</p>'
def test_get_theme_asset(): markdownup = MarkdownUp( Config.from_dict({ 'theme': str( Path(__file__).parent / '..' / '..' / 'test_resources' / 'test_theme'), 'content': { 'root': str( Path(__file__).parent / '..' / '..' / 'test_resources' / 'dummy_docs') } })) response = markdownup.get('/frame.css') assert response.status == '200 OK' assert next(response.body).decode('UTF-8') == 'p { color: #111; }'
def test_title_not_on_first_line(): markdownup = MarkdownUp( Config.from_dict({ 'theme': str( Path(__file__).parent / '..' / '..' / 'test_resources' / 'test_theme'), 'content': { 'root': str( Path(__file__).parent / '..' / '..' / 'test_resources' / 'dummy_docs') } })) response = markdownup.get('/title_not_on_first_line.md') assert response.status == '200 OK' assert response.body[ 0] == b'Title goes here: Title\n\nContent goes here:\n\n<p>Some text first.</p>\n<h1>Title</h1>'
def test_search_with_auth(): markdownup = MarkdownUp( Config.from_dict({ 'content': { 'root': str( Path(__file__).parent / '..' / '..' / 'test_resources' / 'dummy_docs'), } })) results = search(markdownup, {'auth': { 'authenticated': { 'roles': {'keepers'} } }}, ["THIS"]) assert len(results) == 3 assert results[0].name == 'Hello, World!' assert results[1].name == 'Hello, nested World!' assert results[2].name == 'Hello, secret nested World!'
def __init__(self, config: Config): super().__init__( (config.get('cache', 'host'), config.get('cache', 'port')), _BuiltinCacheHandler) self.cache = {}
def _main(): if len(sys.argv) == 2: # initialize config based on argv config = None as_path = Path(sys.argv[1]) if as_path.is_dir(): config = Config.from_dict({'content': {'root': sys.argv[1]}}) elif as_path.is_file(): config = Config.from_file(as_path) os.chdir( as_path.parent) # pretend to run from the config's parent dir else: print(f'No such file or directory: {as_path}') exit(1) # launch a new process for the built in cache server if configured if config.get('cache', 'type') == 'builtin': Process(daemon=True, target=BuiltinCacheServer(config).serve_forever).start() # TODO if configured process and cache all markdown files # launch the main MarkdownUp WSGI application markdownup = MarkdownUp(config) Process(target=WsgiApplication(markdownup).run).start() signal.pause( ) # sleep indefinitely, makes for a cleaner ctrl+c termination # if the above returns we exit normally exit(0) if len(sys.argv) > 2: if sys.argv[1] == '--start-config': config = yaml.dump(default_config) target_file = Path(sys.argv[2]) if target_file.exists(): print('Target file exists, not doing anything') exit(2) target_file.write_text(config) exit(0) elif sys.argv[1] == '--start-theme': target_dir = Path(sys.argv[2]) if target_dir.exists(): print('Target dir exists, not doing anything') exit(3) theme_name = 'default' if len(sys.argv) == 3 else sys.argv[3] theme_dir = Path(__file__).parent / 'themes' / theme_name if not theme_dir.exists(): theme_names = ', '.join( theme.name for theme in theme_dir.parent.iterdir() if theme.is_dir()) print(f'No such theme "{theme_name}", themes: {theme_names}') exit(4) shutil.copytree(theme_dir, target_dir) exit(0) print('Usage option 1: <path-to-markdown-root-directory>\n' 'Usage option 2: <path-to-config-file>\n' 'Usage option 3: --start-config <path-to-new-file>\n' 'Usage option 4: --start-theme <path-to-new-theme> [<seed-theme>]') exit(5)