<filename>handler.py<gh_stars>0
import os

from feedgen.feed import FeedGenerator
from flask import render_template, send_file, redirect, jsonify, request

from config import config as C
from util import parse_posts, make_abs_url, parse_posts_page, extension_of_markdown_file, parse_custom_page, \
    get_categories, get_tags, search_content

_mode_api = 'api'
_mode_web_app = 'web-app'
_mode_mixed = 'mixed'

# make it web app mode as default
C.mode = C.get('mode', _mode_web_app)
if C.mode != _mode_api and C.mode != _mode_web_app and C.mode != _mode_mixed:
    raise SyntaxError('Can not recognize mode "%s"' % C.mode)


def should_return_json():
    return C.mode == _mode_api \
           or (C.mode == _mode_mixed
               and ('application/json' in request.headers.get('Accept', '') or request.args.get('format') == 'json'))


def index():
    """
    Render index page
    """
    return page(1)


def page(page_id):
    """
    Render posts page ('/page/<int:page_id>')
    """
    pg = parse_posts_page(page_id)

    if pg['entries'] or page_id == 1:
        if should_return_json():
            return jsonify(dict(ok=True, site=C, page=pg))
        else:
            return render_template('index.html', site=C, page=pg)
    else:
        return page_not_found()


def post(year, month, day, name):
    """
    Render post
    """
    file_name = '-'.join((year, month, day, name))

    ext = extension_of_markdown_file(os.path.join('posts', file_name))
    if ext is None:
        return page_not_found()

    file_name_with_ext = '.'.join((file_name, ext))

    article = parse_posts(f_list=(file_name_with_ext,))[0]
    article['id_key'] = file_name
    article['absolute_url'] = make_abs_url(C.root_url, '/'.join(('post', year, month, day, name)))

    if should_return_json():
        return jsonify(dict(ok=True, site=C, page=article))
    else:
        return render_template(article['layout'] + '.html', site=C, page=article)


def page_not_found():
    """
    Render 404 page
    """
    if should_return_json():
        return jsonify(dict(ok=False))
    else:
        return render_template('404.html', site=C), 404


def feed():
    """
    Generate atom feed
    """
    entries = parse_posts(0, C.feed_count)
    fg = FeedGenerator()
    fg.id(str(len(entries)))
    fg.title(C.title)
    fg.subtitle(C.subtitle)
    fg.language(C.language)
    fg.author(dict(name=C.author, email=C.email))
    fg.link(href=C.root_url, rel='alternate')
    fg.link(href=make_abs_url(C.root_url, 'feed'), rel='self')
    for entry in entries:
        fe = fg.add_entry()
        fe.id(entry.get('url'))
        fe.title(entry.get('title'))
        fe.published(entry.get('date'))
        fe.updated(entry.get('updated') or entry.get('date'))
        fe.link(href=make_abs_url(C.root_url, entry.get('url')), rel='alternate')
        fe.author(dict(name=entry.get('author'), email=entry.get('email')))
        fe.content(entry.get('body'))

    atom_feed = fg.atom_str(pretty=True)
    return atom_feed


def tag(t):
    """
    Render tag page
    """
    pg = {
        'archive_type': 'tag',
        'archive_name': t,
        'entries': parse_posts(tag=t, cut_by_read_more=C.get('support_read_more', False))
    }
    if pg['entries']:
        if should_return_json():
            return jsonify(dict(ok=True, site=C, page=pg))
        else:
            return render_template('tag.html', site=C, page=pg)
    else:
        return page_not_found()


def tags():
    if should_return_json():
        return jsonify(dict(ok=True, data=get_tags()))
    else:
        return page_not_found()


def category(c):
    """
    Render category page
    """
    pg = {
        'archive_type': 'category',
        'archive_name': c,
        'entries': parse_posts(category=c, cut_by_read_more=C.get('support_read_more', False))
    }
    if pg['entries']:
        if should_return_json():
            return jsonify(dict(ok=True, site=C, page=pg))
        else:
            return render_template('category.html', site=C, page=pg)
    else:
        return page_not_found()


def categories():
    if should_return_json():
        return jsonify(dict(ok=True, data=get_categories()))
    else:
        return page_not_found()


def custom_page(rel_path):
    """
    Render custom page
    """
    if '..' in rel_path or './' in rel_path \
            or '/.' in rel_path or rel_path.startswith('.') \
            or '//' in rel_path:
        # the path is not safe
        return page_not_found()

    file_path = os.path.join('pages', rel_path)

    if os.path.exists(file_path) and os.path.isfile(file_path):
        # the exact file exists, so return it
        return send_file(file_path)

    # try different type of file

    # try directory
    if os.path.isdir(file_path):
        # is a directory
        if not file_path.endswith('/'):
            return redirect(rel_path + '/', code=302)
        return custom_page(os.path.join(rel_path, 'index.html'))

    # # try html
    # if os.path.exists(file_path + '.html'):
    #     # html file exists
    #     return send_file(file_path + '.html')

    # try markdown
    # remove "html" extension if accessing this page through "xxx.html"
    file_path = os.path.splitext(file_path)[0]
    md_ext = extension_of_markdown_file(file_path)
    if md_ext is not None:
        # markdown file exists
        content = parse_custom_page('.'.join((file_path, md_ext)))
        content['id_key'] = rel_path
        content['absolute_url'] = make_abs_url(C.root_url, rel_path)
        if should_return_json():
            return jsonify(dict(ok=True, site=C, page=content))
        else:
            return render_template(content['layout'] + '.html', site=C, page=content)

    return page_not_found()


def search():
    """
    Search for something
    """
    query_text = request.args.get('q')
    count_per_page = int(request.args.get('c', C.get('entry_count_one_page_when_search', 20)))
    current_page = int(request.args.get('p', 1))
    if not query_text or query_text == '':
        # invalid query
        return page_not_found()

    print(query_text)
    pg = search_content(query_text, count_per_page, current_page)

    if pg['entries'] or current_page == 1:
        if should_return_json():
            return jsonify(dict(ok=True, site=C, page=pg))
        else:
            return render_template('search.html', site=C, page=pg)
    else:
        return page_not_found()
