示例#1
0
    def test_should_not_create_educational_booking_when_offer_is_not_an_event(
            self):
        # Given
        educational_institution = educational_factories.EducationalInstitutionFactory(
        )
        educational_factories.EducationalYearFactory()
        educational_redactor = educational_factories.EducationalRedactorFactory(
            email="*****@*****.**")
        stock = offers_factories.ThingStockFactory(
            beginningDatetime=datetime.datetime(2021, 5, 15),
            offer__isEducational=True)
        redactor_informations = AuthenticatedInformation(
            email=educational_redactor.email,
            civility=educational_redactor.civility,
            firstname=educational_redactor.firstName,
            lastname=educational_redactor.lastName,
            uai=educational_institution.institutionId,
        )

        # When
        with pytest.raises(exceptions.OfferIsNotEvent) as error:
            educational_api.book_educational_offer(
                redactor_informations=redactor_informations,
                stock_id=stock.id,
            )

        # Then
        assert error.value.errors == {
            "offer":
            [f"L'offre {stock.offer.id} n'est pas une offre évènementielle"]
        }

        saved_bookings = EducationalBooking.query.join(Booking).filter(
            Booking.stockId == stock.id).all()
        assert len(saved_bookings) == 0
示例#2
0
    def test_should_not_create_educational_booking_when_stock_is_not_bookable(
            self, mocked_get_and_lock_stock):
        # Given
        stock = mock.MagicMock()
        stock.isBookable = False
        stock.id = 1
        mocked_get_and_lock_stock.return_value = stock
        educational_redactor = educational_factories.EducationalRedactorFactory(
            email="*****@*****.**")
        educational_institution = educational_factories.EducationalInstitutionFactory(
        )
        redactor_informations = AuthenticatedInformation(
            email=educational_redactor.email,
            civility=educational_redactor.civility,
            firstname=educational_redactor.firstName,
            lastname=educational_redactor.lastName,
            uai=educational_institution.institutionId,
        )

        # When
        with pytest.raises(exceptions.StockNotBookable) as error:
            educational_api.book_educational_offer(
                redactor_informations=redactor_informations,
                stock_id=stock.id,
            )

        # Then
        assert error.value.errors == {
            "stock": [f"Le stock {stock.id} n'est pas réservable"]
        }
        saved_bookings = EducationalBooking.query.join(Booking).filter(
            Booking.stockId == stock.id).all()
        assert len(saved_bookings) == 0
示例#3
0
    def test_should_not_create_educational_booking_when_educational_institution_unknown(
            self):
        # Given
        stock = offers_factories.EducationalEventStockFactory(
            beginningDatetime=datetime.datetime(2021, 5, 15))
        educational_factories.EducationalInstitutionFactory()
        educational_factories.EducationalYearFactory()
        educational_redactor = educational_factories.EducationalRedactorFactory(
            email="*****@*****.**")
        provided_institution_id = "AU3568Unknown"
        redactor_informations = AuthenticatedInformation(
            email=educational_redactor.email,
            civility=educational_redactor.civility,
            firstname=educational_redactor.firstName,
            lastname=educational_redactor.lastName,
            uai=provided_institution_id,
        )

        # When
        with pytest.raises(exceptions.EducationalInstitutionUnknown) as error:
            educational_api.book_educational_offer(
                redactor_informations=redactor_informations,
                stock_id=stock.id,
            )

        # Then
        assert error.value.errors == {
            "educationalInstitution": ["Cette institution est inconnue"]
        }

        saved_bookings = EducationalBooking.query.join(Booking).filter(
            Booking.stockId == stock.id).all()
        assert len(saved_bookings) == 0
示例#4
0
    def test_should_not_create_educational_booking_when_stock_does_not_exist(
            self):
        # Given
        offers_factories.EducationalEventStockFactory(
            beginningDatetime=datetime.datetime(2021, 5, 15))
        educational_institution = educational_factories.EducationalInstitutionFactory(
        )
        educational_factories.EducationalYearFactory()
        educational_redactor = educational_factories.EducationalRedactorFactory(
            email="*****@*****.**")
        requested_stock_id = 4875
        redactor_informations = AuthenticatedInformation(
            email=educational_redactor.email,
            civility=educational_redactor.civility,
            firstname=educational_redactor.firstName,
            lastname=educational_redactor.lastName,
            uai=educational_institution.institutionId,
        )

        # When
        with pytest.raises(offers_exceptions.StockDoesNotExist):
            educational_api.book_educational_offer(
                redactor_informations=redactor_informations,
                stock_id=requested_stock_id,
            )

        # Then
        saved_bookings = EducationalBooking.query.all()
        assert len(saved_bookings) == 0
示例#5
0
    def wrapper(*args, **kwargs):
        mandatory_authorization_type = "Bearer "
        authorization_header = request.headers.get("Authorization")

        if authorization_header and mandatory_authorization_type in authorization_header:
            adage_jwt = authorization_header.replace(
                mandatory_authorization_type, "")
            try:
                adage_jwt_decoded = user_utils.decode_jwt_token_rs256(
                    adage_jwt)
            except InvalidSignatureError as invalid_signature_error:
                logger.error("Signature of adage jwt cannot be verified",
                             extra={"error": invalid_signature_error})
                raise ForbiddenError({"Authorization": "Unrecognized token"})
            except ExpiredSignatureError as expired_signature_error:
                logger.warning("Token has expired",
                               extra={"error": expired_signature_error})
                raise InvalidTokenError("Token expired")

            if not adage_jwt_decoded.get("exp"):
                logger.warning("Token does not contain an expiration date")
                raise InvalidTokenError("No expiration date provided")

            authenticated_information = AuthenticatedInformation(
                civility=adage_jwt_decoded.get("civilite"),
                lastname=adage_jwt_decoded.get("nom"),
                firstname=adage_jwt_decoded.get("prenom"),
                email=adage_jwt_decoded.get("mail"),
                uai=adage_jwt_decoded.get("uai"),
            )
            kwargs["authenticated_information"] = authenticated_information
            return route_function(*args, **kwargs)

        raise ForbiddenError({"Authorization": "Unrecognized token"})
示例#6
0
    def test_should_send_email_on_educational_booking_creation(self):
        # Given
        stock = offers_factories.EducationalEventStockFactory(
            beginningDatetime=datetime.datetime(2021, 5, 15),
            offer__bookingEmail="*****@*****.**",
        )
        educational_institution = educational_factories.EducationalInstitutionFactory(
        )
        educational_factories.EducationalYearFactory(
            beginningDate=datetime.datetime(2020, 9, 1),
            expirationDate=datetime.datetime(2021, 8, 31))
        educational_factories.EducationalYearFactory(
            beginningDate=datetime.datetime(2021, 9, 1),
            expirationDate=datetime.datetime(2022, 8, 31))
        educational_redactor = educational_factories.EducationalRedactorFactory(
            email="*****@*****.**",
            firstName="Georges",
            lastName="Moustaki",
        )
        redactor_informations = AuthenticatedInformation(
            email=educational_redactor.email,
            civility=educational_redactor.civility,
            firstname=educational_redactor.firstName,
            lastname=educational_redactor.lastName,
            uai=educational_institution.institutionId,
        )

        # When
        educational_api.book_educational_offer(
            redactor_informations=redactor_informations,
            stock_id=stock.id,
        )

        # Then
        assert len(mails_testing.outbox) == 1
        sent_data = mails_testing.outbox[0].sent_data
        offer = stock.offer
        assert sent_data == {
            "FromEmail": "*****@*****.**",
            "MJ-TemplateID": 3174424,
            "MJ-TemplateLanguage": True,
            "To": "*****@*****.**",
            "Vars": {
                "departement": "75",
                "lien_offre_pcpro":
                f"http://*****:*****@example.com",
                "is_event": 1,
            },
        }
示例#7
0
    def test_should_create_educational_booking_on_requested_educational_offer(
            self):
        # Given
        stock = offers_factories.EducationalEventStockFactory(
            beginningDatetime=datetime.datetime(2021, 5, 15))
        educational_institution = educational_factories.EducationalInstitutionFactory(
        )
        educational_year = educational_factories.EducationalYearFactory(
            beginningDate=datetime.datetime(2020, 9, 1),
            expirationDate=datetime.datetime(2021, 8, 31))
        educational_factories.EducationalYearFactory(
            beginningDate=datetime.datetime(2021, 9, 1),
            expirationDate=datetime.datetime(2022, 8, 31))
        educational_redactor = educational_factories.EducationalRedactorFactory(
            email="*****@*****.**")
        redactor_informations = AuthenticatedInformation(
            email=educational_redactor.email,
            civility=educational_redactor.civility,
            firstname=educational_redactor.firstName,
            lastname=educational_redactor.lastName,
            uai=educational_institution.institutionId,
        )

        # When
        returned_booking = educational_api.book_educational_offer(
            redactor_informations=redactor_informations,
            stock_id=stock.id,
        )

        # Then
        saved_educational_booking = EducationalBooking.query.join(
            Booking).filter(Booking.stockId == stock.id).first()

        assert saved_educational_booking.booking.id == returned_booking.id
        assert saved_educational_booking.booking.stock.id == stock.id
        assert saved_educational_booking.booking.stock.dnBookedQuantity == 1
        assert saved_educational_booking.confirmationLimitDate == stock.bookingLimitDatetime
        assert saved_educational_booking.educationalInstitution.institutionId == educational_institution.institutionId
        assert saved_educational_booking.educationalYear.adageId == educational_year.adageId
        assert saved_educational_booking.booking.status == BookingStatus.PENDING
        # Assert we do not create an extra educational redactor when exist
        assert EducationalRedactor.query.count() == 1
示例#8
0
    def test_should_not_create_educational_booking_when_educational_year_not_found(
            self):
        # Given
        date_before_education_year_beginning = datetime.datetime(2018, 9, 20)
        stock = offers_factories.EducationalEventStockFactory(
            beginningDatetime=date_before_education_year_beginning)
        educational_institution = educational_factories.EducationalInstitutionFactory(
        )
        educational_factories.EducationalYearFactory()
        educational_redactor = educational_factories.EducationalRedactorFactory(
            email="*****@*****.**")
        redactor_informations = AuthenticatedInformation(
            email=educational_redactor.email,
            civility=educational_redactor.civility,
            firstname=educational_redactor.firstName,
            lastname=educational_redactor.lastName,
            uai=educational_institution.institutionId,
        )

        # When
        with pytest.raises(exceptions.EducationalYearNotFound) as error:
            educational_api.book_educational_offer(
                redactor_informations=redactor_informations,
                stock_id=stock.id,
            )

        # Then
        assert error.value.errors == {
            "educationalYear": [
                "Aucune année scolaire correspondant à la réservation demandée n'a été trouvée"
            ]
        }

        saved_bookings = EducationalBooking.query.join(Booking).filter(
            Booking.stockId == stock.id).all()
        assert len(saved_bookings) == 0
示例#9
0
    def test_should_create_educational_redactor_when_it_does_not_exist(self):
        # Given
        stock = offers_factories.EducationalEventStockFactory(
            beginningDatetime=datetime.datetime(2021, 5, 15))
        educational_institution = educational_factories.EducationalInstitutionFactory(
        )
        educational_factories.EducationalYearFactory(
            beginningDate=datetime.datetime(2020, 9, 1),
            expirationDate=datetime.datetime(2021, 8, 31))
        educational_factories.EducationalYearFactory(
            beginningDate=datetime.datetime(2021, 9, 1),
            expirationDate=datetime.datetime(2022, 8, 31))
        redactor_informations = AuthenticatedInformation(
            email="*****@*****.**",
            civility="Mme",
            firstname="Project",
            lastname="Redactor",
            uai=educational_institution.institutionId,
        )

        # When
        educational_api.book_educational_offer(
            redactor_informations=redactor_informations,
            stock_id=stock.id,
        )

        # Then
        saved_educational_booking = EducationalBooking.query.join(
            Booking).filter(Booking.stockId == stock.id).first()
        assert saved_educational_booking.educationalRedactor.email == redactor_informations.email
        educational_redactor: EducationalRedactor = EducationalRedactor.query.one(
        )
        assert educational_redactor.email == redactor_informations.email
        assert educational_redactor.firstName == "Project"
        assert educational_redactor.lastName == "Redactor"
        assert educational_redactor.civility == "Mme"
示例#10
0
def book_educational_offer(
    body: BookEducationalOfferRequest,
    authenticated_information: AuthenticatedInformation,
) -> BookEducationalOfferResponse:
    try:
        booking = educational_api.book_educational_offer(
            redactor_informations=
            get_redactor_information_from_adage_authentication(
                authenticated_information),
            stock_id=body.stockId,
        )
    except AdageException as exception:
        logger.info(
            "Could not book offer: adage api call failed",
            extra={
                "redactor_email": authenticated_information.email,
                "status_code": str(exception.status_code),
                "response_text": exception.response_text,
            },
        )
        raise ApiErrors(
            {
                "global":
                "La récupération des informations du rédacteur de projet via Adage a échoué"
            },
            status_code=500,
        )

    except MissingRequiredRedactorInformation:
        logger.info(
            "Could not book offer: missing information in adage jwt",
            extra={
                "authenticated_information": authenticated_information.dict()
            },
        )
        raise ApiErrors(
            {
                "authorization":
                "Des informations sur le rédacteur de projet, et nécessaires à la préréservation, sont manquantes"
            },
            status_code=403,
        )

    except InstitutionalProjectRedactorNotFoundException:
        logger.info(
            "Could not book offer: redactor does not exist in Adage",
            extra={
                "redactor_email": authenticated_information.email,
            },
        )
        raise ApiErrors(
            {"global": "Le rédacteur de projet n'existe pas dans Adage"},
            status_code=404)
    except offers_exceptions.StockDoesNotExist:
        logger.info("Could not book offer: stock does not exist",
                    extra={"stock_id": body.stockId})
        raise ApiErrors({"stock": "Stock introuvable"}, status_code=400)
    except exceptions.StockNotBookable:
        logger.info("Could not book offer: stock is not bookable",
                    extra={"stock_id": body.stockId})
        raise ApiErrors(
            {"stock": "Cette offre n'est pas disponible à la réservation"})
    except exceptions.OfferIsNotEvent:
        logger.info("Could not book offer: offer is not an event",
                    extra={"stock_id": body.stockId})
        raise ApiErrors({"offer": "L'offre n'est pas un évènement"})
    except exceptions.OfferIsNotEducational:
        logger.info("Could not book offer: offer is not educational",
                    extra={"stock_id": body.stockId})
        raise ApiErrors(
            {"offer": "L'offre n'est pas une offre éducationnelle"})
    except exceptions.EducationalInstitutionUnknown:
        logger.info("Could not book offer: educational institution not found",
                    extra={"uai_code": authenticated_information.uai})
        raise ApiErrors({
            "educationalInstitution":
            "Cet établissement n'est pas éligible au pass Culture."
        })
    except exceptions.EducationalYearNotFound:
        logger.info(
            "Could not book offer: associated educational year not found",
            extra={"stock_id": body.stockId})
        raise ApiErrors({
            "educationalYear":
            "Aucune année scolaire ne correspond à cet évènement"
        })

    return BookEducationalOfferResponse(bookingId=booking.id)