mirror of
https://github.com/not-kennethreitz/typy.io.git
synced 2026-06-05 07:06:12 +00:00
basics
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
[[source]]
|
||||
url = "https://pypi.python.org/simple"
|
||||
verify_ssl = true
|
||||
Generated
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"default": {},
|
||||
"develop": {},
|
||||
"_meta": {
|
||||
"sources": [
|
||||
{
|
||||
"url": "https://pypi.python.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
],
|
||||
"requires": {},
|
||||
"hash": {
|
||||
"sha256": "cb65967bdf3a7372749ce6144be4ee63f412aeeac624342fda3a2b58b1c43c15"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,8 @@
|
||||
# typy.io
|
||||
just type™
|
||||
# typy.io: Share text with the masses
|
||||
|
||||
lorem ipusm
|
||||
|
||||
A Kenneth Reitz Project™
|
||||
------------------------
|
||||
|
||||
ۜ\(סּںסּَ` )/ۜ
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// client-side js
|
||||
// run by the browser each time your view template is loaded
|
||||
|
||||
// by default, you've got jQuery,
|
||||
// add other scripts at the bottom of index.html
|
||||
|
||||
$(function() {
|
||||
console.log('hello world :o');
|
||||
|
||||
$.get('/dreams', function(dreams) {
|
||||
dreams.forEach(function(dream) {
|
||||
$('<li></li>').text(dream).appendTo('ul#dreams');
|
||||
});
|
||||
});
|
||||
|
||||
$('form').submit(function(event) {
|
||||
event.preventDefault();
|
||||
dream = $('input').val();
|
||||
$.post('/dreams?' + $.param({dream: dream}), function() {
|
||||
$('<li></li>').text(dream).appendTo('ul#dreams');
|
||||
$('input').val('');
|
||||
$('input').focus();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,82 @@
|
||||
/* styles */
|
||||
/* called by your view template */
|
||||
|
||||
/* You might want to try something fancier: */
|
||||
/* less: http://lesscss.org/ */
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: helvetica, arial, sans-serif;
|
||||
margin: 25px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: bold;
|
||||
color: pink;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
p {
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
form {
|
||||
margin-bottom: 25px;
|
||||
padding: 15px;
|
||||
background-color: cyan;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
max-width: 340px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
input {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
padding: 5px;
|
||||
width: 100%;
|
||||
border: 1px solid lightgrey;
|
||||
border-radius: 3px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
button {
|
||||
font-size: 16px;
|
||||
border-radius: 3px;
|
||||
background-color: lightgrey;
|
||||
border: 1px solid grey;
|
||||
box-shadow: 2px 2px teal;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: yellow;
|
||||
}
|
||||
|
||||
button:active {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
footer {
|
||||
margin-top: 50px;
|
||||
padding-top: 25px;
|
||||
border-top: 1px solid lightgrey;
|
||||
}
|
||||
|
||||
footer > a {
|
||||
color: #BBBBBB;
|
||||
}
|
||||
|
||||
.nicejob {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
class SaferProxyFix(object):
|
||||
"""This middleware can be applied to add HTTP proxy support to an
|
||||
application that was not designed with HTTP proxies in mind. It
|
||||
sets `REMOTE_ADDR`, `HTTP_HOST` from `X-Forwarded` headers.
|
||||
|
||||
If you have more than one proxy server in front of your app, set
|
||||
num_proxy_servers accordingly
|
||||
Do not use this middleware in non-proxy setups for security reasons.
|
||||
|
||||
get_remote_addr will raise an exception if it sees a request that
|
||||
does not seem to have enough proxy servers behind it so long as
|
||||
detect_misconfiguration is True.
|
||||
The original values of `REMOTE_ADDR` and `HTTP_HOST` are stored in
|
||||
the WSGI environment as `werkzeug.proxy_fix.orig_remote_addr` and
|
||||
`werkzeug.proxy_fix.orig_http_host`.
|
||||
:param app: the WSGI application
|
||||
"""
|
||||
|
||||
def __init__(self, app, num_proxy_servers=1, detect_misconfiguration=False):
|
||||
self.app = app
|
||||
self.num_proxy_servers = num_proxy_servers
|
||||
self.detect_misconfiguration = detect_misconfiguration
|
||||
|
||||
def get_remote_addr(self, forwarded_for):
|
||||
"""Selects the new remote addr from the given list of ips in
|
||||
X-Forwarded-For. By default the last one is picked. Specify
|
||||
num_proxy_servers=2 to pick the second to last one, and so on.
|
||||
"""
|
||||
if self.detect_misconfiguration and not forwarded_for:
|
||||
raise Exception("SaferProxyFix did not detect a proxy server. Do not use this fixer if you are not behind a proxy.")
|
||||
if self.detect_misconfiguration and len(forwarded_for) < self.num_proxy_servers:
|
||||
raise Exception("SaferProxyFix did not detect enough proxy servers. Check your num_proxy_servers setting.")
|
||||
|
||||
if forwarded_for and len(forwarded_for) >= self.num_proxy_servers:
|
||||
return forwarded_for[-1 * self.num_proxy_servers]
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
getter = environ.get
|
||||
forwarded_proto = getter('HTTP_X_FORWARDED_PROTO', '')
|
||||
forwarded_for = getter('HTTP_X_FORWARDED_FOR', '').split(',')
|
||||
forwarded_host = getter('HTTP_X_FORWARDED_HOST', '')
|
||||
environ.update({
|
||||
'werkzeug.proxy_fix.orig_wsgi_url_scheme': getter('wsgi.url_scheme'),
|
||||
'werkzeug.proxy_fix.orig_remote_addr': getter('REMOTE_ADDR'),
|
||||
'werkzeug.proxy_fix.orig_http_host': getter('HTTP_HOST')
|
||||
})
|
||||
forwarded_for = [x for x in [x.strip() for x in forwarded_for] if x]
|
||||
remote_addr = self.get_remote_addr(forwarded_for)
|
||||
if remote_addr is not None:
|
||||
environ['REMOTE_ADDR'] = remote_addr
|
||||
if forwarded_host:
|
||||
environ['HTTP_HOST'] = forwarded_host
|
||||
if forwarded_proto:
|
||||
environ['wsgi.url_scheme'] = forwarded_proto
|
||||
return self.app(environ, start_response)
|
||||
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import hashlib
|
||||
|
||||
import bucketstore
|
||||
import mistune
|
||||
from decouple import config
|
||||
from flask import Flask, request, render_template, jsonify, redirect, url_for, Response
|
||||
from flask_caster import FlaskCaster
|
||||
from flask_uuid import FlaskUUID
|
||||
from raven.contrib.flask import Sentry
|
||||
|
||||
from saferproxyfix import SaferProxyFix
|
||||
|
||||
|
||||
# Support for gomix's 'front-end' and 'back-end' UI.
|
||||
app = Flask(__name__, static_folder='public', template_folder='views')
|
||||
app.debug = config('DEBUG', default=True, cast=bool)
|
||||
# app.wsgi_app = SaferProxyFix(app.wsgi_app)
|
||||
|
||||
# Set the app secret key from the secret environment variables.
|
||||
app.secret = config('SECRET')
|
||||
|
||||
|
||||
# Flask plugins
|
||||
|
||||
caster = FlaskCaster(app)
|
||||
FlaskUUID(app)
|
||||
sentry = Sentry(app, dsn=config('SENTRY_DSN'))
|
||||
|
||||
# The S3 Key/Value store.
|
||||
store = bucketstore.get('typy', create=True)
|
||||
store_total = len(store.list())
|
||||
|
||||
@app.after_request
|
||||
def apply_kr_hello(response):
|
||||
"""Adds some headers to all responses."""
|
||||
|
||||
# Made by Kenneth Reitz.
|
||||
if 'MADE_BY' in os.environ:
|
||||
response.headers["X-Was-Here"] = os.environ.get('MADE_BY')
|
||||
|
||||
# Powered by Flask.
|
||||
response.headers["X-Powered-By"] = os.environ.get('POWERED_BY')
|
||||
return response
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def type_away(fork=None):
|
||||
if fork:
|
||||
doc = store[fork]
|
||||
else:
|
||||
doc = None
|
||||
|
||||
return render_template('write.html', total=store_total, seed=doc)
|
||||
|
||||
@app.route('/raw')
|
||||
def document_list():
|
||||
return jsonify({'documents': store.list()})
|
||||
|
||||
|
||||
@app.route('/', methods=['POST'])
|
||||
def put_type():
|
||||
doc = request.form['document']
|
||||
|
||||
# Sha256 of document.
|
||||
sha = hashlib.sha256(doc).hexdigest()
|
||||
|
||||
# Store the document.
|
||||
store[sha] = doc
|
||||
|
||||
return redirect(url_for('get_type', hash=sha))
|
||||
|
||||
|
||||
@app.route('/<hash>')
|
||||
def get_type(hash):
|
||||
doc = mistune.markdown(store[hash])
|
||||
return render_template('doc.html', doc=doc, hash=hash, total=store_total)
|
||||
|
||||
|
||||
@app.route('/<hash>/raw')
|
||||
def get_raw_type(hash):
|
||||
return Response(store[hash], mimetype='text/plain')
|
||||
|
||||
@app.route('/<hash>/fork')
|
||||
def fork_type(hash):
|
||||
return type_away(fork=hash)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run()
|
||||
@@ -0,0 +1,6 @@
|
||||
# For development use (simple logging, etc):
|
||||
# pip install pipenv
|
||||
# python server.py
|
||||
|
||||
# For production use:
|
||||
gunicorn server:app
|
||||
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>typy: something goes here</title>
|
||||
<link id="favicon" rel="icon" href="https://gomix.com/favicon-app.ico" type="image/x-icon">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet">
|
||||
<style>
|
||||
#document {
|
||||
font-family: 'Lato', sans-serif;
|
||||
font-size: 1.7rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<a href="/">
|
||||
<button>
|
||||
typy: just type™
|
||||
</button>
|
||||
</a>
|
||||
<a href="/{{ hash }}/fork">
|
||||
<button class="button-primary">Fork</button>
|
||||
</a>
|
||||
</header>
|
||||
<hr>
|
||||
<main id="document">
|
||||
{{ doc|safe }}
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<hr/>
|
||||
<p> Document (1 of ~{{ total }}): <code># <a href="/{{ hash }}/raw">{{ hash }}</a> </code></p>
|
||||
</footer>
|
||||
<script src="/public/client.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,53 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>typy: something goes here</title>
|
||||
<link id="favicon" rel="icon" href="https://gomix.com/favicon-app.ico" type="image/x-icon">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.css">
|
||||
<script src="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<a href="/">
|
||||
<button>
|
||||
typy: just type™
|
||||
</button>
|
||||
<input type="submit" class="button-primary" form="form" value="save"></input>
|
||||
</a>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<textarea id="document" name="document" form="form">{% if seed %} {{ seed }} {% endif %}</textarea>
|
||||
</main>
|
||||
|
||||
|
||||
<footer>
|
||||
<hr/>
|
||||
<p> Document (1 of ~{{ total }}):</p>
|
||||
</footer>
|
||||
<form id="form" method="post" action="/"></form>
|
||||
<script src="/public/client.js"></script>
|
||||
<script>
|
||||
var simplemde = new SimpleMDE({
|
||||
autosave: {
|
||||
enabled: true,
|
||||
delay: 1000,
|
||||
uniqueId: 'document'
|
||||
},
|
||||
placeholder: "Just type..."
|
||||
});
|
||||
simplemd.autofocus = true;
|
||||
simplemde.placeholder("just type...");
|
||||
|
||||
var array = $('#typ').val().split(/\n|\r/);
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user