def new_diagnostic_vars(user: user_pb2.User, **unused_kwargs: Any) -> Dict[str, str]: """Compute vars for the "New Diagnostic".""" frustrations_set = set(user.profile.frustrations) frustrations_vars = { f'frustration_{name}': campaign.as_template_boolean(key in frustrations_set) for name, key in user_pb2.Frustration.items() } age = datetime.date.today().year - user.profile.year_of_birth has_children = user.profile.family_situation in { user_pb2.FAMILY_WITH_KIDS, user_pb2.SINGLE_PARENT_SITUATION, } survey_token = parse.quote( auth.create_token(user.user_id, role='employment-status')) auth_token = parse.quote( auth.create_token(user.user_id, is_using_timestamp=True)) redirect_url = f'{campaign.BASE_URL}/statut/ne-recherche-plus' return dict( dict(frustrations_vars, **campaign.get_default_vars(user)), **{ 'mayHaveSeekingChildren': campaign.as_template_boolean(has_children and age >= 45), 'loginUrl': f'{campaign.BASE_URL}?userId={user.user_id}&authToken={auth_token}', 'stopSeekingUrl': f'{campaign.BASE_URL}/api/employment-status?user={user.user_id}&token={survey_token}&' f'seeking=STOP_SEEKING&redirect={parse.quote(redirect_url)}', })
def _get_improve_cv_vars( user: user_pb2.User, now: datetime.datetime, **unused_kwargs: Any) -> Optional[Dict[str, Any]]: """Compute vars for the "Improve your CV" email.""" if user_pb2.RESUME not in user.profile.frustrations: logging.info('User is not frustrated by its CV') return None 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') auth_token = parse.quote(auth.create_token(user.user_id, is_using_timestamp=True)) return dict(campaign.get_default_coaching_email_vars(user), **{ 'deepLinkAdviceUrl': deep_link_advice_url, 'hasExperience': has_experience, 'isSeptember': campaign.as_template_boolean(now.month == 9), 'loginUrl': f'{campaign.BASE_URL}?userId={user.user_id}&authToken={auth_token}', })
def _get_vars(user: user_pb2.User, **unused_kwargs: Any) -> Optional[Dict[str, str]]: """Compute vars for one user's email.""" project = next((p for p in user.projects), project_pb2.Project()) area_type = project.area_type is_local = False if not area_type: return None city = project.city if area_type < geo_pb2.COUNTRY: if city.region_id != '93': return None if area_type < geo_pb2.REGION: if city.departement_id != '13': return None if area_type < geo_pb2.DEPARTEMENT: if city.city_id != '13004': return None is_local = True return dict( campaign.get_default_vars(user), **{ 'improveInterviewAdviceUrl': campaign.get_deep_link_advice(user.user_id, project, 'improve-interview'), 'isLocal': campaign.as_template_boolean(is_local), })
def _get_prepare_your_application_vars( user: user_pb2.User, **unused_kwargs: Any) -> Optional[Dict[str, Any]]: """Compute vars for the "Prepare your application" email.""" project = user.projects[0] deep_link_motivation_email_url = \ campaign.get_deep_link_advice(user.user_id, project, 'motivation-email') return dict(campaign.get_default_coaching_email_vars(user), **{ 'deepLinkMotivationEmailUrl': deep_link_motivation_email_url, 'hasInterviewFrustration': campaign.as_template_boolean(user_pb2.INTERVIEW in user.profile.frustrations), 'hasSelfConfidenceFrustration': campaign.as_template_boolean(user_pb2.SELF_CONFIDENCE in user.profile.frustrations), 'loginUrl': campaign.create_logged_url(user.user_id, f'/projet/{project.project_id}'), })
def _make_months_section(months): active_months = [ _FRENCH_MONTHS[month] for month in months if month in _FRENCH_MONTHS ] if not active_months: return None return { 'activeMonths': ' - '.join(active_months), 'onlyOneMonth': campaign.as_template_boolean(len(active_months) == 1), }
def _make_months_section( months: Iterable['job_pb2.Month']) -> Optional[Dict[str, str]]: active_months = [ _FRENCH_MONTHS[month] for month in months if month in _FRENCH_MONTHS ] if not active_months: return None return { 'activeMonths': ' - '.join(active_months), 'onlyOneMonth': campaign.as_template_boolean(len(active_months) == 1), }
def body_language_vars(user, unused_db=None): """Compute vars for a given user for the body language email. Returns: a dict with all vars required for the template, or None if no email should be sent. """ if not user.projects: logging.info('User has no project') return None registered_months_ago = campaign.get_french_months_ago( user.registered_at.ToDatetime()) if not registered_months_ago: logging.info('User registered only recently (%s)', user.registered_at) return None has_read_last_focus_email = any(email.status in _READ_EMAIL_STATUSES for email in user.emails_sent if email.campaign_id.startswith('focus-')) worst_frustration = next( (user_pb2.Frustration.Name(frustration) for frustration in (user_pb2.SELF_CONFIDENCE, user_pb2.INTERVIEW, user_pb2.ATYPIC_PROFILE) if frustration in user.profile.frustrations), '') if not worst_frustration: return None unsubscribe_token = parse.quote( auth.create_token(user.profile.email, role='unsubscribe')) return { 'firstName': french.cleanup_firstname(user.profile.name), 'gender': user_pb2.Gender.Name(user.profile.gender), 'hasReadLastFocusEmail': campaign.as_template_boolean(has_read_last_focus_email), 'registeredMonthsAgo': registered_months_ago, 'unsubscribeLink': '{}/unsubscribe.html?email={}&auth={}'.format( campaign.BASE_URL, parse.quote(user.profile.email), unsubscribe_token), 'worstFrustration': worst_frustration, }
def _get_galita2_vars(user: user_pb2.User, **unused_kwargs: Any) -> Optional[Dict[str, str]]: if not user.projects: return None project = user.projects[0] if project.kind not in {project_pb2.FIND_A_FIRST_JOB, project_pb2.REORIENTATION} and \ project.previous_job_similarity != project_pb2.NEVER_DONE: return None genderized_job_name = french.lower_first_letter( french.genderize_job(project.target_job, user.profile.gender)) return dict( campaign.get_default_coaching_email_vars(user), **{ 'isReorienting': campaign.as_template_boolean( project.kind == project_pb2.REORIENTATION), 'ofJobName': french.maybe_contract_prefix('de ', "d'", genderized_job_name) })
def new_diagnostic_vars(user, unused_db=None): """Compute vars for the "New Diagnostic".""" unsubscribe_token = parse.quote( auth.create_token(user.profile.email, role='unsubscribe')) frustrations_vars = { 'frustration_{}'.format(user_pb2.Frustration.Name(f)): 'True' for f in user.profile.frustrations } age = datetime.date.today().year - user.profile.year_of_birth has_children = user.profile.family_situation in { user_pb2.FAMILY_WITH_KIDS, user_pb2.SINGLE_PARENT_SITUATION, } survey_token = parse.quote( auth.create_token(user.user_id, role='employment-status')) auth_token = parse.quote( auth.create_token(user.user_id, is_using_timestamp=True)) return dict( frustrations_vars, **{ 'firstName': french.cleanup_firstname(user.profile.name), 'gender': user_pb2.Gender.Name(user.profile.gender), 'mayHaveSeekingChildren': campaign.as_template_boolean(has_children and age >= 45), 'loginUrl': '{}?userId={}&authToken={}'.format(campaign.BASE_URL, user.user_id, auth_token), 'stopSeekingUrl': '{}/api/employment-status?user={}&token={}&seeking={}&redirect={}'. format( campaign.BASE_URL, user.user_id, survey_token, 'STOP_SEEKING', parse.quote('{}/statut/ne-recherche-plus'.format( campaign.BASE_URL)), ), 'unsubscribeLink': '{}/unsubscribe.html?email={}&auth={}'.format( campaign.BASE_URL, parse.quote(user.profile.email), unsubscribe_token), })
def _get_self_development_vars(user: user_pb2.User, now: datetime.datetime, **unused_kwargs: Any) \ -> Optional[Dict[str, str]]: """Compute vars for a given user for the self-development email. Returns: a dict with all vars required for the template, or None if no email should be sent. """ project = user.projects[0] job_search_length = campaign.job_search_started_months_ago(project, now) if job_search_length < 0: logging.info('No info on user search duration') return None if job_search_length > 12: logging.info('User has been searching for too long (%s)', job_search_length) return None genderized_job_name = french.lower_first_letter( french.genderize_job(project.target_job, user.profile.gender)) age = datetime.date.today().year - user.profile.year_of_birth max_young = 30 min_old = 50 return dict( campaign.get_default_coaching_email_vars(user), **{ 'hasEnoughExperience': campaign.as_template_boolean( project.seniority > project_pb2.JUNIOR), 'isAdministrativeAssistant': campaign.as_template_boolean( project.target_job.job_group.name == 'Secrétariat'), 'isOld': campaign.as_template_boolean(age >= min_old), 'isOldNotWoman': campaign.as_template_boolean( age >= min_old and user.profile.gender != user_pb2.FEMININE), 'isYoung': campaign.as_template_boolean(age <= max_young), 'isYoungNotWoman': campaign.as_template_boolean( age <= max_young and user.profile.gender != user_pb2.FEMININE), 'jobName': genderized_job_name, 'ofJobName': french.maybe_contract_prefix('de ', "d'", genderized_job_name), })
def _make_departements_section(user_departement_id, best_departements, area_type, database): if area_type < geo_pb2.COUNTRY or not best_departements: return None best_departements_title = '<br />'.join( geo.get_departement_name(database, dep) for dep in best_departements) try: best_departements.remove(user_departement_id) is_best_departement = True except ValueError: is_best_departement = False best_departements_sentence = ' et '.join( geo.get_in_a_departement_text(database, dep) for dep in best_departements) return { 'count': str(len(best_departements)), 'isInBest': campaign.as_template_boolean(is_best_departement), 'title': best_departements_title, 'sentence': best_departements_sentence, }
def _get_vars(user, unused_database): """Compute vars for one user's email.""" project = next((p for p in user.projects), project_pb2.Project()) is_local = False if not project.mobility.area_type: return if project.mobility.area_type < geo_pb2.COUNTRY: if project.mobility.city.region_id != '93': return if project.mobility.area_type < geo_pb2.REGION: if project.mobility.city.departement_id != '13': return if project.mobility.area_type < geo_pb2.DEPARTEMENT: if project.mobility.city.city_id != '13004': return is_local = True return dict(campaign.get_default_vars(user), **{ 'isLocal': campaign.as_template_boolean(is_local), })
def _open_classrooms_vars(user: user_pb2.User, database: Optional[pymongo.database.Database] = None, **unused_kwargs: Any) -> Optional[Dict[str, str]]: """Template variables for viral sharing emails.""" if user.registered_at.ToDatetime() < _SIX_MONTHS_AGO: return None age = datetime.date.today().year - user.profile.year_of_birth if age < 18 or age > 54: return None if user.profile.highest_degree > job_pb2.BAC_BACPRO: return None if user.employment_status and user.employment_status[ -1].seeking != user_pb2.STILL_SEEKING: return None # User has not project. if not (user.projects and user.projects[0]): return None # If the user is happy with their job (no reorientation and enthusiastic about their job) project = user.projects[0] if project.kind != project_pb2.REORIENTATION and not ( project.kind == project_pb2.FIND_A_NEW_JOB and project.passionate_level == project_pb2.ALIMENTARY_JOB): return None has_children = user.profile.family_situation in { user_pb2.FAMILY_WITH_KIDS, user_pb2.SINGLE_PARENT_SITUATION, } assert database job_group_info = jobs.get_group_proto(database, project.target_job.job_group.rome_id) if not job_group_info: return None return dict( campaign.get_default_coaching_email_vars(user), **{ 'hasAtypicProfile': campaign.as_template_boolean( user_pb2.ATYPIC_PROFILE in user.profile.frustrations), 'hasFamilyAndManagementIssue': campaign.as_template_boolean( has_children and user_pb2.TIME_MANAGEMENT in user.profile.frustrations), 'hasSeniority': campaign.as_template_boolean( project.seniority > project_pb2.INTERMEDIARY), 'hasSimpleApplication': campaign.as_template_boolean( job_group_info.application_complexity == job_pb2.SIMPLE_APPLICATION_PROCESS), 'isReorienting': campaign.as_template_boolean( project.kind == project_pb2.REORIENTATION), 'isFrustratedOld': campaign.as_template_boolean( age >= 40 and user_pb2.AGE_DISCRIMINATION in user.profile.frustrations), 'ofFirstName': french.maybe_contract_prefix('de ', "d'", user.profile.name) })
def self_development_vars(user, unused_db=None): """Compute vars for a given user for the self-development email. Returns: a dict with all vars required for the template, or None if no email should be sent. """ if not user.projects: logging.info('User has no project') return None project = user.projects[0] registered_months_ago = campaign.get_french_months_ago( user.registered_at.ToDatetime()) if not registered_months_ago: logging.info('User registered only recently (%s)', user.registered_at) return None job_search_length = campaign.job_search_started_months_ago(project) if job_search_length < 0: logging.info('No info on user search duration') return None if job_search_length >= 12: logging.info('User has been searching for too long (%s)', job_search_length) return None genderized_job_name = french.lower_first_letter( french.genderize_job(project.target_job, user.profile.gender)) age = datetime.date.today().year - user.profile.year_of_birth unsubscribe_token = parse.quote( auth.create_token(user.profile.email, role='unsubscribe')) max_young = 30 min_old = 50 return { 'firstName': french.cleanup_firstname(user.profile.name), 'gender': user_pb2.Gender.Name(user.profile.gender), 'hasEnoughExperience': campaign.as_template_boolean(project.seniority > project_pb2.JUNIOR), 'isAdministrativeAssistant': campaign.as_template_boolean( project.target_job.job_group.name == 'Secrétariat'), 'isOld': campaign.as_template_boolean(age >= min_old), 'isOldNotWoman': campaign.as_template_boolean( age >= min_old and user.profile.gender != user_pb2.FEMININE), 'isYoung': campaign.as_template_boolean(age <= max_young), 'isYoungNotWoman': campaign.as_template_boolean( age <= max_young and user.profile.gender != user_pb2.FEMININE), 'jobName': genderized_job_name, 'ofJobName': french.maybe_contract_prefix('de ', "d'", genderized_job_name), 'registeredMonthsAgo': registered_months_ago, 'unsubscribeLink': '{}/unsubscribe.html?email={}&auth={}'.format( campaign.BASE_URL, parse.quote(user.profile.email), unsubscribe_token), }
def imt_vars(user, database): """Compute vars for the "IMT" email.""" if not user.projects: logging.info('User has no project') return None project = user.projects[0] genderized_job_name = french.lower_first_letter( french.genderize_job(project.target_job, user.profile.gender)) departement_id = project.mobility.city.departement_id rome_id = project.target_job.job_group.rome_id diagnosis_key = '{}:{}'.format(departement_id, rome_id) local_diagnosis = _LOCAL_DIAGNOSIS.get_collection(database).get( diagnosis_key) if not local_diagnosis: logging.info('User market does not exist') return None imt = local_diagnosis.imt if not imt: logging.info('User market has no IMT data') return None shown_sections = 0 market_stress_section = _make_market_stress_section( imt.yearly_avg_offers_per_10_candidates) if market_stress_section: shown_sections += 1 application_modes_section = _make_application_mode_section( campaign.get_application_modes(rome_id, database), project.advices, user.user_id) if application_modes_section: shown_sections += 1 departements_section = _make_departements_section( project.mobility.city.departement_id, _get_best_departements_for_job_group(rome_id, database), project.mobility.area_type, database) if departements_section: shown_sections += 1 employment_types_section = _make_employment_type_section( sorted(imt.employment_type_percentages, key=lambda e: e.percentage)) if employment_types_section: shown_sections += 1 months_section = _make_months_section(imt.active_months) if months_section: shown_sections += 1 if shown_sections < 3: logging.info('Only %d section(s) to be shown for user.', shown_sections) return None imt_link = 'http://candidat.pole-emploi.fr/marche-du-travail/statistiques?' + \ 'codeMetier={}&codeZoneGeographique={}&typeZoneGeographique=DEPARTEMENT'.format( project.target_job.code_ogr, departement_id) job_name_in_departement = '{} {}'.format( genderized_job_name, geo.get_in_a_departement_text(database, project.mobility.city.departement_id)) return dict( campaign.get_default_vars(user), **{ 'applicationModes': _make_section(application_modes_section), 'departements': _make_section(departements_section), 'employmentType': _make_section(employment_types_section), 'imtLink': imt_link, 'inCity': french.in_city(project.mobility.city.name), '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': french.maybe_contract_prefix('de ', "d'", job_name_in_departement), 'ofJobName': french.maybe_contract_prefix('de ', "d'", genderized_job_name), 'showPs': campaign.as_template_boolean( _can_go_to_arles_hotellerie_event(rome_id, project.mobility)), 'statusUpdateUrl': campaign.get_status_update_link(user.user_id, user.profile), })
def _make_section(values): return dict({'showSection': campaign.as_template_boolean(values)}, **(values or {}))
def christmas_vars(user: user_pb2.User, now: datetime.datetime, database: Optional[pymongo.database.Database] = None, **unused_kwargs: Any) -> Optional[Dict[str, str]]: """Compute all variables required for the Christmas campaign.""" project = next((p for p in user.projects), project_pb2.Project()) job_search_started_months_ago = campaign.job_search_started_months_ago( project, now) if job_search_started_months_ago < 0: started_searching_since = '' elif job_search_started_months_ago < 2: started_searching_since = 'depuis peu' else: try: num_months = french.try_stringify_number( round(job_search_started_months_ago)) started_searching_since = f'depuis {num_months} mois' except NotImplementedError: started_searching_since = 'depuis un moment' # A city to commute to. commute_city = next( (city for a in project.advices for city in a.commute_data.cities), '') if commute_city: commute_city = french.in_city(commute_city) commute_advice_url = campaign.get_deep_link_advice(user.user_id, project, 'commute') if not commute_advice_url: commute_city = '' # A departement to relocate to. relocate_departement = next( (departement.name for a in project.advices for departement in a.relocate_data.departement_scores), '') assert database if relocate_departement: try: departement_id = geo.get_departement_id(database, relocate_departement) relocate_departement = geo.get_in_a_departement_text( database, departement_id) except KeyError: relocate_departement = '' relocate_advice_url = campaign.get_deep_link_advice( user.user_id, project, 'relocate') if not relocate_advice_url: relocate_departement = '' # Whether the job may have freelancers. job_group_info = jobs.get_group_proto(database, project.target_job.job_group.rome_id) could_freelance = job_group_info and job_group_info.has_freelancers return dict( campaign.get_default_vars(user), **{ 'adviceUrlBodyLanguage': campaign.get_deep_link_advice(user.user_id, project, 'body-language'), 'adviceUrlCommute': commute_advice_url, 'adviceUrlCreateYourCompany': campaign.get_deep_link_advice(user.user_id, project, 'create-your-company'), 'adviceUrlImproveInterview': campaign.get_deep_link_advice(user.user_id, project, 'improve-interview'), 'adviceUrlRelocate': relocate_advice_url, 'couldFreelance': campaign.as_template_boolean(could_freelance), 'emailInUrl': parse.quote(user.profile.email), 'inCommuteCity': commute_city, 'inRelocateDepartement': relocate_departement, 'startedSearchingSince': started_searching_since, })
def spontaneous_vars(user, previous_email_campaign_id): """Compute vars for a given user for the spontaneous email. Returns: a dict with all vars required for the template, or None if no email should be sent. """ if not user.projects: logging.info('User has no project') return None project = user.projects[0] job_group_info = jobs.get_group_proto(_DB, project.target_job.job_group.rome_id) def _should_use_spontaneous(modes): return any(mode.mode == job_pb2.SPONTANEOUS_APPLICATION and mode.percentage > 20 for mode in modes.modes) application_modes = job_group_info.application_modes if not any( _should_use_spontaneous(modes) for modes in application_modes.values()): return None registered_months_ago = campaign.get_french_months_ago( user.registered_at.ToDatetime()) if not registered_months_ago: logging.warning('User registered only recently (%s)', user.registered_at) return None has_read_previous_email = previous_email_campaign_id and any( email.campaign_id == previous_email_campaign_id and email.status in (user_pb2.EMAIL_SENT_OPENED, user_pb2.EMAIL_SENT_CLICKED) for email in user.emails_sent) contact_mode = job_group_info.preferred_application_medium if not contact_mode: logging.error('There is no contact mode for the job group "%s"', project.target_job.job_group.rome_id) return None contact_mode = job_pb2.ApplicationMedium.Name(contact_mode).replace( 'APPLY_', '') in_a_workplace = job_group_info.in_a_workplace if not in_a_workplace and contact_mode != 'BY_EMAIL': logging.error( 'There is no "in_a_workplace" field for the job group "%s".', project.target_job.job_group.rome_id) return None like_your_workplace = job_group_info.like_your_workplace if in_a_workplace and not like_your_workplace: logging.error( 'There is no "like_your_workplace" field for the job group "%s".', project.target_job.job_group.rome_id) return None to_the_workplace = job_group_info.to_the_workplace if not to_the_workplace: to_the_workplace = "à l'entreprise" some_companies = job_group_info.place_plural if not some_companies: some_companies = 'des entreprises' what_i_love_about = job_group_info.what_i_love_about if user.profile.gender == user_pb2.FEMININE: what_i_love_about_feminine = job_group_info.what_i_love_about_feminine if what_i_love_about_feminine: what_i_love_about = what_i_love_about_feminine if not what_i_love_about and contact_mode == 'BY_EMAIL': logging.error( 'There is no "What I love about" field for the job group "%s".', project.target_job.job_group.rome_id) return None why_specific_company = job_group_info.why_specific_company if not why_specific_company: logging.error( 'There is no "Why this specific company" field for the job group "%s".', project.target_job.job_group.rome_id) return None at_various_companies = job_group_info.at_various_companies if project.weekly_applications_estimate == project_pb2.SOME: weekly_application_count = '5' elif project.weekly_applications_estimate > project_pb2.SOME: weekly_application_count = '15' else: weekly_application_count = '' survey_token = parse.quote( auth.create_token(user.user_id, role='employment-status')) unsubscribe_token = parse.quote( auth.create_token(user.profile.email, role='unsubscribe')) return { 'applicationComplexity': job_pb2.ApplicationProcessComplexity.Name( job_group_info.application_complexity), 'atVariousCompanies': at_various_companies, 'contactMode': contact_mode, 'deepLinkLBB': 'https://labonneboite.pole-emploi.fr/entreprises/commune/{}/rome/' '{}?utm_medium=web&utm_source=bob&utm_campaign=bob-email'.format( project.mobility.city.city_id, project.target_job.job_group.rome_id), 'emailInUrl': parse.quote(user.profile.email), 'experienceAsText': _EXPERIENCE_AS_TEXT.get(project.seniority, 'peu'), 'firstName': french.cleanup_firstname(user.profile.name), 'gender': user_pb2.Gender.Name(user.profile.gender), 'hasReadPreviousEmail': campaign.as_template_boolean(has_read_previous_email), 'inWorkPlace': in_a_workplace, 'jobName': french.lower_first_letter( french.genderize_job(project.target_job, user.profile.gender)), 'lastName': user.profile.last_name, 'likeYourWorkplace': like_your_workplace, 'registeredMonthsAgo': registered_months_ago, 'someCompanies': some_companies, # TODO(cyrille): Use campaign.get_status_update_link 'statusUpdateUrl': '{}/statut/mise-a-jour?user={}&token={}&gender={}'.format( campaign.BASE_URL, user.user_id, survey_token, user_pb2.Gender.Name(user.profile.gender)), 'toTheWorkplace': to_the_workplace, 'unsubscribeLink': '{}/unsubscribe.html?email={}&auth={}'.format( campaign.BASE_URL, parse.quote(user.profile.email), unsubscribe_token), 'weeklyApplicationOptions': weekly_application_count, 'whatILoveAbout': what_i_love_about, 'whySpecificCompany': why_specific_company, }
def network_plus_vars(user, database): """Compute vars for a given user for the network email. Returns: a dict with all vars required for the template, or None if no email should be sent. """ if not user.projects: logging.info('User has no project') return None project = user.projects[0] registered_months_ago = campaign.get_french_months_ago( user.registered_at.ToDatetime()) if not registered_months_ago: logging.warning('User registered only recently (%s)', user.registered_at) return None job_group_info = jobs.get_group_proto(database, project.target_job.job_group.rome_id) in_target_domain = job_group_info.in_domain application_modes = job_group_info.application_modes.values() if not in_target_domain: logging.warning('Could not find a target domain (%s)', project.target_job.job_group) return None fap_modes = [ fap_modes.modes for fap_modes in application_modes if len(fap_modes.modes) ] if not fap_modes: return None flat_fap_modes = [mode for modes in fap_modes for mode in modes] network_percentages = [ mode.percentage for mode in flat_fap_modes if (mode.mode == job_pb2.PERSONAL_OR_PROFESSIONAL_CONTACTS) ] # We want to focus on the user for which network, # as an application mode, has a substantial importance. if not network_percentages: return None average_network_percentage = sum(network_percentages) / len( network_percentages) if average_network_percentage < 55: network_application_importance = 'que la majorité' if average_network_percentage >= 45 and average_network_percentage <= 55: network_application_importance = 'que la moitié' if average_network_percentage >= 25 and average_network_percentage < 45: network_application_importance = "qu'un tiers" else: return None worst_frustration = next( (f for f in (user_pb2.SELF_CONFIDENCE, user_pb2.MOTIVATION) if f in user.profile.frustrations), None) has_children = user.profile.family_situation in { user_pb2.FAMILY_WITH_KIDS, user_pb2.SINGLE_PARENT_SITUATION } age = datetime.date.today().year - user.profile.year_of_birth max_young = 35 return dict( campaign.get_default_vars(user), **{ 'frustration': user_pb2.Frustration.Name(worst_frustration) if worst_frustration else '', 'hasChildren': campaign.as_template_boolean(has_children), 'hasHandicap': campaign.as_template_boolean(user.profile.has_handicap), 'hasHighSchoolDegree': campaign.as_template_boolean( user.profile.highest_degree >= job_pb2.BAC_BACPRO), 'hasLargeNetwork': campaign.as_template_boolean(project.network_estimate >= 2), 'hasWorkedBefore': campaign.as_template_boolean( project.kind != project_pb2.FIND_A_FIRST_JOB), 'inCity': french.in_city(project.mobility.city.name), 'inTargetDomain': in_target_domain, 'isYoung': campaign.as_template_boolean(age <= max_young), 'jobGroupInDepartement': '{} {}'.format( french.lower_first_letter(project.target_job.job_group.name), geo.get_in_a_departement_text( database, project.mobility.city.departement_id)), 'networkApplicationPercentage': network_application_importance, })
def _make_section(values: Optional[Dict[str, str]]) -> Dict[str, str]: return dict({'showSection': campaign.as_template_boolean(bool(values))}, **(values or {}))
def network_plus_vars(user: user_pb2.User, database: Optional[pymongo.database.Database] = None, **unused_kwargs: Any) -> Optional[Dict[str, str]]: """Compute vars for a given user for the network email. Returns: a dict with all vars required for the template, or None if no email should be sent. """ project = user.projects[0] if project.network_estimate < 2: logging.info('User does not have a strong network') return None assert database job_group_info = jobs.get_group_proto(database, project.target_job.job_group.rome_id) if not job_group_info: logging.warning('Could not find job group info for "%s"', project.target_job.job_group.rome_id) return None in_target_domain = job_group_info.in_domain application_modes = job_group_info.application_modes.values() if not in_target_domain: logging.warning('Could not find a target domain (%s)', project.target_job.job_group) return None fap_modes = [ fap_modes.modes for fap_modes in application_modes if len(fap_modes.modes) ] if not fap_modes: return None flat_fap_modes = [mode for modes in fap_modes for mode in modes] network_percentages = [ mode.percentage for mode in flat_fap_modes if (mode.mode == job_pb2.PERSONAL_OR_PROFESSIONAL_CONTACTS) ] # We want to focus on the user for which network, # as an application mode, has a substantial importance. if not network_percentages: return None average_network_percentage = sum(network_percentages) / len( network_percentages) if average_network_percentage > 55: network_application_importance = 'que la majorité' elif average_network_percentage >= 45: network_application_importance = 'que la moitié' elif average_network_percentage >= 25: network_application_importance = "qu'un tiers" else: return None worst_frustration = next( (f for f in (user_pb2.SELF_CONFIDENCE, user_pb2.MOTIVATION) if f in user.profile.frustrations), None) has_children = user.profile.family_situation in { user_pb2.FAMILY_WITH_KIDS, user_pb2.SINGLE_PARENT_SITUATION } age = datetime.date.today().year - user.profile.year_of_birth max_young = 35 try: in_departement = geo.get_in_a_departement_text( database, project.city.departement_id) except KeyError: logging.warning('Could not find departement (%s)', project.city.departement_id) return None job_group_name = french.lower_first_letter( project.target_job.job_group.name) return dict( campaign.get_default_coaching_email_vars(user), **{ 'frustration': user_pb2.Frustration.Name(worst_frustration) if worst_frustration else '', 'hasChildren': campaign.as_template_boolean(has_children), 'hasHighSchoolDegree': campaign.as_template_boolean( user.profile.highest_degree >= job_pb2.BAC_BACPRO), 'hasLargeNetwork': campaign.as_template_boolean(project.network_estimate >= 2), 'hasWorkedBefore': campaign.as_template_boolean( project.kind != project_pb2.FIND_A_FIRST_JOB), 'inCity': french.in_city(project.city.name), 'inTargetDomain': in_target_domain, 'isAbleBodied': campaign.as_template_boolean(not user.profile.has_handicap), 'isYoung': campaign.as_template_boolean(age <= max_young), 'jobGroupInDepartement': f'{job_group_name} {in_departement}', 'networkApplicationPercentage': network_application_importance, })