def _get_first_actions_vars(user: user_pb2.User, database: mongo.NoPiiMongoDatabase, **unused_kwargs: Any) -> dict[str, Any]: job_list = list( filter(None, (jobs.get_job_proto(database, p.target_job.code_ogr, p.target_job.job_group.rome_id) for p in user.projects))) if not job_list: raise campaign.DoNotSend('Need to have at least one job.') job_names = [job.name for job in job_list] quoted_jobs = parse.quote(' '.join(job_names)) scoring_project = scoring.ScoringProject(user.projects[0], user, database) return get_default_vars(user) | { 'departements': ','.join({p.city.departement_id for p in user.projects}), 'hasSeveralJobs': campaign.as_template_boolean(len(job_list) > 1), 'jobIds': ','.join({job.job_group.rome_id for job in job_list}), 'jobs': job_names, 'ofJobName': scoring_project.populate_template('%ofJobName'), 'optLink': 'https://www.orientation-pour-tous.fr/spip.php?' f'page=recherche&rubrique=metiers&recherche={quoted_jobs}', }
def test_get_job_proto(self) -> None: """Regular usage of get_job_proto.""" self.database.job_group_info.insert_one({ '_id': 'correct', 'romeId': 'correct', 'name': 'Job Group with the correct Job', 'jobs': [{ 'codeOgr': 'my-job', 'name': 'This is the job we are looking for', 'feminineName': 'Feminine', 'masculineName': 'Masculine', }], }) job_proto = jobs.get_job_proto(self.database, 'my-job', 'correct') assert job_proto self.assertEqual('This is the job we are looking for', job_proto.name) self.assertEqual('Feminine', job_proto.feminine_name) self.assertEqual('Job Group with the correct Job', job_proto.job_group.name) self.assertFalse(job_proto.job_group.jobs)
def test_get_job_proto_wrong_job_group(self) -> None: """The job is in another job group.""" self.database.job_group_info.insert_many([ { '_id': 'empty', 'romeId': 'empty', 'name': 'Empty Job Group', }, { '_id': 'correct', 'romeId': 'correct', 'name': 'Job Group with the correct Job', 'jobs': [{ 'codeOgr': 'my-job', 'name': 'This is the job we are looking for', }], }, ]) self.assertFalse(jobs.get_job_proto(self.database, 'my-job', 'empty'))
def test_get_job_proto_missing_job_id(self) -> None: """Job ID is missing.""" self.assertFalse(jobs.get_job_proto(self.database, '', '')) self.assertFalse(jobs.get_job_proto(self.database, '', 'A1234'))
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