示例#1
0
    def from_web(item, cities):
        if not item['data0']:
            return None
        obj = Submission()
        obj.name = PersonName({
            'last_name': item['data0'],
            'first_name': item['data1'],
            'middle_name': item['data2'],
            'name_suffix': item['data3']
        })
        try:
            obj.address = Address({
                'address': item['data4'],
                'city': item['data5'],
                'zipcode': item['data6']
            })
        except Exception as ex:
            if str(ex).startswith('Unable to parse address'):
                obj.address = Address({
                    'address': "",
                    'city': item['data5'],
                    'zipcode': item['data6']
                })

        if obj.address.city not in cities:
            for city in cities:
                if city['zipcode'] == obj.address.zipcode:
                    obj.address.city = city['name']
                    break

        return obj
示例#2
0
 def __str__(self):
     return PersonName.display_name({
         'last': self.last_name,
         'first': self.first_name,
         'middle': self.middle_name,
         'suffix': self.name_suffix
     })
示例#3
0
 def lookup(dao, params):
     pn = PersonName(params)
     if 'address' in params and params['address']:
         addr = Address(params)
         matches = Voter.voters_by_name_and_address(dao, addr, pn)
         if matches:
             return matches
     return Voter.__voters_by_name(dao, pn)
示例#4
0
 def __init__(self, d=None):
     self.id = None
     self.name = None
     self.birth_year = None
     self.gender = ''
     self.info = None
     self.address = None
     self.voter_id = None
     self.reg_date = ''
     self.precinct_id = None
     if d:
         for attr in self.__dict__:
             if attr in d:
                 setattr(self, attr, d[attr])
         self.name = PersonName(d)
         self.address = Address(d)
         self.info = ContactInfo(d)
示例#5
0
 def test_get_best_voter(self):
     addr = Address({'address': '3000 Newcastle Rd'})
     pn = PersonName({'last_name': 'weinblatt', 'first_name': 'howard'})
     contact = Contact()
     contact.name = pn
     contact.address = addr
     voter = Contact.get_best_voter_rec(self.dao, contact)
     pass
示例#6
0
 def __init__(self, d=None):
     self.id = None
     self.name = None
     self.address = None
     self.birth_year = None
     self.gender = None
     self.voter_id = None
     self.precinct_id = None
     self.reg_date = None
     self.perm_abs = None
     self.status = None
     self.uocava = None
     self.ballot = None
     if d:
         for attr in self.__dict__:
             if attr in d:
                 setattr(self, attr, d[attr])
         self.name = PersonName(d)
         self.address = Address(d)
示例#7
0
def email_dups():
    dao = Dao(stateful=True)
    # cities = Turf.get_city_names(dao)
    dups = Contact.get_email_dups(dao)
    dao.close()
    for dup in dups:
        dup['name'] = str(PersonName(dup))
        dup['address'] = str(Address(dup))

    return jsonify(dups)
示例#8
0
def contact_matches():
    contact = Contact(json.loads(request.form['params']))
    dao = Dao(stateful=True)
    try:
        matches = contact.get_matches(dao)
        for match in matches:
            match['name'] = str(PersonName(match))
            match['address'] = str(Address(match))
        return jsonify(matches=matches)
    except Exception as ex:
        return jsonify(error=str(ex))
示例#9
0
 def test_init(self):
     d = {
         'last_name': 'Marx',
         'first_name': 'Julius',
         'nickname': 'Groucho',
         'name_suffix': 'JR',
         'alias': 'Capt. Spaulding, ESQ'
     }
     pn = PersonName(d)
     self.assertEqual('MARX, JULIUS, JR', str(pn))
     self.assertEqual('GROUCHO', pn.nickname)
     self.assertEqual('Capt. Spaulding, ESQ', pn.alias)
     self.assertEqual('MRKS', pn.name_metaphone)
示例#10
0
def name_duplicates():
    if request.method == 'GET':
        dao = Dao(stateful=True)
        cities = turf_dao.get_city_names(dao)
        dups = con_dao.get_name_dups(dao)
        dao.close()
        for dup in dups:
            dup['name'] = str(PersonName(dup))
            dup['address'] = str(Address(dup))

        return render_template('contacts/dups.html',
                               title='Name Duplicates',
                               dups=dups,
                               cities=cities)
示例#11
0
    def from_csv(row, cities, with_contact):
        obj = Submission()
        if with_contact:
            obj.name = PersonName({
                'last_name': row[6],
                'first_name': row[7],
                'middle_name': row[8],
                'name_suffix': row[9]
            })
            obj.address = Address({
                'address': row[3],
                'city': row[4],
                'zip': row[5]
            })
            obj.contact = ContactInfo({
                'email': row[0],
                'phone1': row[1],
                'phone2': row[2]
            })
        else:
            obj.name = PersonName({
                'last_name': row[0],
                'first_name': row[1],
                'middle_name': row[2],
                'name_suffix': row[3]
            })
            obj.address = Address({
                'address': row[4],
                'city': row[5],
                'zip': row[6]
            })

        if obj.address.city not in cities:
            obj.set_city_by_zip(cities)

        return obj
def get_voter_rex(c):
    sql = ("SELECT last_name, first_name, middle_name "
           "FROM voters "
           "WHERE last_name_meta=? "
           "AND last_name LIKE ? "
           "AND first_name_meta LIKE ? "
           "AND first_name LIKE ?;")
    vals = (
        c.name.last_meta,
        c.name.last[0] + '%',
        c.name.first_meta + '%',
        c.name.first[0] + '%'
    )
    rex = dao.execute(sql, vals)
    return [PersonName(rec) for rec in rex] if rex else []
示例#13
0
 def __init__(self, d=None):
     self.id = None
     self.name = None
     self.birth_year = None
     self.gender = ''
     self.info = None
     self.address = None
     self.voter_id = None
     self.reg_date = ''
     self.bst_id = None
     if d:
         for attr in self.__dict__:
             if attr in d:
                 setattr(self, attr, d[attr])
         self.name = PersonName(d)
         self.address = Address(d)
         self.info = ContactInfo(d)
示例#14
0
 def __init__(self, d=None):
     self.id = None
     self.name = None
     self.address = None
     self.birth_year = None
     self.gender = None
     self.voter_id = None
     self.reg_date = None
     self.perm_abs = None
     self.status = None
     self.uocava = None
     self.ballot = None
     if d:
         for attr in self.__dict__:
             if attr in d:
                 setattr(self, attr, d[attr])
         self.name = PersonName(d)
         self.address = Address(d)
示例#15
0
    def fuzzy_lookup(params):
        from models.person_name import PersonName
        from models.address import Address

        pn = PersonName(params)
        if 'address' in params and params['address'] != '':
            addr = Address(params)
            matches = Voter.by_fuzzy_name_and_address(pn, addr)
            if matches:
                return matches

        candidates = Voter.by_fuzzy_name(pn)
        candidates_by_name = {
            str(candidate): candidate
            for candidate in candidates
        }
        names = [str(candidate) for candidate in candidates]
        matches = MatchLib.get_best_partials(str(pn), names, 75)
        return [candidates_by_name[match] for match in matches]
示例#16
0
class Contact(object):

    def __init__(self, d=None):
        self.id = None
        self.name = None
        self.birth_year = None
        self.gender = ''
        self.info = None
        self.address = None
        self.voter_id = None
        self.reg_date = ''
        self.bst_id = None
        if d:
            for attr in self.__dict__:
                if attr in d:
                    setattr(self, attr, d[attr])
            self.name = PersonName(d)
            self.address = Address(d)
            self.info = ContactInfo(d)

    def __str__(self):
        return str(self.name)

    def serialize(self):
        return {
            'name': self.name.serialize(),
            'whole_name': str(self.name),
            'birth_year': self.birth_year,
            'gender': self.gender,
            'contact': self.info.serialize(),
            'address': self.address.serialize(),
            'voter_id': self.voter_id,
            'reg_date': self.reg_date,
            'id': self.id,
            'bst_id': self.bst_id
        }

    def get_values(self):
        return (
            self.name.last,
            self.name.first,
            self.name.middle,
            self.name.suffix,
            self.name.nickname,
            self.name.last_meta,
            self.name.first_meta,
            self.name.nickname_meta,
            self.birth_year,
            self.gender,
            self.info.email,
            self.info.phone1,
            self.info.phone2,
            self.address.house_number,
            self.address.pre_direction,
            self.address.street_name,
            self.address.street_type,
            self.address.suf_direction,
            self.address.unit,
            self.address.metaphone,
            self.address.city,
            self.address.zipcode,
            self.address.precinct_id,
            self.voter_id,
            self.reg_date,
            self.bst_id
        )

    def copy_voter(self, voter):
        if not self.name.nickname:
            self.name.nickname = self.name.first
        self.name.last = voter.name.last
        self.name.first = voter.name.first
        self.name.middle = voter.name.middle
        self.name.suffix = voter.name.suffix
        self.address.house_number = voter.address.house_number
        self.address.pre_direction = voter.address.pre_direction
        self.address.street_name = voter.address.street_name
        self.address.street_type = voter.address.street_type
        self.address.suf_direction = voter.address.suf_direction
        self.address.unit = voter.address.unit
        self.address.city = voter.address.city
        self.address.zipcode = voter.address.zipcode
        self.address.precinct_id = voter.address.precinct_id
        self.gender = voter.gender
        self.birth_year = voter.birth_year
        self.reg_date = voter.reg_date
        self.voter_id = voter.voter_id
示例#17
0
 def get_name_only_matches(self, dao):
     rex = PersonName.person_by_name_only(dao, 'contacts', self.name)
     return [Contact[rec] for rec in rex
             if rec['id'] != self.id] if rex else []
示例#18
0
class Voter(object):

    def __init__(self, d=None):
        self.id = None
        self.name = None
        self.address = None
        self.birth_year = None
        self.gender = None
        self.voter_id = None
        self.reg_date = None
        self.perm_abs = None
        self.status = None
        self.uocava = None
        self.ballot = None
        if d:
            for attr in self.__dict__:
                if attr in d:
                    setattr(self, attr, d[attr])
            self.name = PersonName(d)
            self.address = Address(d)

    def __str__(self):
        return str(self.name)

    def serialize(self):
        d = {
            'voter_id': self.voter_id,
            'name': self.name.serialize(),
            'address': self.address.serialize(),
            'precinct_id': self.address.precinct_id,
            'birth_year': self.birth_year,
            'gender': self.gender,
            'reg_date': self.reg_date,
            'perm_abs': self.perm_abs if self.perm_abs else 'N',
            'status': self.status,
            'uocava': self.uocava
        }
        if 'score' in self.__dict__:
            d['score'] = self.__dict__['score']
        return d

    def get_values(self):
        return (
            self.name.last,
            self.name.first,
            self.name.middle,
            self.name.suffix,
            self.name.last_meta,
            self.name.first_meta,
            self.birth_year,
            self.gender,
            self.address.house_number,
            self.address.pre_direction,
            self.address.street_name,
            self.address.street_type,
            self.address.suf_direction,
            self.address.unit,
            self.address.metaphone,
            self.address.city,
            self.address.zipcode,
            self.address.precinct_id,
            self.voter_id,
            self.reg_date,
            self.perm_abs,
            self.status,
            self.uocava
        )
示例#19
0
class Contact(object):

    db_cols = [
        'last_name', 'first_name', 'middle_name', 'name_suffix', 'nickname',
        'last_name_meta', 'first_name_meta', 'nickname_meta', 'birth_year',
        'gender', 'email', 'phone1', 'phone2', 'house_number', 'pre_direction',
        'street_name', 'street_type', 'suf_direction', 'unit',
        'street_name_meta', 'city', 'zipcode', 'precinct_id', 'voter_id',
        'reg_date'
    ]

    def __init__(self, d=None):
        self.id = None
        self.name = None
        self.birth_year = None
        self.gender = ''
        self.info = None
        self.address = None
        self.voter_id = None
        self.reg_date = ''
        self.precinct_id = None
        if d:
            for attr in self.__dict__:
                if attr in d:
                    setattr(self, attr, d[attr])
            self.name = PersonName(d)
            self.address = Address(d)
            self.info = ContactInfo(d)

    def __str__(self):
        return str(self.name)

    def serialize(self):
        return {
            'name': self.name.serialize(),
            'whole_name': str(self.name),
            'birth_year': self.birth_year,
            'gender': self.gender,
            'contact': self.info.serialize(),
            'address': self.address.serialize(),
            'voter_id': self.voter_id,
            'reg_date': self.reg_date,
            'id': self.id,
        }

    def get_values(self):
        return (self.name.last, self.name.first, self.name.middle,
                self.name.suffix, self.name.nickname, self.name.last_meta,
                self.name.first_meta, self.name.nickname_meta, self.birth_year,
                self.gender, self.info.email, self.info.phone1,
                self.info.phone2, self.address.house_number,
                self.address.pre_direction, self.address.street_name,
                self.address.street_type, self.address.suf_direction,
                self.address.unit, self.address.metaphone, self.address.city,
                self.address.zipcode, self.address.precinct_id, self.voter_id,
                self.reg_date)

    @staticmethod
    @get_dao
    def get_all(dao):
        sql = ("SELECT * FROM contacts "
               "ORDER BY last_name, first_name, middle_name")
        rex = dao.execute(sql)
        return [Contact(rec) for rec in rex]

    def get_matches(self, dao=None):
        if not dao:
            dao = Dao(stateful=True)
        if self.info and (self.info.phone1 or self.info.phone2):
            matches = self.get_phone_matches(dao)
            if matches:
                return matches
        if self.info and self.info.email:
            matches = self.get_email_matches(dao)
            if matches:
                return matches
        if self.address:
            matches = self.get_name_addr_matches(dao)
            if matches:
                return matches
        return self.get_name_only_matches(dao)

    def get_email_matches(self, dao):
        sql = ("SELECT * FROM contacts " "WHERE email LIKE ? " "AND id<>?;")
        vals = (self.info.email[0], self.id)
        rex = dao.execute(sql, vals)
        if not rex:
            return []
        candidates = {rec['id']: rec['email'] for rec in rex}
        choices = self.choose_email(candidates.values())
        if not choices:
            return []
        result = []
        for choice in choices:
            for rec in rex:
                if rec['email'] == choice:
                    result.append(Contact(rec))
        return result

    def choose_email(self, candidates):
        target = self.info.email.split('@')
        emails = [c.split('@') for c in candidates]
        best_domain = MatchLib.get_best_match(
            target[1], set([email[1] for email in emails]))[0]
        usernames = [
            email[0] for email in emails
            if email[1] in [target[1], best_domain]
        ]
        matches = MatchLib.get_best_matches(target[0], usernames, 80)
        return [match[0] + '@' + best_domain
                for match in matches] if matches else []

    def get_phone_matches(self, dao):
        if not self.info:
            return []
        if not self.info.phone1 and not self.info.phone2:
            return []
        rex = []
        sql = ("SELECT * FROM contacts "
               "WHERE (phone1=? OR phone2=?) "
               "AND id<>?;")
        if self.info.phone1:
            vals = (self.info.phone1, self.info.phone1, self.id)
            rex = dao.execute(sql, vals)
        if self.info.phone2:
            vals = (self.info.phone2, self.info.phone2, self.id)
            rex += dao.execute(sql, vals)
        d = {}
        for rec in rex:
            if rec['id'] in d:
                continue
            d[rec['id']] = rec
        return list(d.values())

    def get_name_addr_matches(self, dao):
        rex = PersonName.person_by_name_and_address(dao, 'contacts',
                                                    self.address, self.name)
        return [Contact[rec] for rec in rex
                if rec['id'] != self.id] if rex else []

    def get_name_only_matches(self, dao):
        rex = PersonName.person_by_name_only(dao, 'contacts', self.name)
        return [Contact[rec] for rec in rex
                if rec['id'] != self.id] if rex else []

    def add(self, dao):
        sql = ("INSERT INTO contacts (%s) VALUES (%s)") % (','.join(
            self.db_cols), dao.get_param_str(self.db_cols))
        vals = self.get_values()
        return dao.execute(sql, vals)

    def update(self, dao):
        sql = "UPDATE contacts SET %s WHERE id=?;" % (
            '=?,'.join(self.db_cols) + '=?', )
        vals = self.get_values() + (self.id, )
        dao.execute(sql, vals)

    @staticmethod
    def add_many(data, dao=None):
        contacts = [Contact(d) for d in data]
        values = [contact.get_values() for contact in contacts]

        if not dao:
            dao = Dao()
        dao.add_many('contacts', Contact.db_cols, values)

    @staticmethod
    @get_dao
    def update_many(dao, contacts):
        values = [
            contact.get_values() + (contact.id, ) for contact in contacts
        ]
        dao.update_many('contacts', Contact.db_cols, values)

    @staticmethod
    @get_dao
    def drop_many(dao, ids):
        dao.drop_many('contacts', ids)

    @staticmethod
    def get_best_voter_rec(dao, contact):
        from models.voter import Voter

        candidates = Voter.voters_by_name_and_address(dao, contact.address,
                                                      contact.name)
        if not candidates:
            return None
        streets = set(
            [candidate.address.street_name for candidate in candidates])
        best_street = MatchLib.get_best_match(contact.address.street_name,
                                              streets, 85)
        if not best_street:
            return None
        candidates = [
            candidate for candidate in candidates
            if candidate.address.street_name == best_street
        ]
        best_name = MatchLib.get_best_match(
            str(contact), [str(candidate.name) for candidate in candidates],
            85)
        if not best_name:
            return None
        return [
            candidate for candidate in candidates
            if str(candidate.name) == best_name
        ][0]

    @staticmethod
    def get_best_turf(dao, contact):
        turfs = Address.get_turf(dao, contact.address)
        if not turfs:
            return None
        if len(set([turf['precinct_id'] for turf in turfs])) == 1:
            return turfs[0]
        d = {(t['pre_direction'] + ' ' + t['street_name'] + ' ' +
              t['street_type'] + ' ' + t['suf_direction']).strip(): t
             for t in turfs}
        match = MatchLib.get_best_match(str(contact.address), d.keys(), 85)
        return d[match] if match else None

    @staticmethod
    def synchronize(dao):
        # from models.dao import Dao
        from models.voter import Voter

        # dao = Dao(stateful=True)
        contacts = Contact.get_all(dao)
        problems = {'reg': [], 'name': [], 'vrec': [], 'addr': [], 'pct': []}
        for contact in contacts:
            if not contact.voter_id:
                problems['reg'].append(contact)
                continue
            voter = Voter.get_one(dao, contact.voter_id)
            if not voter:
                problems['vrec'].append([
                    contact.id,
                    str(contact.name),
                    str(contact.address), contact.address.city,
                    contact.address.zipcode, contact.address.precinct_id, None
                ])
                continue
            if str(contact.name) != str(voter.name):
                problems['name'].append((str(contact.name), str(voter.name)))
                continue
            if str(contact.address) != str(voter.address):
                problems['addr'].append(contact)
                continue
            if contact.address.precinct_id != voter.address.precinct_id:
                problems['pct'].append(contact)
            # contact.copy_voter(voter)
            # contact.update(dao)
        return problems

    def copy_voter(self, voter):
        if not self.name.nickname:
            self.name.nickname = self.name.first
        self.name.last = voter.name.last
        self.name.first = voter.name.first
        self.name.middle = voter.name.middle
        self.name.suffix = voter.name.suffix
        self.address.house_number = voter.address.house_number
        self.address.pre_direction = voter.address.pre_direction
        self.address.street_name = voter.address.street_name
        self.address.street_type = voter.address.street_type
        self.address.suf_direction = voter.address.suf_direction
        self.address.unit = voter.address.unit
        self.address.city = voter.address.city
        self.address.zipcode = voter.address.zipcode
        self.address.precinct_id = voter.address.precinct_id
        self.gender = voter.gender
        self.birth_year = voter.birth_year
        self.reg_date = voter.reg_date
        self.voter_id = voter.voter_id

    @staticmethod
    def assign_precinct(contacts, dao=None):
        if not dao:
            dao = Dao(stateful=True)
        updates = []
        for contact in contacts:
            # get voter rex by name + address
            voter = Contact.get_best_voter_rec(dao, contact)
            if voter:
                nn = (contact.name.nickname, contact.name.nickname_meta)
                contact.name = voter.name
                contact.nickname = nn[0]
                contact.nickname_meta = nn[1]
                contact.address = voter.address
                contact.birth_year = voter.birth_year
                contact.gender = voter.gender
                contact.voter_id = voter.voter_id
                contact.reg_date = voter.reg_date
                updates.append(contact)
                continue
            turf = Contact.get_best_turf(dao, contact)
            if turf:
                contact.address.pre_direction = turf['pre_direction']
                contact.address.street_name = turf['street_name']
                contact.address.street_type = turf['street_type']
                contact.address.suf_direction = turf['suf_direction']
                contact.address.precinct_id = turf['precinct_id']
                contact.address.city = turf['city']
                contact.address.zipcode = turf['zipcode']
                updates.append(contact)
                continue

            # get voter rex by name only

        # Contact.update_many(dao, updates)
        dao.close()
        return len(updates)

    @staticmethod
    def get_with_missing_precinct(dao=None):
        if not dao:
            dao = Dao()
        sql = ("SELECT * FROM contacts "
               "WHERE precinct_id is null "
               "ORDER BY last_name, first_name, middle_name;")
        rex = dao.execute(sql)
        return rex
        # return [Contact(rec) for rec in rex] if rex else []

    @staticmethod
    @get_dao
    def get_email_dups(dao):
        sql = ("SELECT * "
               "FROM contacts "
               "WHERE email IN "
               "(SELECT email "
               "FROM contacts "
               "WHERE email <> '' "
               "GROUP BY email HAVING COUNT(email) > 1) "
               "ORDER BY last_name, first_name, middle_name;")
        return dao.execute(sql)

    @staticmethod
    @get_dao
    def get_phone_dups(dao):
        p_clause_1 = "(SELECT phone1 FROM contacts " \
                     "WHERE phone1 <> '' " \
                     "GROUP BY phone1 HAVING COUNT(phone1) > 1) "
        p_clause_2 = "(SELECT phone2 FROM contacts " \
                     "WHERE phone2 <> '' " \
                     "GROUP BY phone2 HAVING COUNT(phone2) > 1) "
        sql = ("SELECT * FROM contacts "
               "WHERE phone1 IN %s "
               "OR phone1 IN %s "
               "OR phone2 IN %s "
               "OR phone2 IN %s "
               "ORDER BY last_name, first_name, middle_name;") % (
                   p_clause_1, p_clause_2, p_clause_1, p_clause_2)
        return dao.execute(sql)

    @staticmethod
    @get_dao
    def get_name_addr_dups(dao):
        sql = ("SELECT * FROM contacts "
               "INNER JOIN "
               "(SELECT last_name_meta, street_name_meta FROM contacts "
               "GROUP BY (last_name_meta || ':' || street_name_meta) "
               "HAVING count(id) > 1) dup "
               "ON contacts.last_name_meta=dup.last_name_meta "
               "WHERE contacts.street_name_meta <> '' "
               "ORDER BY last_name, first_name, middle_name;")
        return dao.execute(sql)

    @staticmethod
    @get_dao
    def get_name_dups(dao):
        sql = (
            "SELECT contacts.* FROM contacts "
            "JOIN "
            "(SELECT last_name_meta, last_name, first_name_meta FROM contacts "
            "GROUP BY (last_name_meta || ':' || first_name_meta) "
            "HAVING count(id) > 1) dup "
            "ON contacts.last_name_meta=dup.last_name_meta "
            "AND substr(contacts.last_name,1,1)=substr(dup.last_name,1,1) "
            "AND contacts.first_name_meta LIKE (dup.first_name_meta || '%') "
            "ORDER BY last_name, first_name, middle_name;")
        return dao.execute(sql)

    @staticmethod
    @get_dao
    def get_activists(dao):
        sql = "SELECT * FROM contacts WHERE active=1 ORDER BY last_name, first_name, middle_name;"
        rex = dao.execute(sql)
        return [Contact(rec) for rec in rex] if rex else []

    @staticmethod
    @get_dao
    def get_by_precinct(dao, precinct_id):
        sql = ("SELECT * FROM contacts "
               "WHERE precinct_id=? "
               "AND active=1 "
               "ORDER BY last_name, first_name, middle_name;")
        vals = (precinct_id, )
        rex = dao.execute(sql, vals)
        return [Contact(rec) for rec in rex] if rex else []

    @staticmethod
    @get_dao
    def get_by_precinct_list(dao, precinct_list):
        sql = ("SELECT * FROM contacts "
               "WHERE precinct_id IN (%s) "
               "AND active=1 "
               "ORDER BY last_name, first_name, middle_name;") % (
                   dao.get_param_str(precinct_list))
        rex = dao.execute(sql, precinct_list)
        return [Contact(rec) for rec in rex] if rex else []

    @staticmethod
    def get_by_group(dao, group_id):
        sql = ("SELECT * FROM contacts "
               "WHERE id IN "
               "(SELECT contact_id "
               "FROM group_members "
               "WHERE group_id=?)")
        rex = dao.execute(sql, (group_id, ))
        return [Contact(rec) for rec in rex] if rex else []
示例#20
0
class Voter(object):

    # attrs = [
    #     'id', 'name', 'address', 'turf',
    #     'birth_year', 'gender'
    # ]

    colnames = [
        'Last Name', 'first Name', 'Middle', 'Suffix', 'Address', 'City',
        'Zip', 'Gender', 'Birth Year', 'Party', 'Voter ID', 'Reg Date',
        'Perm Abs', 'Status', 'UOCAVA'
    ]

    def __init__(self, d=None):
        self.id = None
        self.name = None
        self.address = None
        self.birth_year = None
        self.gender = None
        self.voter_id = None
        self.precinct_id = None
        self.reg_date = None
        self.perm_abs = None
        self.status = None
        self.uocava = None
        self.ballot = None
        if d:
            for attr in self.__dict__:
                if attr in d:
                    setattr(self, attr, d[attr])
            self.name = PersonName(d)
            self.address = Address(d)

    def __str__(self):
        return str(self.name)

    def serialize(self):
        d = {
            'voter_id': self.voter_id,
            'name': self.name.serialize(),
            'address': self.address.serialize(),
            'birth_year': self.birth_year,
            'gender': self.gender,
            'reg_date': self.reg_date,
            'perm_abs': self.perm_abs if self.perm_abs else 'N',
            'status': self.status,
            'uocava': self.uocava
        }
        if 'score' in self.__dict__:
            d['score'] = self.__dict__['score']
        return d

    @staticmethod
    def voters_by_name_and_address(dao, addr, pn):
        sql = ("SELECT * FROM voters "
               "WHERE street_name_meta = ? "
               "AND street_name LIKE ? "
               "AND house_number BETWEEN ? AND ? "
               "AND last_name_meta = ? "
               "AND last_name LIKE ?;")
        vals = (addr.metaphone, addr.street_name[0] + '%', addr.block[0],
                addr.block[1], pn.last_meta, pn.last[0] + '%')
        rex = dao.execute(sql, vals)
        return [Voter(rec) for rec in rex] if rex else []

    @staticmethod
    def lookup(dao, params):
        pn = PersonName(params)
        if 'address' in params and params['address']:
            addr = Address(params)
            matches = Voter.voters_by_name_and_address(dao, addr, pn)
            if matches:
                return matches
        return Voter.__voters_by_name(dao, pn)

    @staticmethod
    def __voters_by_location(dao, addr, letter):
        sql = ("SELECT * FROM voters "
               "WHERE street_name_meta LIKE %s "
               "AND street_name LIKE %s "
               "AND house_number BETWEEN %s AND %s "
               "AND last_name LIKE %s;")
        vals = (addr.metaphone + '%', addr.street_name[0] + '%', addr.block[0],
                addr.block[1], letter + '%')
        rex = dao.execute(sql, vals)
        return [Voter(rec) for rec in rex] if rex else []

    @staticmethod
    def __voters_by_name(dao, pn):
        candidates = Voter.__get_candidates_by_name(dao, pn)
        candidates_by_name = {
            str(candidate.name): candidate
            for candidate in candidates
        }
        names = [str(candidate.name) for candidate in candidates]
        matches = MatchLib.get_best_partials(str(pn), names, 75)
        return [candidates_by_name[match] for match in matches]

    @staticmethod
    def __get_candidates_by_name(dao, pn):
        sql = ("SELECT * "
               "FROM voters "
               "WHERE last_name_meta=? "
               "AND last_name LIKE ? "
               "AND first_name LIKE ?")
        vals = [pn.last_meta, pn.last[0] + '%', pn.first[0] + '%']
        rex = dao.execute(sql, vals)
        return [Voter(rec) for rec in rex] if rex else []

    @staticmethod
    def get_one(dao, voter_id):
        sql = "SELECT * FROM voters WHERE voter_id=?;"
        vals = (voter_id, )
        rex = dao.execute(sql, vals)
        if not rex:
            return None
        return Voter(rex[0])

    @staticmethod
    def get_by_name(dao, pn):
        sql = ("SELECT * FROM voters "
               "WHERE last_name=? "
               "AND first_name=? ")
        vals = [pn.last, pn.first]
        if pn.middle:
            sql += "AND middle_name=? "
            vals.append(pn.middle)
        if pn.suffix:
            sql += "AND name_suffix=?"
            vals.append(pn.suffix)
        rex = dao.execute(sql, vals)
        return [Voter(rec) for rec in rex]

    @staticmethod
    def get_voter(dao, voter_id):
        from models.election import Election
        from models.voter_history import VoterHistory

        sql = "SELECT * FROM voters WHERE voter_id=?;"
        vals = (voter_id, )
        rex = dao.execute(sql, vals)
        if not rex:
            return None
        voter_rec = rex[0]

        elections = Election.get(dao)
        election_codes = [election['code'] for election in elections]

        voter_elections = VoterHistory.get_for_voter(dao,
                                                     voter_rec['voter_id'],
                                                     election_codes)
        for election in elections:
            code = 'N'
            if election['code'] in voter_elections:
                code = voter_elections[election['code']]['ballot'] \
                    if voter_elections[election['code']]['ballot'] else 'Y'
                if voter_elections[election['code']]['absentee_flag'] == 'Y':
                    code += 'A'
            voter_rec[election['date']] = code

        return voter_rec

    @staticmethod
    def batch_lookup(submissions):
        from models.street_index import StreetIndex
        from dao.dao import Dao

        dao = Dao(stateful=True)

        for submission in submissions:
            # print(str(submission.name))
            street = '%s %s' % (submission.address.street_name,
                                submission.address.street_type)
            if submission.address.metaphone:
                voters = Voter.__get_by_location(dao, submission)
                if voters:
                    streets = set(
                        [voter.address.street_name for voter in voters])
                    matches = MatchLib.get_best_partials(street, streets, 85)
                    voters = [
                        voter for voter in voters
                        if voter.address.street_name in matches
                    ]
                    voters_by_name = {
                        str(voter.name): voter
                        for voter in voters
                    }
                    names = [str(voter.name) for voter in voters]
                    matches = MatchLib.get_best_partials(
                        str(submission.name), names, 65)
                    if matches:
                        submission.matches = [
                            voters_by_name[match] for match in matches
                        ]
                        top_score = 0
                        for match in submission.matches:
                            Voter.__set_match_score(submission, match)
                            if match.score > top_score:
                                top_score = match.score
                        if top_score < 65:
                            voters = []
                        else:
                            continue
            voters = Voter.__get_by_name(dao, submission)
            if voters:
                if submission.address.street_name:
                    streets = set(
                        [voter.address.street_name for voter in voters])
                    matches = MatchLib.get_best_partials(street, streets, 85)
                    submission.matches = [
                        voter for voter in voters
                        if voter.address.street_name in matches
                    ]
                else:
                    submission.matches = voters
            if not submission.matches:
                if StreetIndex.is_valid_address(submission.address):
                    submission.matches = Voter.__get_household(dao, submission)

            for match in submission.matches:
                Voter.__set_match_score(submission, match)

        dao.close()

    @staticmethod
    def __get_by_location(dao, submission):
        sql = ("SELECT * FROM voters "
               "WHERE street_name_meta LIKE ? "
               "AND street_name LIKE ? "
               "AND house_number BETWEEN ? AND ? "
               "AND last_name LIKE ?;")
        vals = (submission.address.metaphone + '%',
                submission.address.street_name[0] + '%',
                submission.address.block[0], submission.address.block[1],
                submission.name.last[0] + '%')
        rex = dao.execute(sql, vals)
        return [Voter(rec) for rec in rex] if rex else []

    @staticmethod
    def __get_by_name(dao, submission):
        candidates = Voter.__get_candidates_name_only(dao, submission)
        candidates_by_name = {
            str(candidate.name): candidate
            for candidate in candidates
        }
        names = [str(candidate.name) for candidate in candidates]
        matches = MatchLib.get_best_partials(str(submission.name), names, 75)
        return [candidates_by_name[match] for match in matches]

    @staticmethod
    def __get_candidates_name_only(dao, submission):
        pn = submission.name
        addr = submission.address
        sql = ("SELECT * "
               "FROM voters "
               "WHERE last_name_meta=? "
               "AND last_name LIKE ? "
               "AND first_name_meta=? "
               "AND first_name LIKE ?")
        vals = [
            MatchLib.get_single(pn.last), pn.last[0] + '%',
            MatchLib.get_single(pn.first), pn.first[0] + '%'
        ]
        if addr.zipcode:
            sql += " AND zipcode LIKE ?"
            vals.append(addr.zipcode[0:4] + '%')
        elif addr.city:
            sql += " AND city=?"
            vals.append(addr.city)
        rex = dao.execute(sql, vals)
        return [Voter(rec) for rec in rex] if rex else []

    @staticmethod
    def __get_household(dao, submission):
        if not submission.address.metaphone:
            return []
        sql = ("SELECT * "
               "FROM voters "
               "WHERE street_name_meta LIKE ? "
               "AND street_name LIKE ? "
               "AND house_number=? "
               "ORDER BY last_name, first_name, middle_name;")
        vals = [
            submission.address.metaphone + '%',
            submission.address.street[0] + '%', submission.address.house_number
        ]
        rex = dao.execute(sql, vals)
        return [Voter(rec) for rec in rex] if rex else []

    @staticmethod
    def __set_match_score(submission, match):
        from fuzzywuzzy import fuzz

        possible = 100
        score = fuzz.ratio(str(submission.name), str(match.name))
        if score >= 50:
            if submission.address.street_name:
                possible += 100
                score += fuzz.ratio(str(submission.address),
                                    str(match.address))
            if submission.address.city:
                possible += 100
                score += fuzz.ratio(submission.address.city,
                                    match.address.city)
            if submission.address.zipcode:
                possible += 100
                score += fuzz.ratio(submission.address.zipcode,
                                    match.address.zipcode)
        match.score = int(score / possible * 100)

    @staticmethod
    def get_by_block(dao, block, elections=None):

        sql = ("SELECT * "
               "FROM voters "
               "WHERE precinct_id=? "
               "AND street_name=? "
               "AND street_type=? ")
        vals = [
            block['precinct_id'], block['street_name'], block['street_type']
        ]
        if block['low_addr']:
            sql += "AND house_number BETWEEN ? AND ? "
            vals += [block['low_addr'], block['high_addr']]
        if block['odd_even']:
            if block['odd_even'] == 'O':
                sql += "AND (house_number % 2)=1 "
            elif block['odd_even'] == 'E':
                sql += "AND (house_number % 2)=0 "

        sql += "ORDER BY house_number;"

        voters = dao.execute(sql, vals)
        if not voters:
            return []

        if elections:
            from models.voter_history import VoterHistory

            election_codes = [election['code'] for election in elections]

            for voter in voters:
                voter_elections = VoterHistory.get_for_voter(
                    dao, voter['voter_id'], election_codes)
                for election in elections:
                    code = 'N'
                    if election['code'] in voter_elections:
                        code = voter_elections[election['code']]['ballot'] \
                            if voter_elections[election['code']]['ballot'] else 'Y'
                        if voter_elections[
                                election['code']]['absentee_flag'] == 'Y':
                            code += 'A'
                    voter[election['date']] = code

        return voters

    @staticmethod
    def get_by_precinct(precinct_id):
        flds = Voter.__fldnames + Voter.__hx_fldnames
        sql = ("SELECT flds FROM voters AS v "
               "JOIN voter_history AS h "
               "ON v.voter_id=h.voter_id "
               "WHERE v.precinct_id=%s "
               "ORDER BY street_name, street_type, house_number;") % (
                   ','.join(flds))
        vals = (precinct_id, )
        dao = MySqlDao()
        return dao.execute(sql, vals)

    __fldnames = [
        'v.id AS id', 'v.last_name AS last_name', 'v.first_name AS first_name',
        'v.middle_name AS middle_name', 'v.name_suffix AS name_suffix',
        'v.birth_year AS birth_year', 'v.gender AS gender',
        'v.house_number AS house_number', 'v.pre_direction AS pre_direction',
        'v.street_name AS street_name', 'v.street_type AS street_type',
        'v.suf_direction AS suf_direction', 'v.unit AS unit', 'v.city AS city',
        'v.zip AS zip', 'v.voter_id AS voter_id', 'v.reg_date AS reg_date',
        'v.permanent_absentee AS permanent_absentee', 'v.status AS status',
        'v.uocava AS uocava'
    ]

    __hx_fldnames = [
        'h.election_code AS election_code', 'h.absentee_flag AS absentee_flag',
        'h.ballot AS ballot'
    ]