pnbp

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit b1dc38e8e3a4e79bb187c7fca0e271b5c3253358
parent ab23391bf095edcec54167baa76650c7c24631a8
Author: Paul Longtine <paullongtine@gmail.com>
Date:   Mon Sep  1 21:27:23 2014

merged

Diffstat:
 example/includes/header.html |   2 +-
 install.sh                   |   2 +-
 src/buildsite.py             |  89 +------------------
 src/core.py                  | 203 +-----------------------------------------
 src/core/__init__.py         |  48 ++++++++++-
 src/core/builder.py          | 129 ++++++++++++++++++++++++++-
 src/core/helper/__init__.py  |   0
 src/core/helper/cmd.py       |  24 +++++-
 src/core/helper/functions.py |  42 ++++++++-
 src/core/module.py           |  81 ++++++++++++++++-
 src/core/modules/__init__.py |   7 +-
 src/core/modules/admin.py    | 219 ++++++++++++++++++++++++++++++++++++++++++++-
 src/core/modules/blog.py     | 115 +++++++++++++++++++++++-
 src/core/template.py         |  49 ++++++++++-
 src/functions.py             |  24 +-----
 src/init.py                  |  23 +++++-
 src/initbasic.py             |   8 +--
 src/main.py                  |  23 +-----
 src/module/__init__.py       |   7 +-
 src/module/admin.py          | 218 +--------------------------------------------
 src/module/blog.py           | 115 +-----------------------
 21 files changed, 739 insertions(+), 689 deletions(-)

diff --git a/example/includes/header.html b/example/includes/header.html @@ -1,7 +1,7 @@ <div> <h1>This is in fact not a blog. %page%</h1> {: -for i,x in sorted(pagedata.items(),reverse=True): +for i,x in sorted(getConf().items(),reverse=True): l = i if page == "":page = "index" if str(i) == page: c = "current" diff --git a/install.sh b/install.sh @@ -1,4 +1,4 @@ #!/bin/bash cp -r src /usr/local/bin/pnbp -ln -s /usr/local/bin/pnbp/main.py /usr/local/bin/build +ln -s /usr/local/bin/pnbp/init.py /usr/local/bin/build diff --git a/src/buildsite.py b/src/buildsite.py @@ -1,89 +0,0 @@ -''' -' pnbp - pnbp is not a blogging platform -' buildsite.py -' Paul Longtine - paullongtine@gmail.com -' -' For documentation, please visit http://static.nanner.co/pnbp -''' -import os, shutil - -# Builds the site off of a filestructure dictionary. -#site = dict of site directory tree/pages, loc = root of site -def buildSite(site,loc): - try: - shutil.rmtree(loc) - - except: - print("No directory {}, ignoring".format(loc)) - - os.mkdir(loc) - for page, subpages in site.items(): - if page == "index": - if loc[-1] == "/": - currentDir = loc[0:-1] - - else: - currentDir = loc - - else: - if loc[-1] == "/": - currentDir = loc+page - - else: - currentDir = loc+"/"+page - - try: - os.mkdir(currentDir) - - except: - pass - - subpageLoop(subpages,currentDir) - - if loc[-1] != "/": - loc = loc + "/" - try: - for i in os.listdir("data/static/"): - try: - shutil.copytree("data/static/"+i,loc+i) - - except: - shutil.copy2("data/static/"+i,loc+i) - except: - print("No directory data/static, ignoring") - -#Recursive loop through all subpages -#d = dict of all subpages, cd = Current directory -def subpageLoop(d,currentDir): - for k, v in d.iteritems(): - if isinstance(v, dict): - subpageLoop(v,currentDir + "/" + k) - else: - f = "index.html" - - if k == "default": - k = "" - - elif k[0:4] == "php:": - f = "{}.php".format(k[4:]) - k = "" - - else: - k = k + "/" - - try: - file("{}/{}{}".format(currentDir,k,f), "w").write(v) - - except: - try: - os.mkdir("{}".format(currentDir)) - - except: - pass - - try: - os.mkdir("{}/{}".format(currentDir,k)) - except: - pass - - file("{}/{}{}".format(currentDir,k,f), "w").write(v) diff --git a/src/core.py b/src/core.py @@ -1,203 +0,0 @@ -''' -' pnbp - pnbp is not a blogging platform -' core.py -' Paul Longtine - paullongtine@gmail.com -' -' For documentation, please visit http://static.nanner.co/pnbp -''' -#Core imports -import os, sys, json, yaml, re - -#Helper imports -import module -from buildsite import * -from functions import * -from initbasic import * - -#Global variables - -pages = "" -pagedata = {} - -#CLI Interface function -#args = list of command line arguementsn -def cli(args): - bd = "site/" - if len(args) > 1: - for i in args: - if i[0] != "-" and args.index(i) != 0: - bd = i - - elif i == "-d": - try: - os.chdir(args.pop(args.index(i)+1)) - except: - pass - - elif i == "--help": - print("Usage: build [OPTION(s)]... [DIR]...\n" - "Build site in DIR using configuration in pwd\n" - "\n" - " -d DIR Use configuration in DIR, when not specified DIR is 'site/'\n" - " -i, --init Make a new site using the bare minimium config and build it in DIR\n" - " --help Display this help and exit\n") - - sys.exit() - - elif 0 != args.index(i): - print("Unknown option: {}".format(i)) - - if "--init" in args or "-i" in args: - init() - - return bd - -# Adds in variables defined in pages.json -# -# t = raw template, var = "pagevar" variables in pages.json (<pagename> -> "pagevar") -def generateTemplate(t,var,page): - if page == "index": - page = "" - - t = t.replace("%page%",page) - t = runInlineScript(t,page) - - for search,replace in var.items(): - if search[0] == ":": - try: - t.index("%"+search+"%") - exists = True - - except: - exists = False - - if exists: - inc = file(replace).read() - inc = generateTemplate(inc,var,page) - print("Building include: '"+search+"'") - t = t.replace("%"+search+"%",inc) - - else: - t = t.replace("%"+search+"%",replace) - - return t - -#Takes all code blocks in templates ("{:print("Hi"):}") and executes it, and replaces the block with the "returns" variable -def runInlineScript(template,page): - for script in re.findall("{:(.*?):}",template, re.DOTALL): - returns = "" - exec(script) - template = template.replace("{:"+script+":}",returns) - - return template - -# Built-in module, generates page as subpage -def genPage(t,var,data,name,page): - if 'settings' in data: - try: - if 'template' in data['settings']: - template = file(data['settings']['template']).read() - - except: - print("Error occured at {} using module page".format(page)) - print("Cannot open file {}".format(data['settings']['template'])) - sys.exit() - - else: - template = t - - if 'pagevar' in var: - if 'settings' in data: - if 'pagevar' in data['settings']: - var['pagevar'].update(data['settings']['pagevar']) - - template = generateTemplate(template,var['pagevar'],name) - - else: - template = runInlineScript(template,name) - - if not 'settings' == data: - t = {'default':template} - - else: - if 'location' in meta: - t = {data['settings']['location']:{'default':template}} - - return t - -# Gets subpages from module specified in data -def getSubpages(t,var,data,name,page): - returns = {} - if not "settings" in data: - data['settings'] = {} - - try: - returns = getattr(module, data['mod']).getPages(t, data['settings'], name, page) - - except Exception,e: - print("Error occured at {} using module {}:".format(page,data['mod'])) - if type(e) == KeyError: - print("Missing attribute {}".format(e)) - sys.exit() - - else: - print(e) - - return returns - -# Runs modules defined in pages.json -# -# t = raw template, var = "pagemod" variables in pages.json (<pagename> -> "pagemod") -def runMod(t,var,page): - subpage = {} - for name, meta in var['pagemod'].items(): - if meta['mod'] != "page": - subpage.update( - getSubpages(t,var,meta,name,page) - ) - - elif meta['mod'] == "page": - subpage.update( - genPage(t,var,meta,name,page) - ) - - return subpage - -def build(arg): - global pages, pagedata - - bd = cli(arg) - - #Try to get the config - try: pages = file("pages.yml") - except: - print("Can't open file 'pages.yml'") - sys.exit() - - pagedata = yaml.load(pages) - - site = {} - #Loops through defined "sites" - for name,v in pagedata.items(): - #Read the template - if 'template' in v: - try: template = file(v['template']).read() - except: - print("{}: Can't open file '{}'".format(name,v['template'])) - sys.exit() - else: - template = "" - - #Check if pagevar is defined, skip the variable replacement step - if 'pagevar' in v: - template = generateTemplate(template,v['pagevar'],name) - - else: - template = runInlineScript(template,name) - - print("Running modules for page: '"+name+"'") - site[name] = runMod(template,v,name) - print("Built page: '"+ name +"'\n") - - buildSite(site,bd) - diff --git a/src/core/__init__.py b/src/core/__init__.py @@ -0,0 +1,48 @@ +''' +' pnbp - pnbp is not a blogging platform +' __init__.py +' Paul Longtine - paullongtine@gmail.com +' +' For documentation, please visit http://static.nanner.co/pnbp +''' + +import os, sys, yaml + +import core.helper.cmd +import core.builder + +def init(arg): + bd = cli(arg) + + #Try to get the config + try: + pages = file("pages.yml") + + except: + print("Can't open file 'pages.yml'") + sys.exit() + + pagedata = yaml.load(pages) + + core.builder.build(pagedata,bd) + +#CLI Interface function +#args = list of command line arguementsn +def cli(args): + bd = "site/" + for i in args: + if i[0] != "-" and args.index(i) != 0: + bd = i + + elif i == "-d": + os.chdir(args.pop(args.index(i)+1)) + + elif i == "--help": + core.helper.cmd.phelp() + elif i == "--init" or i == "-i": + core.helper.cmd.init() + + elif 0 != args.index(i): + print("Unknown option: {}".format(i)) + + return bd diff --git a/src/core/builder.py b/src/core/builder.py @@ -0,0 +1,129 @@ +''' +' pnbp - pnbp is not a blogging platform +' builder.py +' Paul Longtine - paullongtine@gmail.com +' +' For documentation, please visit http://static.nanner.co/pnbp +''' +import os, shutil + +import core.template +import core.module + +#Builds the site off of a filestructure dictionary. +#site = dict of site directory tree/pages, loc = root of site +def makeSite(site,loc): + try: + shutil.rmtree(loc) + + except: + print("No directory {}, ignoring".format(loc)) + + os.mkdir(loc) + for page, subpages in site.items(): + currentDir = handleDirectory(page,loc) + + subpageLoop(subpages,currentDir) + + if loc[-1] != "/": + loc = loc + "/" + try: + for i in os.listdir("data/static/"): + try: + shutil.copytree("data/static/"+i,loc+i) + + except: + shutil.copy2("data/static/"+i,loc+i) + except: + print("No directory data/static, ignoring") + +# Handles directories +#p = name of page, l = location +def handleDirectory(p,l): + if p == "index": + if l[-1] == "/": + r = l[0:-1] + + else: + r = l + + else: + if l[-1] == "/": + r = l+p + + else: + r = l+"/"+p + + try: + os.mkdir(r) + + except: + pass + + return r + +#Recursive loop through all subpages +#d = dict of all subpages, cd = Current directory +def subpageLoop(d,cur): + for k, v in d.iteritems(): + if isinstance(v, dict): + subpageLoop(v,cur + "/" + k) + else: + f = "index.html" + + if k == "default": + k = "" + + elif k[0:4] == "php:": + f = "{}.php".format(k[4:]) + k = "" + + else: + k = k + "/" + + try: + file("{}/{}{}".format(cur,k,f), "w").write(v) + + except: + try: + os.mkdir("{}".format(cur)) + + except: + pass + + try: + os.mkdir("{}/{}".format(cur,k)) + except: + pass + + file("{}/{}{}".format(cur,k,f), "w").write(v) + +def build(pd,directory): + site = {} + for name,v in pd.items(): + #Read the template + if 'template' in v: + try: + temp = file(v['template']).read() + + except: + print("{}: Can't open file '{}'".format(name,v['template'])) + sys.exit() + + else: + temp = "" + + #Check if pagevar is defined, skip the variable replacement step + if 'pagevar' in v: + temp = core.template.generate(temp,v['pagevar'],name) + + else: + temp = core.template.run(temp,name) + + print("Running modules for page: '"+name+"'") + + site[name] = core.module.run(temp,v,name) + + print("Built page: '"+ name +"'\n") + + makeSite(site,directory) diff --git a/src/core/helper/__init__.py b/src/core/helper/__init__.py diff --git a/src/core/helper/cmd.py b/src/core/helper/cmd.py @@ -0,0 +1,24 @@ +''' +' pnbp - pnbp is not a blogging platform +' cmd.py +' Paul Longtine - paullongtine@gmail.com +' +' For documentation, please visit http://static.nanner.co/pnbp +''' + +basicConfig = "index:\n template: \"template.html\"\n pagevar:\n title: \"I'm basic\"\n pagemod:\n page:\n mod: \"page\"" +basicTemplate = "<html>\n <body>\n <h1>%title%</h1>\n </body>\n</html>" + +def init(): + file("pages.yml","w").write(basicConfig) + file("template.html","w").write(basicTemplate) + +def phelp(): + print( + "Usage: build [OPTION(s)]... [DIR]...\n" + "Build site in DIR using configuration in pwd\n" + "\n" + " -d DIR Use configuration in DIR, when not specified DIR is 'site/'\n" + " -i, --init Make a new site using the bare minimium config and build it in DIR\n" + " --help Display this help and exit\n" + ) diff --git a/src/core/helper/functions.py b/src/core/helper/functions.py @@ -0,0 +1,42 @@ +''' +' pnbp - pnbp is not a blogging platform +' functions.py +' Paul Longtine - paullongtine@gmail.com +' +' For documentation, please visit http://static.nanner.co/pnbp +''' +# Functions file, used for inline scripts +import time, yaml + + +#Return the current date in the format sepecified in config +def now(config): + return time.strftime(config) + +#Return an HTML list. example format: {'root':"<ul class=\"special\">%li%</ul>",'li':"<li class=\"list\">%content%</li>"} +def list(things,formats={}): + formats['root'] = formats.get("root","<ul>%li%</ul>") + formats['li'] = formats.get("li","<li>%content%</li>") + li = "" + for thing in things: + li = li + formats['li'].replace("%content%",thing) + + return formats['root'].replace("%li%",li) + +# slug(string -> "hi's") -> his- removes all "unwanted" characters and creates a URL-friendly slug +def slug(string): + invalidChars = [ + "<",">","#","%","{","}", + "|","\\","^","[","]","`", + "'",";","/","?",":","@", + "&","+",",","." + ] + for x in invalidChars: + string = string.replace(x, "") + + string = string.replace(" ","_") + return string.lower() + +#Returns config +def getConf(): + return yaml.load(file("pages.yml")) diff --git a/src/core/module.py b/src/core/module.py @@ -0,0 +1,81 @@ +''' +' pnbp - pnbp is not a blogging platform +' module.py +' Paul Longtine - paullongtine@gmail.com +' +' For documentation, please visit http://static.nanner.co/pnbp +''' + +import sys, modules, template + +# Built-in module, generates page as subpage +def modPage(t,var,data,name,page): + if 'settings' in data: + try: + if 'template' in data['settings']: + temp = file(data['settings']['template']).read() + + except: + print("Error occured at {} using module page".format(page)) + print("Cannot open file {}".format(data['settings']['template'])) + sys.exit() + + else: + temp = t + + if 'pagevar' in var: + if 'settings' in data: + if 'pagevar' in data['settings']: + var['pagevar'].update(data['settings']['pagevar']) + + temp = template.generate(temp,var['pagevar'],name) + + else: + temp = template.run(template,name) + + if not 'settings' == data: + t = {'default':temp} + + else: + if 'location' in meta: + t = {data['settings']['location']:{'default':temp}} + + return t + +# Gets subpages from module specified in data +def getSubpages(t,var,data,name,page): + returns = {} + if not "settings" in data: + data['settings'] = {} + + try: + returns = getattr(modules, data['mod']).getPages(t, data['settings'], name, page) + + except Exception,e: + print("Error occured at {} using module {}:".format(page,data['mod'])) + if type(e) == KeyError: + print("Missing attribute {}".format(e)) + sys.exit() + + else: + print(e) + + return returns + +# Runs modules defined in pages.json +# +# t = raw template, var = "pagemod" variables in pages.json (<pagename> -> "pagemod") +def run(t,var,page): + subpage = {} + for name, meta in var['pagemod'].items(): + if meta['mod'] == "page": + subpage.update( + modPage(t,var,meta,name,page) + ) + + else: + subpage.update( + getSubpages(t,var,meta,name,page) + ) + + return subpage diff --git a/src/core/modules/__init__.py b/src/core/modules/__init__.py @@ -0,0 +1,7 @@ +#Dynamically imports all files in this directory +import os +for module in os.listdir(os.path.dirname(__file__)): + if module == '__init__.py' or module[-3:] != '.py': + continue + __import__(module[:-3], locals(), globals()) +del module diff --git a/src/core/modules/admin.py b/src/core/modules/admin.py @@ -0,0 +1,219 @@ +import yaml + +def getPages(template,settings,name,page): + blogdb = getBlogDB(settings) + + index = """ +<!DOCTYPE html> +<html> + <head> + <title>Admin Page</title> + <style> +html { + font-family:sans-serif; + background-color:#EFEFEF; + border-top:5px solid #FF9311; +} +a { + text-decoration:none; + color:#4183c4; +} +a:hover { + text-decoration:underline; +} +a:visited { + color:#4183c4; +} +#container { + width:700px; + margin:0 auto; +} +.container { + margin-left:50px; +} + </style> + </head> + <body> + <div id="container"> + <a href="/admin" class="nav">Home</a> + <a href="/admin/post.php">Update</a> +<?php +$databases = [%db%]; +$name = [%dbn%]; +$index = 0; +foreach ($databases as $db) { + $data = json_decode(file_get_contents($db),TRUE); + echo "<h1>".$name[$index]."</h1>"; + echo "<div class='container'>"; + $new = 0; + foreach ($data as $val) { + echo "<a href=\\"edit.php?location=".$db."&post=".$val["post"]."\\">".$val["title"]."</a><br/>"; + $new = $new + 1; + } + echo "<br /><a href=\\"edit.php?location=".$db."&newpost=".$new."\\">New Post</a><br/>"; + echo "</div>"; + $index = $index + 1; +} +?> + </div> + </body> +</html> +""" + + edit = """ +<!DOCTYPE html> +<html> +<head> + <title>Admin</title> + <style> +html { + font-family:sans-serif; + background-color:#EFEFEF; + border-top:5px solid #FF9311; +} +a { + text-decoration:none; + color:#4183c4; +} +a:hover { + text-decoration:underline; +} +a:visited { + color:#4183c4; +} +#wrapper { + width:700px; + margin:0 auto; +} +#wrapper label { + font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, monospace, serif; +} +#post { + width:100%; + height:1000px; +} +#submit { + background-color:#EFEFEF; +} +#submit:hover { + box-shadow:0px 0px 3px black inset; +} +#submit:active { + background-color:#AAEEFF; +} +.input { + outline:none; + padding:5px; + border:1px solid #DEDEDE; + border-radius:5px; + box-shadow:0px 0px 3px #DEDEDE inset; +} + </style> +</head> +<body> + <div id="wrapper"> + <a href="/admin" class="nav">Home</a> +<?php + +if (isset($_GET['location']) && isset($_GET['post'])) { + $data = json_decode(file_get_contents($_GET['location']), TRUE); + $out = ""; + foreach ($data[$_GET['post']] as $key => $val) { + if ($key !== "content") { + $out = $out . $key . "=" . $val . ", "; + } + } + $_SESSION['vars'] = $out; + $_SESSION['post'] = $data[$_GET['post']]['content']; +} else { + $_SESSION['post'] = ""; + $_SESSION['vars'] = ""; + if (isset($_GET['location']) == false) { $_GET['location'] = ""; } + if (isset($_GET['newpost'])) { $_SESSION['vars'] = "post=".$_GET['newpost'].", "; } +} +?> + <form id="update" action="./post.php" method="post" onsubmit="return validate();"> + <label>Variables:</label><input id="vars" name="vars" type="text" class="input" value="<?php echo $_SESSION['vars']; ?>"/><input type="submit" id="submit" class="input"/><br /> + <label>Location :</label><input id="loc" name="loc" type="text" class="input" value="<?php echo $_GET['location']; ?>"/><br /> + <textarea id="post" name="post" form="update" class="input"><?php echo $_SESSION['post']; ?></textarea> + </form> + </div> +</body> +</html> +""" + + post = """ +<!DOCTYPE html> +<html> + <head> + <title>Admin</title> + <style> +html { + font-family:sans-serif; + background-color:#EFEFEF; + border-top:5px solid #FF9311; +} +a { + text-decoration:none; + color:#4183c4; +} +a:hover { + text-decoration:underline; +} +a:visited { + color:#4183c4; +} + +#container { + width:700px; + margin:0 auto; +} + </style> + </head> + <body> + <div id="container"> + <a href="/admin" class="nav">Home</a> + <plaintext> +<?php +if (isset($_POST['loc'])) { + $posts = json_decode(file_get_contents($_POST['loc']),TRUE); + parse_str(str_replace(",", "&", $_POST['vars']), $data); + + $posts[$data["post"]] = array_merge($data,array("content" => $_POST["post"])); + $fp = fopen($_POST['loc'], 'w'); + fwrite($fp, json_encode($posts)); + fclose($fp); + $output = json_decode(file_get_contents($_POST['loc']),TRUE); + echo $output[$data["post"]]["content"]; +} +echo shell_exec("build %destination% -d %root%"); +?> +""" + + return { + "php:index":index.replace("%db%",blogdb[0][:-1]).replace("%dbn%",blogdb[1][:-1]), + "php:edit":edit, + "php:post":post.replace("%root%",settings['root']).replace("%destination%",settings['dest']), + } + +def getBlogDB(s): + dbs = "" + dbn = "" + data = yaml.load(file("pages.yml").read()) + + for k,v in data.items(): + for m,md in v['pagemod'].items(): + if md['mod'] == "blog": + if md['settings']['data'][0:2] == "./" or md['settings']['data'][0] != "/": + if s['root'][-1] != "/": + s['root'] = s['root'] + "/" + + dbs = dbs + "\""+s['root']+md['settings']['data'][2:]+"\"," + + else: + dbs = dbs + "\""+md['settings']['data']+"\"," + + dbn = dbn + "\""+k+"\"," + + return [dbs,dbn] + diff --git a/src/core/modules/blog.py b/src/core/modules/blog.py @@ -0,0 +1,115 @@ +import markdown,json,time + +def getPages(template,settings,name,page): + pages = {} + settings['postTemplate'] = settings.get("postTemplate","./templates/post.html") + settings['defaultPostCount'] = settings.get("defaultPostCount","0") + settings['description'] = settings.get("description","0") + settings['database'] = settings.get("database","markdown") + settings['backend'] = settings.get("backend","json") + + data = getDB(settings['data'],settings['backend'],settings['database']) + + temp = file(settings['postTemplate']).read() + + # Generates all posts on page (/all) + a = "" + posts = 0 + for i in data: + a = generatePost(i,temp,page) + a + posts += 1 + + pages['all']= {} + pages['all']['default'] = template.replace("%"+name+"%",a) + + # Generates index + a = "" + for i in data: + if int(settings['defaultPostCount']) == 0 or int(i['post']) >= posts-int(settings['defaultPostCount']): + back = i['content'] + if settings['description'] != "0": + i['content'] = i['description'] + a = generatePost(i,temp,page) + a + i['content'] = back + + pages['default'] = template.replace("%"+name+"%",a) + + # Generates individual pages referenced by title (/post/<title>) + pages['post'] = {} + for i in data: + post = generatePost(i,temp,page) + pages['post'][slug(i['title'])] = template.replace("%"+name+"%",post) + + return pages + + +#Generates post out of given template, data and page name, returns string +def generatePost(data, post, page): + for name,x in data.items(): + if name == 'title': + if page == "index": + linkpage = "" + + else: + linkpage = page + "/" + + post = post.replace("%titlelink%","/"+linkpage+"post/"+slug(x)) + post = post.replace("%"+name+"%", x) + + elif name == 'date': + config = getConfig("%date:",post) + if config == "none": + post = post.replace("%date:none%",x) + elif config == "-1": + post = post.replace("%date%",x) + else: + post = post.replace( + "%date:"+config+"%", + time.strftime(config.replace("&","%"),time.strptime(x,"%Y-%m-%d"))) + elif name == 'description': + pass + + else: + post = post.replace("%"+name+"%", x) + + return post + + +# Helper functions + +# slug(string -> "hi's") -> his- removes all "unwanted" characters and creates a URL-friendly slug +def slug(string): + invalidChars = [ + "<",">","#","%","{","}", + "|","\\","^","[","]","`", + "'",";","/","?",":","@", + "&","+",",","." + ] + for x in invalidChars: + string = string.replace(x, "") + + string = string.replace(" ","_") + return string.lower() + +# getConfig(string -> index, string -> data) -> gets "config" data ex. (%blah:<config>%) +def getConfig(index,data): + retVal = "" + try: + pointer = data.index(index)+len(index) + except: + retVal = "-1" + if retVal != "-1": + while data[pointer] != "%" and retVal != "-1": + retVal = retVal + data[pointer] + pointer += 1 + return retVal + +def getDB(db, backend, content): + dbdata = {} + if backend == "json": + dbdata = json.load(file(db)) + if content == "markdown": + for post in dbdata: + post['content'] = markdown.markdown(post['content']) + + return dbdata diff --git a/src/core/template.py b/src/core/template.py @@ -0,0 +1,49 @@ +''' +' pnbp - pnbp is not a blogging platform +' template.py +' Paul Longtine - paullongtine@gmail.com +' +' For documentation, please visit http://static.nanner.co/pnbp +''' + +import re, json, yaml +from helper.functions import * + +# Adds in variables defined in pages.json +# +# t = raw template, var = "pagevar" variables in pages.json (<pagename> -> "pagevar") +def generate(t,var,page): + if page == "index": + page = "" + + t = t.replace("%page%",page) + t = run(t,page) + + for search,replace in var.items(): + if search[0] == ":": + try: + t.index("%"+search+"%") + exists = True + + except: + exists = False + + if exists: + inc = file(replace).read() + inc = generate(inc,var,page) + print("Building include: '"+search+"'") + t = t.replace("%"+search+"%",inc) + + else: + t = t.replace("%"+search+"%",replace) + + return t + +#Takes all code blocks in templates ("{:print("Hi"):}") and executes it, and replaces the block with the "returns" variable +def run(template,page): + for script in re.findall("{:(.*?):}",template, re.DOTALL): + returns = "" + exec(script) + template = template.replace("{:"+script+":}",returns) + + return template diff --git a/src/functions.py b/src/functions.py @@ -1,24 +0,0 @@ -''' -' pnbp - pnbp is not a blogging platform -' functions.py -' Paul Longtine - paullongtine@gmail.com -' -' For documentation, please visit http://static.nanner.co/pnbp -''' -# Functions file, used for inline scripts -import time - - -#Return the current date in the format sepecified in config -def now(config): - return time.strftime(config) - -#Return an HTML list. example format: {'root':"<ul class=\"special\">%li%</ul>",'li':"<li class=\"list\">%content%</li>"} -def list(things,formats={}): - formats['root'] = formats.get("root","<ul>%li%</ul>") - formats['li'] = formats.get("li","<li>%content%</li>") - li = "" - for thing in things: - li = li + formats['li'].replace("%content%",thing) - - return formats['root'].replace("%li%",li) diff --git a/src/init.py b/src/init.py @@ -0,0 +1,23 @@ +#!/usr/bin/python +''' +' pnbp - pnbp is not a blogging platform +' init.py +' Paul Longtine - paullongtine@gmail.com +' +' For documentation, please visit http://static.nanner.co/pnbp +''' +import sys +import core +from time import time + +if __name__ == "__main__": + #Save the time for the caluation + start = time() + + #Try to build the site + core.init(sys.argv) + + #Print the time it took to build the site + print("Finished in {} ms.".format((time()-start)*1000)) + + diff --git a/src/initbasic.py b/src/initbasic.py @@ -1,8 +0,0 @@ -basicConfig = "index:\n template: \"template.html\"\n pagevar:\n title: \"I'm basic\"\n pagemod:\n page:\n mod: \"page\"" -basicTemplate = "<html>\n <body>\n <h1>%title%</h1>\n </body>\n</html>" - -def init(): - file("pages.yml","w").write(basicConfig) - file("template.html","w").write(basicTemplate) - - diff --git a/src/main.py b/src/main.py @@ -1,23 +0,0 @@ -#!/usr/bin/python -''' -' pnbp - pnbp is not a blogging platform -' main.py -' Paul Longtine - paullongtine@gmail.com -' -' For documentation, please visit http://static.nanner.co/pnbp -''' -import sys -from time import time -from core import build - -if __name__ == "__main__": - #Save the time for the caluation - start = time() - - #Try to build the site - build(sys.argv) - - #Print the time it took to build the site - print("Finished in {} ms.".format((time()-start)*1000)) - - diff --git a/src/module/__init__.py b/src/module/__init__.py @@ -1,7 +0,0 @@ -#Dynamically imports all files in this directory -import os -for module in os.listdir(os.path.dirname(__file__)): - if module == '__init__.py' or module[-3:] != '.py': - continue - __import__(module[:-3], locals(), globals()) -del module diff --git a/src/module/admin.py b/src/module/admin.py @@ -1,218 +0,0 @@ -import yaml - -def getPages(template,settings,name,page): - blogdb = getBlogDB(settings) - index = """ -<!DOCTYPE html> -<html> - <head> - <title>Admin Page</title> - <style> -html { - font-family:sans-serif; - background-color:#EFEFEF; - border-top:5px solid #FF9311; -} -a { - text-decoration:none; - color:#4183c4; -} -a:hover { - text-decoration:underline; -} -a:visited { - color:#4183c4; -} -#container { - width:700px; - margin:0 auto; -} -.container { - margin-left:50px; -} - </style> - </head> - <body> - <div id="container"> - <a href="/admin" class="nav">Home</a> - <a href="/admin/post.php">Update</a> -<?php -$databases = [%db%]; -$name = [%dbn%]; -$index = 0; -foreach ($databases as $db) { - $data = json_decode(file_get_contents($db),TRUE); - echo "<h1>".$name[$index]."</h1>"; - echo "<div class='container'>"; - $new = 0; - foreach ($data as $val) { - echo "<a href=\\"edit.php?location=".$db."&post=".$val["post"]."\\">".$val["title"]."</a><br/>"; - $new = $new + 1; - } - echo "<br /><a href=\\"edit.php?location=".$db."&newpost=".$new."\\">New Post</a><br/>"; - echo "</div>"; - $index = $index + 1; -} -?> - </div> - </body> -</html> -""" - - edit = """ -<!DOCTYPE html> -<html> -<head> - <title>Admin</title> - <style> -html { - font-family:sans-serif; - background-color:#EFEFEF; - border-top:5px solid #FF9311; -} -a { - text-decoration:none; - color:#4183c4; -} -a:hover { - text-decoration:underline; -} -a:visited { - color:#4183c4; -} -#wrapper { - width:700px; - margin:0 auto; -} -#wrapper label { - font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, monospace, serif; -} -#post { - width:100%; - height:1000px; -} -#submit { - background-color:#EFEFEF; -} -#submit:hover { - box-shadow:0px 0px 3px black inset; -} -#submit:active { - background-color:#AAEEFF; -} -.input { - outline:none; - padding:5px; - border:1px solid #DEDEDE; - border-radius:5px; - box-shadow:0px 0px 3px #DEDEDE inset; -} - </style> -</head> -<body> - <div id="wrapper"> - <a href="/admin" class="nav">Home</a> -<?php - -if (isset($_GET['location']) && isset($_GET['post'])) { - $data = json_decode(file_get_contents($_GET['location']), TRUE); - $out = ""; - foreach ($data[$_GET['post']] as $key => $val) { - if ($key !== "content") { - $out = $out . $key . "=" . $val . ", "; - } - } - $_SESSION['vars'] = $out; - $_SESSION['post'] = $data[$_GET['post']]['content']; -} else { - $_SESSION['post'] = ""; - $_SESSION['vars'] = ""; - if (isset($_GET['location']) == false) { $_GET['location'] = ""; } - if (isset($_GET['newpost'])) { $_SESSION['vars'] = "post=".$_GET['newpost'].", "; } -} -?> - <form id="update" action="./post.php" method="post" onsubmit="return validate();"> - <label>Variables:</label><input id="vars" name="vars" type="text" class="input" value="<?php echo $_SESSION['vars']; ?>"/><input type="submit" id="submit" class="input"/><br /> - <label>Location :</label><input id="loc" name="loc" type="text" class="input" value="<?php echo $_GET['location']; ?>"/><br /> - <textarea id="post" name="post" form="update" class="input"><?php echo $_SESSION['post']; ?></textarea> - </form> - </div> -</body> -</html> -""" - - post = """ -<!DOCTYPE html> -<html> - <head> - <title>Admin</title> - <style> -html { - font-family:sans-serif; - background-color:#EFEFEF; - border-top:5px solid #FF9311; -} -a { - text-decoration:none; - color:#4183c4; -} -a:hover { - text-decoration:underline; -} -a:visited { - color:#4183c4; -} - -#container { - width:700px; - margin:0 auto; -} - </style> - </head> - <body> - <div id="container"> - <a href="/admin" class="nav">Home</a> - <plaintext> -<?php -if (isset($_POST['loc'])) { - $posts = json_decode(file_get_contents($_POST['loc']),TRUE); - parse_str(str_replace(",", "&", $_POST['vars']), $data); - - $posts[$data["post"]] = array_merge($data,array("content" => $_POST["post"])); - $fp = fopen($_POST['loc'], 'w'); - fwrite($fp, json_encode($posts)); - fclose($fp); - $output = json_decode(file_get_contents($_POST['loc']),TRUE); - echo $output[$data["post"]]["content"]; -} -echo shell_exec("build %destination% -d %root%"); -?> -""" - - return { - "php:index":index.replace("%db%",blogdb[0][:-1]).replace("%dbn%",blogdb[1][:-1]), - "php:edit":edit, - "php:post":post.replace("%root%",settings['root']).replace("%destination%",settings['dest']), - } - -def getBlogDB(s): - dbs = "" - dbn = "" - data = yaml.load(file("pages.yml").read()) - - for k,v in data.items(): - for m,md in v['pagemod'].items(): - if md['mod'] == "blog": - if md['settings']['data'][0:2] == "./" or md['settings']['data'][0] != "/": - if s['root'][-1] != "/": - s['root'] = s['root'] + "/" - - dbs = dbs + "\""+s['root']+md['settings']['data'][2:]+"\"," - - else: - dbs = dbs + "\""+md['settings']['data']+"\"," - - dbn = dbn + "\""+k+"\"," - - return [dbs,dbn] - diff --git a/src/module/blog.py b/src/module/blog.py @@ -1,115 +0,0 @@ -import markdown,json,time - -def getPages(template,settings,name,page): - pages = {} - settings['postTemplate'] = settings.get("postTemplate","./templates/post.html") - settings['defaultPostCount'] = settings.get("defaultPostCount","0") - settings['description'] = settings.get("description","0") - settings['database'] = settings.get("database","markdown") - settings['backend'] = settings.get("backend","json") - - data = getDB(settings['data'],settings['backend'],settings['database']) - - temp = file(settings['postTemplate']).read() - - # Generates all posts on page (/all) - a = "" - posts = 0 - for i in data: - a = generatePost(i,temp,page) + a - posts += 1 - - pages['all']= {} - pages['all']['default'] = template.replace("%"+name+"%",a) - - # Generates index - a = "" - for i in data: - if int(settings['defaultPostCount']) == 0 or int(i['post']) >= posts-int(settings['defaultPostCount']): - back = i['content'] - if settings['description'] != "0": - i['content'] = i['description'] - a = generatePost(i,temp,page) + a - i['content'] = back - - pages['default'] = template.replace("%"+name+"%",a) - - # Generates individual pages referenced by title (/post/<title>) - pages['post'] = {} - for i in data: - post = generatePost(i,temp,page) - pages['post'][slug(i['title'])] = template.replace("%"+name+"%",post) - - return pages - - -#Generates post out of given template, data and page name, returns string -def generatePost(data, post, page): - for name,x in data.items(): - if name == 'title': - if page == "index": - linkpage = "" - - else: - linkpage = page + "/" - - post = post.replace("%titlelink%","/"+linkpage+"post/"+slug(x)) - post = post.replace("%"+name+"%", x) - - elif name == 'date': - config = getConfig("%date:",post) - if config == "none": - post = post.replace("%date:none%",x) - elif config == "-1": - post = post.replace("%date%",x) - else: - post = post.replace( - "%date:"+config+"%", - time.strftime(config.replace("&","%"),time.strptime(x,"%Y-%m-%d"))) - elif name == 'description': - pass - - else: - post = post.replace("%"+name+"%", x) - - return post - - -# Helper functions - -# slug(string -> "hi's") -> his- removes all "unwanted" characters and creates a URL-friendly slug -def slug(string): - invalidChars = [ - "<",">","#","%","{","}", - "|","\\","^","[","]","`", - "'",";","/","?",":","@", - "&","+",",","." - ] - for x in invalidChars: - string = string.replace(x, "") - - string = string.replace(" ","_") - return string.lower() - -# getConfig(string -> index, string -> data) -> gets "config" data ex. (%blah:<config>%) -def getConfig(index,data): - retVal = "" - try: - pointer = data.index(index)+len(index) - except: - retVal = "-1" - if retVal != "-1": - while data[pointer] != "%" and retVal != "-1": - retVal = retVal + data[pointer] - pointer += 1 - return retVal - -def getDB(db, backend, content): - dbdata = {} - if backend == "json": - dbdata = json.load(file(db)) - if content == "markdown": - for post in dbdata: - post['content'] = markdown.markdown(post['content']) - - return dbdata