import collections
import functools
import logging
import re
import simplejson
from . import magicnumbers
from . import util
from . import filter
from .xpath import xpb
log = logging.getLogger(__name__)
looking_for_filters = filter.Filters()
looking_for_filters.register_filter_builder(filter.gentation_filter)
looking_for_filters.register_filter_builder(filter.location_filter)
looking_for_filters.register_filter_builder(
filter.age_filter,
decider=filter.Filters.any_not_none_decider
)
@looking_for_filters.register_filter_builder(decider=filter.Filters.any_decider)
def status_filter(status):
return '7,{0}'.format(int(status))
[docs]class LookingFor(object):
"""Represent the looking for attributes belonging to an okcupid.com
profile.
"""
_ages_re = re.compile(u'\s*Ages ([0-9]{1,3})\u2013([0-9]{1,3})\s*')
_ages_re2 = re.compile(u'\s*Age ([0-9]{1,3})')
_looking_for_xpb = xpb.div.with_classes('text', 'what_i_want')
def __init__(self, profile):
self._profile = profile
@util.cached_property
def raw_fields(self):
li_elements = self._looking_for_xpb.li.apply_(
self._profile.profile_tree
)
return {li.attrib['id'].split('_')[1]: li.text_content()
for li in li_elements}
def update_property(function):
@property
@functools.wraps(function)
def wrapped(self):
return function(self)
@wrapped.setter
def wrapped_setter(self, value):
self.update(**{function.__name__: value})
return wrapped_setter
@update_property
def gentation(self):
"""The sex/orientation that the user is looking for."""
return self.raw_fields.get('gentation').lower().strip()
@update_property
def ages(self):
"""The age range that the user is interested in."""
match = self._ages_re.match(self.raw_fields.get('ages'))
if not match:
match = self._ages_re2.match(self.raw_fields.get('ages'))
return self.Ages(int(match.group(1)),int(match.group(1)))
return self.Ages(int(match.group(1)), int(match.group(2)))
@update_property
def single(self):
"""Whether or not the user is only interested in people that are single.
"""
return 'display: none;' not in self._looking_for_xpb.li(id='ajax_single').\
one_(self._profile.profile_tree).attrib['style']
@update_property
def near_me(self):
"""Whether the user is only interested in people that are close to them.
"""
return 'near' in self.raw_fields.get('near', '').lower().strip()
@update_property
def kinds(self):
"""The kinds of relationship tha the user is looking for."""
return self.raw_fields.get('lookingfor', '').\
replace('For', '').strip().split(', ')
[docs] def update(self, ages=None, single=None, near_me=None, kinds=None,
gentation=None):
"""Update the looking for attributes of the logged in user.
:param ages: The ages that the logged in user is interested in.
:type ages: tuple
:param single: Whether or not the user is only interested in people that
are single.
:type single: bool
:param near_me: Whether or not the user is only interested in
people that are near them.
:type near_me: bool
:param kinds: What kinds of relationships the user should be updated to
be interested in.
:type kinds: list
:param gentation: The sex/orientation of people the user is interested
in.
:type gentation: str
"""
ages = ages or self.ages
single = single if single is not None else self.single
near_me = near_me if near_me is not None else self.near_me
kinds = kinds or self.kinds
gentation = gentation or self.gentation
data = {
'okc_api': '1',
'searchprefs.submit': '1',
'update_prefs': '1',
'lquery': '',
'locid': '0',
'filter5': '1, 1' # TODO(@IvanMalison) Do this better...
}
if kinds:
kinds_numbers = self._build_kinds_numbers(kinds)
if kinds_numbers:
data['lookingfor'] = kinds_numbers
age_min, age_max = ages
data.update(looking_for_filters.legacy_build(
status=single, gentation=gentation, radius=25 if near_me else 0,
age_min=age_min, age_max=age_max
))
log.info(simplejson.dumps({'looking_for_update': data}))
util.cached_property.bust_caches(self)
response = self._profile.authcode_post('profileedit2', data=data)
self._profile.refresh(reload=False)
return response.content
@staticmethod
def _build_kinds_numbers(looking_for_items):
looking_for_numbers = []
if not isinstance(looking_for_items, collections.Iterable):
looking_for_numbers = (looking_for_items,)
for item in looking_for_items:
for matcher, number in magicnumbers.looking_for_re_numbers:
if matcher.search(item) is not None:
looking_for_numbers.append(number)
return looking_for_numbers
del update_property
Ages = collections.namedtuple('Ages', ('min', 'max'))