def check_user_is_logged_in_or_email_is_provided(user: User, email: Optional[str]) -> None: if not (user.is_authenticated or email): api_errors = ApiErrors() api_errors.add_error( "email", "Vous devez préciser l'email de l'utilisateur quand vous n'êtes pas connecté(e)" ) raise api_errors
def _get_departement_code_when_authorized_or_error(authorized_emails, departement_codes): email_index = _get_email_index_in_spreadsheet_or_error(authorized_emails) departement_code = departement_codes[email_index] if departement_code.strip() == "": logger.exception("[ERROR] Missing departement code in users spreadsheet for %s", request.json["email"]) e = ApiErrors() e.add_error("email", "Adresse non autorisée pour l'expérimentation") raise e return departement_code
def check_user_can_validate_bookings(user: User, offerer_id: int) -> bool: if not user.is_authenticated: return False if not user.has_access(offerer_id): api_errors = ApiErrors() api_errors.add_error("global", "Cette contremarque n'a pas été trouvée") raise api_errors return True
def test_generate_a_valid_password(self): # Given errors = ApiErrors() # When password = random_password() # Then _ensure_new_password_is_strong_enough("password", password, errors) errors.maybe_raise()
def check_venue_creation(data): if None in [ data.get("audioDisabilityCompliant"), data.get("mentalDisabilityCompliant"), data.get("motorDisabilityCompliant"), data.get("visualDisabilityCompliant"), ]: errors = ApiErrors() errors.add_error("global", "L'accessibilité du lieu doit être définie.") raise errors
def check_reset_token_validity(user): if datetime.utcnow() > user.resetPasswordTokenValidityLimit: user.resetPasswordToken = None user.resetPasswordTokenValidityLimit = None repository.save(user) errors = ApiErrors() errors.add_error( "token", "Votre lien de changement de mot de passe est périmé. Veuillez effectuer une nouvelle demande." ) raise errors
def generate_api_key_route(offerer_id: str) -> GenerateOffererApiKeyResponse: check_user_has_access_to_offerer(current_user, dehumanize(offerer_id)) offerer = load_or_404(Offerer, offerer_id) try: clear_key = api.generate_and_save_api_key(offerer.id) except ApiKeyCountMaxReached: raise ApiErrors({"api_key_count_max": "Le nombre de clés maximal a été atteint"}) except ApiKeyPrefixGenerationError: raise ApiErrors({"api_key": "Could not generate api key"}) return GenerateOffererApiKeyResponse(apiKey=clear_key)
def check_user_can_validate_bookings(self, offerer_id: int): if not self.is_authenticated: return False if not self.hasRights(RightsType.editor, offerer_id): api_errors = ApiErrors() api_errors.add_error("global", "Cette contremarque n'a pas été trouvée") raise api_errors return True
def check_valid_signin(identifier: str, password: str): errors = ApiErrors() errors.status_code = 401 if identifier is None: errors.add_error("identifier", "Identifiant manquant") if password is None: errors.add_error("password", "Mot de passe manquant") errors.maybe_raise()
def check_new_venue_provider_information(payload: json): errors = ApiErrors() errors.status_code = 400 if "venueId" not in payload: errors.add_error("venueId", "Ce champ est obligatoire") if "providerId" not in payload: errors.add_error("providerId", "Ce champ est obligatoire") errors.maybe_raise()
def _get_reimbursements_csv_filter() -> str: offerers = Offerer.query.with_entities(Offerer.id) if not current_user.has_admin_role: offerers = filter_query_where_user_is_user_offerer_and_is_validated( offerers, current_user) elif not request.args.get("venueId"): raise ApiErrors({ "venueId": ["Le filtre par lieu est obligatoire pour les administrateurs"] }) all_offerer_ids = [row[0] for row in offerers.all()] reimbursement_period_field_names = ("reimbursementPeriodBeginningDate", "reimbursementPeriodEndingDate") reimbursement_period_beginning_date, reimbursement_period_ending_date = validate_reimbursement_period( reimbursement_period_field_names, request.args.get) venue_id = dehumanize_id(request.args.get("venueId")) reimbursement_details = find_all_offerers_reimbursement_details( all_offerer_ids, (reimbursement_period_beginning_date, reimbursement_period_ending_date), venue_id, ) reimbursement_details_csv = generate_reimbursement_details_csv( reimbursement_details) return reimbursement_details_csv
def verify_identity_document(payload: VerifyIdentityDocumentRequest) -> None: try: api.verify_identity_document_informations(payload.image_storage_path) return except (exceptions.IdentityDocumentVerificationException, IdCheckMiddlewareException): raise ApiErrors(status_code=503)
def post_for_password_token(body: ResetPasswordBodyModel) -> None: try: check_webapp_recaptcha_token( body.token, original_action="resetPassword", minimal_score=settings.RECAPTCHA_RESET_PASSWORD_MINIMAL_SCORE, ) except ReCaptchaException: raise ApiErrors({"token": "The given token is invalid"}) user = find_user_by_email(body.email) if not user or not user.isActive: # Here we also return a 204 to prevent attacker from discovering which email exists in db return if user.is_beneficiary: send_email = user_emails.send_reset_password_email_to_user else: send_email = send_reset_password_email_to_pro try: send_email(user) except MailServiceException as mail_service_exception: logger.exception("Could not send reset password email", extra={ "user": user.id, "exc": str(mail_service_exception) })
def test_should_not_add_errors_when_password_is_valid_2(self): api_errors = ApiErrors() _ensure_new_password_is_strong_enough("newPassword", "]v4l1dP455sw0rd", api_errors) assert not api_errors.errors
def test_error_is_collected_if_beneficiary_could_not_be_saved( self, send_activation_email, mock_repository, create_beneficiary_from_application, app ): # given information = { "department": "93", "last_name": "Doe", "first_name": "Jane", "birth_date": datetime(2000, 5, 1), "email": "*****@*****.**", "phone": "0612345678", "postal_code": "93130", "application_id": 123, "civility": "Mme", "activity": "Étudiant", } create_beneficiary_from_application.side_effect = [User()] mock_repository.save.side_effect = [ApiErrors({"postalCode": ["baaaaad value"]})] new_beneficiaries = [] error_messages = [] # when remote_import.process_beneficiary_application( information, error_messages, new_beneficiaries, retry_ids=[], procedure_id=123456 ) # then send_activation_email.assert_not_called() assert error_messages == ['{\n "postalCode": [\n "baaaaad value"\n ]\n}'] assert not new_beneficiaries
def test_should_not_add_errors_when_password_is_valid(self, newPassword): api_errors = ApiErrors() _ensure_new_password_is_strong_enough("newPassword", newPassword, api_errors) assert not api_errors.errors
def validate_reimbursement_period( reimbursement_period_field_names: tuple[str, str], get_query_param: Callable) -> Union[list[None], list[date]]: api_errors = ApiErrors() reimbursement_period_dates = [] for field_name in reimbursement_period_field_names: try: reimbursement_period_dates.append( date.fromisoformat(get_query_param(field_name))) except (TypeError, ValueError): api_errors.add_error( field_name, "Vous devez renseigner une date au format ISO (ex. 2021-12-24)" ) if len(api_errors.errors) > 0: raise api_errors return reimbursement_period_dates or [None, None]
def upload_identity_document( user: User, form: serializers.UploadIdentityDocumentRequest, ) -> None: if not user.is_eligible: raise ApiErrors({"code": "USER_NOT_ELIGIBLE"}) try: token = api.validate_token(user.id, form.token) image = form.get_image_as_bytes(request) api.asynchronous_identity_document_verification(image, user.email) token.isUsed = True user.extraData["is_identity_document_uploaded"] = True repository.save(token, user) return except exceptions.ExpiredCode: raise ApiErrors( { "code": "EXPIRED_TOKEN", "message": "Token expiré" }, status_code=400, ) except exceptions.NotValidCode: raise ApiErrors( { "code": "INVALID_TOKEN", "message": "Token invalide" }, status_code=400, ) except FileSizeExceeded: raise ApiErrors( { "code": "FILE_SIZE_EXCEEDED", "message": "L'image envoyée dépasse 10Mo" }, status_code=400, ) except (exceptions.IdentityDocumentUploadException, exceptions.CloudTaskCreationException): raise ApiErrors( { "code": "SERVICE_UNAVAILABLE", "message": "Token invalide" }, status_code=503)
def when_one_password_is_missing_in_the_request_body( self, validate_change_password_request, app): # given api_errors = ApiErrors() api_errors.add_error("password", "missing password") api_errors.status_code = 400 user = users_factories.UserFactory(email="*****@*****.**") validate_change_password_request.side_effect = api_errors data = {} # when response = (TestClient(app.test_client()).with_session_auth( user.email).post("/users/current/change-password", json=data)) # then assert response.status_code == 400 assert response.json["password"] == ["missing password"]
def report_offer(user: User, offer_id: int, body: serializers.OfferReportRequest) -> None: offer = Offer.query.get_or_404(offer_id) try: api.report_offer(user, offer, body.reason, body.custom_reason) except OfferReportError as error: raise ApiErrors({"code": error.code}, status_code=400)
def check_password_validity(new_password: str, new_confirmation_password: str, old_password: str, user: User) -> None: api_errors = ApiErrors() _ensure_new_password_is_strong_enough("newPassword", new_password, api_errors) _ensure_given_old_password_is_correct(user, old_password, api_errors) _ensure_new_password_is_different_from_old(user, new_password, api_errors) _ensure_confirmation_password_is_same_as_new_password(new_password, new_confirmation_password, api_errors) if len(api_errors.errors) > 0: raise api_errors
def validate_new_password_request(request): if "token" not in request.get_json(): errors = ApiErrors() errors.add_error("token", "Votre lien de changement de mot de passe est invalide.") raise errors if "newPassword" not in request.get_json(): errors = ApiErrors() errors.add_error("newPassword", "Vous devez renseigner un nouveau mot de passe.") raise errors
def post_offer(body: offers_serialize.PostOfferBodyModel) -> offers_serialize.OfferResponseIdModel: try: offer = offers_api.create_offer(offer_data=body, user=current_user) except exceptions.OfferCannotBeDuoAndEducational as error: logger.info( "Could not create offer: offer cannot be both 'duo' and 'educational'", extra={"offer_name": body.name, "venue_id": body.venue_id}, ) raise ApiErrors( error.errors, status_code=400, ) except exceptions.UnknownOfferSubCategory as error: logger.info( "Could not create offer: selected subcategory is unknown.", extra={"offer_name": body.name, "venue_id": body.venue_id}, ) raise ApiErrors( error.errors, status_code=400, ) except exceptions.SubCategoryIsInactive as error: logger.info( "Could not create offer: subcategory cannot be selected.", extra={"offer_name": body.name, "venue_id": body.venue_id}, ) raise ApiErrors( error.errors, status_code=400, ) except exceptions.SubcategoryNotEligibleForEducationalOffer as error: logger.info( "Could not create offer: subcategory is not eligible for educational offer.", extra={"offer_name": body.name, "venue_id": body.venue_id}, ) raise ApiErrors( error.errors, status_code=400, ) return offers_serialize.OfferResponseIdModel.from_orm(offer)
def test_should_not_return_error_message_when_datetime_is_valid(): # Given stock = create_stock(beginning_datetime=datetime(2020, 1, 1)) api_errors = ApiErrors() # When api_error = validate(stock, api_errors) # Then assert api_error.errors == {}
def test_should_not_return_error_message_when_stock_is_unlimited(): # Given stock = create_stock(quantity=None) api_errors = ApiErrors() # When api_error = validate(stock, api_errors) # Then assert api_error.errors == {}
def test_should_not_add_an_error_when_new_passwords_are_equals(self): # given api_errors = ApiErrors() # when _ensure_confirmation_password_is_same_as_new_password( "goodNewPassword", "goodNewPassword", api_errors) # then assert not api_errors.errors
def get_stocks(offer_id: str) -> StocksResponseModel: try: offerer = pcapi.core.offerers.repository.get_by_offer_id(dehumanize(offer_id)) except offerers_exceptions.CannotFindOffererForOfferId: raise ApiErrors({"offerer": ["Aucune structure trouvée à partir de cette offre"]}, status_code=404) check_user_has_access_to_offerer(current_user, offerer.id) stocks = get_stocks_for_offer(dehumanize(offer_id)) return StocksResponseModel( stocks=[StockResponseModel.from_orm(stock) for stock in stocks], )
def test_should_return_error_message_when_stock_is_negative(): # Given stock = create_stock(quantity=-1) api_errors = ApiErrors() # When api_error = validate(stock, api_errors) # Then assert api_error.errors["quantity"] == ["La quantité doit être positive."]
def test_should_return_error_message_when_product_is_digital_and_offline(): # Given product = create_product_with_thing_type(is_offline_only=True, is_digital=True) api_errors = ApiErrors() # When api_error = validate(product, api_errors) # Then assert api_error.errors["url"] == ["Une offre de type Cinéma - cartes d'abonnement ne peut pas être numérique"]
def sync_validate(*args: dict, **kwargs: dict) -> Response: try: body_params = request.get_json() except BadRequest as error: logger.info( "Error when decoding request body: %s", error, extra={ "contentTypeHeader": request.headers.get("Content-Type"), "path": request.path }, ) body_params = None query_params = request.args form = request.form if body_in_kwargs: kwargs["body"] = body_in_kwargs(**(body_params or {})) if query_in_kwargs: kwargs["query"] = query_in_kwargs(**query_params) if form_in_kwargs: try: kwargs["form"] = form_in_kwargs(**form) except pydantic.ValidationError as validation_errors: error = ApiErrors() error_dict = {} for errors in validation_errors.errors(): error_dict[errors["loc"][0]] = errors["msg"] raise ApiErrors(error_dict) result = route(*args, **kwargs) if json_format: return _make_json_response( content=result, status_code=on_success_status, by_alias=response_by_alias, exclude_none=exclude_none, headers=response_headers, ) return _make_string_response(content=result, status_code=on_success_status, headers=response_headers)