This commit is contained in:
Matthew Scragg 2013-10-09 16:35:06 -05:00
förälder 9d3751f241
incheckning 3cc69ce06f
24 ändrade filer med 698 tillägg och 8837 borttagningar

3
.bowerrc Normal file
Visa fil

@ -0,0 +1,3 @@
{
"directory": "realms/static/vendor"
}

3
.gitignore vendored
Visa fil

@ -1,5 +1,8 @@
.vagrant .vagrant
.idea .idea
.webassets-cache
*.pyc *.pyc
packed-*.js
config.py config.py
config.sls config.sls
realms/static/vendor

16
bower.json Normal file
Visa fil

@ -0,0 +1,16 @@
{
"name": "realms",
"version": "0.1.1",
"dependencies": {
"components-bootstrap": "3.0.0",
"jquery": "1.9.1",
"components-underscore": "~1.5.1",
"requirejs": "~2.1.8",
"highlightjs": "~7.3.0",
"handlebars": "~1.0.0",
"components-font-awesome": "~3.2.1",
"showdown": "~0.3.1",
"keymaster": "madrobby/keymaster",
"ace": "~1.0.0"
}
}

Visa fil

@ -6,7 +6,7 @@ from threading import Lock
import rethinkdb as rdb import rethinkdb as rdb
from flask import Flask, request, render_template, url_for, redirect, flash from flask import Flask, request, render_template, url_for, redirect, flash
from flask.ext.login import LoginManager, login_required from flask.ext.login import LoginManager, login_required
from flask.ext.assets import Environment from flask.ext.assets import Environment, Bundle
from recaptcha.client import captcha from recaptcha.client import captcha
from werkzeug.routing import BaseConverter from werkzeug.routing import BaseConverter
@ -18,10 +18,18 @@ from models import Site, User, CurrentUser
from ratelimit import get_view_rate_limit, ratelimiter from ratelimit import get_view_rate_limit, ratelimiter
from services import db from services import db
# Flask instance container
instances = {} instances = {}
# Flask extension objects
login_manager = LoginManager()
assets = Environment()
class SubdomainDispatcher(object): class SubdomainDispatcher(object):
"""
Application factory
"""
def __init__(self, domain, create_app): def __init__(self, domain, create_app):
self.domain = domain self.domain = domain
self.create_app = create_app self.create_app = create_app
@ -44,6 +52,9 @@ class SubdomainDispatcher(object):
def init_db(dbname): def init_db(dbname):
"""
Assures DB has minimal setup
"""
if not dbname in rdb.db_list().run(db): if not dbname in rdb.db_list().run(db):
print "Creating DB %s" % dbname print "Creating DB %s" % dbname
rdb.db_create(dbname).run(db) rdb.db_create(dbname).run(db)
@ -65,6 +76,9 @@ def init_db(dbname):
class RegexConverter(BaseConverter): class RegexConverter(BaseConverter):
"""
Enables Regex matching on endpoints
"""
def __init__(self, url_map, *items): def __init__(self, url_map, *items):
super(RegexConverter, self).__init__(url_map) super(RegexConverter, self).__init__(url_map)
self.regex = items[0] self.regex = items[0]
@ -85,7 +99,17 @@ def validate_captcha():
return response.is_valid return response.is_valid
def format_subdomain(s):
s = s.lower()
s = to_canonical(s)
if s in ['www']:
# Not allowed
s = ""
return s
def make_app(subdomain): def make_app(subdomain):
subdomain = format_subdomain(subdomain)
if subdomain and not Wiki.is_registered(subdomain): if subdomain and not Wiki.is_registered(subdomain):
return redirect("http://%s/_new/?site=%s" % (config.hostname, subdomain)) return redirect("http://%s/_new/?site=%s" % (config.hostname, subdomain))
return create_app(subdomain) return create_app(subdomain)
@ -100,7 +124,6 @@ def create_app(subdomain=None):
app.session_interface = RedisSessionInterface() app.session_interface = RedisSessionInterface()
app.url_map.converters['regex'] = RegexConverter app.url_map.converters['regex'] = RegexConverter
login_manager = LoginManager()
login_manager.init_app(app) login_manager.init_app(app)
login_manager.login_view = 'login' login_manager.login_view = 'login'
@ -108,9 +131,26 @@ def create_app(subdomain=None):
def load_user(user_id): def load_user(user_id):
return CurrentUser(user_id) return CurrentUser(user_id)
assets = Environment(app) assets.init_app(app)
assets.url = app.static_url_path if 'js_common' not in assets._named_bundles:
assets.directory = app.static_folder js = Bundle('vendor/jquery/jquery.js',
'vendor/components-underscore/underscore.js',
'vendor/components-bootstrap/js/bootstrap.js',
'vendor/handlebars/handlebars.js',
'vendor/showdown/src/showdown.js',
'js/html-sanitizer-minified.js',
'js/wmd.js',
'vendor/highlightjs/highlight.pack.js',
filters='uglifyjs', output='packed-common.js')
assets.register('js_common', js)
if 'js_editor' not in assets._named_bundles:
js = Bundle('js/ace/ace.js',
'js/ace/mode-markdown.js',
'vendor/keymaster/keymaster.js',
'js/dillinger.js',
filters='uglifyjs', output='packed-editor.js')
assets.register('js_editor', js)
repo_dir = config.repos['dir'] repo_dir = config.repos['dir']
repo_name = subdomain if subdomain else "_" repo_name = subdomain if subdomain else "_"

Filskillnaden har hållits tillbaka eftersom den är för stor Load diff

File diff suppressed because one or more lines are too long

Filskillnaden har hållits tillbaka eftersom den är för stor Load diff

Filskillnaden har hållits tillbaka eftersom den är för stor Load diff

File diff suppressed because one or more lines are too long

Visa fil

@ -1,7 +0,0 @@
/*!
Autosize v1.17.8 - 2013-09-07
Automatically adjust textarea height based on user input.
(c) 2013 Jack Moore - http://www.jacklmoore.com/autosize
license: http://www.opensource.org/licenses/mit-license.php
*/
(function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e(window.jQuery||window.$)})(function(e){var t,o={className:"autosizejs",append:"",callback:!1,resizeDelay:10},i='<textarea tabindex="-1" style="position:absolute; top:-999px; left:0; right:auto; bottom:auto; border:0; padding: 0; -moz-box-sizing:content-box; -webkit-box-sizing:content-box; box-sizing:content-box; word-wrap:break-word; height:0 !important; min-height:0 !important; overflow:hidden; transition:none; -webkit-transition:none; -moz-transition:none;"/>',n=["fontFamily","fontSize","fontWeight","fontStyle","letterSpacing","textTransform","wordSpacing","textIndent"],s=e(i).data("autosize",!0)[0];s.style.lineHeight="99px","99px"===e(s).css("lineHeight")&&n.push("lineHeight"),s.style.lineHeight="",e.fn.autosize=function(i){return this.length?(i=e.extend({},o,i||{}),s.parentNode!==document.body&&e(document.body).append(s),this.each(function(){function o(){var t,o;"getComputedStyle"in window?(t=window.getComputedStyle(u),o=u.getBoundingClientRect().width,e.each(["paddingLeft","paddingRight","borderLeftWidth","borderRightWidth"],function(e,i){o-=parseInt(t[i],10)}),s.style.width=o+"px"):s.style.width=Math.max(p.width(),0)+"px"}function a(){var a={};if(t=u,s.className=i.className,d=parseInt(p.css("maxHeight"),10),e.each(n,function(e,t){a[t]=p.css(t)}),e(s).css(a),o(),window.chrome){var r=u.style.width;u.style.width="0px",u.offsetWidth,u.style.width=r}}function r(){var e,n;t!==u?a():o(),s.value=u.value+i.append,s.style.overflowY=u.style.overflowY,n=parseInt(u.style.height,10),s.scrollTop=0,s.scrollTop=9e4,e=s.scrollTop,d&&e>d?(u.style.overflowY="scroll",e=d):(u.style.overflowY="hidden",c>e&&(e=c)),e+=f,n!==e&&(u.style.height=e+"px",w&&i.callback.call(u,u))}function l(){clearTimeout(h),h=setTimeout(function(){var e=p.width();e!==g&&(g=e,r())},parseInt(i.resizeDelay,10))}var d,c,h,u=this,p=e(u),f=0,w=e.isFunction(i.callback),z={height:u.style.height,overflow:u.style.overflow,overflowY:u.style.overflowY,wordWrap:u.style.wordWrap,resize:u.style.resize},g=p.width();p.data("autosize")||(p.data("autosize",!0),("border-box"===p.css("box-sizing")||"border-box"===p.css("-moz-box-sizing")||"border-box"===p.css("-webkit-box-sizing"))&&(f=p.outerHeight()-p.height()),c=Math.max(parseInt(p.css("minHeight"),10)-f||0,p.height()),p.css({overflow:"hidden",overflowY:"hidden",wordWrap:"break-word",resize:"none"===p.css("resize")||"vertical"===p.css("resize")?"none":"horizontal"}),"onpropertychange"in u?"oninput"in u?p.on("input.autosize keyup.autosize",r):p.on("propertychange.autosize",function(){"value"===event.propertyName&&r()}):p.on("input.autosize",r),i.resizeDelay!==!1&&e(window).on("resize.autosize",l),p.on("autosize.resize",r),p.on("autosize.resizeIncludeStyle",function(){t=null,r()}),p.on("autosize.destroy",function(){t=null,clearTimeout(h),e(window).off("resize",l),p.off("autosize").off(".autosize").css(z).removeData("autosize")}),r())})):this}});

Visa fil

@ -1,4 +0,0 @@
// keymaster.js
// (c) 2011 Thomas Fuchs
// keymaster.js may be freely distributed under the MIT license.
(function(a){function m(a,b,c){a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent&&a.attachEvent("on"+b,function(){c(window.event)})}function l(a){e=a||"all"}function k(a,b,d){var e,h,i,j;d===undefined&&(d=b,b="all"),a=a.replace(/\s/g,""),e=a.split(","),e[e.length-1]==""&&(e[e.length-2]+=",");for(i=0;i<e.length;i++){h=[],a=e[i].split("+");if(a.length>1){h=a.slice(0,a.length-1);for(j=0;j<h.length;j++)h[j]=f[h[j]];a=[a[a.length-1]]}a=a[0],a=g[a]||a.toUpperCase().charCodeAt(0),a in c||(c[a]=[]),c[a].push({shortcut:e[i],scope:b,method:d,key:e[i],mods:h})}}function j(a){var b=a.keyCode,c;if(b==93||b==224)b=91;if(b in d){d[b]=!1;for(c in f)f[c]==b&&(k[c]=!1)}}function i(a){var b,g,i,j,l,m;g=(a.target||a.srcElement).tagName,b=a.keyCode;if(b==93||b==224)b=91;if(b in d){d[b]=!0;for(j in f)f[j]==b&&(k[j]=!0)}else{if(g=="INPUT"||g=="SELECT"||g=="TEXTAREA")return;if(!(b in c))return;for(l=0;l<c[b].length;l++){i=c[b][l];if(i.scope==e||i.scope=="all"){m=i.mods.length>0;for(j in d)if(!d[j]&&h(i.mods,+j)>-1||d[j]&&h(i.mods,+j)==-1)m=!1;(i.mods.length==0&&!d[16]&&!d[18]&&!d[17]&&!d[91]||m)&&i.method(a,i)===!1&&(a.preventDefault?a.preventDefault():a.returnValue=!1,a.stopPropagation&&a.stopPropagation(),a.cancelBubble&&(a.cancelBubble=!0))}}}}function h(a,b){var c=a.length;while(c--)if(a[c]===b)return c;return-1}var b,c={},d={16:!1,18:!1,17:!1,91:!1},e="all",f={"⇧":16,shift:16,"⌥":18,alt:18,option:18,"⌃":17,ctrl:17,control:17,"⌘":91,command:91},g={backspace:8,tab:9,clear:12,enter:13,"return":13,esc:27,escape:27,space:32,left:37,up:38,right:39,down:40,del:46,"delete":46,home:36,end:35,pageup:33,pagedown:34,",":188,".":190,"/":191,"`":192,"-":189,"=":187,";":186,"'":222,"[":219,"]":221,"\\":220};for(b=1;b<20;b++)f["f"+b]=111+b;for(b in f)k[b]=!1;m(document,"keydown",i),m(document,"keyup",j),a.key=k,a.key.setScope=l,typeof module!="undefined"&&(module.exports=key)})(this)

Filskillnaden har hållits tillbaka eftersom den är för stor Load diff

Visa fil

@ -1,5 +0,0 @@
//
// Github Extension (WIP)
// ~~strike-through~~ -> <del>strike-through</del>
//
(function(){var a=function(a){return[{type:"lang",regex:"(~T){2}([^~]+)(~T){2}",replace:function(a,b,c,d){return"<del>"+c+"</del>"}}]};typeof window!="undefined"&&window.Showdown&&window.Showdown.extensions&&(window.Showdown.extensions.github=a),typeof module!="undefined"&&(module.exports=a)})();

Visa fil

@ -1,6 +0,0 @@
//
// Google Prettify
// A showdown extension to add Google Prettify (http://code.google.com/p/google-code-prettify/)
// hints to showdown's HTML output.
//
(function(){var a=function(a){return[{type:"output",filter:function(a){return a.replace(/(<pre>)?<code>/gi,function(a,b){return b?'<pre class="prettyprint linenums" tabIndex="0"><code data-inner="1">':'<code class="prettyprint">'})}}]};typeof window!="undefined"&&window.Showdown&&window.Showdown.extensions&&(window.Showdown.extensions.googlePrettify=a),typeof module!="undefined"&&(module.exports=a)})();

Visa fil

@ -1,105 +0,0 @@
/*global module:true*/
/*
* Basic table support with re-entrant parsing, where cell content
* can also specify markdown.
*
* Tables
* ======
*
* | Col 1 | Col 2 |
* |======== |====================================================|
* |**bold** | ![Valid XHTML] (http://w3.org/Icons/valid-xhtml10) |
* | Plain | Value |
*
*/
(function(){
var table = function(converter) {
var tables = {}, style = 'text-align:left;', filter;
tables.th = function(header){
if (header.trim() === "") { return "";}
var id = header.trim().replace(/ /g, '_').toLowerCase();
return '<th id="' + id + '" style="'+style+'">' + header + '</th>';
};
tables.td = function(cell) {
return '<td style="'+style+'">' + converter.makeHtml(cell) + '</td>';
};
tables.ths = function(){
var out = "", i = 0, hs = [].slice.apply(arguments);
for (i;i<hs.length;i+=1) {
out += tables.th(hs[i]) + '\n';
}
return out;
};
tables.tds = function(){
var out = "", i = 0, ds = [].slice.apply(arguments);
for (i;i<ds.length;i+=1) {
out += tables.td(ds[i]) + '\n';
}
return out;
};
tables.thead = function() {
var out, i = 0, hs = [].slice.apply(arguments);
out = "<thead>\n";
out += "<tr>\n";
out += tables.ths.apply(this, hs);
out += "</tr>\n";
out += "</thead>\n";
return out;
};
tables.tr = function() {
var out, i = 0, cs = [].slice.apply(arguments);
out = "<tr>\n";
out += tables.tds.apply(this, cs);
out += "</tr>\n";
return out;
};
filter = function(text) {
var i=0, lines = text.split('\n'), tbl = [], line, hs, rows, out = [];
for (i; i<lines.length;i+=1) {
line = lines[i];
// looks like a table heading
if (line.trim().match(/^[|]{1}.*[|]{1}$/)) {
line = line.trim();
tbl.push('<table>');
hs = line.substring(1, line.length -1).split('|');
tbl.push(tables.thead.apply(this, hs));
line = lines[++i];
if (!line.trim().match(/^[|]{1}[-=| ]+[|]{1}$/)) {
// not a table rolling back
line = lines[--i];
}
else {
line = lines[++i];
tbl.push('<tbody>');
while (line.trim().match(/^[|]{1}.*[|]{1}$/)) {
line = line.trim();
tbl.push(tables.tr.apply(this, line.substring(1, line.length -1).split('|')));
line = lines[++i];
}
tbl.push('</tbody>');
tbl.push('</table>');
// we are done with this table and we move along
out.push(tbl.join('\n'));
continue;
}
}
out.push(line);
}
return out.join('\n');
};
return [
{
type: 'lang',
filter: filter
}
];
};
// Client-side export
if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) { window.Showdown.extensions.table = table; }
// Server-side export
if (typeof module !== 'undefined') {
module.exports = table;
}
}());

Visa fil

@ -1,6 +0,0 @@
//
// Twitter Extension
// @username -> <a href="http://twitter.com/username">@username</a>
// #hashtag -> <a href="http://twitter.com/search/%23hashtag">#hashtag</a>
//
(function(){var a=function(a){return[{type:"lang",regex:"\\B(\\\\)?@([\\S]+)\\b",replace:function(a,b,c){return b==="\\"?a:'<a href="http://twitter.com/'+c+'">@'+c+"</a>"}},{type:"lang",regex:"\\B(\\\\)?#([\\S]+)\\b",replace:function(a,b,c){return b==="\\"?a:'<a href="http://twitter.com/search/%23'+c+'">#'+c+"</a>"}},{type:"lang",regex:"\\\\@",replace:"@"}]};typeof window!="undefined"&&window.Showdown&&window.Showdown.extensions&&(window.Showdown.extensions.twitter=a),typeof module!="undefined"&&(module.exports=a)})();

Filskillnaden har hållits tillbaka eftersom den är för stor Load diff

File diff suppressed because one or more lines are too long

Visa fil

@ -3,6 +3,10 @@
* Copyright (c) 2010 Caolan McMahon * Copyright (c) 2010 Caolan McMahon
*/ */
/*
* Fork of https://github.com/caolan/wmd
*/
function escapeHtml(s) { function escapeHtml(s) {
s = ('' + s); /* Coerce to string */ s = ('' + s); /* Coerce to string */
s = s.replace(/&/g, '&amp;'); s = s.replace(/&/g, '&amp;');
@ -22,7 +26,9 @@ function escapeHtml(s) {
* @api public * @api public
*/ */
var WMD = function (content, options) { var WMD = {};
WMD.convert = function(content, options) {
var doc = {raw: content, markdown: content}; var doc = {raw: content, markdown: content};
var opt = WMD.readOptions(options); var opt = WMD.readOptions(options);
WMD.preprocess(doc, opt); WMD.preprocess(doc, opt);

Visa fil

@ -10,8 +10,9 @@
<link href="/static/css/bootstrap/spacelab.css" rel="stylesheet"> <link href="/static/css/bootstrap/spacelab.css" rel="stylesheet">
<link href="/static/css/font-awesome.min.css" rel="stylesheet"> <link href="/static/css/font-awesome.min.css" rel="stylesheet">
<link href="/static/js/highlight/styles/github.css" rel="stylesheet"> <link href="/static/vendor/highlightjs/styles/github.css" rel="stylesheet">
<link href="/static/css/style.css" rel="stylesheet"> <link href="/static/css/style.css" rel="stylesheet">
{% block css %}{% endblock %}
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --> <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]> <!--[if lt IE 9]>
@ -99,53 +100,35 @@
</div> </div>
</div> </div>
<script src="/static/js/jquery-1.10.2.min.js"></script> {% assets "js_common" %}
<script src="/static/js/underscore.js"></script> <script type="text/javascript" src="{{ ASSET_URL }}"></script>
<script src="/static/js/bootstrap.min.js"></script> {% endassets %}
<!--<script src="/static/js/marked.js"></script>-->
<script src="/static/js/handlebars.js"></script>
<script src="/static/js/showdown/showdown.js"></script>
<script src="/static/js/html-sanitizer-minified.js"></script>
<script src="/static/js/showdown/wmd.js"></script>
<script src="/static/js/highlight/highlight.pack.js"></script>
<script> <script>
/*
marked.setOptions({
gfm: true,
tables: true,
pedantic: false,
sanitize: false,
smartLists: true,
smartypants: false,
langPrefix: 'lang-'
});
*/
hljs.initHighlightingOnLoad(); hljs.initHighlightingOnLoad();
// Markdown Renderer // Markdown Renderer
MDR = { MDR = {
doc: null, doc: null,
callback: WMD, callback: WMD.convert,
convert: function(md, sanitize){ convert: function(md, sanitize){
this.doc = this.callback(md); this.doc = this.callback(md);
md = this.doc.html; var html = this.doc.html;
if (sanitize) { if (sanitize) {
md = html_sanitize(md); // Causes some problems with inline styles
html = html_sanitize(html);
} }
md = this.hook(md); html = this.hook(html);
return md; return html;
}, },
hook: function(md) { hook: function(html) {
if (!this.doc.metadata) { if (!this.doc.metadata) {
return md; return html;
} }
try { try {
var template = Handlebars.compile(md); var template = Handlebars.compile(html);
return template(this.doc.metadata); return template(this.doc.metadata);
} catch(e) { } catch(e) {
return md; return html;
} }
} }
}; };

Visa fil

@ -1,21 +1,23 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% block js %} {% block js %}
<script src="/static/js/ace/ace.js"></script> {% assets "js_editor" %}
<script src="/static/js/ace/mode-markdown.js"></script> <script type="text/javascript" src="{{ ASSET_URL }}"></script>
<script src="/static/js/keymaster.min.js"></script> {% endassets %}
<script src="/static/js/dillinger.js"></script>
{% endblock %} {% endblock %}
{% block body %} {% block body %}
{% block css %}
<style> <style>
#main-body { #main-body {
background: inherit; background: inherit;
border: inherit; border: inherit;
padding: 0; padding: 0;
-webkit-box-shadow: 0; -webkit-box-shadow: 0;
-moz-box-shadow: 0; -moz-box-shadow: 0;
box-shadow: 0; box-shadow: 0;
} }
</style> </style>
{% endblock %}
<div id="app-wrap" class="container-fluid"> <div id="app-wrap" class="container-fluid">
<div id="app-controls" class="row"> <div id="app-controls" class="row">
@ -37,7 +39,7 @@
<li><a tabindex="-1" href="#" data-value="ace/theme/cobalt" class="">Cobalt</a></li> <li><a tabindex="-1" href="#" data-value="ace/theme/cobalt" class="">Cobalt</a></li>
<li><a tabindex="-1" href="#" data-value="ace/theme/crimson_editor" class="">Crimson Editor</a></li> <li><a tabindex="-1" href="#" data-value="ace/theme/crimson_editor" class="">Crimson Editor</a></li>
<li><a tabindex="-1" href="#" data-value="ace/theme/dawn" class="selected">Dawn</a></li> <li><a tabindex="-1" href="#" data-value="ace/theme/dawn" class="selected">Dawn</a></li>
<li><a tabindex="-1" href="#" data-value="ace/theme/dawn" class="">Dreamweaver</a></li> <li><a tabindex="-1" href="#" data-value="ace/theme/dreamweaver" class="">Dreamweaver</a></li>
<li><a tabindex="-1" href="#" data-value="ace/theme/eclipse" class="">Eclipse</a></li> <li><a tabindex="-1" href="#" data-value="ace/theme/eclipse" class="">Eclipse</a></li>
<li><a tabindex="-1" href="#" data-value="ace/theme/idle_fingers" class="">idleFingers</a></li> <li><a tabindex="-1" href="#" data-value="ace/theme/idle_fingers" class="">idleFingers</a></li>
<li><a tabindex="-1" href="#" data-value="ace/theme/kr_theme" class="">krTheme</a></li> <li><a tabindex="-1" href="#" data-value="ace/theme/kr_theme" class="">krTheme</a></li>

Visa fil

@ -34,6 +34,7 @@ def unescape_html(s):
s = s.replace('&#39;', "'") s = s.replace('&#39;', "'")
return s return s
def mkdir_safe(path): def mkdir_safe(path):
if path and not(os.path.exists(path)): if path and not(os.path.exists(path)):
os.makedirs(path) os.makedirs(path)

Visa fil

@ -7,5 +7,3 @@ nginx:
- reload: True - reload: True
- require: - require:
- pkg: nginx - pkg: nginx
/etc/

9
srv/salt/nodejs/init.sls Normal file
Visa fil

@ -0,0 +1,9 @@
node-repos:
pkgrepo.managed:
- ppa: chris-lea/node.js
nodejs:
pkg:
- installed
- require:
- pkgrepo.managed: node-repos