def make_tag_list(self, tag_id, number): tag_id = Path.urldecode(tag_id) conf = self.blog.default_conf list_size = conf('local.list_size') bundle = self.blog.post_bundle.bundle_list tagged = [ post for post in bundle.values() if not post.hidden and tag_id in post.tags ] list_count = int(math.ceil(float(len(tagged)) / float(list_size))) if not 0 < number <= list_count: abort(404) if tagged is None or list_count < 1: abort(404) post_list = tagged[ list_size * (number - 1):list_size * number ] for post in post_list: post = self.blog.plugin_manager.do_filter('dx_post', post) prev_page = next_page = True if number == 1: prev_page = False if number == list_count: next_page = False list_url = Path.format_url(self.tags_url, tag_id) url = list_url if list_url.endswith('/') else list_url + '/' web_title = self.i18n.get('{0} - Page {1}', tag_id, number) return self.blog.get_render( 'list.html', posts=post_list, list_id=number, list_url=url, prev_page=prev_page, next_page=next_page, web_title=web_title)
def init_runtime(self): '''Initialize runtime environments of DelogX.''' conf = self.default_conf runtime = self.runtime app_path = runtime.get('path.app') module_path = runtime.get('path.module') init_path_list = [ 'directory.post', 'directory.page', 'directory.static', 'directory.themes', 'directory.plugins' ] init_url_list = [ 'url_prefix.post', 'url_prefix.page', 'url_prefix.static', 'url_prefix.post_list' ] for key in init_path_list: runtime.let(key, Path.abs_path(app_path, conf(key))) for key in init_url_list: runtime.let(key, Path.format_url(conf(key))) themes_dir = runtime.get('directory.themes') theme = conf('local.theme') theme = 'default' if not theme else theme theme_path = os.path.join(themes_dir, theme) self.framework.template_folder = theme_path self.i18n = I18n( Path.format_url(module_path, 'locale'), conf('local.locale'))
def load_meta(self): '''Load the meta of this item, include `hidden`, `url` and `title`.''' if not self.valid(): return self.hidden = self.filename.startswith('.') self.url = os.path.splitext(self.filename)[0] if self.hidden: self.url = self.url[1:] atx_re = re.compile(r'^\s*#\s*([^#]+)\s*#*\s*$') setext_re = re.compile(r'^\s*=+\s*$') lines = Path.read_file(self.path) first_line = Path.get_first_line(lines) line1 = lines[first_line] if first_line < len(lines) else '' line2 = lines[first_line + 1] if first_line + 1 < len(lines) else '' line1 = line1.strip('\n').strip('\r') line2 = line2.strip('\n').strip('\r') atx_match = atx_re.match(line1) setext_match = setext_re.match(line2) if atx_match and atx_match.group(1): self.title = atx_match.group(1) self.title_line = first_line + 1 elif setext_match and line1.strip(): self.title = line1 self.title_line = first_line + 2 else: self.title = self.url self.title_line = 0
def run(self): conf = self.blog.default_conf self.config = Config(os.path.join(self.workspace, 'config.json')) self.i18n = I18n( Path.format_url(self.workspace, 'locale'), conf('local.locale')) self.tags_url = self.config.get('delog_tags.url') if not self.tags_url: self.tags_url = '/tag' self.tags_url = Path.format_url(self.tags_url) tag_rule = Path.format_url(self.tags_url, '<tag_id>/') tag_list_rule = Path.format_url(tag_rule, '<int:number>/') self.blog.add_url_rule(tag_rule, 'delog_tag', self.make_tag) self.blog.add_url_rule( tag_list_rule, 'delog_tag_list', self.make_tag_list) self.manager.add_action('dx_post_update', self.load_tags)
def route_list(self, number): '''Response a list of posts. Hidden posts will be ignored. Args: number (int): Page number of the list. Returns: str: Rendered HTML of the posts list. Abort: 404: No such page of posts list. ''' runtime = self.runtime.get post_count = self.post_bundle.get_list_count() post_list = self.post_bundle.get_list(number) if post_list is None: abort(404) for post in post_list: post = self.plugin_manager.do_filter('dx_post', post) prev_page = next_page = True if number == 1: prev_page = False if number == post_count: next_page = False list_url = Path.format_url(runtime('url_prefix.post_list')) url = list_url if list_url.endswith('/') else list_url + '/' return self.get_render( 'list.html', posts=post_list, list_id=number, list_url=url, prev_page=prev_page, next_page=next_page)
def __init__(self, app_path, framework, config='config.json'): '''Initialize DelogX object. Args: app_path (str): Absolute path of the blog application. framework (Flask): Flask application object. config (str): Config file of DelogX, defaults `config.json`. ''' self.framework = framework app_path = os.path.realpath(app_path) config = Path.abs_path(app_path, config) config = Config(config) runtime = Config() module_path = os.path.dirname(os.path.realpath(__file__)) runtime.let('path.app', app_path) runtime.let('path.module', module_path) ver_file = os.path.join(module_path, 'VERSION') with codecs.open(ver_file, encoding='utf-8') as f: version = ''.join(f.readlines()).strip() runtime.let('blog.version', version) self.config = config self.runtime = runtime self.markdown_ext = list() self.init_runtime() self.init_plugins() self.init_bundles() self.init_route() self.update_header()
def __init__(self, blog, directory): '''Initialize a DelogX bundle. Args: blog (DelogX): DelogX object. directory (str): Name of items directory. ''' self.blog = blog self.bundle_list = OrderedDict() app_path = blog.runtime.get('path.app') self.directory = Path.abs_path(app_path, directory) if not os.path.exists(self.directory): try: os.makedirs(self.directory) except OSError as exception: if (exception.errno != errno.EEXIST or not os.path.isdir(self.directory)): raise exception for filename in os.listdir(self.directory): real_path = os.path.join(self.directory, filename) if (os.path.isfile(real_path) and os.path.splitext(filename)[1] == '.md'): self.update(filename) self.sort()
def load_content(self): '''Load and parse the content of this item.''' lines = Path.read_file(self.path) if lines is None: lines = list() lines = lines[self.title_line:] self.markdown = ''.join(lines) self.content = Markdown.markdown(self.markdown, self.blog.markdown_ext)
def load_tags(self, *args, **kwargs): post = kwargs.get('post') if not post: return post.tags = list() title = post.title title_split = list(filter(None, title.split('::', 1))) if title_split: post.title = title_split[0].strip() tags = ''.join(title_split[1:]).split(',') post.tags = list(filter(None, list(map(str.strip, tags)))) tags_link = list() tags_html = '<div class="post-tags">{0}</div>' for tag in post.tags: tags_link.append('<a href="{0}">{1}</a>'.format( Path.format_url(self.tags_url, Path.urlencode(tag)), tag)) if tags_link: tags_html = tags_html.format(' '.join(tags_link)) post.content = tags_html + post.content
def cook_page(self, page): '''Cook a Page. Add prefix to the URL of the Page. Args: page (Page): Page needs to cook. Returns: Page: Cooked Page. ''' runtime = self.runtime.get if not page: return None page_url = runtime('url_prefix.page') page.cooked_url = Path.format_url(page_url, Path.urlencode(page.url)) return page
def init_route(self): '''Initialize URL routes of DelogX.''' runtime = self.runtime static_rule = Path.format_url( runtime.get('url_prefix.static'), '<static_file>') list_rule = Path.format_url( runtime.get('url_prefix.post_list'), '<int:number>/') item_rule = Path.format_url( runtime.get('url_prefix.page'), '<item_id>/') page_rule = Path.format_url( runtime.get('url_prefix.page'), '<page_id>/') post_rule = Path.format_url( runtime.get('url_prefix.post'), '<post_id>/') icon_rule = Path.format_url( runtime.get('url_prefix.static'), 'favicon.ico') self.add_url_rule('/', 'delogx_index', self.route_index) self.add_url_rule(static_rule, 'delogx_static', self.route_static) self.add_url_rule(list_rule, 'delogx_list', self.route_list) if runtime.get('url_prefix.post') == runtime.get('url_prefix.page'): self.add_url_rule(item_rule, 'delogx_page', self.route_item) else: self.add_url_rule(page_rule, 'delogx_page', self.route_page) self.add_url_rule(post_rule, 'delogx_post', self.route_post) self.framework.add_url_rule( '/favicon.ico', 'delogx_favicon', redirect_to=icon_rule) self.framework.errorhandler(404)(self.route_not_found)
def parse_readmore(self, post): if not post: return content_split = re.split(r'<[Hh][Rr](?:\s+\/)?>', post.content, 1) if len(content_split) == 2: summary, more = content_split else: summary = content_split[0] more = '' post_url = self.blog.runtime.get('url_prefix.post') post_url = Path.format_url(post_url, Path.urlencode(post.url)) content = '''{0} <div class="{1}"><a href="{2}">{3}</a></div> <div class="post-more">{4}</div> ''' more_class = ['read-more'] if not more: more_class.append('no-more-content') more_class = ' '.join(more_class) content = content.format( summary, more_class, post_url, self.i18n.get('Read More'), more) post.content = content
def run(self): self.config = Config(os.path.join(self.workspace, 'config.json')) self.feed_url = self.config.get('delog_feed.url') self.feed_limit = self.config.get('delog_feed.limit') if not self.feed_url: self.feed_url = '/feed' if not self.feed_limit: self.feed_limit = 10 self.feed_url = Path.format_url(self.feed_url) if not self.feed_url.endswith('/'): self.feed_url += '/' self.blog.add_url_rule(self.feed_url, 'delog_feed', self.make_feed) self.manager.add_filter('dx_render', self.add_link)
def cook_post(self, post): '''Cook a Post. Add prefix to the URL of the Post and convert timestamp to string. Args: post (Post): Post needs to cook. Returns: Post: Cooked Post. ''' conf = self.config.get runtime = self.runtime.get if not post: return None post_url = runtime('url_prefix.post') time_format = conf('local.time_format') post.cooked_url = Path.format_url(post_url, Path.urlencode(post.url)) post.cooked_time = time.strftime( time_format, time.localtime(post.time)) post.cooked_time = post.cooked_time return post
def get_post(self, post_id): '''Return cooked Post object by id. Args: post_id (str): Request ID of the post. Returns: Post: Cooked Post object. ''' post_id = Path.urldecode(post_id) post = self.post_bundle.get(post_id) self.plugin_manager.do_action('dx_post') return self.plugin_manager.do_filter('dx_post', post)
def get_page(self, page_id): '''Return cooked Page object by id. Args: page_id (str): Request ID of the page. Returns: Page: Cooked Page object. ''' page_id = Path.urldecode(page_id) page = self.page_bundle.get(page_id) self.plugin_manager.do_action('dx_page') page = self.plugin_manager.do_filter('dx_page', page) return page
def cook_static(self, statics): '''Cook a list of static files. Convert all relative links to absolute. Args: statics (list of str): Static files. Returns: list: Cooked list of static files. ''' runtime = self.runtime.get static_url = runtime('url_prefix.static') if not statics: statics = list() for i, link in enumerate(statics): if not link.startswith(('/', 'http://', 'https://')): statics[i] = Path.format_url(static_url, link) return statics
def run(self): conf = self.blog.default_conf self.i18n = I18n( Path.format_url(self.workspace, 'locale'), conf('local.locale')) self.manager.add_action('dx_post_update', self.parse_readmore)