Ejemplo n.º 1
0
def patch_offer(offer_id: str, body: offers_serialize.PatchOfferBodyModel) -> offers_serialize.OfferResponseIdModel:
    offer = load_or_404(Offer, human_id=offer_id)
    check_user_has_access_to_offerer(current_user, offer.venue.managingOffererId)

    offer = offers_api.update_offer(offer, **body.dict(exclude_unset=True))

    return offers_serialize.OfferResponseIdModel.from_orm(offer)
Ejemplo n.º 2
0
def upsert_stocks(body: StocksUpsertBodyModel) -> StockIdsResponseModel:
    offerer = offerer_queries.get_by_offer_id(body.offer_id)
    check_user_has_access_to_offerer(current_user, offerer.id)

    stocks = offers_api.upsert_stocks(body.offer_id, body.stocks)
    return StockIdsResponseModel(
        stockIds=[StockIdResponseModel.from_orm(stock) for stock in stocks],
    )
Ejemplo n.º 3
0
def get_stocks(offer_id: str) -> StocksResponseModel:
    offerer = offerer_queries.get_by_offer_id(dehumanize(offer_id))
    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],
    )
Ejemplo n.º 4
0
    def test_raises_if_user_cannot_access_offerer(self, app):
        user = users_factories.UserFactory()
        offerer = offers_factories.OffererFactory()
        with pytest.raises(ApiErrors) as error:
            check_user_has_access_to_offerer(user, offerer.id)

        assert error.value.errors["global"] == [
            "Vous n'avez pas les droits d'accès suffisant pour accéder à cette information."
        ]
        assert error.value.status_code == 403
Ejemplo n.º 5
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],
    )
Ejemplo n.º 6
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)
Ejemplo n.º 7
0
def activate_venue_offers(venue_id):
    venue = load_or_404(Venue, venue_id)
    check_user_has_access_to_offerer(current_user, venue.managingOffererId)
    offers = venue.offers
    activated_offers = update_is_active_status(offers, True)
    repository.save(*activated_offers)
    if feature_queries.is_active(FeatureToggle.SYNCHRONIZE_ALGOLIA):
        redis.add_venue_id(client=app.redis_client, venue_id=venue.id)
    return jsonify([
        as_dict(offer, includes=OFFER_INCLUDES) for offer in activated_offers
    ]), 200
Ejemplo n.º 8
0
def upsert_stocks(body: StocksUpsertBodyModel) -> StockIdsResponseModel:
    try:
        offerer = pcapi.core.offerers.repository.get_by_offer_id(body.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 = offers_api.upsert_stocks(body.offer_id, body.stocks, current_user)
    return StockIdsResponseModel(
        stockIds=[StockIdResponseModel.from_orm(stock) for stock in stocks],
    )
Ejemplo n.º 9
0
 def test_check_user_has_access_to_offerer(self, app):
     pro = users_factories.UserFactory()
     offerer = offers_factories.OffererFactory()
     offers_factories.UserOffererFactory(user=pro, offerer=offerer)
     # fmt: off
     n_queries = (
         1  # select Offerer
         + 1  # select User
         + 1  # select UserOfferer
     )
     # fmt: on
     with assert_num_queries(n_queries):
         check_user_has_access_to_offerer(pro, offerer.id)
Ejemplo n.º 10
0
def update_mediation(
        mediation_id: str,
        body: UpdateMediationBodyModel) -> UpdateMediationResponseModel:

    mediation = Mediation.query.filter_by(
        id=dehumanize(mediation_id)).first_or_404()

    check_user_has_access_to_offerer(current_user,
                                     mediation.offer.venue.managingOffererId)

    mediation = offers_api.update_mediation(mediation=mediation,
                                            is_active=body.isActive)

    return UpdateMediationResponseModel.from_orm(mediation)
Ejemplo n.º 11
0
def create_thumbnail(form: CreateThumbnailBodyModel) -> CreateThumbnailResponseModel:
    offer = get_offer_by_id(form.offer_id)
    check_user_has_access_to_offerer(current_user, offer.venue.managingOffererId)

    image_as_bytes = form.get_image_as_bytes(request)
    thumbnail = offers_api.create_mediation(
        user=current_user,
        offer=offer,
        credit=form.credit,
        image_as_bytes=image_as_bytes,
        crop_params=form.crop_params,
    )

    return CreateThumbnailResponseModel(id=thumbnail.id)
Ejemplo n.º 12
0
def upsert_venue_banner(venue_id: str) -> None:
    venue = load_or_404(Venue, venue_id)

    check_user_has_access_to_offerer(current_user, venue.managingOffererId)

    venue_banner = venues_serialize.VenueBannerContentModel.from_request(request)

    offerers_api.save_venue_banner(
        user=current_user,
        venue=venue,
        content=venue_banner.content,
        content_type=venue_banner.content_type,
        file_name=venue_banner.file_name,
    )
Ejemplo n.º 13
0
def patch_booking_by_token(token: str) -> tuple[str, int]:
    email: Optional[str] = request.args.get("email", None)
    humanized_offer_id: Optional[str] = request.args.get("offer_id")
    offer_id: Optional[int] = dehumanize(humanized_offer_id)
    booking = booking_repository.find_by(token, email, offer_id)

    if current_user.is_authenticated:
        check_user_has_access_to_offerer(current_user, booking.offererId)
    else:
        check_email_and_offer_id_for_anonymous_user(email, offer_id)

    bookings_api.mark_as_used(booking)

    return "", 204
Ejemplo n.º 14
0
def get_venue_stats(humanized_venue_id: str) -> VenueStatsResponseModel:
    venue = load_or_404(Venue, humanized_venue_id)
    check_user_has_access_to_offerer(current_user, venue.managingOffererId)

    active_bookings_quantity = get_legacy_active_bookings_quantity_for_venue(venue.id)
    validated_bookings_count = get_legacy_validated_bookings_quantity_for_venue(venue.id)
    active_offers_count = get_active_offers_count_for_venue(venue.id)
    sold_out_offers_count = get_sold_out_offers_count_for_venue(venue.id)

    return VenueStatsResponseModel(
        activeBookingsQuantity=active_bookings_quantity,
        validatedBookingsQuantity=validated_bookings_count,
        activeOffersCount=active_offers_count,
        soldOutOffersCount=sold_out_offers_count,
    )
Ejemplo n.º 15
0
def create_mediation(
        form: CreateMediationBodyModel) -> MediationResponseIdModel:
    check_user_has_access_to_offerer(current_user, form.offerer_id)

    offer = get_offer_by_id(form.offer_id)
    image_as_bytes = form.get_image_as_bytes(request)

    mediation = offers_api.create_mediation(
        user=current_user,
        offer=offer,
        credit=form.credit,
        image_as_bytes=image_as_bytes,
        crop_params=form.crop_params,
    )

    return MediationResponseIdModel.from_orm(mediation)
Ejemplo n.º 16
0
def delete_stock(stock_id: str) -> StockIdResponseModel:
    # fmt: off
    stock = (
        Stock.queryNotSoftDeleted()
            .filter_by(id=dehumanize(stock_id))
            .join(Offer, Venue)
            .first_or_404()
    )
    # fmt: on

    offerer_id = stock.offer.venue.managingOffererId
    check_user_has_access_to_offerer(current_user, offerer_id)

    offers_api.delete_stock(stock)

    return StockIdResponseModel.from_orm(stock)
Ejemplo n.º 17
0
def patch_booking_by_token(token: str):
    email = request.args.get("email", None)
    offer_id = dehumanize(request.args.get("offer_id", None))
    booking_token_upper_case = token.upper()
    booking = booking_repository.find_by(booking_token_upper_case, email,
                                         offer_id)

    if current_user.is_authenticated:
        check_user_has_access_to_offerer(
            current_user, booking.stock.offer.venue.managingOffererId)
    else:
        check_email_and_offer_id_for_anonymous_user(email, offer_id)

    bookings_api.mark_as_used(booking)

    return "", 204
Ejemplo n.º 18
0
def patch_cancel_booking_by_token(token: str):
    """Let a pro user cancel a booking."""
    valid_api_key = _get_api_key_from_header(request)
    token = token.upper()
    booking = booking_repository.find_by(token=token)
    offerer_id = booking.stock.offer.venue.managingOffererId

    if current_user.is_authenticated:
        check_user_has_access_to_offerer(current_user, offerer_id)

    if valid_api_key:
        check_api_key_allows_to_cancel_booking(valid_api_key, offerer_id)

    bookings_api.cancel_booking_by_offerer(booking)

    return "", 204
Ejemplo n.º 19
0
def create_offer(offer_data: PostOfferBodyModel, user: User) -> Offer:
    venue = load_or_raise_error(Venue, offer_data.venue_id)

    check_user_has_access_to_offerer(user, offerer_id=venue.managingOffererId)

    if offer_data.product_id:
        product = load_or_raise_error(Product, offer_data.product_id)
        offer = Offer(
            product=product,
            type=product.type,
            name=product.name,
            description=product.description,
            url=product.url,
            mediaUrls=product.mediaUrls,
            conditions=product.conditions,
            ageMin=product.ageMin,
            ageMax=product.ageMax,
            durationMinutes=product.durationMinutes,
            isNational=product.isNational,
            extraData=product.extraData,
        )
    else:
        if offer_data.type == str(EventType.ACTIVATION):
            validation.check_user_can_create_activation_event(user)
        data = offer_data.dict(by_alias=True)
        product = Product()
        if data.get("url"):
            data["isNational"] = True
        product.populate_from_dict(data)
        offer = Offer()
        offer.populate_from_dict(data)
        offer.product = product
        offer.product.owningOfferer = venue.managingOfferer

    offer.venue = venue
    offer.bookingEmail = offer_data.booking_email
    offer.externalTicketOfficeUrl = offer_data.external_ticket_office_url
    offer.audioDisabilityCompliant = offer_data.audio_disability_compliant
    offer.mentalDisabilityCompliant = offer_data.mental_disability_compliant
    offer.motorDisabilityCompliant = offer_data.motor_disability_compliant
    offer.visualDisabilityCompliant = offer_data.visual_disability_compliant
    repository.save(offer)
    admin_emails.send_offer_creation_notification_to_administration(
        offer, user)

    return offer
Ejemplo n.º 20
0
def patch_cancel_booking_by_token(token: str) -> None:
    # in French, to be used by Swagger for the API documentation
    """Annulation d'une réservation.

    Bien que, dans le cas d’un événement, l’utilisateur ne peut plus annuler sa réservation 72h avant le début de ce dernier,
    cette API permet d’annuler la réservation d’un utilisateur si elle n’a pas encore été validé.
    """
    token = token.upper()
    booking = booking_repository.find_by(token=token)

    if current_user.is_authenticated:
        check_user_has_access_to_offerer(current_user, booking.offererId)

    if current_api_key:
        check_api_key_allows_to_cancel_booking(
            current_api_key,  # type: ignore[arg-type]
            booking.offererId,
        )

    bookings_api.cancel_booking_by_offerer(booking)
Ejemplo n.º 21
0
def get_venues_by_offerer_with_stats(humanized_offerer_id: str) -> GetOffererResponseModel:
    check_user_has_access_to_offerer(current_user, dehumanize(humanized_offerer_id))
    offerer = load_or_404(Offerer, humanized_offerer_id)

    venue_stats_by_ids = {}
    active_bookings_quantity_by_venue = get_active_bookings_quantity_for_offerer(offerer.id)
    validated_bookings_quantity_by_venue = get_validated_bookings_quantity_for_offerer(offerer.id)

    for managedVenue in offerer.managedVenues:
        active_offers_count = get_active_offers_count_for_venue(managedVenue.id)
        sold_out_offers_count = get_sold_out_offers_count_for_venue(managedVenue.id)

        venue_stats_by_ids[managedVenue.id] = VenueStatsResponseModel(
            activeBookingsQuantity=active_bookings_quantity_by_venue.get(managedVenue.id, 0),
            validatedBookingsQuantity=validated_bookings_quantity_by_venue.get(managedVenue.id, 0),
            activeOffersCount=active_offers_count,
            soldOutOffersCount=sold_out_offers_count,
        )

    return GetOffererResponseModel.from_orm(offerer, venue_stats_by_ids)
Ejemplo n.º 22
0
def edit_venue(venue_id):
    venue = load_or_404(Venue, venue_id)
    previous_venue = copy.deepcopy(venue)
    check_valid_edition(request, venue)
    validate_coordinates(request.json.get("latitude", None),
                         request.json.get("longitude", None))
    check_user_has_access_to_offerer(current_user, venue.managingOffererId)
    venue.populate_from_dict(request.json)

    if not venue.isVirtual:
        delete_venue_from_iris_venues(venue.id)

    repository.save(venue)
    link_valid_venue_to_irises(venue)

    if is_algolia_indexing(previous_venue, request.json):
        if feature_queries.is_active(FeatureToggle.SYNCHRONIZE_ALGOLIA):
            redis.add_venue_id(client=app.redis_client,
                               venue_id=dehumanize(venue_id))

    return jsonify(as_dict(venue, includes=VENUE_INCLUDES)), 200
Ejemplo n.º 23
0
def create_offer(offer_data: PostOfferBodyModel, user: User) -> Offer:
    subcategory = subcategories.ALL_SUBCATEGORIES_DICT.get(
        offer_data.subcategory_id)
    venue = load_or_raise_error(Venue, offer_data.venue_id)
    check_user_has_access_to_offerer(user, offerer_id=venue.managingOffererId)
    _check_offer_data_is_valid(offer_data)
    if _is_able_to_create_book_offer_from_isbn(subcategory):
        offer = _initialize_book_offer_from_template(offer_data)
    else:
        offer = _initialize_offer_with_new_data(offer_data, subcategory, venue)

    _complete_common_offer_fields(offer, offer_data, venue)

    repository.save(offer)
    logger.info("Offer has been created",
                extra={
                    "offer": offer.id,
                    "venue": venue.id,
                    "product": offer.productId
                })

    return offer
Ejemplo n.º 24
0
def edit_venue(venue_id: str, body: EditVenueBodyModel) -> GetVenueResponseModel:
    venue = load_or_404(Venue, venue_id)

    check_user_has_access_to_offerer(current_user, venue.managingOffererId)
    not_venue_fields = {
        "isAccessibilityAppliedOnAllOffers",
        "isEmailAppliedOnAllOffers",
        "isWithdrawalAppliedOnAllOffers",
        "contact",
    }
    update_venue_attrs = body.dict(exclude=not_venue_fields, exclude_unset=True)
    venue_attrs = as_dict(venue)
    accessibility_fields = [
        "audioDisabilityCompliant",
        "mentalDisabilityCompliant",
        "motorDisabilityCompliant",
        "visualDisabilityCompliant",
    ]
    have_accessibility_changes = any(
        (field in update_venue_attrs and update_venue_attrs[field] != venue_attrs[field])
        for field in accessibility_fields
    )
    have_withdrawal_details_changes = body.withdrawalDetails != venue.withdrawalDetails
    venue = offerers_api.update_venue(venue, body.contact, **update_venue_attrs)
    venue_attrs = as_dict(venue)

    if have_accessibility_changes and body.isAccessibilityAppliedOnAllOffers:
        edited_accessibility = {field: venue_attrs[field] for field in accessibility_fields}
        update_all_venue_offers_accessibility_job.delay(venue, edited_accessibility)

    if FeatureToggle.ENABLE_VENUE_WITHDRAWAL_DETAILS.is_active():
        if have_withdrawal_details_changes and body.isWithdrawalAppliedOnAllOffers:
            update_all_venue_offers_withdrawal_details_job.delay(venue, body.withdrawalDetails)

    if body.bookingEmail and body.isEmailAppliedOnAllOffers:
        update_all_venue_offers_email_job.delay(venue, body.bookingEmail)

    return GetVenueResponseModel.from_orm(venue)
Ejemplo n.º 25
0
def get_venue(venue_id):
    venue = load_or_404(Venue, venue_id)
    check_user_has_access_to_offerer(current_user, venue.managingOffererId)
    return jsonify(as_dict(venue, includes=VENUE_INCLUDES)), 200
Ejemplo n.º 26
0
def post_create_venue(body: PostVenueBodyModel) -> VenueResponseModel:
    dehumanized_managing_offerer_id = dehumanize(body.managingOffererId)
    check_user_has_access_to_offerer(current_user, dehumanized_managing_offerer_id)
    venue = offerers_api.create_venue(body)

    return VenueResponseModel.from_orm(venue)
Ejemplo n.º 27
0
def get_venue(venue_id: str) -> GetVenueResponseModel:
    venue = load_or_404(Venue, venue_id)
    check_user_has_access_to_offerer(current_user, venue.managingOffererId)

    return GetVenueResponseModel.from_orm(venue)
Ejemplo n.º 28
0
def get_offerer(offerer_id: str) -> GetOffererResponseModel:
    check_user_has_access_to_offerer(current_user, dehumanize(offerer_id))
    offerer = load_or_404(Offerer, offerer_id)

    return GetOffererResponseModel.from_orm(offerer)