Browse Source

reorganization and initial fabric file

pull/1/head
wes 8 years ago
parent
commit
3c34a79b47
  1. 4
      .ghci
  2. 1
      .gitignore
  3. 59
      ;
  4. 6
      Makefile
  5. 17
      blog.ini
  6. 69
      blog.scss
  7. 12
      blog.service
  8. 17
      build/blog.ini
  9. 12
      build/blog.service
  10. 0
      build/comment.py
  11. 0
      build/posts.py
  12. 1
      build/scripts/riotblog.min.js
  13. 0
      build/scripts/tags.min.js
  14. 57
      build/styles/riotblog.min.css
  15. 0
      build/styles/spectre.min.css
  16. 8
      build/templates/index.html
  17. 4
      build/website.py
  18. 57
      fabfile.py
  19. 10
      requirements.txt
  20. 33
      riotblog.cabal
  21. 28
      src/Main.hs
  22. 18
      src/comment.py
  23. 1
      src/posts.py
  24. 0
      src/scripts/riotblog.js
  25. 154
      src/scripts/tags.js
  26. 0
      src/styles/riotblog.scss
  27. 1
      src/styles/spectre.min.css
  28. 0
      src/tags/bbutton.tag
  29. 0
      src/tags/comment.tag
  30. 0
      src/tags/comments.tag
  31. 0
      src/tags/post.tag
  32. 0
      src/tags/posts.tag
  33. 42
      src/templates/index.html
  34. 88
      src/website.py
  35. 7
      stack.yaml

4
.ghci

@ -0,0 +1,4 @@
:set -isrc
:set -hide-package MonadCatchIO-mtl
:set -hide-package monads-fd
:set -XOverloadedStrings

1
.gitignore

@ -3,3 +3,4 @@
*.scssc
*.swp
*.bak
*venv*

59
;

@ -0,0 +1,59 @@
from __future__ import with_statement
from fabric.api import *
from fabric.contrib.console import confirm
from fabric.contrib.project import rsync_project
import fabric.operations as op
env.hosts = ["wes@mgoal.ca:444"]
@task
def buildTags():
with lcd("./build"):
local("riot ../src/tags scripts/tags.min.js")
@task
def buildScss():
with lcd("./build"):
local("sassc ../src/styles/riotblog.scss > styles/riotblog.min.css")
@task
def minifyJS():
with lcd("./build"):
local("uglifyjs ../src/scripts/riotblog.js > scripts/riotblog.min.js")
@task
def buildVenv():
local("virtualenv -p $(which python3) ./venv")
with prefix("source ./venv/bin/activate"):
local("pip3 install -r requirements.txt")
local("mv venv ./build/")
@task
def copyFiles():
local("cp ./{blog.ini,blog.service} ./build/")
local("cp ./src/*py ./build/")
local("cp ./src/styles/*.css ./build/styles/")
local("cp -r ./src/templates ./build/templates")
@task
def upload():
run("mkdir -p ~/build")
rsync_project(local_dir="./build/", remote_dir="~/build/", delete=True, exclude=[".git"])
@task
def serveUp():
sudo("cp -r /home/wes/build /srv/riotblog")
sudo("cp /home/wes/build/blog.service /etc/systemd/system/blog.service")
sudo("systemctl enable blog.service")
@task(default=True)
def build():
local("rm -r ./build")
local("mkdir -p build/{scripts,styles}")
buildTags()
buildScss()
minifyJS()
buildVenv()
copyFiles()
upload()
serveUp()

6
Makefile

@ -1,6 +0,0 @@
default:
sass blog.scss > styles/blog.min.css
riot tags/ scripts/tags.js
watch:
while true; do make ; inotifywait -qre close_write .; done

17
blog.ini

@ -0,0 +1,17 @@
[uwsgi]
wsgi_file = /srv/http/riotblog/website.py
chdir = /srv/http/riotblog/
module = website
callable = app
virtualenv = /srv/http/riotblog/venv
uid = http
gid = http
master = true
processes = 5
socket = /tmp/blog.sock
chown-socket = http:http
chmod-socket = 660
vacuum = true
die-on-term = true

69
blog.scss

@ -1,69 +0,0 @@
@mixin responsive-block($bw) {
@media (max-width: 700px) {
max-width: $bw+20%;
}
@media (max-width: 500px) {
max-width: $bw+40%;
}
}
.post-text {
text-align: center;
}
.blog-title {
@extend .post-text;
}
.post {
@extend .post-text;
}
.post-content {
max-width: 50%;
text-align: justify;
font-size: 1.5em;
@include responsive-block(50);
}
.comment-block {
max-width: 30%;
@include responsive-block(30);
}
.comments {
margin-top: 5%;
@extend .comment-block;
}
.comment {
margin-top: 2%;
max-width: 40%;
@include responsive-block(45);
}
.comments-loader {
margin-top: 2%;
}
.comment-body {
margin-left: 10px;
margin-right: 10px;
}
.postnav {
@extend .post-text;
}
.rounded-button {
border-radius: 13px;
}
.maxinput {
background-color: grey;
}
.maxwarn {
margin-top: 15px;
@extend .comment-block;
}

12
blog.service

@ -0,0 +1,12 @@
[Unit]
Description=My Blargh
After=network.target
[Service]
User=http
Group=http
WorkingDirectory=/srv/http/riotblog
ExecStart=/usr/bin/uwsgi --ini /srv/http/riotblog/blog.ini
[Install]
WantedBy=multi.user.target

17
build/blog.ini

@ -0,0 +1,17 @@
[uwsgi]
wsgi_file = /srv/http/riotblog/website.py
chdir = /srv/http/riotblog/
module = website
callable = app
virtualenv = /srv/http/riotblog/venv
uid = http
gid = http
master = true
processes = 5
socket = /tmp/blog.sock
chown-socket = http:http
chmod-socket = 660
vacuum = true
die-on-term = true

12
build/blog.service

@ -0,0 +1,12 @@
[Unit]
Description=My Blargh
After=network.target
[Service]
User=http
Group=http
WorkingDirectory=/srv/http/riotblog
ExecStart=/usr/bin/uwsgi --ini /srv/http/riotblog/blog.ini
[Install]
WantedBy=multi.user.target

0
comment.py → build/comment.py

0
posts.py → build/posts.py

1
build/scripts/riotblog.min.js

@ -0,0 +1 @@
riot.mount("post",{creator:"wes",title:"A cool post here"});riot.mount("bbutton");

0
scripts/tags.js → build/scripts/tags.min.js

57
build/styles/riotblog.min.css

@ -0,0 +1,57 @@
.post-text, .blog-title, .post, .postnav {
text-align: center; }
.post-content {
max-width: 50%;
text-align: justify;
font-size: 1.5em; }
@media (max-width: 700px) {
.post-content {
max-width: 70%; } }
@media (max-width: 500px) {
.post-content {
max-width: 90%; } }
.comment-block, .comments, .maxwarn {
max-width: 30%; }
@media (max-width: 700px) {
.comment-block, .comments, .maxwarn {
max-width: 50%; } }
@media (max-width: 500px) {
.comment-block, .comments, .maxwarn {
max-width: 70%; } }
.comments {
margin-top: 5%; }
.comment {
margin-top: 2%;
max-width: 40%; }
@media (max-width: 700px) {
.comment {
max-width: 65%; } }
@media (max-width: 500px) {
.comment {
max-width: 85%; } }
.comments-loader {
margin-top: 2%; }
.comment-body {
margin-left: 10px;
margin-right: 10px; }
.rounded-button {
border-radius: 13px; }
.maxinput {
background-color: grey; }
.maxwarn {
margin-top: 15px; }

0
styles/spectre.min.css → build/styles/spectre.min.css

8
templates/index.html → build/templates/index.html

@ -2,7 +2,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<header class="text-center nav navbar">
<section class="centered page-top navbar-section">
<h1 class="blog-title">Null Quantification</h1>
<h1 class="blog-title">blog</h1>
</section>
</header>
{% endblock %}
@ -25,7 +25,7 @@
{% block styles %}
<link rel="stylesheet" href="/styles/spectre.min.css">
<link rel="stylesheet" href="/styles/blog.min.css">
<link rel="stylesheet" href="/styles/riotblog.min.css">
{% endblock %}
@ -34,8 +34,8 @@
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/riot/2.6.7/riot+compiler.min.js"></script>
<script type="text/javascript" src="//cdn.jsdelivr.net/riot-route/3.0.2/route.min.js"></script>
<script type="text/javascript" src="/scripts/tags.js"></script>
<script type="text/javascript" src="/scripts/blog.js"></script>
<script type="text/javascript" src="/scripts/tags.min.js"></script>
<script type="text/javascript" src="/scripts/riotblog.min.js"></script>
{% endblock %}
</body>

4
website.py → build/website.py

@ -2,7 +2,6 @@
from functools import partial
from flask import abort, Flask, render_template, flash, request, send_from_directory
from flask_bootstrap import Bootstrap
from flask_appconfig import AppConfig
from time import sleep
@ -48,7 +47,7 @@ def NeverWhere(configfile=None):
@app.route("/scripts/<filename>", methods=("GET", "POST"))
def send_script(filename):
print("matched scripts route")
return send_from_directory("/home/wes/riotblog/scripts/", filename)
return send_from_directory("./scripts", filename)
@app.route("/styles/<filename>", methods=("GET", "POST"))
def send_style(filename):
@ -80,7 +79,6 @@ def NeverWhere(configfile=None):
def page_not_found(path):
return "Custom failure message"
Bootstrap(app)
app.run(debug=True)
return app

57
fabfile.py

@ -0,0 +1,57 @@
from __future__ import with_statement
from fabric.api import *
from fabric.contrib.console import confirm
from fabric.contrib.project import rsync_project
import fabric.operations as op
env.hosts = ["wes@mgoal.ca:444"]
@task
def buildTags():
with lcd("./build"):
local("riot ../src/tags scripts/tags.min.js")
@task
def buildScss():
with lcd("./build"):
local("sassc ../src/styles/riotblog.scss > styles/riotblog.min.css")
@task
def minifyJS():
with lcd("./build"):
local("uglifyjs ../src/scripts/riotblog.js > scripts/riotblog.min.js")
@task
def buildVenv():
local("virtualenv -p $(which python3) ./venv")
with prefix("source ./venv/bin/activate"):
local("pip3 install -r requirements.txt")
local("mv venv ./build/")
@task
def copyFiles():
local("cp ./{blog.ini,blog.service} ./build/")
local("cp ./src/*py ./build/")
local("cp ./src/styles/*.css ./build/styles/")
local("cp -r ./src/templates ./build/templates")
@task
def upload():
run("mkdir -p ~/build")
rsync_project(local_dir="./build/", remote_dir="~/build/", delete=True, exclude=[".git"])
@task
def serveUp():
sudo("cp -r /home/wes/build /srv/riotblog")
@task(default=True)
def build():
local("rm -r ./build")
local("mkdir -p build/{scripts,styles}")
buildTags()
buildScss()
minifyJS()
buildVenv()
copyFiles()
upload()
serveUp()

10
requirements.txt

@ -0,0 +1,10 @@
appdirs==1.4.0
click==6.7
Flask==0.12
itsdangerous==0.24
Jinja2==2.9.5
MarkupSafe==0.23
packaging==16.8
pyparsing==2.1.10
six==1.10.0
Werkzeug==0.11.15

33
riotblog.cabal

@ -1,33 +0,0 @@
Name: riotblog
Version: 0.1
Synopsis: Project Synopsis Here
Description: Project Description Here
License: AllRightsReserved
Author: Author
Maintainer: maintainer@example.com
Stability: Experimental
Category: Web
Build-type: Simple
Cabal-version: >=1.2
Executable riotblog
hs-source-dirs: src
main-is: Main.hs
Build-depends:
base >= 4 && < 5,
bytestring >= 0.9.1 && < 0.11,
monad-control >= 1.0 && < 1.1,
mtl >= 2 && < 3,
snap-core >= 1.0 && < 1.1,
snap-server >= 1.0 && < 1.1,
text -any,
unordered-containers -any,
data-default -any,
shakespeare >=2.0.11.2
if impl(ghc >= 6.12.0)
ghc-options: -threaded -Wall -fwarn-tabs -funbox-strict-fields -O2
-fno-warn-unused-do-bind
else
ghc-options: -threaded -Wall -fwarn-tabs -funbox-strict-fields -O2

28
src/Main.hs

@ -1,28 +0,0 @@
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Control.Applicative
import Snap.Core
import Snap.Util.FileServe
import Snap.Http.Server
import qualified Data.Text.IO as TIO (readFile)
import Data.Text
import qualified Data.HashMap.Strict as HM
import Text.Hamlet
main :: IO ()
main = quickHttpServe site
site :: Snap ()
site =
ifTop (writeBS "Hello, world! Hey Hey Hey") <|>
route [ ("foo", writeBS "bar")
, ("echo/:echoparam", echoHandler)
] <|>
dir "static" (serveDirectory ".")
echoHandler :: Snap ()
echoHandler = do
param <- getParam "echoparam"
maybe (writeBS "must specify echo/param in URL")
writeBS param

18
src/comment.py

@ -0,0 +1,18 @@
from json import dumps
def comment(author, title, text):
return {
"title" : title,
"author" : author,
"text" : text
}
testcomments = {
1 : dumps(
[
comment("Anonymous Coward", "Some comment?", "super duper awesome comment here"),
comment("Anonymous Coward 3", "Something? IDEK", "super duper worse comment here"),
comment("Anonymous Coward 2", "Some other comment?", "super duper dang terrible comment here")
])
}

1
src/posts.py

@ -0,0 +1 @@
from functools import total_ordering

0
scripts/blog.js → src/scripts/riotblog.js

154
src/scripts/tags.js

@ -0,0 +1,154 @@
riot.tag2('bbutton', '<button class="btn rounded-button"> </button>', '', '', function(opts) {
});
riot.tag2('comment', '<div class="comment centered"> <div class="card"> <div class="card-header"> <h4 class="card-title">{title} by {author}</h4> </div> <div class="card-body comment-body"> {R.join(⁗ ⁗)(R.repeat(text, 20))} </div> </div> </div>', '', '', function(opts) {
});
riot.tag2('comments', '<div if="{loading}" class="loading comments-loader"> </div> <comment if="{!loading}" each="{comments}" data="{this}"></comment> <textarea onfocus="{clearplaceholder}" onblur="{checkplaceholder}" oninput="{echo}" __disabled="{disabled}" class="{⁗form-input comments centered ⁗ + maxed}" name="textarea" rows="10" cols="50" maxlength="{maxlength}"> {placeholder} </textarea> <div if="{warn}" class="toast toast-danger maxwarn centered"> <button onclick="{closewarning}" class="btn btn-clear float-right"> </button> You\'ve reached the max comment size </div>', '', '', function(opts) {
comments = [];
maxlength = 700;
placeholder = "Comment here!";
focused = false;
maxed = false;
warn = false;
disabled = "";
loading = true;
this.clearplaceholder = function() {
if (!this.focused) {
this.update({
"placeholder" : "",
"focused" : true
})
}
}.bind(this)
this.checkplaceholder = function() {
if (this.textarea.value.trim().length == 0) {
this.update({
"placeholder" : "Comment here!",
"focused" : false
});
}
}.bind(this)
this.closewarning = function() {
this.update({"warn" : false});
}.bind(this)
this.echo = function(ev) {
if (this.textarea.value.length >= maxlength) {
this.update({
"maxed" : "maxinput",
"warn" : true
});
}
else {
this.update({
"maxed" : false,
"warn" : false
});
window.setTimeout(this.closewarning, 5000);
}
}.bind(this)
var self = this;
this.getComments = function(pid) {
fetch("/comments/"+pid)
.then(
function(resp) {
return resp.text();
})
.then(
function(body) {
self.update(
{
"comments" : JSON.parse(body),
"loading" : false
});
});
}.bind(this)
this.on("mount",
function() {
this.getComments(self.opts.pid);
});
});
riot.tag2('post', '<div class="postnav centered"> <button class="{⁗btn btn-primary ⁗ + (this.pid <= 1 ? ⁗disabled⁗ : ⁗ ⁗) + this.prevloading}" onclick="{prev}">Previous Post</button> <button class="{⁗btn btn-primary ⁗ + (this.nomore ? ⁗disabled⁗ : ⁗ ⁗) + this.nextloading}" onclick="{next}">Next Post</button> </div> <h4 class="post centered" if="{nomore}"> No More Posts! </h4> <div if="{!(loading || nomore)}" class="post centered"> <h4>{opts.title}</h4> <h5>By {opts.creator}</h5> <p class="post-content centered text-break">{content}</p> <div class="divider"></div> <comments pid="{pid}"> </comments> </div>', '', '', function(opts) {
var self = this;
this.loading = false;
this.prevloading = "";
this.nextloading = "";
this.nomore = false
this.pid = 1;
content = "";
this.prev = function() {
if (self.prevloading || self.nextloading) {
return;
}
self.prevloading = " loading";
if (self.nomore) {
self.nomore = false;
}
if (self.pid > 1) {
self.pid--;
self.setPost(self.pid);
self.update();
}
}.bind(this)
this.next = function() {
if (self.nextloading || self.prevloading) {
return;
}
self.nextloading = " loading";
console.log(self.pid);
console.log(self.nomore);
if (!self.nomore) {
self.pid++;
self.setPost(self.pid);
self.update();
}
}.bind(this)
this.setPost = function(pid) {
self.update();
self.loading = true;
fetch("/switchpost/"+pid)
.then(
function(resp) {
return resp.text();
})
.then(
function(body) {
if (body === "false") {
self.nomore = true;
route("/");
self.update()
}
else {
self.content = R.join(" ")(R.repeat(body, 20));
route("/"+pid);
}
self.loading = false;
self.prevloading = "";
self.nextloading = "";
self.update();
});
}
this.on("mount", function() { this.setPost(self.pid) });
});
riot.tag2('posts', '<yield></yield>', '', '', function(opts) {
});

0
styles/blog.min.css → src/styles/riotblog.scss

1
src/styles/spectre.min.css

File diff suppressed because one or more lines are too long

0
tags/bbutton.tag → src/tags/bbutton.tag

0
tags/comment.tag → src/tags/comment.tag

0
tags/comments.tag → src/tags/comments.tag

0
tags/post.tag → src/tags/post.tag

0
tags/posts.tag → src/tags/posts.tag

42
src/templates/index.html

@ -0,0 +1,42 @@
{% block head %}
<meta name="viewport" content="width=device-width, initial-scale=1">
<header class="text-center nav navbar">
<section class="centered page-top navbar-section">
<h1 class="blog-title">blog</h1>
</section>
</header>
{% endblock %}
<html>
<body>
{% block content %}
<posts>
<post></post>
</posts>
<editor>
</editor>
{% endblock %}
<footer class="footer">
</footer>
{% block styles %}
<link rel="stylesheet" href="/styles/spectre.min.css">
<link rel="stylesheet" href="/styles/riotblog.min.css">
{% endblock %}
{% block scripts %}
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/fetch/1.0.0/fetch.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/riot/2.6.7/riot+compiler.min.js"></script>
<script type="text/javascript" src="//cdn.jsdelivr.net/riot-route/3.0.2/route.min.js"></script>
<script type="text/javascript" src="/scripts/tags.min.js"></script>
<script type="text/javascript" src="/scripts/riotblog.min.js"></script>
{% endblock %}
</body>
</html>

88
src/website.py

@ -0,0 +1,88 @@
#! /usr/bin/python3
from functools import partial
from flask import abort, Flask, render_template, flash, request, send_from_directory
from flask_appconfig import AppConfig
from time import sleep
from urllib.parse import unquote
from urllib.parse import quote, unquote
from json import dumps, loads
from comment import testcomments
from werkzeug.contrib.cache import MemcachedCache
cache = MemcachedCache(['127.0.0.1:11211'])
import os
def cacheit(key, thunk):
"""
Tries to find a cached version of ``key''
If there is no cached version then it will
evaluate thunk (which must be a generator)
and cache that, then return the result
"""
cached = cache.get(quote(key))
if cached is None:
result = list(thunk())
cache.set(quote(key), result)
return result
return cached
def NeverWhere(configfile=None):
app = Flask(__name__)
app.config["TEMPLATES_AUTO_RELOAD"] = True
#def favicon():
#return send_from_directory("/srv/http/goal/favicon.ico",
#'favicon.ico', mimetype='image/vnd.microsoft.icon')
@app.route("/", methods=("GET", "POST"))
def index():
print("matched index")
return render_template("index.html")
@app.route("/scripts/<filename>", methods=("GET", "POST"))
def send_script(filename):
print("matched scripts route")
return send_from_directory("./scripts", filename)
@app.route("/styles/<filename>", methods=("GET", "POST"))
def send_style(filename):
return send_from_directory("./styles", filename)
@app.route("/switchpost/<pid>")
def switchPost(pid):
posts = {
"1" : "Post one is changed! ",
"2" : "Post two here and it's changed! "
}
return posts.get(pid, "false")
@app.route("/comments/<pid>")
def comments(pid):
sleep(5);
try:
return testcomments.get(int(pid), dumps([]))
except ValueError as e:
print(e)
return dumps([])
@app.route("/insert/<pid>")
def insert(pid):
print("inserting new post")
@app.route("/<path:path>")
def page_not_found(path):
return "Custom failure message"
app.run(debug=True)
return app
app = NeverWhere()
if __name__ == "__main__":
NeverWhere("./appconfig").run(host="localhost", port=8001, debug=True)

7
stack.yaml

@ -1,7 +0,0 @@
flags: {}
extra-package-dbs: []
packages:
- '.'
extra-deps:
- ginger-0.3.7.2
resolver: lts-7.12
Loading…
Cancel
Save