<commit_before>#!/usr/bin/env python

import string
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, ProgrammingError
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, setup=False, debug=False):
    self.engine = create_engine(url, echo=debug)

    if setup:
      self.setup()
    else:
      self.session = sessionmaker(self.engine)()

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

  def setup(self):
    # todo: avoid setting up if tables already exsit and/or have data?
    # as long as we only read the first hash in __init__, we should be
    # ok calling this function again, but it will add extra hash records
    SQLAlchemyBase.metadata.create_all(self.engine)
    self.session = sessionmaker(self.engine)()
    salt = self.random_string()
    rounds = 12345
    hash_params = Hash(salt, rounds)
    self.session.add(hash_params)
    self.session.commit()

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

  def hash(self, email_address):
    # todo: 1. support for other hash algorithms based on hash_params.name
    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, setup=False, debug=False):
    db = None
    try:
      db = Database(url, setup, debug)
    except OperationalError as e:
      print e
      print "Check that the database exists and DATABASE_URL is configured correctly"
      exit(1)
    except ProgrammingError as e:
      print e
      print "Did you forget to run `./unsubscribe --setup` ?"
      exit(1)
    return db

if __name__ == "__main__":<commit_msg>Fix argument name<commit_after>#!/usr/bin/env python

import string
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, ProgrammingError
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, setup=False, debug=False):
    self.engine = create_engine(url, echo=debug)

    if setup:
      self.setup()
    else:
      self.session = sessionmaker(self.engine)()

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

  def setup(self):
    # todo: avoid setting up if tables already exsit and/or have data?
    # as long as we only read the first hash in __init__, we should be
    # ok calling this function again, but it will add extra hash records
    SQLAlchemyBase.metadata.create_all(self.engine)
    self.session = sessionmaker(self.engine)()
    salt = self.random_string()
    rounds = 12345
    hash_params = Hash(salt, rounds)
    self.session.add(hash_params)
    self.session.commit()

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

  def hash(self, email_address):
    # todo: 1. support for other hash algorithms based on hash_params.name
    return sha1_crypt.encrypt(email_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, setup=False, debug=False):
    db = None
    try:
      db = Database(url, setup, debug)
    except OperationalError as e:
      print e
      print "Check that the database exists and DATABASE_URL is configured correctly"
      exit(1)
    except ProgrammingError as e:
      print e
      print "Did you forget to run `./unsubscribe --setup` ?"
      exit(1)
    return db

if __name__ == "__main__":
{'fraction_non_alphanumeric': 0.09787234042553192, 'fraction_numerical': 0.004609929078014184, 'mean_word_length': 4.032114183764496, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6223602', 'n_tokens_mistral': 1791, 'n_tokens_neox': 1714, 'n_words': 481}