Exemple #1
0
    def test_unknown_user(self, mock_requests: requests_mock.Mocker) -> None:
        """Test update_users_client_metrics with an unknown user."""

        mock_db = mongomock.MongoClient().test
        mock_db.user.insert_one({
            '_id':
            mongomock.ObjectId('7ed900dbfbebdee97f9e2332'),
            'registeredAt':
            '2017-11-17T10:57:12Z',
        })
        patcher = mock.patch(sync_amplitude.__name__ + '._DB', new=mock_db)
        patcher.start()
        self.addCleanup(patcher.stop)

        mock_requests.get(
            'https://amplitude.com/api/2/usersearch?user=7ed900dbfbebdee97f9e2332',
            json={'matches': []})

        sync_amplitude.main([
            '--registered-from', '2017-11-14', '--registered-to', '2017-11-18',
            '--disable-sentry', '--no-dry-run'
        ])

        user = user_pb2.User()
        proto.parse_from_mongo(mock_db.user.find_one({}), user)

        self.assertEqual('Not Found', user.client_metrics.amplitude_id)
Exemple #2
0
    def test_missing_sentry(self, unused_mock_requests: requests_mock.Mocker,
                            mock_logging: mock.MagicMock) -> None:
        """Missing sentry env var."""

        mock_db = mongomock.MongoClient().test
        mock_db.user.insert_one({
            '_id':
            mongomock.ObjectId('7ed900dbfbebdee97f9e2332'),
            'registeredAt':
            '2017-11-17T10:57:12Z',
        })
        patcher = mock.patch(sync_amplitude.__name__ + '._DB', new=mock_db)
        patcher.start()
        self.addCleanup(patcher.stop)

        sync_amplitude.main([
            '--registered-from', '2017-11-14', '--registered-to', '2017-11-18',
            '--no-dry-run'
        ])

        user = user_pb2.User()
        proto.parse_from_mongo(mock_db.user.find_one({}), user)
        self.assertFalse(user.client_metrics.amplitude_id)

        mock_logging.assert_called_once()
Exemple #3
0
def fetch_use_case_pools() -> use_case_pb2.UseCasePools:
    """Retrieve a list of the available pools of anonymized user examples."""

    use_case_pools = use_case_pb2.UseCasePools()
    use_case_pool_dicts = flask.current_app.config[
        'EVAL_DATABASE'].use_case.aggregate([
            {
                '$group': {
                    '_id': '$poolName',
                    'useCaseCount': {
                        '$sum': 1
                    },
                    'evaluatedUseCaseCount': {
                        '$sum': {
                            '$cond': [{
                                '$gt': ['$evaluation', None]
                            }, 1, 0]
                        }
                    },
                    'lastUserRegisteredAt': {
                        '$max': '$userData.registeredAt'
                    },
                }
            },
            {
                '$sort': {
                    'lastUserRegisteredAt': -1
                }
            },
        ])
    for use_case_pool_dict in use_case_pool_dicts:
        use_case_pool_proto = use_case_pools.use_case_pools.add()
        proto.parse_from_mongo(use_case_pool_dict, use_case_pool_proto, 'name')

    return use_case_pools
Exemple #4
0
    def test_main(self, mock_post: mock.MagicMock) -> None:
        """Overall test."""

        _db = pymongo.MongoClient('mongodb://my-db/db').db
        _db.user.drop()
        _db.user.insert_one({
            '_id':
            mongomock.ObjectId('5daf2298484ae6c93351b822'),
            'profile': {
                'name': 'Pascal',
                'lastName': 'Corpet',
                'email': '*****@*****.**',
                'locale': 'en',
            },
            'registeredAt':
            datetime.datetime(2018, 1, 22, 10, 0, 0).isoformat() + 'Z',
            'projects': [{
                'title': 'Project Title',
            }],
        })

        mail_nps.main(self._now, '1')

        sent_messages = mailjetmock.get_all_sent_messages()
        self.assertEqual(['*****@*****.**'],
                         [m.recipient['Email'] for m in sent_messages])
        self.assertEqual(100819, sent_messages[0].properties['TemplateID'])
        template_vars = sent_messages[0].properties['Variables']
        nps_form_urlstring = template_vars.pop('npsFormUrl')
        self.assertEqual(
            {
                'baseUrl': 'http://localhost:3000',
                'firstName': 'Pascal',
            }, template_vars)
        nps_form_url = parse.urlparse(nps_form_urlstring)
        self.assertEqual(
            'http://localhost:3000/api/nps',
            parse.urlunparse(nps_form_url[:4] + ('', ) + nps_form_url[5:]))
        nps_form_args = parse.parse_qs(nps_form_url.query)
        self.assertEqual({'user', 'token', 'redirect'}, nps_form_args.keys())
        self.assertEqual(['5daf2298484ae6c93351b822'], nps_form_args['user'])
        auth.check_token('5daf2298484ae6c93351b822',
                         nps_form_args['token'][0],
                         role='nps')
        self.assertEqual(['http://localhost:3000/retours?hl=en'],
                         nps_form_args['redirect'])
        mock_post.assert_called_once_with(
            'https://slack.example.com/webhook',
            json={
                'text':
                "Report for NPS blast: I've sent 1 emails (with 0 errors)."
            },
        )

        modified_user = user_pb2.User()
        proto.parse_from_mongo(_db.user.find_one(), modified_user)
        self.assertEqual(
            [sent_messages[0].message_id],
            [m.mailjet_message_id for m in modified_user.emails_sent])
        self.assertEqual('nps', modified_user.emails_sent[0].campaign_id)
Exemple #5
0
    def volunteering_missions(self, project: scoring_base.ScoringProject) \
            -> association_pb2.VolunteeringMissions:
        """Return a list of volunteering mission close to the project."""

        departement_id = project.details.city.departement_id

        # Get data from MongoDB.
        volunteering_missions_dict: dict[str, association_pb2.VolunteeringMissions] = \
            collections.defaultdict(association_pb2.VolunteeringMissions)
        collection = project.database.volunteering_missions
        for record in collection.find({'_id': {'$in': [departement_id, '']}}):
            record_id = record.pop('_id')
            proto.parse_from_mongo(record,
                                   volunteering_missions_dict[record_id])

        # TODO(pascal): First get missions from target city if any.

        # Merge data.
        project_missions = association_pb2.VolunteeringMissions()
        for scope in [departement_id, '']:
            for mission in volunteering_missions_dict[scope].missions:
                mission.is_available_everywhere = not scope
                project_missions.missions.add().CopyFrom(mission)

        return project_missions
Exemple #6
0
    def test_registered_from_days_ago(
            self, mock_requests: requests_mock.Mocker) -> None:
        """Test update_users_client_metrics."""

        mock_db = mongomock.MongoClient().test
        mock_db.user.insert_many([
            {
                '_id': mongomock.ObjectId('7ed900dbfbebdee97f9e2332'),
                'registeredAt': '2017-11-17T10:57:12Z',
            },
            # User registered just "today" (the day the script is run).
            {
                '_id': mongomock.ObjectId('7ed900dbfbebd00000000004'),
                'registeredAt': '2017-11-19T10:57:12Z',
            },
        ])
        patcher = mock.patch(sync_amplitude.__name__ + '._DB', new=mock_db)
        patcher.start()
        self.addCleanup(patcher.stop)

        mock_requests.get(
            'https://amplitude.com/api/2/usersearch?user=7ed900dbfbebdee97f9e2332',
            json={'matches': [{
                'amplitude_id': 42
            }]})
        mock_requests.get(
            'https://amplitude.com/api/2/useractivity?user=42',
            json={
                'events': [
                    {
                        'event_time': '2017-10-24 10:41:00.412000',
                        'event_properties': {
                            'Mobile Version': True,
                        },
                    },
                    # Last event of the session: 25 min, 5.1 sec later.
                    {
                        'event_time': '2017-10-24 11:06:05.512000'
                    },
                ]
            })

        sync_amplitude.main([
            '--registered-from', '2017-11-14', '--disable-sentry',
            '--no-dry-run'
        ])

        user = user_pb2.User()
        proto.parse_from_mongo(
            mock_db.user.find_one({
                '_id':
                mongomock.ObjectId('7ed900dbfbebdee97f9e2332'),
            }), user)
        self.assertEqual('42', user.client_metrics.amplitude_id)
        self.assertEqual(25 * 60 + 5,
                         user.client_metrics.first_session_duration_seconds)
        self.assertEqual(project_pb2.TRUE,
                         user.client_metrics.is_first_session_mobile)
Exemple #7
0
    def test_long_continuous_session(
            self, mock_requests: requests_mock.Mocker) -> None:
        """Test update_users_client_metrics with a user using Bob continuously for an hour."""

        mock_db = mongomock.MongoClient().test
        mock_db.user.insert_one({
            '_id':
            mongomock.ObjectId('7ed900dbfbebdee97f9e2332'),
            'registeredAt':
            '2017-11-17T10:57:12Z',
        })
        patcher = mock.patch(sync_amplitude.__name__ + '._DB', new=mock_db)
        patcher.start()
        self.addCleanup(patcher.stop)

        mock_requests.get(
            'https://amplitude.com/api/2/usersearch?user=7ed900dbfbebdee97f9e2332',
            json={'matches': [{
                'amplitude_id': 42
            }]})
        mock_requests.get('https://amplitude.com/api/2/useractivity?user=42',
                          json={
                              'events': [
                                  {
                                      'event_time': '2017-10-24 10:40:00'
                                  },
                                  {
                                      'event_time': '2017-10-24 10:45:08'
                                  },
                                  {
                                      'event_time': '2017-10-24 11:06:05'
                                  },
                                  {
                                      'event_time': '2017-10-24 11:26:05'
                                  },
                                  {
                                      'event_time': '2017-10-24 11:46:05'
                                  },
                                  {
                                      'event_time': '2017-10-24 12:05:05'
                                  },
                              ]
                          })

        sync_amplitude.main([
            '--registered-from', '2017-11-14', '--registered-to', '2017-11-18',
            '--disable-sentry', '--no-dry-run'
        ])

        user = user_pb2.User()
        proto.parse_from_mongo(mock_db.user.find_one({}), user)

        self.assertEqual('42', user.client_metrics.amplitude_id)
        self.assertEqual(85 * 60 + 5,
                         user.client_metrics.first_session_duration_seconds)
        self.assertEqual(project_pb2.FALSE,
                         user.client_metrics.is_first_session_mobile)
    def test_main(self, mock_mail, mock_report_mail):
        """Overall test."""

        self._db.user.insert_one({
            '_id':
            'my-own-user-id',
            'profile': {
                'name': 'Pascal',
                'lastName': 'Corpet',
                'email': '*****@*****.**',
            },
            'registeredAt':
            datetime.datetime(2018, 1, 22, 10, 0, 0).isoformat() + 'Z',
            'projects': [{
                'title': 'Project Title',
            }],
        })
        mock_mail.send_template.return_value.status_code = 200
        mock_mail.send_template.return_value.json.return_value = {
            'Sent': [{
                'MessageID': 123456,
            }]
        }
        mock_report_mail.send_template_to_admins.return_value.status_code = 200

        mail_nps.main(self._db.user, 'http://*****:*****@bayes.org', profile.email)
        nps_form_urlstring = template_vars.pop('npsFormUrl')
        self.assertEqual(
            {
                'baseUrl': 'http://localhost:3000',
                'firstName': 'Pascal',
            }, template_vars)
        nps_form_url = parse.urlparse(nps_form_urlstring)
        self.assertEqual(
            'http://localhost:3000/api/nps',
            parse.urlunparse(nps_form_url[:4] + ('', ) + nps_form_url[5:]))
        nps_form_args = parse.parse_qs(nps_form_url.query)
        self.assertEqual({'user', 'token', 'redirect'}, nps_form_args.keys())
        self.assertEqual(['my-own-user-id'], nps_form_args['user'])
        auth.check_token('my-own-user-id',
                         nps_form_args['token'][0],
                         role='nps')
        self.assertEqual(['http://localhost:3000/retours'],
                         nps_form_args['redirect'])
        self.assertTrue(mock_report_mail.send_template_to_admins.called)

        modified_user = user_pb2.User()
        proto.parse_from_mongo(self._db.user.find_one(), modified_user)
        self.assertEqual(123456,
                         modified_user.emails_sent[0].mailjet_message_id)
        self.assertEqual('nps', modified_user.emails_sent[0].campaign_id)
Exemple #9
0
def fetch_use_cases(pool_name: str) -> use_case_pb2.UseCases:
    """Retrieve a list of anonymized user examples from one pool."""

    use_cases = use_case_pb2.UseCases()
    use_case_dicts = _get_eval_db().use_case\
        .find({'poolName': pool_name}).sort('indexInPool', 1)
    for use_case_dict in use_case_dicts:
        use_case_proto = use_cases.use_cases.add()
        proto.parse_from_mongo(use_case_dict, use_case_proto, 'use_case_id')
    return use_cases
Exemple #10
0
def fetch_use_cases(pool_name: str) -> use_case_pb2.UseCases:
    """Retrieve a list of anonymized user examples from one pool."""

    use_cases = use_case_pb2.UseCases()
    use_case_dicts = flask.current_app.config['EVAL_DATABASE'].use_case\
        .find({'poolName': pool_name}).sort('indexInPool', 1)
    for use_case_dict in use_case_dicts:
        use_case_proto = use_cases.use_cases.add()
        proto.parse_from_mongo(use_case_dict, use_case_proto, 'use_case_id')
    return use_cases
Exemple #11
0
    def test_update_users_client_metrics(
            self, mock_requests: requests_mock.Mocker) -> None:
        """Test update_users_client_metrics."""

        mock_db = mongomock.MongoClient().test
        mock_db.user.insert_one({
            '_id':
            mongomock.ObjectId('7ed900dbfbebdee97f9e2332'),
            'registeredAt':
            '2017-11-17T10:57:12Z',
        })
        patcher = mock.patch(sync_amplitude.__name__ + '._DB', new=mock_db)
        patcher.start()
        self.addCleanup(patcher.stop)

        mock_requests.get(
            'https://amplitude.com/api/2/usersearch?user=7ed900dbfbebdee97f9e2332',
            json={'matches': [{
                'amplitude_id': 42
            }]})
        mock_requests.get(
            'https://amplitude.com/api/2/useractivity?user=42',
            json={
                'events': [
                    {
                        'event_time': '2017-10-24 10:41:08.396000'
                    },
                    # Event out of order, this one is actually the first of the session.
                    {
                        'event_time': '2017-10-24 10:41:00.412000'
                    },
                    # Last event of the session: 25 min, 5.1 sec later.
                    {
                        'event_time': '2017-10-24 11:06:05.512000'
                    },
                    # Event really later: next session.
                    {
                        'event_time': '2017-10-24 13:06:05'
                    },
                ]
            })

        sync_amplitude.main([
            '--registered-from', '2017-11-14', '--registered-to', '2017-11-18',
            '--disable-sentry', '--no-dry-run'
        ])

        user = user_pb2.User()
        proto.parse_from_mongo(mock_db.user.find_one({}), user)

        self.assertEqual('42', user.client_metrics.amplitude_id)
        self.assertEqual(25 * 60 + 5,
                         user.client_metrics.first_session_duration_seconds)
        self.assertEqual(project_pb2.FALSE,
                         user.client_metrics.is_first_session_mobile)
Exemple #12
0
    def test_unknown_field_in_test_env(self) -> None:
        """Unknown fields make the function choke in a test environment."""

        message = test_pb2.Simple()
        with mock.patch(proto.__name__ + '._IS_TEST_ENV', new=True):
            with self.assertRaises(json_format.ParseError) as error_context:
                proto.parse_from_mongo({
                    'name': 'A123',
                    'unknownField': 14
                }, message)

        self.assertIn('no field named "unknownField"',
                      str(error_context.exception))
Exemple #13
0
    def _google_authenticate(
            self, auth_request: auth_pb2.AuthRequest) -> auth_pb2.AuthResponse:
        try:
            id_info = token.decode_google_id_token(
                auth_request.google_token_id)
        except i18n.TranslatableException as error:
            flask.abort(401, error.flask_translate())
        response = auth_pb2.AuthResponse()
        user_dict = self._user_collection.find_one(
            {'googleId': id_info['sub']})
        if proto.parse_from_mongo(user_dict, response.authenticated_user,
                                  'user_id'):
            self._handle_returning_user(response)
        else:
            is_existing_user = self._load_user_from_token_or_email(
                auth_request, response.authenticated_user, id_info['email'])
            response.authenticated_user.profile.picture_url = id_info.get(
                'picture', '')
            response.authenticated_user.google_id = id_info['sub']
            response.is_new_user = not response.authenticated_user.has_account
            response.authenticated_user.has_account = True
            if is_existing_user:
                self._handle_returning_user(response, force_update=True)
            else:
                self.save_new_user(response.authenticated_user,
                                   auth_request.user_data)

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

        return response
Exemple #14
0
    def test_timestamp(self):
        """Parse correctly Python timestamps."""

        action = action_pb2.Action()
        now = datetime.datetime.now()
        self.assertTrue(proto.parse_from_mongo({'createdAt': now}, action))
        self.assertEqual(now, action.created_at.ToDatetime())
Exemple #15
0
    def test_dry_run(self, mock_requests: requests_mock.Mocker,
                     mock_logging: mock.MagicMock) -> None:
        """Test update_users_client_metrics."""

        mock_db = mongomock.MongoClient().test
        mock_db.user.insert_one({
            '_id':
            mongomock.ObjectId('7ed900dbfbebdee97f9e2332'),
            'registeredAt':
            '2017-11-17T10:57:12Z',
        })
        patcher = mock.patch(sync_amplitude.__name__ + '._DB', new=mock_db)
        patcher.start()
        self.addCleanup(patcher.stop)

        mock_requests.get(
            'https://amplitude.com/api/2/usersearch?user=7ed900dbfbebdee97f9e2332',
            json={'matches': [{
                'amplitude_id': 42
            }]})
        mock_requests.get('https://amplitude.com/api/2/useractivity?user=42',
                          json={
                              'events': [
                                  {
                                      'event_time':
                                      '2017-10-24 10:41:00.412000'
                                  },
                                  {
                                      'event_time':
                                      '2017-10-24 11:06:05.512000'
                                  },
                              ]
                          })

        sync_amplitude.main([
            '--registered-from', '2017-11-14', '--registered-to', '2017-11-18',
            '--disable-sentry'
        ])

        user = user_pb2.User()
        proto.parse_from_mongo(mock_db.user.find_one({}), user)

        self.assertFalse(user.client_metrics.amplitude_id)
        self.assertFalse(user.client_metrics.first_session_duration_seconds)
        self.assertFalse(user.client_metrics.is_first_session_mobile)

        mock_logging.assert_called_once()
Exemple #16
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, i18n.flask_translate('Mauvais paramètre nonce'))
        bearer = token_data.get('token_type', 'Bearer')
        access_token = token_data.get('access_token', '')
        authorization_header = f'{bearer} {access_token}'

        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())

        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 = 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 is_existing_user:
                self._handle_returning_user(response,
                                            force_update=force_update)
            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_profile_pb2.UNKNOWN_GENDER)
                self.save_new_user(user, auth_request.user_data)

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

        return response
Exemple #17
0
def _parse_user_from_mongo(user_dict: dict[str, Any],
                           user: user_pb2.User) -> None:
    if not proto.parse_from_mongo(user_dict, user, 'user_id'):
        flask.abort(
            500,
            i18n.flask_translate(
                'Les données utilisateur sont corrompues dans la base de données.'
            ))
Exemple #18
0
    def test_id_field(self) -> None:
        """if an id_field is specified, its value is filled with _id from mongo."""

        message = test_pb2.Simple()
        self.assertTrue(
            proto.parse_from_mongo({
                '_id': 'Hello',
                'multipleWords': '123'
            }, message, 'name'))
        self.assertEqual('Hello', message.name)
Exemple #19
0
    def test_unknown_field(self):
        """Unknown fields do not make the function choke."""

        job_group = job_pb2.JobGroup()
        self.assertTrue(
            proto.parse_from_mongo({
                'romeId': 'A123',
                'unknownField': 14
            }, job_group))
        self.assertEqual('A123', job_group.rome_id)
Exemple #20
0
    def test_unknown_field(self) -> None:
        """Unknown fields do not make the function choke."""

        message = test_pb2.Simple()
        self.assertTrue(
            proto.parse_from_mongo({
                'name': 'A123',
                'unknownField': 14
            }, message))
        self.assertEqual('A123', message.name)
Exemple #21
0
 def _load_user_from_token_or_email(
         self, auth_request: auth_pb2.AuthRequest, user: user_pb2.User,
         email: Optional[str]) -> Tuple[bool, bool]:
     is_existing_user = email and proto.parse_from_mongo(
         self._user_collection.find_one({'hashedEmail': hash_user_email(email)}),
         user, 'user_id') or \
         self._load_user_with_token(auth_request, user, is_timestamp_required=False)
     had_email = bool(user.profile.email)
     if not had_email and email:
         user.profile.email = email
     return is_existing_user, had_email
Exemple #22
0
    def load_set(cls, filename: str) -> Dict[str, '_Persona']:
        """Load a set of personas from a JSON file."""

        with open(filename) as personas_file:
            personas_json = pyjson5.load(personas_file)
        personas: Dict[str, _Persona] = {}
        for name, blob in personas_json.items():
            user = user_pb2.User()
            assert proto.parse_from_mongo(blob['user'], user.profile)
            if 'featuresEnabled' in blob:
                assert proto.parse_from_mongo(blob['featuresEnabled'],
                                              user.features_enabled)
            if 'project' in blob:
                assert proto.parse_from_mongo(blob['project'],
                                              user.projects.add())
            if 'projects' in blob:
                for project in blob['projects']:
                    assert proto.parse_from_mongo(project, user.projects.add())
            assert name not in personas
            personas[name] = cls(name, user)
        return personas
Exemple #23
0
    def load_set(cls, filename):
        """Load a set of personas from a JSON file."""

        with open(filename) as personas_file:
            personas_json = json.load(personas_file)
        personas = {}
        for name, blob in personas_json.items():
            user_profile = user_pb2.UserProfile()
            assert proto.parse_from_mongo(blob['user'], user_profile)
            features_enabled = user_pb2.Features()
            if 'featuresEnabled' in blob:
                assert proto.parse_from_mongo(blob['featuresEnabled'],
                                              features_enabled)
            project = project_pb2.Project()
            assert proto.parse_from_mongo(blob['project'], project)
            assert name not in personas
            personas[name] = cls(name,
                                 user_profile=user_profile,
                                 project=project,
                                 features_enabled=features_enabled)
        return personas
Exemple #24
0
def main():
    """Populate departement prefix for users that don't already have one."""

    query = {
        'projects': {
            '$elemMatch': {
                'mobility.city.departementId': {
                    '$exists': True
                },
                'mobility.city.departementPrefix': {
                    '$exists': False
                },
            }
        }
    }
    user_count = 0
    for user_in_db in _USER_DB.user.find(query):
        user_id = user_in_db.pop('_id')
        user = user_pb2.User()
        if not proto.parse_from_mongo(user_in_db, user):
            logging.warning('Impossible to parse user %s', user_id)
            continue

        departement_ids = [
            project.mobility.city.departement_id for project in user.projects
        ]

        try:
            departement_prefixes = [
                _DEPARTEMENTS.get_collection(_DB)[dep_id].prefix
                for dep_id in departement_ids
            ]
        except KeyError:
            logging.warning(
                'User %s has at least one invalid departement ID %s.', user_id,
                ', '.join(departement_ids))
            continue

        modifs = {
            '$set': {
                'projects.{}.mobility.city.departementPrefix'.format(i):
                dep_prefix
                for i, dep_prefix in enumerate(departement_prefixes)
            },
        }
        if not DRY_RUN:
            _USER_DB.user.update_one({'_id': user_id}, modifs, upsert=False)
        else:
            logging.info('Prefix populated for user %s)', user_id)
        user_count += 1

    logging.warning('User modified:\n%s', user_count)
Exemple #25
0
    def test_timestamp(self) -> None:
        """Parse correctly Python timestamps."""

        message = test_pb2.Timely()
        now = datetime.datetime.now()
        self.assertTrue(
            proto.parse_from_mongo(
                {
                    'createdAt': now,
                    'modifiedAt': [now, now],
                }, message))
        self.assertEqual(now, message.created_at.ToDatetime())
        self.assertEqual(now, message.modified_at[0].ToDatetime())
Exemple #26
0
def list_use_cases_from_filters(request: use_case_pb2.UseCaseFiltersRequest) \
        -> use_case_pb2.UseCases:
    """Fetch a list of recent use cases satisfying a given list of filters."""

    request.max_count = request.max_count or _MAX_MATCHING_USE_CASES
    request.max_search_count = request.max_search_count or _MAX_SEARCHED_USE_CASES

    use_cases = use_case_pb2.UseCases()
    use_case_iterator = _get_eval_db().use_case.find(
        {'_id': _AUTOMATIC_EVAL_USE_CASE_ID_REGEX}
    ).sort([('_id', -1)]).limit(request.max_search_count)
    for use_case_json in use_case_iterator:
        use_case = use_cases.use_cases.add()
        proto.parse_from_mongo(use_case_json, use_case, 'use_case_id')
        try:
            if not _match_filters_for_use_case(request.filters, use_case):
                del use_cases.use_cases[-1]
        except KeyError as err:
            flask.abort(404, str(err))
        if len(use_cases.use_cases) >= request.max_count:
            break
    return use_cases
Exemple #27
0
def user_to_use_case(user, pool_name, index_in_pool):
    """Extracts a use case from a real user."""

    use_case = use_case_pb2.UseCase()
    if not proto.parse_from_mongo(user, use_case.user_data):
        return None
    use_case.title = next((p.title for p in use_case.user_data.projects), '')
    anonymize_proto(use_case.user_data, field_usages_to_clear={
        options_pb2.PERSONAL_IDENTIFIER, options_pb2.APP_ONLY, options_pb2.ALGORITHM_RESULT,
    })
    use_case.pool_name = pool_name
    use_case.index_in_pool = index_in_pool
    use_case.use_case_id = '{}_{:02x}'.format(pool_name, index_in_pool)
    return use_case
Exemple #28
0
    def test_weird_objects(self, mock_warning):
        """Raises a TypeError when an object is not of the right type."""

        job_group = job_pb2.JobGroup()
        self.assertFalse(proto.parse_from_mongo({'romeId': 123}, job_group))
        mock_warning.assert_called_once()
        self.assertEqual(
            'Error %s while parsing a JSON dict for proto type %s:\n%s',
            mock_warning.call_args[0][0])
        self.assertEqual(
            'Failed to parse romeId field: expected string or bytes-like object.',
            str(mock_warning.call_args[0][1]))
        self.assertEqual('JobGroup', str(mock_warning.call_args[0][2]))
        self.assertEqual("{'romeId': 123}", str(mock_warning.call_args[0][3]))
Exemple #29
0
    def test_weird_objects(self, mock_warning: mock.MagicMock) -> None:
        """Raises a TypeError when an object is not of the right type."""

        message = test_pb2.Simple()
        self.assertFalse(proto.parse_from_mongo({'name': 123}, message))
        mock_warning.assert_called_once()
        self.assertEqual(
            'Error %s while parsing a JSON dict for proto type %s:\n%s',
            mock_warning.call_args[0][0])
        self.assertEqual(
            'Failed to parse name field: expected string or bytes-like object.',
            str(mock_warning.call_args[0][1]))
        self.assertEqual('Simple', str(mock_warning.call_args[0][2]))
        self.assertEqual("{'name': 123}", str(mock_warning.call_args[0][3]))
Exemple #30
0
    def _linked_in_authenticate(self, code):
        token_data = _get_oauth2_access_token(
            'https://www.linkedin.com/oauth/v2/accessToken',
            code=code,
            client_id=_LINKED_IN_CLIENT_ID,
            client_secret=_LINKED_IN_CLIENT_SECRET,
            auth_name='LinkedIn Auth',
        )

        authorization_header = '{} {}'.format(
            token_data.get('token_type', 'Bearer'),
            token_data.get('access_token', ''))

        user_info_response = requests.get(
            'https://api.linkedin.com/v1/people/~:'
            '(id,location,first-name,last-name,email-address)?format=json',
            headers={'Authorization': authorization_header})
        if user_info_response.status_code < 200 or user_info_response.status_code >= 400:
            logging.warning('LinkedIn Auth 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()

        response = user_pb2.AuthResponse()
        # TODO(cyrille): Factorize with other 3rd party auth.
        user_dict = self._user_db.user.find_one(
            {'linkedInId': user_info['id']})
        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('emailAddress')
            if email:
                self._assert_user_not_existing(email)
                response.authenticated_user.profile.email = email
            user = response.authenticated_user
            user.linked_in_id = user_info['id']
            # TODO(pascal): Handle the case where one of the name is missing.
            user.profile.name = user_info.get('firstName', '')
            user.profile.last_name = user_info.get('lastName', '')
            self._save_new_user(user)
            response.is_new_user = True

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

        return response