big refactor 1

This commit is contained in:
Andreas Stephanides
2017-08-30 15:35:25 +02:00
parent 434bfbff18
commit 2d0f074315
9 changed files with 226 additions and 138 deletions

View File

@@ -1,18 +1,18 @@
import sys import sys
from flask import Flask, render_template, send_from_directory,jsonify from flask import Flask, Blueprint,render_template, send_from_directory,jsonify, url_for
from flask_flatpages import FlatPages, pygments_style_defs from flask_flatpages import FlatPages, pygments_style_defs
from flatpages import FlatPagesIndex
from flask_frozen import Freezer from flask_frozen import Freezer
from config import Config from config import Config
import os import os
import re import re
from os.path import isfile, abspath from os.path import isfile, abspath
from utils import pjoin2 from utils import pjoin2
from utils import pjoin from utils import pjoin, list_dir, path_depth
from functools import partial
from collections import namedtuple
package_directory = os.path.dirname(os.path.abspath(__file__)) package_directory = os.path.dirname(os.path.abspath(__file__))
#cfg = Config(file('./config.cfg'))
cfg = Config(file(os.path.join(package_directory, 'config.cfg'))) cfg = Config(file(os.path.join(package_directory, 'config.cfg')))
# Loading constants from config file # Loading constants from config file
@@ -23,168 +23,93 @@ FLATPAGES_FP_ROOT = abspath(cfg.pages_root)
# Initialize application # Initialize application
app = Flask(__name__) app = Flask(__name__)
flatpages = FlatPages(app)
flatpages = FlatPagesIndex(app)
flatpages.get('index') flatpages.get('index')
freezer = Freezer(app) freezer = Freezer(app)
app.config.from_object(__name__) app.config.from_object(__name__)
page_blueprint = Blueprint('intern', __name__)
# List all non *.md files within the directory # List all non *.md files within the directory
def list_dir_md(mypath): list_dir_md=partial(list_dir, not_ext=["md","~"])
return [f for f in os.listdir(mypath) if isfile(os.path.join(mypath, f)) and re.match('.*\%s.*' % FLATPAGES_EXTENSION,f) is None]
# List all jpg images within the directory # List all jpg images within the directory
def list_dir_img(mypath): list_dir_img=partial(list_dir, ext="jpg")
return [f for f in os.listdir(mypath) if isfile(os.path.join(mypath, f)) and re.match('.*\.jpg',f) is not None]
def path_depth(path):
p_split=path.split('/')
if path =="":
cc=0
else:
cc=len(path.split('/'))
if p_split[-1]=='index' or p_split[-1]=='index.json' :
cc=cc-1
return cc
# List all subpages of the current page # List all subpages of the current page
def get_sub_pages(path): get_sub_pages = partial(FlatPagesIndex.get_sub_pages, flatpages)
return [p for p in flatpages get_sub_ipages = partial(FlatPagesIndex.get_sub_ipages, flatpages)
if (p.path.startswith(path) and # is a subpage
( re.match('.*index',p.path) is None) and # is no index
path_depth(p.path)<path_depth(path)+2) ]
# List all index subpages of the current page i.e. all pages in subdirectories
def get_sub_ipages(path):
# ppath=page.path
cc=len(path.split('/'))
if path=="":
cc=0
ppath="index"
else:
ppath=pjoin2([path,"index"])
ps=[p for p in flatpages
if (p.path.startswith(path) and # subpages of this page
not ( re.match('.*index',p.path) is None) and # only index
( ppath != p.path) and # not identical page
len(p.path.split('/'))<=cc+2) ] # only one level
return ps
# breadcrumbs decompose the path
# a/b/index -> [a/index a/b/index]
def get_breadcrumb_paths(path):
elements = path.split('/')
elements2 = ['index']
for i in range(1,len(elements)):
elements2.append(pjoin2(elements[0:i])+u'/index')
return elements2
def get_breadcrumb_pages(paths):
pages=[flatpages.get(p) for p in paths]
return pages
def get_paths(pages):
paths=[p.path for p in pages]
return paths
def get_bc(path): def get_bc(path):
return get_breadcrumb_pages(get_breadcrumb_paths(path)) return flatpages.get_pages(FlatPagesIndex.breadcrumbs(path))
# return get_breadcrumb_pages(get_breadcrumb_paths(path))
# load a page from a path information
def get_flatpage(path):
is_index=False
# root index
if path == 'index' or path=='':
is_index=True
path=''
pathi='index'
else:
if path.split('/')[-1]=='index': # last element is "index" ?
is_index=True
path='/'.join(path.split('/')[0:-1]) # remove index from path
pathi = u'{}/{}'.format(path, 'index') # try to add index to the path
page = flatpages.get(pathi) # try to load index page
if not page is None: # if successful it is a index
is_index=True
else:
page=flatpages.get(path)
return (is_index, path, page)
# completes the meta hash if a configuration is not set
def misskey(a,key):
if not a.has_key(key):
return True
return a[key] is None
def page_defaults(page, is_index, path): def page_defaults(page, is_index, path):
if misskey(page.meta,"title"): page.meta["title"]=page.meta.get("title", path.split('/')[-1])
page.meta["title"]=path.split('/')[-1] page.meta["template"]=page.meta.get("template", cfg.default_template)
if misskey(page.meta, "template"):
page.meta["template"]='page.html'
return page return page
@app.route('/<path:name>/') def load_lists_for_templates(path, is_index):
def post(name='index'):
is_index, path, page = get_flatpage(name)
app.logger.info('render '+name)
path2 = pjoin(FLATPAGES_ROOT,path) path2 = pjoin(FLATPAGES_ROOT,path)
if is_index == True:
if is_index == True and not page is None:
ld=list_dir_md(path2) ld=list_dir_md(path2)
il=list_dir_img(path2) il=list_dir_img(path2)
sp=get_sub_pages(path) sp=list(get_sub_pages(path))
spi=get_sub_ipages(path) spi=list(get_sub_ipages(path))
else: else:
ld=[] ld=[]
sp=[] sp=[]
spi=[] spi=[]
il=[] il=[]
bc=get_bc(path)
return (ld, il, sp, spi,bc)
@page_blueprint.route('/<path:name>/')
@page_blueprint.route('/')
def post(name='index'):
is_index, path, page = flatpages.get_flatpage(name)
app.logger.info('render '+name)
if not page is None: if not page is None:
page_defaults(page,is_index,path) page=page_defaults(page, is_index, path)
app.logger.info("Render Template"+page["template"] +"for "+path) ld, il, sp, spi, bc = load_lists_for_templates(path,is_index)
return render_template(page.meta["template"], ld=ld, post=page, sp=sp, spi=spi, il=il, pth=path, pagebreadcrumbs=get_bc(path)) return render_template(page.meta["template"], ld=ld, post=page, sp=sp, spi=spi, il=il, pth=path, pagebreadcrumbs=bc)
if os.path.exists(u'{}/{}'.format(FLATPAGES_ROOT,path)): if os.path.exists(os.path.join(FLATPAGES_ROOT,path)):
return send_from_directory(FLATPAGES_ROOT,path) return send_from_directory(FLATPAGES_ROOT,path)
else: else:
return send_from_directory('static',path) return send_from_directory('static',path)
def json_url_for(paths):
@app.route('/<path:name>.json/') for p in paths:
def postjson(name='index'): yield url_for('intern.postjson', name=p)
is_index, path, page = get_flatpage(name)
app.logger.info('render '+name)
path2 = pjoin(FLATPAGES_ROOT,path)
if is_index == True and not page is None: @page_blueprint.route('/<path:name>.json/')
ld=list_dir_md(path2) def postjson(name='index'):
il=list_dir_img(path2) is_index, path, page = flatpages.get_flatpage(name)
sp=get_sub_pages(path)
spi=get_sub_ipages(path)
else:
ld=[]
sp=[]
spi=[]
il=[]
if not page is None: if not page is None:
page_defaults(page,is_index,path) ld, il, sp, spi, bc = load_lists_for_templates(path, is_index)
app.logger.info("Render Template"+page["template"] +"for "+path) page_defaults(page, is_index, path)
p=page.meta p=page.meta
bc=get_breadcrumb_paths(path)
p["depth"]=path_depth(path) p["depth"]=path_depth(path)
p["path"]=path p["path"]=path
p["breadcrumbs"]=bc p["breadcrumbs"]=list(bc)
p["subfolders"]=get_paths(spi) p["subfolders"]=list(json_url_for(FlatPagesIndex.get_paths(spi)))
p["subpages"]= [u'%s.json' % p1 for p1 in get_paths(sp)] p["subpages"]= list(json_url_for(FlatPagesIndex.get_paths(sp)))
p["text"]=page.html p["text"]=page.html
return jsonify(page=p) return jsonify(page=p)
# return render_template(page.meta["template"], ld=ld, post=page, sp=sp, spi=spi, il=il, pth=path, pagebreadcrumbs=get_bc(path,page))
if os.path.exists(u'{}/{}'.format(FLATPAGES_ROOT,path)): if os.path.exists(u'{}/{}'.format(FLATPAGES_ROOT,path)):
return send_from_directory(FLATPAGES_ROOT,path) return send_from_directory(FLATPAGES_ROOT,path)
else: else:
return send_from_directory('static',path) return send_from_directory('static',path)
app.register_blueprint(page_blueprint, url_prefix=cfg.url_prefix,static_folder='static')
app.add_url_rule('%s/<path:name>/' % cfg.url_prefix,'page', post)

View File

@@ -1,3 +1,5 @@
pages_root: 'data' pages_root: 'data'
pages_reload: True pages_reload: True
static_root: 'static' static_root: 'static'
default_template: 'page.html'
url_prefix: "/int"

3
config.cfg.sample Normal file
View File

@@ -0,0 +1,3 @@
pages_root: 'data'
pages_reload: True
static_root: 'static'

94
flatpages.py Normal file
View File

@@ -0,0 +1,94 @@
from flask_flatpages import FlatPages, pygments_style_defs
import flask_flatpages
import re
from utils import path_depth,pjoin2
from collections import namedtuple
FileLists=namedtuple("FileLists", ["list_files", "list_images", "sub_pages", "sub_index_pages", "breadcrumbs"])
class FlatPagesIndex(FlatPages):
@staticmethod
def get_breadcrumb_paths(path):
"""
breadcrumbs decompose the path
a/b/index -> [a/index a/b/index]
"""
elements = path.split('/')
elements2 = ['index']
for i in range(1,len(elements)):
elements2.append(pjoin2(elements[0:i])+u'/index')
return elements2
@staticmethod
def get_paths(pages):
return (p.path for p in pages)
@staticmethod
def breadcrumbs(page):
"Parse a path or the path of a page into breadcrumbs"
if type(page) is flask_flatpages.Page:
return FlatPagesIndex.get_breadcrumb_paths(page.path)
else:
return FlatPagesIndex.get_breadcrumb_paths(page)
def get_pages(self, paths):
if paths is None:
raise AttributeError("paths for get_pages can't be None")
return (self.get(p) for p in paths)
def get_sub_pages(self, path):
def is_subpage(path, root):
return (path.startswith(root) and # is a subpage
( re.match('.*index',path) is None) and # is no index
path_depth(path)<path_depth(root)+2
)
return (p for p in self
if is_subpage(str(p.path),path))
# List all index subpages of the current page i.e. all pages in subdirectories
def get_sub_ipages(self, path):
cc=path_depth(path)
ppath="index" if path=="" else pjoin2([path,"index"])
ps=[p for p in self
if (p.path.startswith(path) and # subpages of this page
not ( re.match('.*index',p.path) is None) and # only index
( ppath != p.path) and # not identical page
len(p.path.split('/'))<=cc+2) ] # only one level
return ps
# load a page from a path information
def get_flatpage(self,path):
is_index= path=='' or path.split('/')[-1]=='index'
if path == 'index' or path=='':
is_index=True
path=''
pathi='index'
else:
if path.split('/')[-1]=='index': # last element is "index" ?
is_index=True
path='/'.join(path.split('/')[0:-1]) # remove index from path
pathi = u'{}/{}'.format(path, 'index') # try to add index to the path
page = FlatPages.get(self,pathi) # try to load index page
if not page is None: # if successful it is a index
is_index=True
else:
page=FlatPages.get(self,path)
return (is_index, path, page)
def load_lists_for_templates(self, path, is_index):
path2 = pjoin(FLATPAGES_ROOT,path)
if is_index == True:
ld=list_dir_md(path2)
il=list_dir_img(path2)
sp=list(get_sub_pages(path))
spi=list(get_sub_ipages(path))
else:
ld=[]
sp=[]
spi=[]
il=[]
bc=get_bc(path)
return (ld, il, sp, spi,bc)

View File

@@ -10,6 +10,6 @@ ln ./_parent_files/run ..
ln ./_parent_files/uwsgi.ini .. ln ./_parent_files/uwsgi.ini ..
ln ./_parent_files/requirements.txt .. ln ./_parent_files/requirements.txt ..
cd .. cd ..
virtualenv env virtualenv .env
. ./env/bin/activate . ./.env/bin/activate
pip install -r requirements.txt pip install -r requirements.txt

View File

@@ -1,15 +1,16 @@
{# -*-jinja2-*- #}
<html> <html>
<head></head> <head></head>
<LINK href="/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css"> <LINK href="{{ url_for('static', filename='bootstrap/css/bootstrap.min.css')}}" rel="stylesheet" type="text/css">
<body> <body>
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<nav class="breadcrumb" style="background-color: #FFF"> <nav class="breadcrumb" style="background-color: #FFF">
{% for b in pagebreadcrumbs %} {% for b in pagebreadcrumbs %}
<a href="{{url_for('post',name=b.path)}}" class="breadcrumb-item">{{b.title}} </a> <a href="{{url_for('page',name=b.path)}}" class="breadcrumb-item">{{b.title}} </a>
{% endfor %} {% endfor %}
<a href="{{url_for('post',name=post.path)}}" class="breadcrumb-item active">{{post.title}} </a> <a href="{{url_for('page',name=post.path)}}" class="breadcrumb-item active">{{post.title}} </a>
</nav> </nav>
{% block content %} {% block content %}

View File

@@ -1,15 +1,16 @@
{# -*-jinja2-*- #}
{% extends "layout.html" %} {% extends "layout.html" %}
{% block content %} {% block content %}
<h1>{{post.title}}</h1> <h1>{{post.title}}</h1>
{{post.date}} {{post.date}}
{% if spi|length > 0 %} {% if spi | length > 0 %}
<hr/> <hr/>
<b id="up_head"> Unterseiten: </b> <b id="up_head"> Unterseiten: </b>
<ul class="nav flex-column flex-sm-row " labeledby="up_head"> <ul class="nav flex-column flex-sm-row " labeledby="up_head">
{% for d in spi %} {% for d in spi %}
<li class="nav-item"> <li class="nav-item">
<a href="{{url_for('post',name=d['path'])}}" class="nav-link"> <a href="{{url_for('page',name=d['path'])}}" class="nav-link">
<h6> {{d.title}} <small class="text-muted">{{'/'.join(d.path.split('/')[-2:-1])}} </small> <h6> {{d.title}} <small class="text-muted">{{'/'.join(d.path.split('/')[-2:-1])}} </small>
</h6> </h6>
</a> </a>
@@ -26,7 +27,7 @@
<ul class="nav flex-column flex-sm-row" labeledby="inf_head"> <ul class="nav flex-column flex-sm-row" labeledby="inf_head">
{% for d in sp %} {% for d in sp %}
<li class="nav-item"> <li class="nav-item">
<a href="{{url_for('post',name=d['path'])}}" class="nav-link text-info"> <a href="{{url_for('page',name=d['path'])}}" class="nav-link text-info">
<h6> {{d.title}} <small class="text-muted">{{d.path.split('/')[-1]}} </small> <h6> {{d.title}} <small class="text-muted">{{d.path.split('/')[-1]}} </small>
</h6> </h6>
</a> </a>
@@ -41,7 +42,8 @@
<ul> <ul>
{% for d in ld %} {% for d in ld %}
<li> <li>
<a href="/{{pth}}/{{d}}">{{d}} </a> <a href="{{url_for('page', name=d)}}">{{d}} </a>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>

32
test_utils.py Normal file
View File

@@ -0,0 +1,32 @@
import unittest
import utils
from mock import patch
class TestUtils(unittest.TestCase):
def test_pjoin2(self):
self.assertEquals(utils.pjoin2(["a","b"]),"a/b")
self.assertEquals(utils.pjoin2(["b"]),"b")
self.assertEquals(utils.pjoin2(["b",""]),"b")
self.assertEquals(utils.pjoin2(["","b"]),"b")
with self.assertRaises(AttributeError):
utils.pjoin2("sdf")
with self.assertRaises(AttributeError):
utils.pjoin2([""])
def test_pjoin(self):
self.assertEquals(utils.pjoin("a","b"), "a/b")
self.assertEquals(utils.pjoin("a",""),"a")
with self.assertRaises(AttributeError):
utils.pjoin("sdf",[])
def test_list_dir(self):
with patch("os.listdir") as mock_listdir:
with patch("os.path.isfile") as mock_isfile:
mock_listdir=["test.jpg"]
mock_isfile=True
self.assertEquals(list(utils.list_dir(".")), ["test.jpg"])
if __name__ == '__main__':
unittest.main()

View File

@@ -1,5 +1,34 @@
def pjoin (rt,pth): """
return u'{}/{}'.format(rt,pth) Utility Functions for handling files and paths
"""
import os
import re
from os.path import isfile, abspath
def pjoin2 (pth): def pjoin2 (pth):
if (not type(pth) is list):
raise AttributeError("path should be a list")
pth=filter(lambda s: len(s.strip())>0, pth)
if len(pth)==0:
raise AttributeError("List for pjoin2 can't be empty")
return u'/'.join(pth) or u'' return u'/'.join(pth) or u''
def pjoin (rt,pth):
return pjoin2([rt,pth])
def list_dir(mypath,ext=None, not_ext=None):
return (f for f in os.listdir(mypath)
if os.path.isfile(os.path.join(mypath, f))
and ((re.match('.*%s$' % not_ext, f) is None) or (not_ext is None))
and ((re.match('.*%s$' % ext, f) is not None) or (ext is None))
)
def path_depth(path):
if path =="":
return 0
p_split=path.split('/')
cc=len(p_split)
if p_split[-1]=='index' or p_split[-1]=='index.json' :
cc=cc-1
return cc