def validate_rome_codes(rome_code_list): for rome in rome_code_list: if rome not in ROME_CODES: # ROME_CODES contains ascii data but rome is unicode. msg = 'Unknown rome_code: %s - Possible reasons: 1) %s 2) %s' % ( rome, 'This rome_code does not exist.', 'This rome code exists but is very recent and thus \ we do not have enough data yet to build relevant results for it. \ We typically need at least 12 months of data before we can build \ relevant results for a given rome_code.') raise InvalidFetcherArgument(msg) if len(rome_code_list) == 0: raise InvalidFetcherArgument("At least one rome_code is required.")
def get_location(request_args): """ Parse request arguments to compute location objects. Args: request_args (dict) Return: location (Location) zipcode (str) commune_id (str) departements (str) """ location = None zipcode = None commune_id = None departements = None # Commune_id or longitude/latitude if 'commune_id' in request_args: commune_id = request_args['commune_id'] city = geocoding.get_city_by_commune_id(commune_id) if not city: raise InvalidFetcherArgument( 'could not resolve latitude and longitude from given commune_id' ) latitude = city['coords']['lat'] longitude = city['coords']['lon'] location = Location(latitude, longitude) zipcode = city['zipcode'] elif 'latitude' in request_args and 'longitude' in request_args: if not request_args.get('latitude') or not request_args.get( 'longitude'): raise InvalidFetcherArgument( 'latitude or longitude (or both) have no value') try: latitude = float(request_args['latitude']) longitude = float(request_args['longitude']) location = Location(latitude, longitude) except ValueError: raise InvalidFetcherArgument( 'latitude and longitude must be float') elif 'departments' not in request_args: raise InvalidFetcherArgument( 'missing arguments: either commune_id or departments or both latitude and longitude' ) if 'departments' in request_args: departements = request_args.get('departments') return location, zipcode, commune_id, departements
def get_page_and_page_size(request_args): page = check_positive_integer_argument(request_args, 'page', 1) page_size = check_positive_integer_argument(request_args, 'page_size', pagination.OFFICES_PER_PAGE) if page_size > pagination.OFFICES_MAXIMUM_PAGE_SIZE: raise InvalidFetcherArgument( 'page_size is too large. Maximum value is %s' % pagination.OFFICES_MAXIMUM_PAGE_SIZE ) return page, page_size
def create_visible_market_fetcher(request_args): UNSUPPORTED_PARAMETERS = [ 'sort', 'naf_codes', 'headcount', 'departments', 'longitude', 'latitude' ] MANDATORY_PARAMETERS = ['rome_codes', 'commune_id', 'contract'] for param in UNSUPPORTED_PARAMETERS: if request_args.get(param): raise InvalidFetcherArgument('parameter %s is not supported' % param) for param in MANDATORY_PARAMETERS: if not request_args.get(param): raise InvalidFetcherArgument('parameter %s is required' % param) commune_id = request_args.get('commune_id') romes = [ code.upper() for code in request_args.get('rome_codes').split(',') ] validate_rome_codes(romes) page, page_size = get_page_and_page_size(request_args) if page != 1: raise InvalidFetcherArgument( 'only page=1 is supported as pagination is not implemented') distance = get_distance(request_args) contract = request_args.get('contract') if contract == hiring_type_util.CONTRACT_ALTERNANCE: hiring_type = hiring_type_util.CONTRACT_TO_HIRING_TYPE[contract] else: # FIXME: if only contract = alternance is supported, remove the param hiring_type raise InvalidFetcherArgument('only contract=alternance is supported') return offers.VisibleMarketFetcher( romes=romes, commune_id=commune_id, distance=distance, hiring_type=hiring_type, page_size=page_size, )
def check_positive_integer_argument(args, name, default_value): """ Return value from arguments, check that value is integer and positive. Args: args (dict) name (str) default_value (int) """ value = check_integer_argument(args, name, default_value) if value <= 0: raise InvalidFetcherArgument('{} must be positive'.format(name)) return value
def check_integer_argument(args, name, default_value): """ Return value from arguments, check that value is integer. Args: args (dict) name (str) default_value (int) """ value = args.get(name, default_value) try: value = int(value) except (TypeError, ValueError): raise InvalidFetcherArgument('{} must be integer'.format(name)) return value
def check_bool_argument(args, name, default_value): """ Return value from arguments, check that value is boolean. Args: args (dict) name (str) default_value (int) """ value = args.get(name, default_value) try: value = int(value) if value not in [0, 1]: raise ValueError except (TypeError, ValueError): raise InvalidFetcherArgument('{} must be boolean (0 or 1)'.format(name)) return value
def create_hidden_market_fetcher(location, departements, request_args): """ Returns the filters given a set of parameters. Required parameters: - `location` (Location): location near which to search. May be None if departements is set. - `departements`: a list of french "departements". May be None if location is set. - `rome_codes`: one or more "Pôle emploi ROME" codes, comma separated. Optional parameters: - `distance`: perimeter of the search radius (in Km) in which to search. - `page`: number of the requested page. - `page_size`: number of results per page ( maximum : pagination.OFFICES_MAXIMUM_PAGE_SIZE, default: pagination.OFFICES_PER_PAGE ). - `naf_codes`: one or more naf_codes, comma separated. If empty or missing, no filter will be used - `contract`: one value, only between 'all' (default) or 'alternance' - `sort`: one value, only between 'score' (default) and 'distance' - `headcount`: one value, only between 'all' (default), 'small' or 'big' - `departments`: one or more departments, comma separated. - `flag_pmsmp`: 1 to see only companies having flag_pmsmp=1, all companies otherwise. """ # Arguments to build the HiddenMarketFetcher object kwargs = {} # Sort sort = sorting.SORT_FILTER_DEFAULT if 'sort' in request_args: sort = request_args.get('sort') if sort not in sorting.SORT_FILTERS: raise InvalidFetcherArgument('sort. Possible values : %s' % ', '.join(sorting.SORT_FILTERS)) if sort != sorting.SORT_FILTER_SCORE and location is None: raise InvalidFetcherArgument('sort. %s is the only possible value with departement search. Please remove sort or departments.' % sorting.SORT_FILTER_SCORE) kwargs['sort'] = sort # Rome_code rome_codes = request_args.get('rome_codes') rome_codes_keyword_search = request_args.get('rome_codes_keyword_search') if not rome_codes_keyword_search: if not rome_codes: raise InvalidFetcherArgument('you must use rome_codes or rome_codes_keyword_search') else: if rome_codes: raise InvalidFetcherArgument('you must either use rome_codes or rome_codes_keyword_search but not both') else: # ROME keyword search : select first match of what the autocomplete result would be suggestions = autocomplete.build_job_label_suggestions(rome_codes_keyword_search, size=1) if len(suggestions) >= 1: rome_codes = suggestions[0]['id'] else: msg = 'No match found for rome_codes_keyword_search.' raise InvalidFetcherArgument(msg) rome_code_list = [code.upper() for code in rome_codes.split(',')] validate_rome_codes(rome_code_list) kwargs['romes'] = rome_code_list # Page and page_size page, page_size = get_page_and_page_size(request_args) kwargs['to_number'] = page * page_size kwargs['from_number'] = kwargs['to_number'] - page_size + 1 # Distance # WARNING: MAP uses distance=0 in their use of the API. kwargs['distance'] = get_distance(request_args) if request_args.get('distance') is not None and location is None: raise InvalidFetcherArgument('filter. Long/lat is not provided so distance can not be computed. Please remove the distance param.') # Naf naf_codes = {} if request_args.get('naf_codes'): naf_codes = [naf.upper() for naf in request_args['naf_codes'].split(',')] expected_naf_codes = mapping_util.map_romes_to_nafs(kwargs['romes']) invalid_nafs = [naf for naf in naf_codes if naf not in expected_naf_codes] if invalid_nafs: raise InvalidFetcherArgument('NAF code(s): %s. Possible values : %s ' % ( ' '.join(invalid_nafs), ', '.join(expected_naf_codes) )) kwargs['naf_codes'] = naf_codes # Convert contract to hiring type (DPAE/LBB or Alternance/LBA) contract = request_args.get('contract', hiring_type_util.CONTRACT_DEFAULT) if contract not in hiring_type_util.CONTRACT_VALUES: raise InvalidFetcherArgument('contract. Possible values : %s' % ', '.join(hiring_type_util.CONTRACT_VALUES)) kwargs['hiring_type'] = hiring_type_util.CONTRACT_TO_HIRING_TYPE[contract] # Headcount headcount = settings.HEADCOUNT_WHATEVER if 'headcount' in request_args: headcount = settings.HEADCOUNT_VALUES.get(request_args.get('headcount')) if not headcount: raise InvalidFetcherArgument('headcount. Possible values : %s' % ', '.join(sorted(settings.HEADCOUNT_VALUES.keys()))) kwargs['headcount'] = headcount # Departments departments = [] if 'departments' in request_args and request_args.get('departments'): departments = request_args.get('departments').split(',') unknown_departments = [dep for dep in departments if not geocoding.is_departement(dep)] if unknown_departments: raise InvalidFetcherArgument('departments : %s' % ', '.join(unknown_departments)) kwargs['departments'] = departments # from value in GET to enum # audience filter defaults to ALL kwargs['audience'] = get_enum_from_value(AudienceFilter, request_args.get('audience'), AudienceFilter.ALL) if (api_util.has_scope(request.args['user'], request.args.get('origin_user'), Scope.COMPANY_PMSMP)): kwargs['flag_pmsmp'] = check_bool_argument(request_args, 'flag_pmsmp', 0) if location is not None: return HiddenMarketFetcher(location.longitude, location.latitude, **kwargs) return HiddenMarketFetcher(None, None, **kwargs)