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')
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()
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')
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
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
def test_no_city_id(self): """No city_id.""" self.assertFalse(geo.get_city_proto(None))
def test_no_city_id(self) -> None: """No city_id.""" self.assertFalse(geo.get_city_proto(''))