def test_application_with_known_email_are_saved_as_rejected( self, process_beneficiary_application, app): # given get_all_application_ids = Mock(return_value=[123]) find_applications_ids_to_retry = Mock(return_value=[]) get_details = Mock( return_value=make_old_application_detail(123, "closed")) user = User() user.email = "*****@*****.**" has_already_been_imported = Mock(return_value=False) has_already_been_created = Mock(return_value=True) # when old_remote_import.run( ONE_WEEK_AGO, get_all_applications_ids=get_all_application_ids, get_applications_ids_to_retry=find_applications_ids_to_retry, get_details=get_details, already_imported=has_already_been_imported, already_existing_user=has_already_been_created, ) # then beneficiary_import = BeneficiaryImport.query.first() assert beneficiary_import.currentStatus == ImportStatus.REJECTED assert beneficiary_import.applicationId == 123 assert beneficiary_import.detail == "Compte existant avec cet email" process_beneficiary_application.assert_not_called()
def activate_beneficiary( user: users_models.User, deposit_source: str = None, has_activated_account: Optional[bool] = True ) -> users_models.User: if not deposit_source: beneficiary_import = subscription_repository.get_beneficiary_import_for_beneficiary(user) if not beneficiary_import: raise exceptions.BeneficiaryImportMissingException() eligibility = beneficiary_import.eligibilityType deposit_source = beneficiary_import.get_detailed_source() else: eligibility = users_models.EligibilityType.AGE18 if eligibility == users_models.EligibilityType.UNDERAGE: user.add_underage_beneficiary_role() elif eligibility == users_models.EligibilityType.AGE18: user.add_beneficiary_role() else: raise users_exception.InvalidEligibilityTypeException() if "apps_flyer" in user.externalIds: apps_flyer_job.log_user_becomes_beneficiary_event_job.delay(user.id) deposit = payments_api.create_deposit(user, deposit_source=deposit_source, eligibility=eligibility) db.session.add_all((user, deposit)) db.session.commit() logger.info("Activated beneficiary and created deposit", extra={"user": user.id, "source": deposit_source}) db.session.refresh(user) update_external_user(user) _send_beneficiary_activation_email(user, has_activated_account) return user
def on_model_change(self, form: Form, model: User, is_created: bool) -> None: if is_created: model.password = random_password() model.publicName = f"{model.firstName} {model.lastName}" model.isBeneficiary = False model.isAdmin = False
def test_application_with_known_application_id_are_not_processed( self, process_beneficiary_application): # given get_all_application_ids = Mock(return_value=[123, 456]) find_applications_ids_to_retry = Mock(return_value=[]) get_details = Mock( return_value=make_old_application_detail(123, "closed")) user = User() user.email = "*****@*****.**" has_already_been_imported = Mock(return_value=True) has_already_been_created = Mock(return_value=False) # when old_remote_import.run( ONE_WEEK_AGO, get_all_applications_ids=get_all_application_ids, get_applications_ids_to_retry=find_applications_ids_to_retry, get_details=get_details, already_imported=has_already_been_imported, already_existing_user=has_already_been_created, ) # then process_beneficiary_application.assert_not_called()
def test_should_raise_multiple_errors_at_once(self): # given user = User() user.setPassword("weakpassword") new_password = "******" new_confirmation_password = "******" old_password = "******" # when with pytest.raises(ApiErrors) as api_errors: check_password_validity(new_password, new_confirmation_password, old_password, user) # then assert api_errors.value.errors["newPassword"] == [ "Ton mot de passe doit contenir au moins :\n" "- 12 caractères\n" "- Un chiffre\n" "- Une majuscule et une minuscule\n" "- Un caractère spécial", "Ton nouveau mot de passe est identique à l’ancien.", ] assert api_errors.value.errors["newConfirmationPassword"] == [ "Les deux mots de passe ne sont pas identiques." ]
def create_account( email: str, password: str, birthdate: date, has_allowed_recommendations: bool = False, is_email_validated: bool = False, send_activation_mail: bool = True, ) -> User: if find_user_by_email(email): raise exceptions.UserAlreadyExistsException() user = User( email=format_email(email), dateOfBirth=birthdate, isEmailValidated=is_email_validated, departementCode="007", publicName=" ", # Required because model validation requires 3+ chars hasSeenTutorials=False, firstName="", hasAllowedRecommendations=has_allowed_recommendations, ) user.setPassword(password) repository.save(user) if not is_email_validated and send_activation_mail: request_email_confirmation(user) return user
def create_account( email: str, password: str, birthdate: date, has_allowed_recommendations: bool = False, is_email_validated: bool = False, send_activation_mail: bool = True, ) -> User: if find_user_by_email(email): raise exceptions.UserAlreadyExistsException() user = User( email=format_email(email), dateOfBirth=datetime.combine(birthdate, datetime.min.time()), isEmailValidated=is_email_validated, departementCode="007", publicName=VOID_PUBLIC_NAME, # Required because model validation requires 3+ chars hasSeenTutorials=False, firstName=VOID_FIRST_NAME, hasAllowedRecommendations=has_allowed_recommendations, ) age = user.calculate_age() if not age or age < constants.ACCOUNT_CREATION_MINIMUM_AGE: raise exceptions.UnderAgeUserException() user.setPassword(password) repository.save(user) if not is_email_validated and send_activation_mail: request_email_confirmation(user) return user
def initialize_account( user: User, password: str, apps_flyer_user_id: str = None, apps_flyer_platform: str = None, send_activation_mail: bool = True, remote_updates: bool = True, ) -> User: user.setPassword(password) if apps_flyer_user_id and apps_flyer_platform: if user.externalIds is None: user.externalIds = {} user.externalIds["apps_flyer"] = {"user": apps_flyer_user_id, "platform": apps_flyer_platform.upper()} repository.save(user) logger.info("Created user account", extra={"user": user.id}) delete_all_users_tokens(user) if remote_updates: update_external_user(user) if not user.isEmailValidated and send_activation_mail: request_email_confirmation(user) return user
def fulfill_user_data(user: User, deposit_source: str) -> User: user.password = random_password() generate_reset_token(user, validity_duration_hours=THIRTY_DAYS_IN_HOURS) deposit = payment_api.create_deposit(user, deposit_source) user.deposits = [deposit] return user
def _set_offerer_departement_code(new_user: User, offerer: Offerer) -> User: if settings.IS_INTEGRATION: new_user.departementCode = "00" elif offerer.postalCode is not None: new_user.departementCode = PostalCode(offerer.postalCode).get_departement_code() else: new_user.departementCode = "XX" # We don't want to trigger an error on this: # we want the error on user return new_user
def test_a_partner_should_never_be_a_beneficiary(self, app, db_session): # given user = User() user.add_beneficiary_role() view = PartnerUserView(model=User, session=db_session) # when view.on_model_change(Form(), model=user, is_created=False) # then assert not user.has_beneficiary_role
def test_should_generate_a_random_password_on_creation(self, app, db_session): # given user = User() user.password = None view = PartnerUserView(model=User, session=db_session) # when view.on_model_change(Form(), model=user, is_created=True) # then assert user.password is not None
def test_should_preserve_password_on_edition(self, app, db_session): # given user = User() user.password = "******" view = PartnerUserView(model=User, session=db_session) # when view.on_model_change(Form(), model=user, is_created=False) # then assert user.password == "OriginalPassword"
def unsuspend_account(user: User, actor: User) -> None: user.isActive = True user.suspensionReason = "" repository.save(user) logger.info( "Account has been unsuspended", extra={ "actor": actor.id, "user": user.id, }, )
def update_cultural_survey(user: User, body: serializers.CulturalSurveyRequest) -> None: with transaction(): if not body.needs_to_fill_cultural_survey: user.needsToFillCulturalSurvey = False if body.cultural_survey_id: logger.info("User %s updated cultural survey", user.id, extra={"actor": user.id}) user.culturalSurveyId = body.cultural_survey_id user.culturalSurveyFilledDate = datetime.now() return
def suspend_account(user: User, reason: constants.SuspensionReason, actor: User) -> None: user.isActive = False user.suspensionReason = str(reason) # If we ever unsuspend the account, we'll have to explictly enable # isAdmin again. An admin now may not be an admin later. user.isAdmin = False user.setPassword(secrets.token_urlsafe(30)) repository.save(user) sessions = UserSession.query.filter_by(userId=user.id) repository.delete(*sessions) logger.info("user=%s has been suspended by actor=%s for reason=%s", user.id, actor.id, reason)
def test_should_create_the_public_name(self, app, db_session): # Given user = User() user.firstName = "Ken" user.lastName = "Thompson" user.publicName = None view = ProUserView(model=User, session=db_session) # When view.on_model_change(Form(), model=user, is_created=False) # Then assert user.publicName == "Ken Thompson"
def test_does_not_raise_error_when_user_is_authenticated(self): # Given user = User() user.is_authenticated = True email = "*****@*****.**" # When try: check_user_is_logged_in_or_email_is_provided(user, email) # Then except ApiErrors: assert False
def test_check_user_can_validate_v2_bookings_raise_api_error_when_user_is_authenticated_but_does_not_have_editor_rights_on_booking( self, app): # Given user = User() user.is_authenticated = True # When with pytest.raises(ApiErrors) as errors: check_user_can_validate_bookings_v2(user, None) # Then assert errors.value.errors["user"] == [ "Vous n'avez pas les droits suffisants pour valider cette contremarque." ]
def test_check_user_can_validate_bookings_raise_api_error_when_user_is_authenticated_and_does_not_have_editor_rights_on_booking( self, app): # Given user = User() user.is_authenticated = True # When with pytest.raises(ApiErrors) as errors: check_user_can_validate_bookings(user, None) # Then assert errors.value.errors["global"] == [ "Cette contremarque n'a pas été trouvée" ]
def on_model_change(self, form: Form, model: User, is_created: bool) -> None: model.publicName = f"{model.firstName} {model.lastName}" if is_created: model.isBeneficiary = False model.password = random_password() generate_reset_token(model, 24 * 14) offerer = create_offerer(form) create_digital_venue(offerer) user_offerer = create_user_offerer(user=model, offerer=offerer) model.userOfferers = [user_offerer] super().on_model_change(form, model, is_created)
def test_check_user_can_validate_v2_bookings_raise_api_error_when_user_is_authenticated_but_does_not_have_editor_rights_on_booking( self, app): # Given user = User() user.is_authenticated = True # When with pytest.raises(ApiErrors) as errors: check_user_can_validate_bookings_v2(user, None) # Then assert errors.value.errors["user"] == [ "Vous n’avez pas les droits suffisants pour valider cette contremarque car cette réservation n'a pas été faite sur une de vos offres, ou que votre rattachement à la structure est encore en cours de validation" ]
def update_cultural_survey(user: User, body: serializers.CulturalSurveyRequest) -> None: with transaction(): if not body.needs_to_fill_cultural_survey: user.needsToFillCulturalSurvey = False if body.cultural_survey_id: if user.culturalSurveyId: raise ApiErrors({ "culturalSurveyId": "L'utilisateur a déjà rempli le formulaire" }) user.culturalSurveyId = body.cultural_survey_id user.culturalSurveyFilledDate = datetime.now() return
def get_user_attributes(user: User) -> UserAttributes: from pcapi.core.users.api import get_domains_credit is_pro_user = user.has_pro_role or db.session.query( UserOfferer.query.filter_by(userId=user.id).exists()).scalar() user_bookings: List[Booking] = _get_user_bookings( user) if not is_pro_user else [] last_favorite = (Favorite.query.filter_by(userId=user.id).order_by( Favorite.id.desc()).first() if not is_pro_user else None) domains_credit = get_domains_credit( user, user_bookings) if not is_pro_user else None booking_categories, booking_subcategories = _get_bookings_categories_and_subcategories( user_bookings) return UserAttributes( booking_categories=booking_categories, booking_count=len(user_bookings), booking_subcategories=booking_subcategories, date_created=user.dateCreated, date_of_birth=user.dateOfBirth, departement_code=user.departementCode, deposit_activation_date=user.deposit_activation_date, deposit_expiration_date=user.deposit_expiration_date, domains_credit=domains_credit, eligibility=user.eligibility, first_name=user.firstName, has_completed_id_check=user.hasCompletedIdCheck, user_id=user.id, is_beneficiary=user.has_beneficiary_role, is_eligible=user.is_eligible, is_email_validated=user.isEmailValidated, is_pro=is_pro_user, last_booking_date=user_bookings[0].dateCreated if user_bookings else None, last_favorite_creation_date=last_favorite.dateCreated if last_favorite else None, last_name=user.lastName, last_visit_date=user.lastConnectionDate, marketing_email_subscription=user.get_notification_subscriptions( ).marketing_email, marketing_push_subscription=user.get_notification_subscriptions(). marketing_push, postal_code=user.postalCode, products_use_date={ f"product_{TRACKED_PRODUCT_IDS[booking.stock.offer.productId]}_use": booking.dateUsed for booking in user_bookings if booking.dateUsed and booking.stock.offer.productId in TRACKED_PRODUCT_IDS }, )
def test_raises_an_error_when_no_email_nor_user_logged(self): # Given user = User() user.is_authenticated = False email = None # When with pytest.raises(ApiErrors) as excinfo: check_user_is_logged_in_or_email_is_provided(user, email) # Then assert excinfo.value.errors["email"] == [ "Vous devez préciser l'email de l'utilisateur quand vous n'êtes pas connecté(e)" ]
def create_pro_user(pro_user: ProUserCreationBodyModel) -> User: objects_to_save = [] new_pro_user = User(from_dict=pro_user.dict(by_alias=True)) new_pro_user.hasAllowedRecommendations = pro_user.contact_ok existing_offerer = Offerer.query.filter_by(siren=pro_user.siren).first() if existing_offerer: user_offerer = _generate_user_offerer_when_existing_offerer(new_pro_user, existing_offerer) offerer = existing_offerer else: offerer = _generate_offerer(pro_user.dict(by_alias=True)) user_offerer = offerer.grant_access(new_pro_user) digital_venue = create_digital_venue(offerer) objects_to_save.extend([digital_venue, offerer]) objects_to_save.append(user_offerer) new_pro_user.isBeneficiary = False new_pro_user.isAdmin = False new_pro_user.needsToFillCulturalSurvey = False new_pro_user = _set_offerer_departement_code(new_pro_user, offerer) new_pro_user.generate_validation_token() objects_to_save.append(new_pro_user) repository.save(*objects_to_save) try: user_emails.send_user_validation_email(new_pro_user) except MailServiceException: logger.exception("Could not send validation email when creating pro user=%s", new_pro_user.id) return new_pro_user
def fill_user_from(csv_row: list[str], user: User) -> User: user.lastName = csv_row[USER_LAST_NAME_COLUMN_INDEX] user.firstName = csv_row[USER_FIRST_NAME_COLUMN_INDEX].split(" ")[0] user.publicName = "%s %s" % (user.firstName, user.lastName) user.email = sanitize_email(csv_row[USER_EMAIL_COLUMN_INDEX]) user.departementCode = csv_row[USER_DEPARTMENT_CODE_COLUMN_INDEX] user.remove_beneficiary_role() user.add_pro_role() fulfill_account_password(user) return user
def test_change_password_raises_an_error_if_new_confirmation_password_is_not_given_as_key_in_json( self): # given user = User() user.setPassword("0ld__p455w0rd") json = {"oldPassword": "******", "newPassword": "******"} # when with pytest.raises(ApiErrors) as api_errors: validate_change_password_request(json) # then assert api_errors.value.errors["newConfirmationPassword"] == [ "Confirmation du nouveau mot de passe manquante" ]
def test_change_password_should_add_an_error_if_old_password_does_not_match_existing_password( self): # given api_errors = ApiErrors() user = User() user.setPassword("0ld__p455w0rd") old_password = "******" # when _ensure_given_old_password_is_correct(user, old_password, api_errors) # then assert api_errors.errors["oldPassword"] == [ "Ton ancien mot de passe est incorrect." ]
def change_password(user: User, body: ChangePasswordRequest) -> None: try: users_repo.check_user_and_credentials(user, body.current_password) except users_exceptions.InvalidIdentifier: raise ApiErrors({"code": "INVALID_PASSWORD", "currentPassword": ["Le mot de passe est incorrect"]}) except users_exceptions.CredentialsException: raise ForbiddenError() try: check_password_strength("newPassword", body.new_password) except ApiErrors: raise ApiErrors({"code": "WEAK_PASSWORD", "newPassword": ["Le nouveau mot de passe est trop faible"]}) user.setPassword(body.new_password) repository.save(user)