コード例 #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)
コード例 #2
0
ファイル: stocks.py プロジェクト: ragekit75/pass-culture-api
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],
    )
コード例 #3
0
ファイル: stocks.py プロジェクト: ragekit75/pass-culture-api
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],
    )
コード例 #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
コード例 #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],
    )
コード例 #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)
コード例 #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
コード例 #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],
    )
コード例 #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)
コード例 #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)
コード例 #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)
コード例 #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,
    )
コード例 #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
コード例 #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,
    )
コード例 #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)
コード例 #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)
コード例 #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
コード例 #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
コード例 #19
0
ファイル: api.py プロジェクト: ragekit75/pass-culture-api
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
コード例 #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)
コード例 #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)
コード例 #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
コード例 #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
コード例 #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)
コード例 #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
コード例 #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)
コード例 #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)
コード例 #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)