A Quick and Dirty URL Shortener in Web2py

This URL Shortener: http://s-o.link, is built using the web2py framework. I built this web software to easily send tiny links for easy sharing over SMS, for various mobile apps that I build. In particular this mobile app: www.missedmybus.ca.


db.py

import os
import uuid
from datetime import datetime
from pytz import timezone
import pytz

utc = pytz.utc
fmt = '%Y-%m-%d %H:%M:%S'
now = datetime.now(timezone('America/Vancouver'))
current_time =  now.strftime(fmt)

db = DAL('sqlite://seishin.sqlite')

response.generic_patterns = ['*'] if request.is_local else []
from gluon.tools import Auth, Service, PluginManager

try:
    import json
except ImportError:
    from gluon.contrib import simplejson as json

from gluon.contrib.login_methods.oauth20_account import OAuthAccount

class GoogleAccount(OAuthAccount):
    "OAuth 2.0 for Google"

    def __init__(self):
        with open(os.path.join(request.folder, 'private/google_auth.json'), 'rb') as f:
            gai = Storage(json.load(f)['web'])

        OAuthAccount.__init__(self, None, gai.client_id, gai.client_secret,
                              gai.auth_uri, gai.token_uri,
                              scope='https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email',
                              approval_prompt='auto', state="auth_provider=google")

    def get_user(self):

        token = self.accessToken()
        if not token:
            return None

        uinfo_url = 'https://www.googleapis.com/oauth2/v2/userinfo?access_token=%s' % urllib2.quote(token, safe='')

        uinfo = None

        try:
            uinfo_stream = urllib2.urlopen(uinfo_url)
        except:
            session.token = None
            return
        data = uinfo_stream.read()
        uinfo = json.loads(data)

        #username = uinfo['email']

        return dict(first_name = uinfo['given_name'],
                    last_name = uinfo['family_name'],
                    username = uinfo['email'],
                    email = uinfo['email'])
    
auth.settings.actions_disabled=['change_password','request_reset_password']
auth.define_tables(username=True, signature=False)

GoogleForm = GoogleAccount()
auth.settings.login_form = GoogleForm


### Other Standard Web2py Stuff ###


from gluon.contrib.sms_utils import SMSCODES, sms_email

mykeys = ['%s' % (k) for k,v in SMSCODES.iteritems()]

db.define_table('seishin',
    Field('url', label='URL', comment='Website address to shorten', requires=IS_URL()),
    Field('uuid', label='UUID', length=64, default=str(uuid.uuid4())[:4]),
    Field('views', 'integer', default=0, readable=False, writable=False),
    Field('time_clicked', default=current_time, writable=False, readable=False))


db.define_table('sendToSMS',
    Field('userinfo', db.auth_user, default=auth.user_id, writable=False, readable=False),
    Field('phone_number', label="To: 1 (111) 111-1111", required=True),
    Field('phone_network', label="Phone Network:", requires=IS_IN_SET(mykeys, zero = 'Please Choose One' )),
    Field('subject', label="Subject:", comment='Max 50 characters', requires=IS_LENGTH(maxsize=50, minsize=3), length=120),
    Field('message', label="Message:", comment='Max 255 characters', requires=IS_LENGTH(maxsize=255, minsize=5)),
    Field('time_pushed', default=current_time, writable=False, readable=False))

default.py

import random
import string
import uuid
import re

def count_sms(form):
    msg_append = DOMAIN+"/index/"+request.args(0)
    check = db(db.seishin.uuid == str(request.args(0))).select(db.seishin.ALL).first()
    userinfo = db(db.auth_user.id == auth.user).select(db.auth_user.ALL).first()
    if check:
        number = str(form.vars.phone_number).rstrip()
        network = str(form.vars.phone_network).rstrip()
        topic = str(form.vars.subject).rstrip()
        mmessage = str(form.vars.message).rstrip() 
        msg_len = len(mmessage)
        mmessage = mmessage + "\n\n" + msg_append
        reply = userinfo.email
        email = sms_email(number, network)
        mail.send(to=email, subject=topic, message=mmessage, reply_to=str(reply))
    else:
        session.flash = 'I dunno wht happered, I was on my way to gert a pack of smokes... . and here I am...'
        return redirect(DOMAIN)
        
@auth.requires_login()
def sendToSMS():
    if not request.args(0):
        session.flash = 'I dunno wht happered, I was on my way to gert a pack of smokes... . and here I am...'
        return redirect(DOMAIN)      

    public_key = ''
    private_key = ''

    ninjaTimeCheck = db(db.sendToSMS.userinfo == auth.user_id).select(db.sendToSMS.ALL).first()
    if ninjaTimeCheck:
        start = ninjaTimeCheck.time_pushed
        start = datetime.strptime(str(start), fmt)
        end = datetime.strptime(str(current_time), fmt)

        diff = end - start
        totalSeconds = diff.total_seconds()
        totalSeconds = int(totalSeconds)

        if totalSeconds <= 3600:
            session.flash = 'Stumble, stumble, roll, crawl, stagger, stagger - Please wait 60 minutes to send again.'
            return redirect(DOMAIN)

    form = SQLFORM(db.sendToSMS, formstyle='bootstrap')
    form[0].insert(4, DIV(Recaptcha(request, public_key, private_key, use_ssl=True, options="theme : 'clean'")))
    
    if form.accepts(request.vars, session, onvalidation=count_sms):
        userinfo = db(db.auth_user.id == auth.user).select(db.auth_user.ALL).first()
        number = str(form.vars.phone_number).rstrip()
        network = str(form.vars.phone_network).rstrip()
        topic = str(form.vars.subject).rstrip()
        reply = userinfo.email
        session.flash = '%s %s %s %s - sent' % (number, network, topic, reply)
        return redirect(DOMAIN)    
    elif form.errors.has_key('captcha'):
        response.flash='WHY IS captcha so annoying? - Captcha had a heart attack, please try again'
        return dict(form=form)
    elif form.errors:
        response.flash = 'Keyboard fail! Let\'s try that again'
        return dict(form=form)
    else:
        return dict(form=form)


def validate_url(form):
    uuidN = str(form.vars.uuid)
    uuidN = uuidN.replace(" ", "")
    
    if ("://" in uuidN):
        uuidN = uuidN.replace("://", "")
        
    uuidN = IS_SLUG()(uuidN)[0]
    
    url = form.vars.url
    url = url.lower()
    website = DOMAIN
    
    if (website in url):
        form.errors.url = T("Invalid: %s in url" % DOMAIN)
    
    form.vars.uuid = uuidN
    
    check = db(db.seishin.uuid == uuidN).select(db.seishin.ALL).first()
    if check:
        rand = random.choice(string.letters)
        N = uuid.uuid4()
        uuidN = uuidN + str(N)[:2]
        form.vars.uuid = str(rand) + "_" + uuidN

def index():
    uid = request.args(0)
    if not uid:
        form = SQLFORM(db.seishin, formstyle='bootstrap')
        websites = session.websites or []  
        if form.accepts(request.vars, session, onvalidation=validate_url):
            session.flash = 'and in the shortest moment a great lengthening occurred'
            websites.append(dict(url = form.vars.uuid))
            session.websites = websites
            return dict(form=form, websites=websites)    
        elif form.errors:
            response.flash = 'Keyboard fail! Let\'s try that again'
            return dict(form=form, websites=websites)
       
        if session.flash == None or session.flash == "": 
            response.flash = 'I see your website address is as big as mine. *wink *wink'         
        return dict(form=form, websites=websites)
    else:    
        post = db(db.seishin.uuid == str(uid)).select(db.seishin.ALL).first() or redirect(DOMAIN)
        if post:
            post.update_record(views=post.views+1)
            
            start = post.time_clicked
            start = datetime.strptime(str(start), fmt)
            end = datetime.strptime(str(current_time), fmt)
            
            diff = end - start
            totalSeconds = diff.total_seconds()
            totalSeconds = int(totalSeconds)
            
            if totalSeconds <= 2:
                post.update_record(time_clicked=current_time)
                #session.flash = 'end: %s - start: %s = totalSeconds: %s' % (end, start, totalSeconds)
                session.flash = 'Clicking to fast leads to heart failure'
                return redirect(DOMAIN)
            
            post.update_record(time_clicked=current_time)
            #session.flash = 'end: %s - start: %s = totalSeconds: %s' % (end, start, totalSeconds)
            return redirect(post.url)