예제 #1
0
        def when_stock_is_on_an_offer_from_provider(self, app):
            # given
            tite_live_provider = Provider \
                .query \
                .filter(Provider.localClass == 'TiteLiveThings') \
                .first()

            user = create_user(email='*****@*****.**')
            offerer = create_offerer()
            user_offerer = create_user_offerer(user, offerer)
            venue = create_venue(offerer)
            offer = create_offer_with_thing_product(
                venue, last_provider_id=tite_live_provider.id)
            stock = create_stock(offer=offer)
            PcObject.save(user, stock, user_offerer)

            # when
            response = TestClient(app.test_client()).with_auth('*****@*****.**') \
                .delete('/stocks/' + humanize(stock.id))

            # then
            assert response.status_code == 400
            assert response.json["global"] == [
                "Les offres importées ne sont pas modifiables"
            ]
예제 #2
0
def save_thumb(model_with_thumb,
               thumb,
               image_index,
               image_type=None,
               dominant_color=None,
               convert=True,
               crop=None,
               symlink_path=None,
               need_save=True,
               store_thumb: Callable = store_public_object):
    new_thumb = thumb

    if convert:
        crop_params = crop if crop is not None else DO_NOT_CROP
        new_thumb = standardize_image(thumb, crop_params)

    if image_index == 0:
        if dominant_color:
            model_with_thumb.firstThumbDominantColor = dominant_color
        else:
            model_with_thumb.firstThumbDominantColor = compute_dominant_color(
                new_thumb)

    store_thumb('thumbs',
                model_with_thumb.get_thumb_storage_id(image_index),
                new_thumb,
                'image/' + (image_type or 'jpeg'),
                symlink_path=symlink_path)

    model_with_thumb.thumbCount = model_with_thumb.thumbCount + 1

    if need_save:
        PcObject.save(model_with_thumb)
예제 #3
0
        def expect_bookings_to_be_cancelled(self, app):
            # given
            user = create_user(email='*****@*****.**')
            other_user = create_user(email='*****@*****.**')
            offerer = create_offerer()
            user_offerer = create_user_offerer(user, offerer)
            venue = create_venue(offerer)
            stock = create_stock_with_event_offer(offerer, venue, price=0)
            booking1 = create_booking(other_user,
                                      stock=stock,
                                      is_cancelled=False)
            booking2 = create_booking(other_user,
                                      stock=stock,
                                      is_cancelled=False)
            PcObject.save(user, stock, user_offerer, booking1, booking2)

            # when
            response = TestClient(app.test_client()).with_auth(
                '*****@*****.**').delete('/stocks/' + humanize(stock.id))

            # then
            assert response.status_code == 200
            bookings = Booking.query.filter_by(isCancelled=True).all()
            assert booking1 in bookings
            assert booking2 in bookings
    def test_does_not_create_thing_if_too_few_elements_in_data_line(
            self, get_lines_from_thing_file,
            get_files_to_process_from_titelive_ftp, app):
        # mock
        files_list = list()
        files_list.append('Quotidien30.tit')

        get_files_to_process_from_titelive_ftp.return_value = files_list

        data_line = "9782895026310"

        get_lines_from_thing_file.return_value = iter([data_line])

        # given

        offerer = create_offerer(siren='775671464')
        venue = create_venue(offerer,
                             name='Librairie Titelive',
                             siret='77567146400110')
        PcObject.save(venue)

        provider_test(app,
                      TiteLiveThings,
                      None,
                      checkedObjects=1,
                      createdObjects=0,
                      updatedObjects=0,
                      erroredObjects=0,
                      checkedThumbs=0,
                      createdThumbs=0,
                      updatedThumbs=0,
                      erroredThumbs=0,
                      Product=0)
예제 #5
0
        def when_booking_limit_datetime_after_beginning_datetime(self, app):
            # Given
            user = create_user(email='*****@*****.**', can_book_free_offers=False, is_admin=True)
            offerer = create_offerer()
            venue = create_venue(offerer)
            offer = create_offer_with_event_product(venue)
            PcObject.save(user, offer)

            beginningDatetime = datetime(2019, 2, 14)

            data = {
                'price': 1222,
                'offerId': humanize(offer.id),
                'beginningDatetime': serialize(beginningDatetime),
                'endDatetime': serialize(beginningDatetime + timedelta(days=1)),
                'bookingLimitDatetime': serialize(beginningDatetime + timedelta(days=2))
            }

            # When
            response = TestClient(app.test_client()).with_auth(user.email) \
                .post('/stocks', json=data)

            # Then
            assert response.status_code == 400
            assert response.json['bookingLimitDatetime'] == [
                'La date limite de réservation pour cette offre est postérieure à la date de début de l\'évènement'
            ]
예제 #6
0
        def when_booking_limit_datetime_is_none_for_thing(self, app):
            # Given
            user = create_user(email='*****@*****.**', can_book_free_offers=False, is_admin=True)
            offerer = create_offerer()
            venue = create_venue(offerer)
            offer = create_offer_with_thing_product(venue)
            PcObject.save(user, offer)

            data = {
                'price': 0,
                'offerId': humanize(offer.id),
                'bookingLimitDatetime': None
            }

            # When
            response = TestClient(app.test_client()).with_auth(user.email) \
                .post('/stocks', json=data)

            # Then
            assert response.status_code == 201
            assert response.json["price"] == 0
            assert response.json["bookingLimitDatetime"] is None

            id = response.json['id']
            stock = Stock.query.filter_by(id=dehumanize(id)).first()
            assert stock.price == 0
            assert stock.bookingLimitDatetime is None
예제 #7
0
        def when_offer_come_from_provider(self, app):
            # given
            tite_live_provider = Provider \
                .query \
                .filter(Provider.localClass == 'TiteLiveThings') \
                .first()

            user = create_user(email='*****@*****.**')
            offerer = create_offerer()
            user_offerer = create_user_offerer(user, offerer)
            venue = create_venue(offerer)
            offer = create_offer_with_thing_product(venue, last_provider_id=tite_live_provider.id)
            stock = create_stock(offer=offer, available=10)
            PcObject.save(user, user_offerer, stock)
            humanized_stock_id = humanize(stock.id)

            # when
            request_update = TestClient(app.test_client()).with_auth('*****@*****.**') \
                .patch('/stocks/' + humanized_stock_id, json={'available': 5})

            # then
            assert request_update.status_code == 400
            request_after_update = TestClient(app.test_client()).with_auth('*****@*****.**').get(
                '/stocks/' + humanized_stock_id)
            assert request_after_update.json['available'] == 10
            assert request_update.json["global"] == ["Les offres importées ne sont pas modifiables"]
    def test_does_not_create_thing_if_no_files_found(
            self, get_files_to_process_from_titelive_ftp, app):
        # mock
        files_list = list()
        get_files_to_process_from_titelive_ftp.return_value = files_list

        # given
        offerer = create_offerer(siren='775671464')
        venue = create_venue(offerer,
                             name='Librairie Titelive',
                             siret='77567146400110')
        PcObject.save(venue)

        provider_test(app,
                      TiteLiveThings,
                      None,
                      checkedObjects=0,
                      createdObjects=0,
                      updatedObjects=0,
                      erroredObjects=0,
                      checkedThumbs=0,
                      createdThumbs=0,
                      updatedThumbs=0,
                      erroredThumbs=0,
                      Product=0)
def create_industrial_thing_offers(things_by_name, offerers_by_name,
                                   venues_by_name):
    logger.info('create_industrial_thing_offers')

    thing_offers_by_name = {}

    id_at_providers = 1234
    thing_index = 0
    offer_index = 0
    thing_items = list(things_by_name.items())

    for offerer in offerers_by_name.values():

        virtual_venue = [
            venue for venue in offerer.managedVenues if venue.isVirtual
        ][0]

        physical_venue_name = virtual_venue.name.replace(
            " (Offre en ligne)", "")
        physical_venue = venues_by_name.get(physical_venue_name)

        for venue_thing_index in range(0, THINGS_PER_OFFERER):

            thing_venue = None
            while thing_venue is None:
                rest_thing_index = (venue_thing_index +
                                    thing_index) % len(thing_items)

                (thing_name, thing) = thing_items[rest_thing_index]

                if thing.offerType['offlineOnly']:
                    thing_venue = physical_venue
                elif thing.offerType['onlineOnly']:
                    thing_venue = virtual_venue
                else:
                    thing_venue = physical_venue

                thing_index += 1

            name = "{} / {}".format(thing_name, thing_venue.name)
            if offer_index % DEACTIVATED_OFFERS_PICK_MODULO == 0:
                is_active = False
            else:
                is_active = True
            thing_offers_by_name[name] = create_offer_with_thing_product(
                thing_venue,
                product=thing,
                thing_type=thing.type,
                is_active=is_active,
                id_at_providers=str(id_at_providers))
            offer_index += 1
            id_at_providers += 1

        thing_index += THINGS_PER_OFFERER

    PcObject.save(*thing_offers_by_name.values())

    logger.info('created {} thing_offers'.format(len(thing_offers_by_name)))

    return thing_offers_by_name
예제 #10
0
def create_industrial_pro_users():
    logger.info('create_industrial_pro_users')

    users_by_name = {}

    for departement_code in departement_codes:

        for pro_count in range(PROS_COUNT):
            email = "pctest.pro{}.{}@btmx.fr".format(departement_code,
                                                     pro_count)
            users_by_name['pro{} {}'.format(
                departement_code, pro_count)] = create_user(
                    can_book_free_offers=False,
                    departement_code=str(departement_code),
                    date_of_birth=None,
                    email=email,
                    first_name="PC Test Pro",
                    is_admin=False,
                    last_name="{} {}".format(departement_code, pro_count),
                    postal_code="{}100".format(departement_code),
                    public_name="PC Test Pro {} {}".format(
                        departement_code, pro_count),
                )

    PcObject.save(*users_by_name.values())

    logger.info('created {} users'.format(len(users_by_name)))

    return users_by_name
    def test_create_multiple_things_with_sandboxes_data(
            self, get_lines_from_thing_file,
            get_files_to_process_from_titelive_ftp, app):
        # mock
        files = get_ordered_thing_files_from_sandbox_files()
        get_files_to_process_from_titelive_ftp.return_value = files

        files_content = []
        for file in files:
            content = get_lines_from_thing_file_sandboxes(file)
            files_content.append(content)

        get_lines_from_thing_file.side_effect = files_content

        # given
        offerer = create_offerer(siren='775671464')
        venue = create_venue(offerer,
                             name='Librairie Titelive',
                             siret='77567146400110')
        PcObject.save(venue)

        provider_test(app,
                      TiteLiveThings,
                      None,
                      checkedObjects=422,
                      createdObjects=340,
                      updatedObjects=16,
                      erroredObjects=0,
                      checkedThumbs=0,
                      createdThumbs=0,
                      updatedThumbs=0,
                      erroredThumbs=0,
                      Product=340)
def create_industrial_thing_stocks(thing_offers_by_name):
    logger.info('create_industrial_thing_stocks')

    thing_stocks_by_name = {}
    short_names_to_increase_price = []

    thing_offer_items = list(thing_offers_by_name.items())

    thing_offer_items_with_stocks = remove_every(
        thing_offer_items, THING_OFFERS_WITH_STOCK_REMOVE_MODULO)

    for thing_offer_item_with_stocks in thing_offer_items_with_stocks:
        (thing_offer_with_stocks_name,
         thing_offer_with_stocks) = thing_offer_item_with_stocks
        available = 10

        short_name = get_occurrence_short_name(thing_offer_with_stocks_name)
        price = get_price_by_short_name(short_name)
        fcount = short_names_to_increase_price.count(short_name)
        if (fcount > 2):
            price = price + fcount
        short_names_to_increase_price.append(short_name)
        # price = 10

        name = thing_offer_with_stocks_name + " / " + str(
            available) + " / " + str(price)
        thing_stocks_by_name[name] = create_stock_from_offer(
            thing_offer_with_stocks, available=available, price=price)

    PcObject.save(*thing_stocks_by_name.values())

    logger.info('created {} thing_stocks'.format(len(thing_stocks_by_name)))

    return thing_stocks_by_name
예제 #13
0
        def when_setting_beginning_and_end_datetimes_on_offer_with_thing(self, app):
            # Given
            user = create_user(email='*****@*****.**', can_book_free_offers=False, is_admin=True)
            offerer = create_offerer()
            venue = create_venue(offerer)
            offer = create_offer_with_thing_product(venue)
            PcObject.save(user, offer)
            beginningDatetime = datetime(2019, 2, 14)

            data = {
                'price': 0,
                'offerId': humanize(offer.id),
                'beginningDatetime': serialize(beginningDatetime),
                'endDatetime': serialize(beginningDatetime + timedelta(days=1)),
                'bookingLimitDatetime': serialize(beginningDatetime - timedelta(days=2))
            }

            # When
            response = TestClient(app.test_client()).with_auth(user.email) \
                .post('/stocks', json=data)

            # Then
            assert response.status_code == 400
            assert response.json['global'] == [
                'Impossible de mettre des dates de début et fin si l\'offre ne porte pas sur un évenement'
            ]
예제 #14
0
def create_industrial_criteria() -> dict:
    logger.info('create_industrial_criteria')

    criteria_by_name = {}

    criterion1 = Criterion()
    criterion1.name = 'Bonne offre d’appel'
    criterion1.description = 'Offre déjà beaucoup réservée par les autres jeunes'
    criterion1.scoreDelta = 1
    criteria_by_name[criterion1.name] = criterion1

    criterion2 = Criterion()
    criterion2.name = 'Mauvaise accroche'
    criterion2.description = 'Offre ne possédant pas une accroche de qualité suffisante'
    criterion2.scoreDelta = -1
    criteria_by_name[criterion2.name] = criterion2

    criterion3 = Criterion()
    criterion3.name = 'Offre de médiation spécifique'
    criterion3.description = 'Offre possédant une médiation orientée pour les jeunes de 18 ans'
    criterion3.scoreDelta = 2
    criteria_by_name[criterion3.name] = criterion3

    PcObject.save(*criteria_by_name.values())

    logger.info('created {} criteria'.format(len(criteria_by_name)))

    return criteria_by_name
def create_industrial_user_offerers(users_by_name, offerers_by_name):
    logger.info('create_industrial_user_offerers')

    user_offerers_by_name = {}

    # special validation
    user = users_by_name['pro93 real-validation']
    offerer = offerers_by_name['414819409 lat:48.8 lon:1.48']
    user_offerers_by_name['pro93 real-validation / 414819409 lat:48.8 lon:1.48'] = create_user_offerer(
        offerer=offerer,
        user=user
    )

    # loop on users
    for (user_name, user) in users_by_name.items():

        for (offerer_name, offerer) in offerers_by_name.items():

            if offerer.postalCode[:2] != user.departementCode or\
               'real-validation' in user_name:
                continue

            user_offerers_by_name['{} / {}'.format(user_name, offerer_name)] = create_user_offerer(
                offerer=offerer,
                user=user
            )

    PcObject.save(*user_offerers_by_name.values())

    logger.info('created {} user_offerers'.format(len(user_offerers_by_name)))

    return user_offerers_by_name
예제 #16
0
def update_mediation(mediation_id):
    mediation = load_or_404(Mediation, mediation_id)
    ensure_current_user_has_rights(RightsType.editor,
                                   mediation.offer.venue.managingOffererId)
    mediation = Mediation.query.filter_by(id=dehumanize(mediation_id)).first()
    data = request.json
    mediation.populate_from_dict(data)
    invalidate_recommendations_if_deactivating_object(
        data, mediation.recommendations)
    PcObject.save(mediation)
    return jsonify(as_dict(mediation, includes=MEDIATION_INCLUDES)), 200
예제 #17
0
def associate_criterion_to_one_offer_with_mediation(offers_by_name: dict,
                                                    criteria_by_name: dict):
    offer = list(
        filter(lambda o: o.mediations is not None,
               list(offers_by_name.values())))[0]
    criterion = criteria_by_name['Offre de médiation spécifique']

    offer_criterion = OfferCriterion()
    offer_criterion.offer = offer
    offer_criterion.criterion = criterion

    PcObject.save(offer_criterion)
예제 #18
0
def edit_stock(stock_id):
    stock_data = request.json
    query = Stock.queryNotSoftDeleted().filter_by(id=dehumanize(stock_id))
    stock = query.first_or_404()
    check_offer_is_editable(stock.offer)
    check_dates_are_allowed_on_existing_stock(stock_data, stock.offer)
    offerer_id = stock.resolvedOffer.venue.managingOffererId
    ensure_current_user_has_rights(RightsType.editor, offerer_id)

    stock.populate_from_dict(stock_data)
    PcObject.save(stock)

    return jsonify(as_dict(stock)), 200
예제 #19
0
def create_mediation():
    check_thumb_in_request(files=request.files, form=request.form)
    offerer_id = dehumanize(request.form['offererId'])
    offer_id = dehumanize(request.form['offerId'])
    credit = request.form.get('credit')
    ensure_current_user_has_rights(RightsType.editor, offerer_id)
    mediation = create_new_mediation(offer_id, offerer_id, current_user,
                                     credit)
    thumb = read_thumb(files=request.files, form=request.form)
    check_thumb_quality(thumb)
    PcObject.save(mediation)
    save_thumb(mediation, thumb, 0, crop=_get_crop(request.form))
    return jsonify(as_dict(mediation)), 201
def create_industrial_event_offers(
        events_by_name,
        offerers_by_name
):
    logger.info('create_industrial_event_offers')

    event_offers_by_name = {}

    event_index = 0
    offer_index = 0

    event_items = list(events_by_name.items())

    for offerer in offerers_by_name.values():

        event_venues = [
            venue for venue in offerer.managedVenues
            if not venue.isVirtual
        ]

        if not event_venues:
            continue

        event_venue = event_venues[0]

        for venue_event_index in range(0, EVENTS_PER_OFFERER_WITH_PHYSICAL_VENUE):

            rest_event_index = (venue_event_index + event_index) % len(event_items)

            (event_name, event) = event_items[rest_event_index]

            name = "{} / {}".format(event_name, event_venue.name)
            if offer_index % DEACTIVATED_OFFERS_PICK_MODULO == 0:
                is_active = False
            else:
                is_active = True
            event_offers_by_name[name] = create_offer_with_event_product(
                event_venue,
                product=event,
                event_type=event.type,
                is_active=is_active
            )
            offer_index += 1

        event_index += EVENTS_PER_OFFERER_WITH_PHYSICAL_VENUE

    PcObject.save(*event_offers_by_name.values())

    logger.info('created {} event_offers'.format(len(event_offers_by_name)))

    return event_offers_by_name
예제 #21
0
def create_venue_provider():
    venue_provider_payload = request.json
    validate_new_venue_provider_information(venue_provider_payload)

    new_venue_provider = VenueProvider(from_dict=venue_provider_payload)
    PcObject.save(new_venue_provider)

    subprocess.Popen('PYTHONPATH="." python scripts/pc.py update_providables' +
                     ' --venue-provider-id %s' % str(new_venue_provider.id),
                     shell=True,
                     cwd=API_ROOT_PATH)

    return jsonify(
        as_dict(new_venue_provider, includes=VENUE_PROVIDER_INCLUDES)), 201
예제 #22
0
def create_stock():
    request_data = request.json
    check_request_has_offer_id(request_data)
    offer_id = dehumanize(request_data.get('offerId', None))
    offer = find_offer_by_id(offer_id)
    check_offer_is_editable(offer)
    check_dates_are_allowed_on_new_stock(request_data, offer)
    offerer = offerer_queries.get_by_offer_id(offer_id)
    ensure_current_user_has_rights(RightsType.editor, offerer.id)

    new_stock = Stock(from_dict=request_data)
    PcObject.save(new_stock)

    return jsonify(as_dict(new_stock)), 201
예제 #23
0
        def when_current_user_has_no_rights_on_offer(self, app):
            # given
            user = create_user(email='*****@*****.**')
            offerer = create_offerer()
            venue = create_venue(offerer)
            stock = create_stock_with_event_offer(offerer, venue)
            PcObject.save(user, stock)

            # when
            response = TestClient(app.test_client()).with_auth('*****@*****.**') \
                .delete('/stocks/' + humanize(stock.id))

            # then
            assert response.status_code == 403
예제 #24
0
        def when_end_limit_datetime_is_none_for_event(self, app):
            # given
            user = create_user(email='*****@*****.**', can_book_free_offers=False, is_admin=True)
            offerer = create_offerer()
            venue = create_venue(offerer)
            stock = create_stock_with_event_offer(offerer, venue)
            PcObject.save(stock, user)

            # when
            response = TestClient(app.test_client()).with_auth('*****@*****.**') \
                .patch('/stocks/' + humanize(stock.id), json={'endDatetime': None})

            # then
            assert response.status_code == 400
            assert response.json['endDatetime'] == ['Ce paramètre est obligatoire']
예제 #25
0
        def when_feature_is_not_active(self, app):
            # Given
            data = BASE_DATA.copy()
            feature = Feature.query.filter_by(
                name=FeatureToggle.WEBAPP_SIGNUP).first()
            feature.isActive = False
            PcObject.save(feature)

            # When
            response = TestClient(app.test_client()) \
                .post('/users/signup/webapp',
                      json=data, headers={'origin': 'http://localhost:3000'})

            # Then
            assert response.status_code == 403
예제 #26
0
        def when_missing_offer_id(self, app):
            # Given
            user = create_user(email='*****@*****.**', can_book_free_offers=False, is_admin=True)
            offerer = create_offerer()
            venue = create_venue(offerer)
            offer = create_offer_with_thing_product(venue)
            PcObject.save(user, offer)

            # When
            response = TestClient(app.test_client()).with_auth(user.email) \
                .post('/stocks', json={'price': 1222})

            # Then
            assert response.status_code == 400
            assert response.json["offerId"] == ['Ce paramètre est obligatoire']
예제 #27
0
        def when_user_has_no_rights(self, app):
            # given
            user = create_user(email='*****@*****.**')
            offerer = create_offerer()
            venue = create_venue(offerer)
            stock = create_stock_with_event_offer(offerer, venue)
            PcObject.save(user, stock)

            # when
            response = TestClient(app.test_client()).with_auth('*****@*****.**') \
                .patch('/stocks/' + humanize(stock.id), json={'available': 5})

            # then
            assert response.status_code == 403
            assert "Vous n'avez pas les droits d'accès suffisant pour accéder à cette information." in response.json[
                'global']
예제 #28
0
        def when_user_has_no_rights_and_creating_stock_from_offer_id(self, app):
            # Given
            user = create_user(email='*****@*****.**')
            offerer = create_offerer()
            venue = create_venue(offerer)
            offer = create_offer_with_thing_product(venue)
            PcObject.save(user, offer)

            data = {'price': 1222, 'offerId': humanize(offer.id)}

            # When
            response = TestClient(app.test_client()).with_auth(user.email) \
                .post('/stocks', json=data)

            # Then
            assert response.status_code == 403
            assert response.json["global"] == ["Vous n'avez pas les droits d'accès suffisant pour accéder à cette information."]
예제 #29
0
    def test_open_agenda_events_creaet_data_from_sandboxe_file(
            self, get_data, app):
        # mock
        open_agenda_sandboxes_files = [1, 2]
        sandboxes_data = []
        for page in open_agenda_sandboxes_files:
            data_content = get_data_from_sandbox_files(page)
            sandboxes_data.append(data_content)

        get_data.side_effect = sandboxes_data

        # given
        offerer = create_offerer(siren='123456789')
        venue = create_venue(offerer,
                             name='Librairie OpenAgenda',
                             siret='12345678901231')
        PcObject.save(venue)
        venue_id = venue.id

        open_agenda_provider = get_provider_by_local_class('OpenAgendaEvents')
        venue_provider = VenueProvider()
        venue_provider.venueId = venue_id
        venue_provider.provider = open_agenda_provider
        venue_provider.isActive = True
        venue_provider.venueIdAtOfferProvider = '49050769'
        PcObject.save(venue_provider)
        venue_provider = VenueProvider.query \
            .filter_by(venueIdAtOfferProvider='49050769') \
            .one_or_none()
        provider_test(app,
                      OpenAgendaEvents,
                      venue_provider,
                      checkedObjects=18,
                      createdObjects=18,
                      updatedObjects=0,
                      erroredObjects=0,
                      checkedThumbs=3,
                      createdThumbs=3,
                      updatedThumbs=0,
                      erroredThumbs=0,
                      Event=3,
                      EventOccurrence=12,
                      Offer=3,
                      Stock=0,
                      Venue=0,
                      Offerer=0)
예제 #30
0
def _upsert_tuto_mediation(index, has_back=False):
    existing_mediation = Mediation.query.filter_by(tutoIndex=index) \
        .first()
    if existing_mediation:
        return
    mediation = Mediation()
    mediation.tutoIndex = index
    PcObject.save(mediation)

    with open(TUTOS_PATH / (str(index) + '.png'), "rb") as f:
        save_thumb(mediation, f.read(), 0, convert=False, image_type='png')

    if has_back:
        with open(TUTOS_PATH / (str(index) + '_verso.png'), "rb") as f:
            save_thumb(mediation, f.read(), 1, convert=False, image_type='png')

    PcObject.save(mediation)