ssg/generators/blogindex.py

Summary

Maintainability
C
1 day
Test Coverage
'''
BlogIndexGenerator
==================

Generate an ``index.html`` file from a template of the same name. This is
useful for blogs and pages for indexing articles, creating the index on the
fly.
Adds a list of post to the Jinja2 context, called 'posts'.
Adds keys 'page', and 'pages' to the metadata of the indices. 'page' is the
current page, anmd 'pages' is the total number of pages.
Content is sorted by date.

Adds the config key "POSTSPERINDEX", to set the number of posts per index page.
If 'POSTSPERINDEX' is not defined, 'pages' and 'n_pages' equals zero.
'''
import os
from datetime import datetime
from ssg import generator
from ssg.log import logger
from ssg.settings import SETTINGS
from ssg.metadata import ishidden


class BlogIndexGenerator(generator.GeneratorBase):
    '''
    Generate an ``index.html`` from a template.
    '''
    def __init__(self):
        '''
        Constructor
        '''
        generator.GeneratorBase.__init__(self)

    def _create_index_metadata(self, page=''):
        '''Create metadata and data structure for the index.

        :param page: If the index spans multiply pages, gives page number.
        :type page: string
        '''
        # Create meta data for index
        # Create a dictionary for metadata
        metadata = dict()
        # Omit page number from first index file
        metadata['src_file'] = ''
        metadata['dst_file'] = os.path.join(SETTINGS['ROOTDIR'],
                                            SETTINGS['OUTPUTDIR'])
        metadata['dst_file'] += '/index' + page + '.html'
        metadata['title'] = 'index'
        metadata['date'] = datetime.now()
        metadata['template'] = 'index'
        # Page number
        if page == '':
            metadata['page'] = 1
        else:
            metadata['page'] = int(page)
        # Create a contents node for the index
        content = dict()
        # Add meta data
        content['metadata'] = metadata
        # Empty content
        content['content'] = ''
        logger.debug('Autogenerated content: ' + str(content))
        # Add contents to context
        return content

    def _create_index(self, context, page, n_pages, posts):
        '''Create an index(n).html from a context.

        :param context:
        :type context:
        :param page: Current page number.
        :type page: int
        :param page: Number of index pages.
        :type n_pages: int
        :param posts: List of posts in the index.
        :type posts: list
        '''
        logger.debug('Creating new page.')
        # Special case to create index.html
        if page == 0:
            index = self._create_index_metadata()
        else:
            index = self._create_index_metadata(page=str(page))
        # Number of pages
        index['metadata']['pages'] = n_pages
        # Add local context
        index['context'] = {'context': context,
                            'posts': posts,
                            'content': index}

        context.contents.append(index)

    def _set_template_post(self, context):
        '''Apply post template to all content that has type post, if no
        template is set.
        '''
        for content in context.contents:
            # Check if meta data has 'type'
            if 'type' in content['metadata'].keys():
                # Check if type is 'post'
                if content['metadata']['type'] == 'post':
                    # Check if template is set
                    if 'template' not in content['metadata'].keys():
                        # Set template to 'post'
                        content['metadata']['template'] = 'post'

    def run(self, context):
        '''Run the generator.

        :param context: The context of the site.
        :type context: ssg.context.Context
        '''
        logger.debug('Running BlogIndexGenerator extension.')
        content = self._set_template_post(context)
        # Sort by date
        context.contents = sorted(context.contents,
                                  key=lambda c: c['metadata']['date'],
                                  reverse=True)

        page = 0
        n_pages = 0
        # Check if we're supposed to use pagination
        if 'POSTSPERINDEX' in SETTINGS.keys():
            logger.debug(str(SETTINGS['POSTSPERINDEX']) + ' post per page.')
            # Get number of pages
            n_pages = 0
            for content in context.contents:
                # Only do posts
                if content['metadata']['template'] == 'post':
                    if not ishidden(content['metadata']):
                        n_pages += 1
            # TODO: Check for rounding error when result is something
            # like x,1-4
            n_pages = int(n_pages / SETTINGS['POSTSPERINDEX'])
            logger.debug('Index spans ' + str(n_pages) + ' pages.')
            # Keep track of the page number
            page = 1
            # Create a list of posts
            posts = list()
            # Run trough all content
            for content in context.contents:
                # Only do posts
                if ((content['metadata']['template'] == 'post') and
                    (not ishidden(content['metadata']))):
                    # Split by 'POSTSPERINDEX', and create indices
                    if len(posts) <= SETTINGS['POSTSPERINDEX']:
                        logger.debug('Adding post to page ' + str(page) + ' ' +
                                     content['metadata']['title'])
                        posts.append(content)
                    else:
                        self._create_index(context,
                                           page,
                                           n_pages,
                                           posts)
                        # Generate an index.html as well as an index1.html
                        if page == 1:
                            self._create_index(context, 0, n_pages, posts)
                        page += 1
                        # New posts list
                        posts = list()
                        posts.append(content)
                else:
                    logger.debug('Skipping ' +
                                 content['metadata']['src_file'])
            # Get any remaining posts
            if len(posts) > 0:
                logger.debug('Last page is ' + str(len(posts)) +
                             'posts long.')
                self._create_index(context,
                                   page,
                                   n_pages,
                                   posts)
                # Generate an index.html as well as an index1.html
                if page == 1:
                    self._create_index(context, 0, n_pages, posts)
        else:
            logger.debug('No pagination.')
            # Create a list of posts
            posts = list()
            # Run trough all content
            for content in context.contents:
                # Only do posts
                if ((content['metadata']['template'] == 'post') and
                    (not ishidden(content['metadata']))):
                    logger.debug('Adding post to index page.')
                    posts.append(content)

            self._create_index(context,
                               page,
                               n_pages,
                               posts)
            # Generate an index.html as well as an index1.html
            if page == 1:
                self._create_index(context, 0, n_pages, posts)
# Add CategoriMetaParser to list of parsers
generator.GENERATORS.append(BlogIndexGenerator())