Skip to content

Commit

Permalink
add code
Browse files Browse the repository at this point in the history
  • Loading branch information
jettify committed Oct 29, 2017
1 parent e9cf0c5 commit 074850c
Show file tree
Hide file tree
Showing 14 changed files with 339 additions and 0 deletions.
9 changes: 9 additions & 0 deletions demos/shortify/config/config.yml
@@ -0,0 +1,9 @@
redis:
host: 127.0.0.1
port: 6379
db: 7
minsize: 1
maxsize: 5

host: 127.0.0.1
port: 9002
4 changes: 4 additions & 0 deletions demos/shortify/docker-compose.yml
@@ -0,0 +1,4 @@
redis:
image: redis:4
ports:
- 6379:6379
37 changes: 37 additions & 0 deletions demos/shortify/setup.py
@@ -0,0 +1,37 @@
import os
import re

from setuptools import find_packages, setup


def read_version():
regexp = re.compile(r"^__version__\W*=\W*'([\d.abrc]+)'")
init_py = os.path.join(os.path.dirname(__file__),
'shortify', '__init__.py')
with open(init_py) as f:
for line in f:
match = regexp.match(line)
if match is not None:
return match.group(1)
else:
msg = 'Cannot find version in shortify/__init__.py'
raise RuntimeError(msg)


install_requires = [
'aiohttp',
'trafaret',
'aiohttp_jinja2',
'pyyaml',
'aioredis==1.0.0b2'
]


setup(name='shortify',
version=read_version(),
description='Url shortener for aiohttp',
platforms=['POSIX'],
packages=find_packages(),
include_package_data=True,
install_requires=install_requires,
zip_safe=False)
1 change: 1 addition & 0 deletions demos/shortify/shortify/__init__.py
@@ -0,0 +1 @@
__version__ = '0.0.1'
3 changes: 3 additions & 0 deletions demos/shortify/shortify/__main__.py
@@ -0,0 +1,3 @@
from shortify.main import main

main()
59 changes: 59 additions & 0 deletions demos/shortify/shortify/main.py
@@ -0,0 +1,59 @@
import asyncio
import logging
import pathlib

import aiohttp_jinja2
import jinja2
from aiohttp import web

from shortify.routes import setup_routes
from shortify.utils import init_redis, load_config
from shortify.views import SiteHandler


PROJ_ROOT = pathlib.Path(__file__).parent.parent
TEMPLATES_ROOT = pathlib.Path(__file__).parent / 'templates'


async def setup_redis(app, conf, loop):
pool = await init_redis(conf['redis'], loop)

async def close_redis(app):
pool.close()
await pool.wait_closed()

app.on_cleanup.append(close_redis)
app['redis_pool'] = pool
return pool


def setup_jinja(app):
loader = jinja2.FileSystemLoader(str(TEMPLATES_ROOT))
jinja_env = aiohttp_jinja2.setup(app, loader=loader)
return jinja_env


async def init(loop):
conf = load_config(PROJ_ROOT / 'config' / 'config.yml')

app = web.Application(loop=loop)
redis_pool = await setup_redis(app, conf, loop)
setup_jinja(app)

handler = SiteHandler(redis_pool, conf)

setup_routes(app, handler, PROJ_ROOT)
host, port = conf['host'], conf['port']
return app, host, port


def main():
logging.basicConfig(level=logging.DEBUG)

loop = asyncio.get_event_loop()
app, host, port = loop.run_until_complete(init(loop))
web.run_app(app, host=host, port=port)


if __name__ == '__main__':
main()
9 changes: 9 additions & 0 deletions demos/shortify/shortify/routes.py
@@ -0,0 +1,9 @@
def setup_routes(app, handler, project_root):
router = app.router
h = handler
router.add_get('/', h.index, name='index')
router.add_get('/{short_id}', h.redirect, name='short')
router.add_post('/shortify', h.shotify, name='shortfy')
router.add_static(
'/static/', path=str(project_root / 'static'),
name='static')
68 changes: 68 additions & 0 deletions demos/shortify/shortify/templates/index.html
@@ -0,0 +1,68 @@
<!DOCTYPE html>
<html>
<head>
<title>shortify - aiohttp url shortener</title>
<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/css/materialize.min.css">
<link rel=stylesheet type=text/css href="{{ url('static', filename='css/custom.css') }}">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>

<script type="text/javascript">
$(function() {
$('#submitButton').click(function() {
$.ajax({
type: "POST",
url: "/shortify",
data: JSON.stringify({'url' : $('#url').val()}),
success: returnSuccess,
dataType: 'json',
contentType: "application/json",
});
});
});

function returnSuccess(data, textStatus, jqXHR) {
if(data.url) {
$('#url-result').text(data.url);
$('#url').val("");
$("a").attr("href", data.url)
} else {
$('#url-result').text("Please enter a URL!");
}
}
</script>

<body>
<div id="wrap">
<header>
<h1><a href="">shortify</a></h1>
<p>aiohttp URL shortener demo</p>
</header>
<div class="container">
<div class="row">
<div class="col s12">
<input type="text" name="url" id="url" class="form-control input-sm" placeholder="http://www.google.com" />
</div>
</div>
<div class="row">
<div class="col s4 offset-s4">
<button id="submitButton" class="waves-effect waves-light btn-large blue darken-1">Shorten</button>
</div>
</div>
<div class="row">
<div class="col s12">
<div class="panel-footer">
<h4>
<a href="#" id="url-result">Enter URL</a>
</h4>
</div>
</div>
</div>
</div>
</div>
<footer><a href="https://github.com/aio-libs">https://github.com/aio-libs</a></footer>
</body>
</html>
49 changes: 49 additions & 0 deletions demos/shortify/shortify/utils.py
@@ -0,0 +1,49 @@
import aioredis
import trafaret as t
import yaml
from aiohttp import web


def load_config(fname):
with open(fname, 'rt') as f:
data = yaml.load(f)
# TODO: add config validation
return data


async def init_redis(conf, loop):
pool = await aioredis.create_redis_pool(
(conf['host'], conf['port']),
minsize=conf['minsize'],
maxsize=conf['maxsize'],
loop=loop
)
return pool


CHARS = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"


def encode(num, alphabet=CHARS):
if num == 0:
return alphabet[0]
arr = []
base = len(alphabet)
while num:
num, rem = divmod(num, base)
arr.append(alphabet[rem])
arr.reverse()
return ''.join(arr)


ShortifyRequest = t.Dict({
t.Key('url'): t.URL
})


def fetch_url(data):
try:
data = ShortifyRequest(data)
except t.DataError:
raise web.HTTPBadRequest('URL is not valid')
return data['url']
40 changes: 40 additions & 0 deletions demos/shortify/shortify/views.py
@@ -0,0 +1,40 @@
import aiohttp_jinja2
from aiohttp import web

from .utils import encode, fetch_url


class SiteHandler:

def __init__(self, redis, conf):
self._redis = redis
self._conf = conf

@aiohttp_jinja2.template('index.html')
async def index(self, request):
return {}

@aiohttp_jinja2.template('timeline.html')
async def shotify(self, request):
data = await request.json()
long_url = fetch_url(data)

index = await self._redis.incr("shortify:count")
path = encode(index)
key = "shortify:{}".format(path)
await self._redis.set(key, long_url)

url = "http://{host}:{port}/{path}".format(
host=self._conf['host'],
port=self._conf['port'],
path=path)

return web.json_response({"url": url})

async def redirect(self, request):
short_id = request.match_info['short_id']
key = 'shortify:{}'.format(short_id)
location = await self._redis.get(key)
if not location:
raise web.HTTPNotFound()
return web.HTTPFound(location=location.decode())
44 changes: 44 additions & 0 deletions demos/shortify/static/css/custom.css
@@ -0,0 +1,44 @@
* {
margin: 0;
}

html, body {
height: 100%;
}

#content {
margin-top: 20px;
margin-bottom: 60px;
}

header {
margin-bottom: 30px;
padding-bottom: 10px;
clear: both;
}

#wrap {
margin: 5px 10px -50px 10px;
padding: 10px;
text-align: center;
min-height: 100%;
}
#url-result {
color: #039be5;
display: hidden;
}

.btn {
float: right;
}

footer {
color: #039be5;
text-align: center;
height: 50px;
line-height: 50px;
}

footer a{
color: #039be5;
}
16 changes: 16 additions & 0 deletions demos/shortify/static/css/materialize.min.css

Large diffs are not rendered by default.

Binary file not shown.
Binary file not shown.

0 comments on commit 074850c

Please sign in to comment.