def _get_first_eval_reminder_vars( user: user_pb2.User, *, now: datetime.datetime, **unused_kwargs: Any, ) -> dict[str, Any]: if not any(email.campaign_id == 'jobflix-first-eval' for email in user.emails_sent): raise campaign.DoNotSend( 'Only useful for user that have received the first campaign') next_week = now + datetime.timedelta(days=7) return campaign.get_default_vars(user) | { 'closingDate': next_week.strftime('%A %d %B'), }
def _get_nps_vars(user: user_pb2.User, **unused_kwargs: Any) -> dict[str, str]: user_id = user.user_id return campaign.get_default_vars(user) | { 'npsFormUrl': campaign.get_bob_link( '/api/nps', { 'user': user_id, 'token': auth_token.create_token(user_id, 'nps'), 'redirect': campaign.get_bob_link('/retours', {'hl': user.profile.locale}), }), }
def _employment_vars( user: user_pb2.User, *, now: datetime.datetime, database: mongo.NoPiiMongoDatabase, **unused_kwargs: Any, ) -> dict[str, str]: """Computes vars for a given user for the employment survey. Returns a dict with all vars required for the template. """ num_months_ago = round((now - user.registered_at.ToDatetime()).days / 30.5) if num_months_ago <= 0 and not user.features_enabled.alpha: raise campaign.DoNotSend( f'User registered only recently ({user.registered_at})') scoring_project = scoring.ScoringProject(project_pb2.Project(), user, database) registered_since = scoring_project.get_several_months_text(num_months_ago) for status in user.employment_status: if status.created_at.ToDatetime() > _ONE_MONTH_AGO: raise campaign.DoNotSend( 'User has already updated their employment status less than one month ago.' ) base_params = { 'user': user.user_id, 'token': parse.quote( auth_token.create_token(user.user_id, role='employment-status')), } return campaign.get_default_vars(user) | { 'registeredSince': registered_since, 'seekingUrl': campaign.get_bob_link( '/api/employment-status', base_params | { 'seeking': user_pb2.SeekingStatus.Name(user_pb2.STILL_SEEKING), 'redirect': campaign.get_bob_link('/statut/en-recherche'), }), 'stopSeekingUrl': campaign.get_bob_link( '/api/employment-status', base_params | { 'seeking': user_pb2.SeekingStatus.Name(user_pb2.STOP_SEEKING), 'redirect': campaign.get_bob_link('/statut/ne-recherche-plus'), }), }
def _get_ffs_vars( user: user_pb2.User, *, now: datetime.datetime, **unused_kwargs: Any, ) -> dict[str, str]: user_id = user.user_id days_since_registered = (now - user.registered_at.ToDatetime()).days if user.net_promoter_score_survey_response.score: raise campaign.DoNotSend('User already answered the NPS survey') is_alpha = user.features_enabled.alpha if (days_since_registered < 6 or days_since_registered > 13) and not is_alpha: raise campaign.DoNotSend( 'User registered too long ago or too recently') main_challenge_id = user.projects[ 0].diagnostic.category_id if user.projects else '' return campaign.get_default_vars(user) | { 'buttonBackgroundColor': '#58bbfb', 'buttonTextColor': '#ffffff', 'ffsFormUrl': campaign.get_bob_link( '/api/first-followup-survey', { 'user': user_id, 'token': auth_token.create_token(user_id, 'first-followup-survey'), 'redirect': campaign.get_bob_link( '/first-followup-survey', { 'hl': user.profile.locale, 'gender': user_profile_pb2.Gender.Name( user.profile.gender), 'mainChallenge': main_challenge_id, }), }), }
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))
def _get_first_eval_vars(user: user_pb2.User, **unused_kwargs: Any) -> dict[str, Any]: if not _is_bob_jobflix_user(user): raise campaign.DoNotSend('Only interesting for Bob-Jobflix users.') return campaign.get_default_vars(user)
def _get_vars(user: user_pb2.User, *, now: datetime.datetime, database: mongo.NoPiiMongoDatabase, **unused_kwargs: Any) -> dict[str, str]: if not user.projects or not user.projects[0].actions: raise campaign.DoNotSend('User has no project or no actions yet') project = user.projects[0] most_recent_date = max(d.ToDatetime() for d in (user.registered_at, project.created_at, project.action_plan_started_at)) if (now - most_recent_date).days > 7: raise campaign.DoNotSend( 'User has registered a while ago, too late to send the activation') # Set locale. user_locale = user.profile.locale.split('@', 1)[0] date_format = '%d %B %Y' if user_locale == 'fr' or not user_locale: locale.setlocale(locale.LC_ALL, 'fr_FR.UTF-8') elif user_locale == 'en_UK': locale.setlocale(locale.LC_ALL, 'en_GB.UTF-8') date_format = '%B %d %Y' elif user_locale == 'en': locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') date_format = '%B %d %Y' else: logging.exception('Sending an email with an unknown locale: %s', user_locale) scoring_project = scoring.ScoringProject(project, user, database, now=now) auth_token = parse.quote( token.create_token(user.user_id, is_using_timestamp=True)) settings_token = parse.quote( token.create_token(user.user_id, role='settings')) coaching_email_frequency_name = \ email_pb2.EmailFrequency.Name(user.profile.coaching_email_frequency) # This uses tutoiement by default, because its content adressed from the user to a third party # (that we assume the user is familiar enough with), not from Bob to the user. virality_template = parse.urlencode({ 'body': scoring_project.translate_static_string( 'Salut,\n\n' "Est-ce que tu connais Bob\u00A0? C'est un site qui propose de t'aider dans ta " "recherche d'emploi en te proposant un diagnostic et des conseils personnalisés. " 'Tu verras, ça vaut le coup\u00A0: en 15 minutes, tu en sauras plus sur où tu en es, ' 'et ce que tu peux faire pour avancer plus efficacement. ' "Et en plus, c'est gratuit\u00A0!\n\n" '{invite_url}\n\n' 'En tous cas, bon courage pour la suite,\n\n' '{first_name}', ).format(invite_url=parse.urljoin( product.bob.base_url, 'invite#vm2m'), first_name=user.profile.name), 'subject': scoring_project.translate_static_string("Ça m'a fait penser à toi"), }) change_email_settings_url = parse.urljoin( product.bob.base_url, 'unsubscribe.html?' + parse.urlencode({ 'user': user.user_id, 'auth': settings_token, 'coachingEmailFrequency': coaching_email_frequency_name, 'hl': user.profile.locale, })) team_members = ( 'Tabitha', 'Paul', 'John', 'Pascal', 'Sil', 'Cyrille', 'Flo', 'Nicolas', 'Florian', 'Lillie', 'Benjamin', 'Émilie', ) # Selected and pending actions. highlighted_actions = [ action for action in project.actions if action.status == action_pb2.ACTION_CURRENT ] if len(highlighted_actions) < 2: highlighted_actions.extend( action for action in project.actions if action.status == action_pb2.ACTION_UNREAD) else: highlighted_actions = sorted( highlighted_actions, key=lambda action: action.expected_completion_at.ToDatetime()) actions = [{ 'title': action.title, 'url': parse.urljoin( product.bob.base_url, f'/projet/{project.project_id}/action/{action.action_id}' f'?userId={user.user_id}&authToken={auth_token}') } for action in highlighted_actions[:2]] data: dict[str, Any] = campaign.get_default_vars(user) data |= { 'actions': actions, 'changeEmailSettingsUrl': change_email_settings_url, 'coachingEmailFrequency': email_pb2.EmailFrequency.Name(user.profile.coaching_email_frequency) if user.profile.coaching_email_frequency and user.profile.coaching_email_frequency != email_pb2.EMAIL_NONE else '', 'date': now.strftime(date_format), 'firstTeamMember': team_members[0], 'isActionPlanCompleted': project.HasField('action_plan_started_at'), 'isCoachingEnabled': 'True' if user.profile.coaching_email_frequency and user.profile.coaching_email_frequency != email_pb2.EMAIL_NONE else '', 'loginUrl': parse.urljoin(product.bob.base_url, f'?userId={user.user_id}&authToken={auth_token}'), 'numActions': len(actions), 'numberUsers': '270\u00A0000', 'numberTeamMembers': len(team_members), 'ofJob': scoring_project.populate_template('%ofJobName', raise_on_missing_var=True) if project.target_job.name else '', 'teamMembers': ', '.join(team_members[1:]), 'viralityTemplate': f'mailto:?{virality_template}' } return data