예제 #1
0
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.")
예제 #2
0
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
예제 #3
0
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
예제 #4
0
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,
    )
예제 #5
0
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
예제 #6
0
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
예제 #7
0
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
예제 #8
0
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)