예제 #1
0
def _get_short_diploma_vars(user: user_pb2.User, *,
                            database: mongo.NoPiiMongoDatabase,
                            **unused_kwargs: Any) -> dict[str, Any]:

    if not user.projects:
        raise scoring.NotEnoughDataException('No project yet', {'projects.0'})

    project = user.projects[0]

    if user.projects[0].diagnostic.category_id != 'missing-diploma':
        raise campaign.DoNotSend('The user has no missing-diploma category')

    scoring_project = scoring.ScoringProject(project, user, database)

    login_url = campaign.create_logged_url(user.user_id,
                                           f'/projet/{project.project_id}')

    # TODO(sil): Let's check if this is needed to have access to the method.
    if not project.target_job.job_group.rome_id:
        raise scoring.NotEnoughDataException(
            'Need a job group to find trainings',
            # TODO(pascal): Use project_id instead of 0.
            {'projects.0.targetJob.jobGroup.romeId'})

    deep_link_training_url = \
        campaign.get_deep_link_advice(user.user_id, project, 'training')

    return campaign.get_default_coaching_email_vars(user) | {
        'deepTrainingAdviceUrl':
        deep_link_training_url,
        'ofJobName':
        scoring_project.populate_template('%ofJobName'),
        'productUrl':
        f'{login_url}?utm_source=bob-emploi&utm_medium=email',
    }
예제 #2
0
def _get_improve_cv_vars(user: user_pb2.User, *, now: datetime.datetime,
                         **unused_kwargs: Any) -> dict[str, Any]:
    """Compute vars for the "Improve your CV" email."""

    if user_profile_pb2.RESUME not in user.profile.frustrations:
        raise campaign.DoNotSend('User is not frustrated by its CV')

    if not user.projects:
        raise scoring.NotEnoughDataException('No project yet', {'projects.0'})

    project = user.projects[0]
    if project.kind == project_pb2.FIND_A_FIRST_JOB:
        has_experience = 'False'
    elif project.kind in (project_pb2.FIND_A_NEW_JOB,
                          project_pb2.FIND_ANOTHER_JOB):
        has_experience = 'True'
    else:
        has_experience = ''

    deep_link_advice_url = \
        campaign.get_deep_link_advice(user.user_id, project, 'improve-resume') or \
        campaign.get_deep_link_advice(user.user_id, project, 'fresh-resume')

    return campaign.get_default_coaching_email_vars(user) | {
        'deepLinkAdviceUrl': deep_link_advice_url,
        'hasExperience': has_experience,
        'isSeptember': campaign.as_template_boolean(now.month == 9),
        'loginUrl': campaign.create_logged_url(user.user_id)
    }
예제 #3
0
def _get_action_plan_vars(user: user_pb2.User, now: datetime.datetime,
                          **unused_kwargs: Any) -> dict[str, Any]:
    if not user.projects:
        raise campaign.DoNotSend('User does not have any projects.')
    project = user.projects[0]
    plan_actions = sorted(
        [
            action for action in project.actions
            if (action.status == action_pb2.ACTION_CURRENT
                or action.status == action_pb2.ACTION_DONE)
        ],
        key=lambda action: action.expected_completion_at.ToDatetime())
    if not plan_actions or not project.HasField('action_plan_started_at'):
        raise campaign.DoNotSend('User does not have a ready action plan.')

    actions_by_sections = _make_action_lists(plan_actions, user.user_id,
                                             project.project_id, now)
    creation_date = i18n.translate_date(
        project.action_plan_started_at.ToDatetime(), user.profile.locale)
    # TODO(Sil): Put actions and sections visibility in the same object.
    # TODO(cyrille) Make the variables so that we can loop on sections directly.
    return campaign.get_default_coaching_email_vars(user) | {
        'actionPlanUrl':
        campaign.create_logged_url(
            user.user_id, f'/projet/{project.project_id}/plan-action'),
        'actions':
        actions_by_sections,
        'creationDate':
        creation_date,
        'numActionsBySections': {
            section: len(actions_by_sections.get(section, []))
            for section in _ACTIONS_SECTIONS
        }
    }
예제 #4
0
def _format_action(action: action_pb2.Action, user_id: str,
                   project_id: str) -> dict[str, Any]:
    return {
        'title':
        action.title,
        'url':
        campaign.create_logged_url(
            user_id, f'/projet/{project_id}/action/{action.action_id}')
    }
예제 #5
0
    def test_create_logged_url(self) -> None:
        """Test the create logged url function."""

        user_id = '02499e64387edfcc2ab7a948'
        base_url = 'https://www.bob-emploi.fr/project/0/wow-baker?'
        regex = re.compile(
            rf'^{re.escape(base_url)}authToken=(\d+\.[a-f0-9]+)&userId={user_id}$'
        )
        logged_url = campaign.create_logged_url(user_id,
                                                '/project/0/wow-baker')
        self.assertRegex(logged_url, regex)

        match_token = regex.match(logged_url)
        assert match_token
        token = match_token.group(1)
        self.assertTrue(auth_token.check_token(user_id, token, role='auth'))
예제 #6
0
    def test_logged_url(self) -> None:
        """Test that logged URL allows for actual authentication."""

        user_id = self.create_user_with_token()[0]
        logged_url = campaign.create_logged_url(user_id, '/foo')
        params = parse.parse_qs(parse.urlparse(logged_url).query)
        self.assertEqual([user_id], params['userId'])
        [token] = params['authToken']

        response = self.app.post('/api/user/authenticate',
                                 data=json.dumps({
                                     'userId': user_id,
                                     'authToken': token
                                 }),
                                 content_type='application/json')

        auth_response = self.json_from_response(response)
        user_id = auth_response['authenticatedUser']['userId']
def _get_prepare_your_application_vars(user: user_pb2.User, **unused_kwargs: Any) -> dict[str, Any]:
    """Compute vars for the "Prepare your application" email."""

    if not user.projects:
        raise scoring.NotEnoughDataException('No project yet', {'projects.0'})

    project = user.projects[0]

    deep_link_motivation_email_url = \
        campaign.get_deep_link_advice(user.user_id, project, 'motivation-email')

    return campaign.get_default_coaching_email_vars(user) | {
        'deepLinkMotivationEmailUrl': deep_link_motivation_email_url,
        'hasInterviewFrustration':
        campaign.as_template_boolean(user_profile_pb2.INTERVIEW in user.profile.frustrations),
        'hasSelfConfidenceFrustration':
        campaign.as_template_boolean(user_profile_pb2.SELF_CONFIDENCE in user.profile.frustrations),
        'loginUrl': campaign.create_logged_url(user.user_id, f'/projet/{project.project_id}'),
    }
예제 #8
0
def _get_find_diploma_vars(user: user_pb2.User, *,
                           database: mongo.NoPiiMongoDatabase,
                           **unused_kwargs: Any) -> dict[str, Any]:
    """Compute vars for the "Prepare your application" email."""

    if not user.projects:
        raise scoring.NotEnoughDataException('No project yet', {'projects.0'})

    project = user.projects[0]
    scoring_project = scoring.ScoringProject(project, user, database)

    if not any(s.strategy_id == 'get-diploma'
               for s in project.opened_strategies):
        raise campaign.DoNotSend(
            'The user has not started a strategy to get a diploma')

    if not project.target_job.job_group.rome_id:
        raise scoring.NotEnoughDataException(
            'Need a job group to find trainings',
            # TODO(pascal): Use project_id instead of 0.
            {'projects.0.targetJob.jobGroup.romeId'})

    trainings = scoring_project.get_trainings()[:3]

    deep_link_training_url = \
        campaign.get_deep_link_advice(user.user_id, project, 'training')

    return campaign.get_default_coaching_email_vars(user) | {
        'deepTrainingAdviceUrl':
        deep_link_training_url,
        'inDepartement':
        scoring_project.populate_template('%inDepartement'),
        'loginUrl':
        campaign.create_logged_url(user.user_id,
                                   f'/projet/{project.project_id}'),
        'numTrainings':
        len(trainings),
        'ofJobName':
        scoring_project.populate_template('%ofJobName'),
        'trainings': [json_format.MessageToDict(t) for t in trainings],
    }
예제 #9
0
def _get_jobbing_vars(
        user: user_pb2.User, *, database: mongo.NoPiiMongoDatabase,
        **unused_kwargs: Any) -> dict[str, Any]:
    """Compute vars for the "Jobbing" email."""

    if not user.projects:
        raise scoring.NotEnoughDataException('No project yet', {'projects.0'})

    project = user.projects[0]

    if not any(s.strategy_id == 'diploma-free-job' for s in project.opened_strategies):
        raise campaign.DoNotSend(
            'The user has not started a strategy to get a job without a diploma')

    scoring_project = scoring.ScoringProject(project, user, database)
    model = scoring.get_scoring_model('advice-reorient-jobbing')
    if not model:
        raise campaign.DoNotSend('The advice-reorient-jobbing model is not implemented')
    reorient_jobs = typing.cast(
        reorient_jobbing_pb2.JobbingReorientJobs,
        model.get_expanded_card_data(scoring_project),
    ).reorient_jobbing_jobs
    if not reorient_jobs:
        raise campaign.DoNotSend("We didn't find any jobbing jobs to reorient to for the user")

    if project.target_job.name:
        of_job_name = scoring_project.populate_template('%ofJobName')
    else:
        # This is not translated to fr@tu because the email templates are only in fr for now.
        of_job_name = 'de definir votre projet professionnel'

    return campaign.get_default_coaching_email_vars(user) | {
        'inDepartement': scoring_project.populate_template('%inDepartement'),
        'jobs': [{'name': job.name} for job in reorient_jobs],
        'loginUrl': campaign.create_logged_url(user.user_id, f'/projet/{project.project_id}'),
        'ofJobName': of_job_name,
    }
예제 #10
0
def _account_deletion_notice_vars(user: user_pb2.User, **unused_kwargs: Any) -> dict[str, str]:
    return dict(
        campaign.get_default_vars(user),
        loginUrl=campaign.create_logged_url(user.user_id))
예제 #11
0
        # "des personnes qui travaillent comme {{var:jobNameInDepartement}} ont décroché leur poste"
        # That'd make a weird but ok sentence and should not happened anyway as this block relies
        # on job info.
        genderized_job_name = scoring_project.translate_static_string('vous')

    job_name_in_departement = f'{genderized_job_name} {in_departement}'
    of_job_name_in_departement = f'{of_job_name} {in_departement}'

    return campaign.get_default_coaching_email_vars(user) | {
        'applicationModes': _make_section(application_modes_section),
        'departements': _make_section(departements_section),
        'employmentType': _make_section(employment_types_section),
        'imtLink': imt_link,
        'inCity': scoring_project.populate_template('%inCity'),
        'jobNameInDepartement': job_name_in_departement,
        'loginUrl': campaign.create_logged_url(user.user_id),
        'marketStress': _make_section(market_stress_section),
        'months': _make_section(months_section),
        'ofJobNameInDepartement': of_job_name_in_departement,
        'ofJobName': of_job_name,
    }


campaign.register_campaign(campaign.Campaign(
    campaign_id='imt',
    mongo_filters={
        'projects': {
            '$elemMatch': {
                'isIncomplete': {'$ne': True},
            },
        },