Commits

Tarek Ziadé  committed 088c3d5

first draft of shortener

  • Participants
  • Parent commits 4fa14fd

Comments (0)

Files changed (8)

 include
 local
 .*\.egg-info
+.*\.pyc
 pyramid.debug_templates = true
 pyramid.default_locale_name = en
 
+keys = booba76
+
 [server:main]
 use = egg:Paste#http
 host = 0.0.0.0

File errli/__init__.py

 """Main entry point
 """
 from pyramid.config import Configurator
+from errli.db import MemoryStorage
 
 
 def main(global_config, **settings):
     config = Configurator(settings=settings)
     config.include("cornice")
     config.scan("errli.views")
+    config.registry['storage'] = MemoryStorage()
     return config.make_wsgi_app()
+""" Database
+"""
+import binascii
+import os
+
+
+class MemoryStorage(dict):
+    def add_short(self, long_url):
+        new_key = None
+        tries = 0
+
+        while new_key is None and tries < 100:
+            key = binascii.b2a_hex(os.urandom(4))[:4]
+            if key not in self:
+                new_key = key
+            else:
+                tries += 1
+
+        if new_key is None:
+            raise exc.HTTPServiceUnavailable()
+
+        self[new_key] = long_url
+        return new_key
+
+    def get_redirect(self, key):
+        return self[key]

File errli/tests/__init__.py

Empty file added.

File errli/tests/test_errli.py

+import unittest
+
+from pyramid import testing
+from errli.views import new_url, get_url
+from errli.db import MemoryStorage
+
+
+class ViewTests(unittest.TestCase):
+    def setUp(self):
+        self.config = testing.setUp()
+        self.config.include("cornice")
+        self.config.scan("errli.views")
+        self.config.registry['storage'] = MemoryStorage()
+
+    def tearDown(self):
+        testing.tearDown()
+
+    def test_url(self):
+
+        request = testing.DummyRequest()
+        url = request.body = 'http://google.com'
+
+        result = new_url(request)
+        key = result['short']
+        self.assertEqual(len(key), 4)
+
+        request.body = ''
+        request.matchdict['key'] = key
+        res = get_url(request)
+        self.assertEqual(res.status_int, 302)
+        self.assertEqual(res.location, url)

File errli/views.py

 """ Cornice services.
 """
 from cornice import Service
+from webob import exc
 
+short = Service(name='shortener', path='/', description="URL Shortener")
+redirect = Service(name='redirec', path='/{key}', description="URL Shortener")
 
-hello = Service(name='hello', path='/', description="Simplest app")
 
+def auth(request):
+    """Look for an authorized key.
+    """
+    key = request.headers.get('X-Short')
+    if key is None or not key in request.config.settings['keys']:
+        raise exc.HTTPUnauthorized()
 
-@hello.get()
-def get_info(request):
-    """Returns Hello in JSON."""
-    return {'Hello': 'World'}
+
+def unique(request):
+    """Makes sure the url is not already listed.
+    """
+    url = request.body
+    try:
+        key = request.registry['storage'].get_short(url)
+    except KeyError:
+        pass
+    else:
+        request.errors.add('body', 'url', 'Already shortened at %s' % key)
+
+
+@short.put(validator=(auth, unique))
+def new_url(request):
+    """Adds a shortened URL."""
+    url = request.body
+    short = request.registry['storage'].add_short(url)
+    return {'short': short}
+
+
+@redirect.get()
+def get_url(request):
+    """Adds a shortened URL."""
+    key = request.matchdict['key']
+    try:
+        url = request.registry['storage'].get_redirect(key)
+    except KeyError:
+        raise exc.HTTPNotFound()
+
+    return exc.HTTPFound(location=url)
+
+
+@redirect.delete(validator=auth)
+def delete_url(request):
+    """Removes a shortened URL."""
+    key = request.matchdict['key']
+    try:
+        url = request.registry['storage'].get_redirect(key)
+    except KeyError:
+        raise exc.HTTPNotFound()
+
+    return exc.HTTPRedirect(location=url)
     packages=find_packages(),
     include_package_data=True,
     zip_safe=False,
-    install_requires=['cornice', 'PasteScript'],
-    entry_points = """\
+    install_requires=['cornice', 'PasteScript', 'WebTest'],
+    entry_points="""\
     [paste.app_factory]
     main = errli:main
     """,