#!/usr/bin/env python

from passlib.hash import sha1_crypt
from random import SystemRandom
from sqlalchemy import MetaData, Table, Column, String, ForeignKey, create_engine, Integer
from sqlalchemy.orm import mapper, relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.exc import OperationalError
SQLAlchemyBase = declarative_base()

class BlockedEmail(SQLAlchemyBase):
  __tablename__ = 'unsubscribe'
  hashed_address = Column(String, primary_key=True)

  def __init__(self, hashed_address):
    self.hashed_address = hashed_address

class Hash(SQLAlchemyBase):
  __tablename__ = 'hash'
  uid = Column(Integer, primary_key=True)
  salt = Column(String)
  rounds = Column(Integer)
  name = Column(String) # just for reference

  def __init__(self, salt, rounds, name='SHA1'):
    self.salt = salt
    self.rounds = rounds
    self.name = name


class Database():
  def __init__(self, url, create=False):
    self.engine = create_engine(url, echo=True)

    if create:
      self.create()
      self.session = sessionmaker(self.engine)()
      self.create_hash_params() # requires self.session
    else:
      self.session = sessionmaker(engine)()

    self.hash_params = self.session.query(Hash).last()

  def create(self):
    SQLAlchemyBase.metadata.create_all(self.engine)


  def random_string(self):
    return ''.join(SystemRandom.choice(string.ascii_uppercase + string.digits) for x in range(32))

  def create_hash_params(self):
    salt = self.random_string()
    rounds = 12345
    hash_params = Hash(salt, rounds)
    self.session.add(hash_params)
    self.session.commit()

  def hash(self, email_address):
    # todo: 1. support for other hash algorithms based on hash_params.name
    #       2. hash using all the configs, iteratively. this way if the
    #          salt is ever compromised, just add a new salt on top.
    return sha1_crypt.encrypt(address, rounds=self.hash_params.rounds, salt=self.hash_params.salt)

  def find(self, email_address):
    self.session.query(BlockedEmail).filter_by(hashed_address=self.hash(email_address)).first()

  def add(self, email_address):
    block = BlockedEmail(self.hash(email_address))
    self.session.add(block)
    self.session.commit()


def block_email(address, db):
    if not db.find(address):
      db.add(address)

def getDatabase(url, create=False):
    try:
      db = Database(url, create)
    except OperationalError as e:
      print e
      exit(1)

if __name__ == "__main__":
    import argparse
    parser = argparse.ArgumentParser(description="Cryptobot unsubscribe parser")
    parser.add_argument('--create', dest='createDB', action='store_true', default=False)
    parser.add_argument('--add', dest='email', action='store')
    args = parser.parse_args()

    from config import DATABASE_URL
    db = getDatabase(DATABASE_URL, args.createDB)

    if args.email:
      block_email(email)

    print db.session.query(BlockedEmail).all()

@@ -1032,113 +1032,8 @@
 e()%0A
-      self.session = sessionmaker(self.engine)()%0A      self.create_hash_params() # requires self.session%0A
     
@@ -1072,16 +1072,21 @@
 onmaker(
+self.
 engine)(
@@ -1136,18 +1136,19 @@
 y(Hash).
-la
+fir
 st()%0A%0A  
@@ -1221,168 +1221,104 @@
 ne)%0A
-%0A%0A  def random_string(self):%0A    return ''.join(SystemRandom.choice(string.ascii_uppercase + string.digits) for x in range(32))%0A%0A  def create_hash_params(self):
+    self.session = sessionmaker(self.engine)()%0A    hash_count = self.session.query(Hash).count()
 %0A   
@@ -1388,16 +1388,32 @@
  = Hash(
+hash_count + 1, 
 salt, ro
@@ -1489,250 +1489,236 @@
 def 
-hash(self, email_address):%0A    # todo: 1. support for other hash algorithms based on hash_params.name%0A    #       2. hash using all the configs, iteratively. this way if the%0A    #          salt is ever compromised, just add a new salt on top.
+random_string(self):%0A    return ''.join(SystemRandom.choice(string.ascii_uppercase + string.digits) for x in range(32))%0A%0A  def hash(self, email_address):%0A    # todo: 1. support for other hash algorithms based on hash_params.name
 %0A   

refactor database setup a bit