Ejemplo n.º 1
0
    def test_unknown_city(self):
        """Unknown city."""

        self.cities_index.get_object.return_value = None
        self.assertFalse(geo.get_city_proto('69386'))

        self.cities_index.get_object.assert_called_once_with('69386')
Ejemplo n.º 2
0
    def test_format_error(self, mock_logging):
        """The data returned by Algolia is not compatible."""

        self.cities_index.get_object.return_value = {
            'population': 'not a number',
        }

        self.assertFalse(geo.get_city_proto('69386'))
        mock_logging.assert_called_once()
Ejemplo n.º 3
0
    def test_get_city_proto(self):
        """Get a city proto from Algolia."""

        self.cities_index.get_object.return_value = {
            'name': 'Lyon 6e arrondissement',
            'departementId': '69',
            'transport': 6,
            'urban': 0,
            'zipCode': '69006',
            'otherField': 'yipe',
        }

        city = geo.get_city_proto('69386')

        self.assertEqual('Lyon 6e arrondissement', city.name)
        self.assertEqual('69', city.departement_id)
        self.assertEqual(-1, city.urban_score)
        self.assertEqual(6, city.public_transportation_score)
        self.assertEqual('69006', city.postcodes)
        self.cities_index.get_object.assert_called_once_with('69386')
Ejemplo n.º 4
0
    def _pe_connect_authenticate(self, code, nonce):
        token_data = _get_oauth2_access_token(
            'https://authentification-candidat.pole-emploi.fr/connexion/oauth2/access_token?'
            'realm=/individu',
            code=code,
            client_id=_EMPLOI_STORE_CLIENT_ID,
            client_secret=_EMPLOI_STORE_CLIENT_SECRET,
            auth_name='PE Connect',
        )

        if token_data.get('nonce') != nonce:
            flask.abort(403, 'Mauvais paramètre nonce')
        authorization_header = '{} {}'.format(
            token_data.get('token_type', 'Bearer'),
            token_data.get('access_token', ''))
        scopes = token_data.get('scope', '').split(' ')

        user_info_response = requests.get(
            'https://api.emploi-store.fr/partenaire/peconnect-individu/v1/userinfo',
            headers={'Authorization': authorization_header})
        if user_info_response.status_code < 200 or user_info_response.status_code >= 400:
            logging.warning('PE Connect fails (%d): "%s"',
                            user_info_response.status_code,
                            user_info_response.text)
            flask.abort(403, user_info_response.text)

        user_info = user_info_response.json()

        city = None
        if 'coordonnees' in scopes:
            coordinates_response = requests.get(
                'https://api.emploi-store.fr/partenaire/peconnect-coordonnees/v1/coordonnees',
                headers={
                    'Authorization': authorization_header,
                    'pe-nom-application': 'Bob Emploi',
                })
            if coordinates_response.status_code >= 200 and coordinates_response.status_code < 400:
                coordinates = coordinates_response.json()
                city = geo.get_city_proto(coordinates.get('codeINSEE'))

        job = None
        if 'competences' in scopes:
            competences_response = requests.get(
                'https://api.emploi-store.fr/partenaire/peconnect-competences/v1/competences',
                headers={'Authorization': authorization_header},
            )
            if competences_response.status_code >= 200 and competences_response.status_code < 400:
                competences = competences_response.json()
                job_id, rome_id = next(
                    ((c.get('codeAppellation'), c.get('codeRome'))
                     for c in competences), (None, None))
                job = jobs.get_job_proto(self._db, job_id, rome_id)

        response = user_pb2.AuthResponse()
        user_dict = self._user_db.user.find_one(
            {'peConnectId': user_info['sub']})
        user_id = str(user_dict.pop('_id')) if user_dict else ''
        if proto.parse_from_mongo(user_dict, response.authenticated_user):
            response.authenticated_user.user_id = user_id
            self._handle_returning_user(response)
        else:
            email = user_info.get('email')
            if email:
                self._assert_user_not_existing(email)
                response.authenticated_user.profile.email = email
            user = response.authenticated_user
            user.pe_connect_id = user_info['sub']
            # TODO(pascal): Handle the case where one of the name is missing.
            user.profile.name = french.cleanup_firstname(
                user_info.get('given_name', ''))
            user.profile.last_name = french.cleanup_firstname(
                user_info.get('family_name', ''))
            user.profile.gender = \
                _PE_CONNECT_GENDER.get(user_info.get('gender', ''), user_pb2.UNKNOWN_GENDER)
            if city or job:
                user.projects.add(
                    is_incomplete=True,
                    mobility=geo_pb2.Location(city=city) if city else None,
                    target_job=job)
            self._save_new_user(user)
            response.is_new_user = True

        response.auth_token = create_token(response.authenticated_user.user_id,
                                           'auth')

        return response
Ejemplo n.º 5
0
    def _pe_connect_authenticate(
            self, auth_request: auth_pb2.AuthRequest) -> auth_pb2.AuthResponse:
        token_data = _get_oauth2_access_token(
            'https://authentification-candidat.pole-emploi.fr/connexion/oauth2/access_token?'
            'realm=/individu',
            code=auth_request.pe_connect_code,
            client_id=_EMPLOI_STORE_CLIENT_ID or '',
            client_secret=_EMPLOI_STORE_CLIENT_SECRET or '',
            auth_name='PE Connect',
        )

        if token_data.get('nonce') != auth_request.pe_connect_nonce:
            flask.abort(403, 'Mauvais paramètre nonce')
        bearer = token_data.get('token_type', 'Bearer')
        access_token = token_data.get('access_token', '')
        authorization_header = f'{bearer} {access_token}'
        scopes = token_data.get('scope', '').split(' ')

        user_info_response = requests.get(
            'https://api.emploi-store.fr/partenaire/peconnect-individu/v1/userinfo',
            headers={'Authorization': authorization_header})
        if user_info_response.status_code < 200 or user_info_response.status_code >= 400:
            logging.warning('PE Connect fails (%d): "%s"',
                            user_info_response.status_code,
                            user_info_response.text)
            flask.abort(403, user_info_response.text)

        user_info = typing.cast(Dict[str, str], user_info_response.json())

        city = None
        if 'coordonnees' in scopes:
            coordinates_response = requests.get(
                'https://api.emploi-store.fr/partenaire/peconnect-coordonnees/v1/coordonnees',
                headers={
                    'Authorization': authorization_header,
                    'pe-nom-application': 'Bob Emploi',
                })
            if coordinates_response.status_code >= 200 and coordinates_response.status_code < 400:
                coordinates = typing.cast(Dict[str, str],
                                          coordinates_response.json())
                code_insee = coordinates.get('codeINSEE')
                if code_insee:
                    clean_code_insee = _replace_arrondissement_insee_to_city(
                        code_insee)
                    city = geo.get_city_proto(clean_code_insee)

        job = None
        if 'competences' in scopes:
            competences_response = requests.get(
                'https://api.emploi-store.fr/partenaire/peconnect-competences/v1/competences',
                headers={'Authorization': authorization_header},
            )
            if competences_response.status_code >= 200 and competences_response.status_code < 400:
                competences = typing.cast(List[Dict[str, str]],
                                          competences_response.json())
                job_id, rome_id = next(
                    ((c.get('codeAppellation'), c.get('codeRome'))
                     for c in competences), (None, None))
                if job_id and rome_id:
                    job = jobs.get_job_proto(self._db, job_id, rome_id)

        response = auth_pb2.AuthResponse()
        user_dict = self._user_collection.find_one(
            {'peConnectId': user_info['sub']})
        if proto.parse_from_mongo(user_dict, response.authenticated_user,
                                  'user_id'):
            self._handle_returning_user(response)
        else:
            user = response.authenticated_user
            is_existing_user, had_email = self._load_user_from_token_or_email(
                auth_request, user, user_info.get('email'))
            user.pe_connect_id = user_info['sub']
            response.is_new_user = force_update = not user.has_account
            user.has_account = True
            if city or job and not user.projects:
                force_update = True
                user.projects.add(is_incomplete=True,
                                  city=city or None,
                                  target_job=job)
            if is_existing_user:
                self._handle_returning_user(response,
                                            force_update=force_update,
                                            had_email=had_email)
            else:
                # TODO(pascal): Handle the case where one of the name is missing.
                user.profile.name = french.cleanup_firstname(
                    user_info.get('given_name', ''))
                user.profile.last_name = french.cleanup_firstname(
                    user_info.get('family_name', ''))
                user.profile.gender = \
                    _PE_CONNECT_GENDER.get(user_info.get('gender', ''), user_pb2.UNKNOWN_GENDER)
                self.save_new_user(user, auth_request.user_data)

        response.auth_token = create_token(response.authenticated_user.user_id,
                                           'auth')

        return response
Ejemplo n.º 6
0
    def test_no_city_id(self):
        """No city_id."""

        self.assertFalse(geo.get_city_proto(None))
Ejemplo n.º 7
0
    def test_no_city_id(self) -> None:
        """No city_id."""

        self.assertFalse(geo.get_city_proto(''))