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
Exemple #2
0
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
Exemple #4
0
    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
Exemple #6
0
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
Exemple #7
0
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)
Exemple #8
0
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
Exemple #9
0
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)
                         })
Exemple #14
0
    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
Exemple #16
0
    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
Exemple #17
0
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]
Exemple #18
0
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"]
Exemple #20
0
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)
Exemple #21
0
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
Exemple #22
0
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 == {}
Exemple #26
0
    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
Exemple #27
0
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"]
Exemple #30
0
        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)