Compare commits
12 Commits
c8aea5747e
...
57e26d83f9
Author | SHA1 | Date |
---|---|---|
Frédéric Péters | 57e26d83f9 | |
Frédéric Péters | e2dc898695 | |
Lauréline Guérin | 7c91b91d89 | |
Lauréline Guérin | a167a91cde | |
Lauréline Guérin | 56b794468f | |
Lauréline Guérin | 184cf83dd7 | |
Yann Weber | 4e6f41c4de | |
Benjamin Dauvergne | 42f73e2626 | |
Valentin Deniaud | 3576928b2c | |
Frédéric Péters | ae55827939 | |
Lauréline Guérin | d733e91135 | |
Lauréline Guérin | 4b8c3412e4 |
|
@ -1172,6 +1172,9 @@ class Agenda(WithSnapshotMixin, WithApplicationMixin, WithInspectMixin, models.M
|
|||
event_queryset = Agenda.filter_for_guardian(
|
||||
event_queryset, guardian_external_id, user_external_id
|
||||
)
|
||||
event_queryset = event_queryset.prefetch_related(
|
||||
Prefetch('primary_event', queryset=Event.objects.all().order_by())
|
||||
)
|
||||
|
||||
return qs.filter(kind='events').prefetch_related(
|
||||
Prefetch(
|
||||
|
@ -2699,6 +2702,12 @@ class Event(WithInspectMixin, models.Model):
|
|||
except ValueError:
|
||||
raise AgendaImportError(_('Bad datetime format "%s"') % data['start_datetime'])
|
||||
|
||||
if data.get('end_time'):
|
||||
try:
|
||||
data['end_time'] = datetime.datetime.strptime(data['end_time'], '%H:%M').time()
|
||||
except ValueError:
|
||||
raise AgendaImportError(_('Bad time format "%s"') % data['end_time'])
|
||||
|
||||
if data.get('recurrence_days'):
|
||||
# keep stable weekday numbering after switch to ISO in db
|
||||
data['recurrence_days'] = [i + 1 for i in data['recurrence_days']]
|
||||
|
@ -2718,6 +2727,7 @@ class Event(WithInspectMixin, models.Model):
|
|||
update_fields = {
|
||||
field: getattr(event, field)
|
||||
for field in [
|
||||
'end_time',
|
||||
'label',
|
||||
'duration',
|
||||
'publication_datetime',
|
||||
|
@ -2737,6 +2747,7 @@ class Event(WithInspectMixin, models.Model):
|
|||
)
|
||||
return {
|
||||
'start_datetime': make_naive(self.start_datetime).strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'end_time': self.end_time.strftime('%H:%M') if self.end_time else None,
|
||||
'publication_datetime': make_naive(self.publication_datetime).strftime('%Y-%m-%d %H:%M:%S')
|
||||
if self.publication_datetime
|
||||
else None,
|
||||
|
@ -3132,9 +3143,16 @@ class Booking(models.Model):
|
|||
del self.user_check
|
||||
return super().refresh_from_db(*args, **kwargs)
|
||||
|
||||
def cancel(self, trigger_callback=False):
|
||||
def cancel(self, trigger_callback=False, request=None):
|
||||
timestamp = now()
|
||||
with transaction.atomic():
|
||||
audit(
|
||||
'booking',
|
||||
_('cancellation of booking (%(booking_id)s) in event "%(event)s"')
|
||||
% {'booking_id': self.id, 'event': self.event},
|
||||
request=request,
|
||||
agenda=self.event.agenda,
|
||||
)
|
||||
self.secondary_booking_set.update(cancellation_datetime=timestamp)
|
||||
self.cancellation_datetime = timestamp
|
||||
self.save()
|
||||
|
@ -3142,15 +3160,29 @@ class Booking(models.Model):
|
|||
r = requests_wrapper.post(self.cancel_callback_url, remote_service='auto', timeout=15)
|
||||
r.raise_for_status()
|
||||
|
||||
def accept(self):
|
||||
def accept(self, request=None):
|
||||
self.in_waiting_list = False
|
||||
with transaction.atomic():
|
||||
audit(
|
||||
'booking',
|
||||
_('acceptation of booking (%(booking_id)s) in event "%(event)s"')
|
||||
% {'booking_id': self.id, 'event': self.event},
|
||||
request=request,
|
||||
agenda=self.event.agenda,
|
||||
)
|
||||
self.secondary_booking_set.update(in_waiting_list=False)
|
||||
self.save()
|
||||
|
||||
def suspend(self):
|
||||
def suspend(self, request=None):
|
||||
self.in_waiting_list = True
|
||||
with transaction.atomic():
|
||||
audit(
|
||||
'booking',
|
||||
_('suspension of booking (%(booking_id)s) in event "%(event)s"')
|
||||
% {'booking_id': self.id, 'event': self.event},
|
||||
request=request,
|
||||
agenda=self.event.agenda,
|
||||
)
|
||||
self.secondary_booking_set.update(in_waiting_list=True)
|
||||
self.save()
|
||||
|
||||
|
|
|
@ -332,9 +332,11 @@ def get_short_event_detail(
|
|||
details = {
|
||||
'id': '%s@%s' % (agenda.slug, event.slug) if multiple_agendas else event.slug,
|
||||
'slug': event.slug, # kept for compatibility
|
||||
'primary_event': None,
|
||||
'text': get_event_text(event, agenda),
|
||||
'label': event.label or '',
|
||||
'agenda_label': agenda.label,
|
||||
'agenda_slug': agenda.slug,
|
||||
'date': format_response_date(event.start_datetime),
|
||||
'datetime': format_response_datetime(event.start_datetime),
|
||||
'end_datetime': format_response_datetime(event.end_datetime) if event.end_datetime else '',
|
||||
|
@ -346,6 +348,12 @@ def get_short_event_detail(
|
|||
'check_locked': event.check_locked,
|
||||
'invoiced': event.invoiced,
|
||||
}
|
||||
if event.primary_event:
|
||||
details['primary_event'] = (
|
||||
'%s@%s' % (agenda.slug, event.primary_event.slug)
|
||||
if multiple_agendas
|
||||
else event.primary_event.slug
|
||||
)
|
||||
for key, value in event.get_custom_fields().items():
|
||||
details['custom_field_%s' % key] = value
|
||||
return details
|
||||
|
@ -664,6 +672,7 @@ class Datetimes(APIView):
|
|||
entries = Event.annotate_queryset_for_user(entries, user_external_id)
|
||||
if lock_code:
|
||||
entries = Event.annotate_queryset_for_lock_code(entries, lock_code=lock_code)
|
||||
entries = entries.prefetch_related(Prefetch('primary_event', queryset=Event.objects.all().order_by()))
|
||||
entries = entries.order_by('start_datetime', 'duration', 'label')
|
||||
|
||||
if payload['hide_disabled']:
|
||||
|
@ -744,6 +753,9 @@ class MultipleAgendasDatetimes(APIView):
|
|||
entries = Event.annotate_queryset_for_user(entries, user_external_id, with_status=with_status)
|
||||
if lock_code:
|
||||
Event.annotate_queryset_for_lock_code(entries, lock_code)
|
||||
entries = entries.prefetch_related(
|
||||
Prefetch('primary_event', queryset=Event.objects.all().order_by())
|
||||
)
|
||||
|
||||
if check_overlaps:
|
||||
entries = Event.annotate_queryset_with_overlaps(entries)
|
||||
|
@ -1307,7 +1319,7 @@ class EventsAgendaFillslot(APIView):
|
|||
|
||||
if to_cancel_booking:
|
||||
cancelled_booking_id = to_cancel_booking.pk
|
||||
to_cancel_booking.cancel()
|
||||
to_cancel_booking.cancel(request=request)
|
||||
|
||||
# now we have a list of events, book them.
|
||||
primary_booking = None
|
||||
|
@ -1320,6 +1332,14 @@ class EventsAgendaFillslot(APIView):
|
|||
in_waiting_list=in_waiting_list,
|
||||
)
|
||||
new_booking.save()
|
||||
audit(
|
||||
'booking',
|
||||
_('created a booking (%(booking_id)s) for event %(event)s')
|
||||
% {'booking_id': new_booking.id, 'event': event},
|
||||
request=request,
|
||||
agenda=event.agenda,
|
||||
)
|
||||
|
||||
if lock_code and not confirm_after_lock:
|
||||
Lease.objects.create(
|
||||
booking=new_booking,
|
||||
|
@ -1544,7 +1564,7 @@ class MeetingsAgendaFillslot(APIView):
|
|||
).delete()
|
||||
if to_cancel_booking:
|
||||
cancelled_booking_id = to_cancel_booking.pk
|
||||
to_cancel_booking.cancel()
|
||||
to_cancel_booking.cancel(request=request)
|
||||
|
||||
# book event
|
||||
event.save()
|
||||
|
@ -1557,6 +1577,14 @@ class MeetingsAgendaFillslot(APIView):
|
|||
color=color,
|
||||
)
|
||||
booking.save()
|
||||
audit(
|
||||
'booking',
|
||||
_('created a booking (%(booking_id)s) for event %(event)s')
|
||||
% {'booking_id': booking.id, 'event': event},
|
||||
request=request,
|
||||
agenda=event.agenda,
|
||||
)
|
||||
|
||||
if lock_code and not confirm_after_lock:
|
||||
Lease.objects.create(
|
||||
booking=booking,
|
||||
|
@ -1846,6 +1874,7 @@ class RecurringFillslots(APIView):
|
|||
min_start=start_datetime,
|
||||
max_start=end_datetime,
|
||||
)
|
||||
events = events.prefetch_related(Prefetch('primary_event', queryset=Event.objects.all().order_by()))
|
||||
|
||||
return events
|
||||
|
||||
|
@ -2004,6 +2033,7 @@ class EventsFillslots(APIView):
|
|||
output_field=BooleanField(),
|
||||
)
|
||||
)
|
||||
events = events.prefetch_related(Prefetch('primary_event', queryset=Event.objects.all().order_by()))
|
||||
waiting_list_event_ids = [event.pk for event in events if event.in_waiting_list]
|
||||
|
||||
extra_data = get_extra_data(request, payload)
|
||||
|
@ -2228,9 +2258,13 @@ class MultipleAgendasEventsFillslotsRevert(APIView):
|
|||
if booking.previous_state == 'cancelled':
|
||||
bookings_to_cancel.append(booking)
|
||||
|
||||
events = Event.objects.filter(
|
||||
pk__in=[b.event_id for b in bookings_to_cancel + bookings_to_book + bookings_to_delete]
|
||||
).prefetch_related('agenda')
|
||||
events = (
|
||||
Event.objects.filter(
|
||||
pk__in=[b.event_id for b in bookings_to_cancel + bookings_to_book + bookings_to_delete]
|
||||
)
|
||||
.prefetch_related('agenda')
|
||||
.prefetch_related(Prefetch('primary_event', queryset=Event.objects.all().order_by()))
|
||||
)
|
||||
events_by_id = {x.id: x for x in events}
|
||||
with transaction.atomic():
|
||||
cancellation_datetime = now()
|
||||
|
@ -2778,10 +2812,12 @@ class BookingsAPI(ListAPIView):
|
|||
return Response({'err': 0, 'data': data})
|
||||
|
||||
def get_queryset(self):
|
||||
event_queryset = Event.objects.all().prefetch_related(
|
||||
'agenda', 'desk', Prefetch('primary_event', queryset=Event.objects.all().order_by())
|
||||
)
|
||||
return (
|
||||
Booking.objects.filter(primary_booking__isnull=True, cancellation_datetime__isnull=True)
|
||||
.select_related('event', 'event__agenda', 'event__desk')
|
||||
.prefetch_related('user_checks')
|
||||
.prefetch_related('user_checks', Prefetch('event', queryset=event_queryset))
|
||||
.order_by('event__start_datetime', 'event__slug', 'event__agenda__slug', 'pk')
|
||||
)
|
||||
|
||||
|
@ -2937,7 +2973,7 @@ class BookingAPI(APIView):
|
|||
if self.booking.primary_booking is not None:
|
||||
raise APIError(N_('secondary booking'), err=2)
|
||||
|
||||
self.booking.cancel()
|
||||
self.booking.cancel(request=request)
|
||||
response = {'err': 0, 'booking_id': self.booking.pk}
|
||||
return Response(response)
|
||||
|
||||
|
@ -2961,7 +2997,7 @@ class CancelBooking(APIView):
|
|||
raise APIError(N_('already cancelled'))
|
||||
if booking.primary_booking is not None:
|
||||
raise APIError(N_('secondary booking'), err=2)
|
||||
booking.cancel()
|
||||
booking.cancel(request=request)
|
||||
response = {'err': 0, 'booking_id': booking.id}
|
||||
return Response(response)
|
||||
|
||||
|
@ -2988,7 +3024,7 @@ class AcceptBooking(APIView):
|
|||
raise APIError(N_('secondary booking'), err=2)
|
||||
if not booking.in_waiting_list:
|
||||
raise APIError(N_('booking is not in waiting list'), err=3)
|
||||
booking.accept()
|
||||
booking.accept(request=request)
|
||||
event = booking.event
|
||||
response = {
|
||||
'err': 0,
|
||||
|
@ -3020,7 +3056,7 @@ class SuspendBooking(APIView):
|
|||
raise APIError(N_('secondary booking'), err=2)
|
||||
if booking.in_waiting_list:
|
||||
raise APIError(N_('booking is already in waiting list'), err=3)
|
||||
booking.suspend()
|
||||
booking.suspend(request=request)
|
||||
response = {'err': 0, 'booking_id': booking.pk}
|
||||
return Response(response)
|
||||
|
||||
|
|
|
@ -208,6 +208,7 @@ class Place(models.Model):
|
|||
'annulation_url': self.cancel_url,
|
||||
'plages': list(self.iter_open_dates()),
|
||||
'rdvs': list(self.iter_predemandes()),
|
||||
'logo_url': self.logo_url,
|
||||
}
|
||||
return payload
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import io
|
||||
import json
|
||||
import tarfile
|
||||
|
||||
|
@ -29,7 +28,7 @@ from rest_framework.generics import GenericAPIView
|
|||
from rest_framework.response import Response
|
||||
|
||||
from chrono.agendas.models import Agenda, Category, EventsType, Resource, UnavailabilityCalendar
|
||||
from chrono.api.utils import APIError
|
||||
from chrono.api.utils import APIErrorBadRequest
|
||||
from chrono.apps.export_import.models import Application, ApplicationElement
|
||||
from chrono.manager.utils import import_site
|
||||
|
||||
|
@ -237,14 +236,14 @@ def component_redirect(request, component_type, slug):
|
|||
class BundleCheck(GenericAPIView):
|
||||
permission_classes = (permissions.IsAdminUser,)
|
||||
|
||||
def put(self, request, *args, **kwargs):
|
||||
tar_io = io.BytesIO(request.read())
|
||||
def post(self, request, *args, **kwargs):
|
||||
bundle = request.FILES['bundle']
|
||||
try:
|
||||
with tarfile.open(fileobj=tar_io) as tar:
|
||||
with tarfile.open(fileobj=bundle) as tar:
|
||||
try:
|
||||
manifest = json.loads(tar.extractfile('manifest.json').read().decode())
|
||||
except KeyError:
|
||||
raise APIError(_('Invalid tar file, missing manifest'))
|
||||
raise APIErrorBadRequest(_('Invalid tar file, missing manifest'))
|
||||
application_slug = manifest.get('slug')
|
||||
application_version = manifest.get('version_number')
|
||||
if not application_slug or not application_version:
|
||||
|
@ -334,7 +333,7 @@ class BundleCheck(GenericAPIView):
|
|||
}
|
||||
)
|
||||
except tarfile.TarError:
|
||||
raise APIError(_('Invalid tar file'))
|
||||
raise APIErrorBadRequest(_('Invalid tar file'))
|
||||
|
||||
return Response(
|
||||
{
|
||||
|
@ -355,15 +354,15 @@ class BundleImport(GenericAPIView):
|
|||
permission_classes = (permissions.IsAdminUser,)
|
||||
install = True
|
||||
|
||||
def put(self, request, *args, **kwargs):
|
||||
tar_io = io.BytesIO(request.read())
|
||||
def post(self, request, *args, **kwargs):
|
||||
bundle = request.FILES['bundle']
|
||||
components = {}
|
||||
try:
|
||||
with tarfile.open(fileobj=tar_io) as tar:
|
||||
with tarfile.open(fileobj=bundle) as tar:
|
||||
try:
|
||||
manifest = json.loads(tar.extractfile('manifest.json').read().decode())
|
||||
except KeyError:
|
||||
raise APIError(_('Invalid tar file, missing manifest'))
|
||||
raise APIErrorBadRequest(_('Invalid tar file, missing manifest'))
|
||||
self.application = Application.update_or_create_from_manifest(
|
||||
manifest,
|
||||
tar,
|
||||
|
@ -382,7 +381,7 @@ class BundleImport(GenericAPIView):
|
|||
tar.extractfile('%s/%s' % (element['type'], element['slug'])).read().decode()
|
||||
)
|
||||
except KeyError:
|
||||
raise APIError(
|
||||
raise APIErrorBadRequest(
|
||||
_(
|
||||
'Invalid tar file, missing component %s/%s'
|
||||
% (element['type'], element['slug'])
|
||||
|
@ -390,7 +389,7 @@ class BundleImport(GenericAPIView):
|
|||
)
|
||||
components[component_type].append(json.loads(component_content).get('data'))
|
||||
except tarfile.TarError:
|
||||
raise APIError(_('Invalid tar file'))
|
||||
raise APIErrorBadRequest(_('Invalid tar file'))
|
||||
|
||||
# init cache of application elements, from manifest
|
||||
self.application_elements = set()
|
||||
|
|
|
@ -38,7 +38,7 @@ class Migration(migrations.Migration):
|
|||
(
|
||||
'user',
|
||||
models.ForeignKey(
|
||||
null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
|
||||
null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -72,7 +72,7 @@ class Migration(migrations.Migration):
|
|||
(
|
||||
'user',
|
||||
models.ForeignKey(
|
||||
null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
|
||||
null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -106,7 +106,7 @@ class Migration(migrations.Migration):
|
|||
(
|
||||
'user',
|
||||
models.ForeignKey(
|
||||
null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
|
||||
null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -140,7 +140,7 @@ class Migration(migrations.Migration):
|
|||
(
|
||||
'user',
|
||||
models.ForeignKey(
|
||||
null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
|
||||
null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -174,7 +174,7 @@ class Migration(migrations.Migration):
|
|||
(
|
||||
'user',
|
||||
models.ForeignKey(
|
||||
null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
|
||||
null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -45,7 +45,7 @@ class WithSnapshotMixin:
|
|||
|
||||
class AbstractSnapshot(models.Model):
|
||||
timestamp = models.DateTimeField(auto_now_add=True)
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True)
|
||||
comment = models.TextField(blank=True, null=True)
|
||||
serialization = models.JSONField(blank=True, default=dict)
|
||||
label = models.CharField(_('Label'), max_length=150, blank=True)
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: chrono 0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-03-21 13:40+0100\n"
|
||||
"POT-Creation-Date: 2024-04-04 15:40+0200\n"
|
||||
"PO-Revision-Date: 2024-02-01 09:50+0100\n"
|
||||
"Last-Translator: Frederic Peters <fpeters@entrouvert.com>\n"
|
||||
"Language: French\n"
|
||||
|
@ -500,6 +500,11 @@ msgstr "Annulation en cours"
|
|||
msgid "Bad datetime format \"%s\""
|
||||
msgstr "Mauvais format pour la date/heure « %s »"
|
||||
|
||||
#: agendas/models.py
|
||||
#, python-format
|
||||
msgid "Bad time format \"%s\""
|
||||
msgstr "Mauvais format pour l’heure « %s »"
|
||||
|
||||
#: agendas/models.py
|
||||
msgid "Daily"
|
||||
msgstr "Tous les jours"
|
||||
|
@ -1558,10 +1563,12 @@ msgid "Booked"
|
|||
msgstr "Réservé"
|
||||
|
||||
#: api/views.py manager/forms.py
|
||||
#: manager/templates/chrono/manager_partial_bookings_month_view.html
|
||||
msgid "Present"
|
||||
msgstr "Présent"
|
||||
|
||||
#: api/views.py manager/forms.py
|
||||
#: manager/templates/chrono/manager_partial_bookings_month_view.html
|
||||
msgid "Absent"
|
||||
msgstr "Absent"
|
||||
|
||||
|
@ -2096,6 +2103,7 @@ msgid "Without booking"
|
|||
msgstr "Sans réservation"
|
||||
|
||||
#: manager/forms.py
|
||||
#: manager/templates/chrono/manager_partial_bookings_month_view.html
|
||||
msgid "Not checked"
|
||||
msgstr "Non pointé"
|
||||
|
||||
|
|
|
@ -4293,7 +4293,7 @@ class BookingCancelView(ViewableAgendaMixin, UpdateView):
|
|||
def form_valid(self, form):
|
||||
trigger_callback = not form.cleaned_data['disable_trigger']
|
||||
try:
|
||||
self.booking.cancel(trigger_callback)
|
||||
self.booking.cancel(trigger_callback, request=self.request)
|
||||
except requests.RequestException:
|
||||
form.add_error(None, _('There has been an error sending cancellation notification to form.'))
|
||||
form.add_error(None, _('Check this box if you are sure you want to proceed anyway.'))
|
||||
|
|
|
@ -58,6 +58,7 @@ def test_sync_ants_hub(db, hub, place_agenda, freezer):
|
|||
'rdvs': [],
|
||||
'url': '',
|
||||
'ville': 'Newcity',
|
||||
'logo_url': '',
|
||||
}
|
||||
assert len(payload['collectivites'][0]['lieux'][0]['plages']) == 39
|
||||
assert payload['collectivites'][0]['lieux'][0]['plages'][0] == {
|
||||
|
|
|
@ -58,6 +58,7 @@ def ants_setup(db, freezer):
|
|||
address='2 rue du four',
|
||||
zipcode='99999',
|
||||
city_name='Saint-Didier',
|
||||
logo_url='https://saint-didier.fr/logo.png',
|
||||
)
|
||||
annexe = Place.objects.create(
|
||||
id=2,
|
||||
|
@ -525,6 +526,7 @@ def test_export_to_push(ants_setup):
|
|||
'types_rdv': ['CNI', 'PASSPORT'],
|
||||
},
|
||||
],
|
||||
'logo_url': 'https://saint-didier.fr/logo.png',
|
||||
},
|
||||
{
|
||||
'full': True,
|
||||
|
@ -618,6 +620,7 @@ def test_export_to_push(ants_setup):
|
|||
'types_rdv': ['CNI', 'PASSPORT'],
|
||||
},
|
||||
],
|
||||
'logo_url': '',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
|
@ -129,6 +129,7 @@ def test_datetime_api_label(app):
|
|||
agenda=agenda,
|
||||
)
|
||||
resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
||||
assert resp.json['data'][0]['primary_event'] is None
|
||||
assert resp.json['data'][0]['text'] == 'Hello world'
|
||||
assert resp.json['data'][0]['label'] == 'Hello world'
|
||||
|
||||
|
@ -692,6 +693,8 @@ def test_recurring_events_api(app, user, freezer):
|
|||
assert data[0]['id'] == 'abc--2021-01-19-1305'
|
||||
assert data[0]['datetime'] == '2021-01-19 13:05:00'
|
||||
assert data[0]['text'] == "Rock'n roll (Jan. 19, 2021, 1:05 p.m.)"
|
||||
assert data[0]['label'] == "Rock'n roll"
|
||||
assert data[0]['primary_event'] == 'abc'
|
||||
assert data[3]['id'] == 'abc--2021-02-09-1305'
|
||||
assert Event.objects.count() == 6
|
||||
|
||||
|
@ -713,7 +716,7 @@ def test_recurring_events_api(app, user, freezer):
|
|||
# check querysets
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
app.get('/api/agenda/%s/datetimes/' % agenda.slug)
|
||||
assert len(ctx.captured_queries) == 3
|
||||
assert len(ctx.captured_queries) == 4
|
||||
|
||||
# events follow agenda display template
|
||||
agenda.event_display_template = '{{ event.label }} - {{ event.start_datetime }}'
|
||||
|
|
|
@ -34,12 +34,14 @@ def test_datetimes_multiple_agendas(app):
|
|||
Desk.objects.create(agenda=first_agenda, slug='_exceptions_holder')
|
||||
Event.objects.create(
|
||||
slug='event',
|
||||
label='Event',
|
||||
start_datetime=now() + datetime.timedelta(days=5),
|
||||
places=5,
|
||||
agenda=first_agenda,
|
||||
)
|
||||
event = Event.objects.create( # base recurring event not visible in datetimes api
|
||||
slug='recurring',
|
||||
label='Recurring',
|
||||
start_datetime=now() + datetime.timedelta(hours=1),
|
||||
recurrence_days=[localtime().isoweekday()],
|
||||
recurrence_end_date=now() + datetime.timedelta(days=15),
|
||||
|
@ -60,11 +62,18 @@ def test_datetimes_multiple_agendas(app):
|
|||
Booking.objects.create(event=event)
|
||||
|
||||
agenda_slugs = '%s,%s' % (first_agenda.slug, second_agenda.slug)
|
||||
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs})
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs})
|
||||
assert len(ctx.captured_queries) == 3
|
||||
assert len(resp.json['data']) == 5
|
||||
assert resp.json['data'][0]['id'] == 'first-agenda@recurring--2021-05-06-1700'
|
||||
assert resp.json['data'][0]['text'] == 'Recurring (May 6, 2021, 5 p.m.)'
|
||||
assert resp.json['data'][0]['label'] == 'Recurring'
|
||||
assert resp.json['data'][0]['primary_event'] == 'first-agenda@recurring'
|
||||
assert resp.json['data'][1]['id'] == 'first-agenda@event'
|
||||
assert resp.json['data'][1]['text'] == 'May 11, 2021, 4 p.m.'
|
||||
assert resp.json['data'][1]['text'] == 'Event'
|
||||
assert resp.json['data'][1]['label'] == 'Event'
|
||||
assert resp.json['data'][1]['primary_event'] is None
|
||||
assert resp.json['data'][1]['places']['available'] == 5
|
||||
|
||||
assert resp.json['data'][2]['id'] == 'second-agenda@event'
|
||||
|
|
|
@ -434,7 +434,7 @@ def test_recurring_events_api_list_multiple_agendas_queries(app):
|
|||
'/api/agendas/recurring-events/?subscribed=category-a&user_external_id=xxx&guardian_external_id=father_id'
|
||||
)
|
||||
assert len(resp.json['data']) == 40
|
||||
assert len(ctx.captured_queries) == 5
|
||||
assert len(ctx.captured_queries) == 6
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-09-06 12:00')
|
||||
|
|
|
@ -936,6 +936,7 @@ def test_api_events_fillslots_multiple_agendas_revert(app, user):
|
|||
'cancelled_events': [
|
||||
{
|
||||
'agenda_label': 'Foo bar',
|
||||
'agenda_slug': 'foo-bar',
|
||||
'check_locked': False,
|
||||
'checked': False,
|
||||
'date': '2021-02-28',
|
||||
|
@ -950,6 +951,7 @@ def test_api_events_fillslots_multiple_agendas_revert(app, user):
|
|||
'slug': 'event',
|
||||
'text': 'Event',
|
||||
'url': None,
|
||||
'primary_event': None,
|
||||
}
|
||||
],
|
||||
'deleted_booking_count': 0,
|
||||
|
@ -972,6 +974,7 @@ def test_api_events_fillslots_multiple_agendas_revert(app, user):
|
|||
'cancelled_events': [
|
||||
{
|
||||
'agenda_label': 'Foo bar',
|
||||
'agenda_slug': 'foo-bar',
|
||||
'check_locked': False,
|
||||
'checked': False,
|
||||
'date': '2021-02-28',
|
||||
|
@ -986,6 +989,7 @@ def test_api_events_fillslots_multiple_agendas_revert(app, user):
|
|||
'slug': 'event',
|
||||
'text': 'Event',
|
||||
'url': None,
|
||||
'primary_event': None,
|
||||
}
|
||||
],
|
||||
'deleted_booking_count': 0,
|
||||
|
@ -1014,6 +1018,7 @@ def test_api_events_fillslots_multiple_agendas_revert(app, user):
|
|||
'booked_events': [
|
||||
{
|
||||
'agenda_label': 'Foo bar',
|
||||
'agenda_slug': 'foo-bar',
|
||||
'check_locked': False,
|
||||
'checked': False,
|
||||
'date': '2021-02-28',
|
||||
|
@ -1028,6 +1033,7 @@ def test_api_events_fillslots_multiple_agendas_revert(app, user):
|
|||
'slug': 'event',
|
||||
'text': 'Event',
|
||||
'url': None,
|
||||
'primary_event': None,
|
||||
}
|
||||
],
|
||||
}
|
||||
|
@ -1050,6 +1056,7 @@ def test_api_events_fillslots_multiple_agendas_revert(app, user):
|
|||
'booked_events': [
|
||||
{
|
||||
'agenda_label': 'Foo bar',
|
||||
'agenda_slug': 'foo-bar',
|
||||
'check_locked': False,
|
||||
'checked': False,
|
||||
'date': '2021-02-28',
|
||||
|
@ -1064,6 +1071,7 @@ def test_api_events_fillslots_multiple_agendas_revert(app, user):
|
|||
'slug': 'event',
|
||||
'text': 'Event',
|
||||
'url': None,
|
||||
'primary_event': None,
|
||||
}
|
||||
],
|
||||
}
|
||||
|
@ -1086,6 +1094,7 @@ def test_api_events_fillslots_multiple_agendas_revert(app, user):
|
|||
'deleted_events': [
|
||||
{
|
||||
'agenda_label': 'Foo bar',
|
||||
'agenda_slug': 'foo-bar',
|
||||
'check_locked': False,
|
||||
'checked': False,
|
||||
'date': '2021-02-28',
|
||||
|
@ -1100,6 +1109,7 @@ def test_api_events_fillslots_multiple_agendas_revert(app, user):
|
|||
'slug': 'event',
|
||||
'text': 'Event',
|
||||
'url': None,
|
||||
'primary_event': None,
|
||||
}
|
||||
],
|
||||
'booked_booking_count': 0,
|
||||
|
@ -1124,6 +1134,7 @@ def test_api_events_fillslots_multiple_agendas_revert(app, user):
|
|||
'deleted_events': [
|
||||
{
|
||||
'agenda_label': 'Foo bar',
|
||||
'agenda_slug': 'foo-bar',
|
||||
'check_locked': False,
|
||||
'checked': False,
|
||||
'date': '2021-02-28',
|
||||
|
@ -1138,6 +1149,7 @@ def test_api_events_fillslots_multiple_agendas_revert(app, user):
|
|||
'slug': 'event',
|
||||
'text': 'Event',
|
||||
'url': None,
|
||||
'primary_event': None,
|
||||
}
|
||||
],
|
||||
'booked_booking_count': 0,
|
||||
|
@ -1169,10 +1181,14 @@ def test_api_events_fillslots_multiple_agendas_revert(app, user):
|
|||
duration=120,
|
||||
places=1,
|
||||
agenda=agenda,
|
||||
recurrence_days=[7],
|
||||
recurrence_end_date=now() + datetime.timedelta(days=14), # 2 weeks
|
||||
)
|
||||
event.create_all_recurrences()
|
||||
event = event.recurrences.first()
|
||||
Booking.objects.create(
|
||||
event=event, request_uuid=request_uuid, previous_state='unbooked', cancellation_datetime=now()
|
||||
)
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = app.post(revert_url)
|
||||
assert len(ctx.captured_queries) == 14
|
||||
assert len(ctx.captured_queries) == 15
|
||||
|
|
|
@ -107,7 +107,7 @@ def test_recurring_events_api_fillslots(app, user, freezer, action):
|
|||
params['user_external_id'] = 'user_id_3'
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert len(ctx.captured_queries) in [12, 13]
|
||||
assert len(ctx.captured_queries) in [15, 16]
|
||||
# everything goes in waiting list
|
||||
assert events.filter(booked_waiting_list_places=1).count() == 6
|
||||
# but an event was full
|
||||
|
@ -1368,7 +1368,7 @@ def test_recurring_events_api_fillslots_multiple_agendas_queries(app, user):
|
|||
)
|
||||
assert resp.json['booking_count'] == 180
|
||||
assert resp.json['cancelled_booking_count'] == 0
|
||||
assert len(ctx.captured_queries) == 15
|
||||
assert len(ctx.captured_queries) == 17
|
||||
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = app.post_json(
|
||||
|
@ -1382,7 +1382,7 @@ def test_recurring_events_api_fillslots_multiple_agendas_queries(app, user):
|
|||
)
|
||||
assert resp.json['booking_count'] == 0
|
||||
assert resp.json['cancelled_booking_count'] == 5
|
||||
assert len(ctx.captured_queries) == 17
|
||||
assert len(ctx.captured_queries) == 18
|
||||
|
||||
father = Person.objects.create(user_external_id='father_id', first_name='John', last_name='Doe')
|
||||
mother = Person.objects.create(user_external_id='mother_id', first_name='Jane', last_name='Doe')
|
||||
|
@ -1401,7 +1401,7 @@ def test_recurring_events_api_fillslots_multiple_agendas_queries(app, user):
|
|||
params={'slots': events_to_book, 'user_external_id': 'xxx'},
|
||||
)
|
||||
assert resp.json['booking_count'] == 100
|
||||
assert len(ctx.captured_queries) == 14
|
||||
assert len(ctx.captured_queries) == 16
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2022-03-07 14:00') # Monday of 10th week
|
||||
|
|
|
@ -320,7 +320,7 @@ def test_agendas_api(settings, app):
|
|||
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = app.get('/api/agenda/', params={'with_open_events': '1'})
|
||||
assert len(ctx.captured_queries) == 3
|
||||
assert len(ctx.captured_queries) == 4
|
||||
|
||||
|
||||
def test_agenda_detail_api(app):
|
||||
|
|
|
@ -375,8 +375,7 @@ def test_unknown_compoment_type_dependencies(app, admin_user):
|
|||
app.get('/api/export-import/unknown/foo/dependencies/', status=404)
|
||||
|
||||
|
||||
def test_redirect(app, user):
|
||||
app.authorization = ('Basic', ('john', 'doe'))
|
||||
def test_redirect(app):
|
||||
agenda = Agenda.objects.create(label='Rdv', slug='rdv', kind='meetings')
|
||||
category = Category.objects.create(slug='cat', label='Category')
|
||||
resource = Resource.objects.create(slug='foo', label='Foo')
|
||||
|
@ -541,7 +540,7 @@ def test_bundle_import(app, admin_user):
|
|||
EventsType.objects.all().delete()
|
||||
UnavailabilityCalendar.objects.all().delete()
|
||||
|
||||
resp = app.put('/api/export-import/bundle-import/', bundles[0])
|
||||
resp = app.post('/api/export-import/bundle-import/', upload_files=[('bundle', 'bundle.tar', bundles[0])])
|
||||
assert Agenda.objects.all().count() == 4
|
||||
assert resp.json['err'] == 0
|
||||
assert Application.objects.count() == 1
|
||||
|
@ -576,7 +575,7 @@ def test_bundle_import(app, admin_user):
|
|||
)
|
||||
|
||||
# check update
|
||||
resp = app.put('/api/export-import/bundle-import/', bundles[1])
|
||||
resp = app.post('/api/export-import/bundle-import/', upload_files=[('bundle', 'bundle.tar', bundles[1])])
|
||||
assert Agenda.objects.all().count() == 4
|
||||
assert resp.json['err'] == 0
|
||||
assert Application.objects.count() == 1
|
||||
|
@ -599,7 +598,9 @@ def test_bundle_import(app, admin_user):
|
|||
assert last_snapshot.application_version == '42.1'
|
||||
|
||||
# bad file format
|
||||
resp = app.put('/api/export-import/bundle-import/', b'garbage')
|
||||
resp = app.post(
|
||||
'/api/export-import/bundle-import/', upload_files=[('bundle', 'bundle.tar', b'garbage')], status=400
|
||||
)
|
||||
assert resp.json['err']
|
||||
assert resp.json['err_desc'] == 'Invalid tar file'
|
||||
|
||||
|
@ -610,7 +611,11 @@ def test_bundle_import(app, admin_user):
|
|||
tarinfo = tarfile.TarInfo('foo.json')
|
||||
tarinfo.size = len(foo_fd.getvalue())
|
||||
tar.addfile(tarinfo, fileobj=foo_fd)
|
||||
resp = app.put('/api/export-import/bundle-import/', tar_io.getvalue())
|
||||
resp = app.post(
|
||||
'/api/export-import/bundle-import/',
|
||||
upload_files=[('bundle', 'bundle.tar', tar_io.getvalue())],
|
||||
status=400,
|
||||
)
|
||||
assert resp.json['err']
|
||||
assert resp.json['err_desc'] == 'Invalid tar file, missing manifest'
|
||||
|
||||
|
@ -626,7 +631,11 @@ def test_bundle_import(app, admin_user):
|
|||
tarinfo = tarfile.TarInfo('manifest.json')
|
||||
tarinfo.size = len(manifest_fd.getvalue())
|
||||
tar.addfile(tarinfo, fileobj=manifest_fd)
|
||||
resp = app.put('/api/export-import/bundle-import/', tar_io.getvalue())
|
||||
resp = app.post(
|
||||
'/api/export-import/bundle-import/',
|
||||
upload_files=[('bundle', 'bundle.tar', tar_io.getvalue())],
|
||||
status=400,
|
||||
)
|
||||
assert resp.json['err']
|
||||
assert resp.json['err_desc'] == 'Invalid tar file, missing component agendas/foo'
|
||||
|
||||
|
@ -635,7 +644,7 @@ def test_bundle_declare(app, admin_user):
|
|||
app.authorization = ('Basic', ('admin', 'admin'))
|
||||
|
||||
bundle = create_bundle(app, admin_user, visible=False)
|
||||
resp = app.put('/api/export-import/bundle-declare/', bundle)
|
||||
resp = app.post('/api/export-import/bundle-declare/', upload_files=[('bundle', 'bundle.tar', bundle)])
|
||||
assert Agenda.objects.all().count() == 4
|
||||
assert resp.json['err'] == 0
|
||||
assert Application.objects.count() == 1
|
||||
|
@ -662,14 +671,16 @@ def test_bundle_declare(app, admin_user):
|
|||
# and remove agendas to have unknown references in manifest
|
||||
Agenda.objects.all().delete()
|
||||
|
||||
resp = app.put('/api/export-import/bundle-declare/', bundle)
|
||||
resp = app.post('/api/export-import/bundle-declare/', upload_files=[('bundle', 'bundle.tar', bundle)])
|
||||
assert Application.objects.count() == 1
|
||||
application = Application.objects.latest('pk')
|
||||
assert application.visible is True
|
||||
assert ApplicationElement.objects.count() == 4 # category, events_type, unavailability_calendar, resource
|
||||
|
||||
# bad file format
|
||||
resp = app.put('/api/export-import/bundle-declare/', b'garbage')
|
||||
resp = app.post(
|
||||
'/api/export-import/bundle-declare/', upload_files=[('bundle', 'bundle.tar', b'garbage')], status=400
|
||||
)
|
||||
assert resp.json['err']
|
||||
assert resp.json['err_desc'] == 'Invalid tar file'
|
||||
|
||||
|
@ -680,7 +691,11 @@ def test_bundle_declare(app, admin_user):
|
|||
tarinfo = tarfile.TarInfo('foo.json')
|
||||
tarinfo.size = len(foo_fd.getvalue())
|
||||
tar.addfile(tarinfo, fileobj=foo_fd)
|
||||
resp = app.put('/api/export-import/bundle-declare/', tar_io.getvalue())
|
||||
resp = app.post(
|
||||
'/api/export-import/bundle-declare/',
|
||||
upload_files=[('bundle', 'bundle.tar', tar_io.getvalue())],
|
||||
status=400,
|
||||
)
|
||||
assert resp.json['err']
|
||||
assert resp.json['err_desc'] == 'Invalid tar file, missing manifest'
|
||||
|
||||
|
@ -696,7 +711,11 @@ def test_bundle_declare(app, admin_user):
|
|||
tarinfo = tarfile.TarInfo('manifest.json')
|
||||
tarinfo.size = len(manifest_fd.getvalue())
|
||||
tar.addfile(tarinfo, fileobj=manifest_fd)
|
||||
resp = app.put('/api/export-import/bundle-declare/', tar_io.getvalue())
|
||||
resp = app.post(
|
||||
'/api/export-import/bundle-declare/',
|
||||
upload_files=[('bundle', 'bundle.tar', tar_io.getvalue())],
|
||||
status=400,
|
||||
)
|
||||
assert resp.json['err']
|
||||
assert resp.json['err_desc'] == 'Invalid tar file, missing component agendas/foo'
|
||||
|
||||
|
@ -779,13 +798,17 @@ def test_bundle_check(app, admin_user):
|
|||
incomplete_bundles.append(tar_io.getvalue())
|
||||
|
||||
# incorrect bundles, missing information
|
||||
resp = app.put('/api/export-import/bundle-check/', incomplete_bundles[0])
|
||||
resp = app.post(
|
||||
'/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', incomplete_bundles[0])]
|
||||
)
|
||||
assert resp.json == {'data': {}}
|
||||
resp = app.put('/api/export-import/bundle-check/', incomplete_bundles[1])
|
||||
resp = app.post(
|
||||
'/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', incomplete_bundles[1])]
|
||||
)
|
||||
assert resp.json == {'data': {}}
|
||||
|
||||
# not yet imported
|
||||
resp = app.put('/api/export-import/bundle-check/', bundles[0])
|
||||
resp = app.post('/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', bundles[0])])
|
||||
assert resp.json == {
|
||||
'data': {
|
||||
'differences': [],
|
||||
|
@ -805,13 +828,13 @@ def test_bundle_check(app, admin_user):
|
|||
}
|
||||
|
||||
# import bundle
|
||||
resp = app.put('/api/export-import/bundle-import/', bundles[0])
|
||||
resp = app.post('/api/export-import/bundle-import/', upload_files=[('bundle', 'bundle.tar', bundles[0])])
|
||||
assert Application.objects.count() == 1
|
||||
assert ApplicationElement.objects.count() == 8
|
||||
|
||||
# remove application links
|
||||
Application.objects.all().delete()
|
||||
resp = app.put('/api/export-import/bundle-check/', bundles[0])
|
||||
resp = app.post('/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', bundles[0])])
|
||||
assert resp.json == {
|
||||
'data': {
|
||||
'differences': [],
|
||||
|
@ -871,12 +894,12 @@ def test_bundle_check(app, admin_user):
|
|||
}
|
||||
|
||||
# import bundle again, recreate links
|
||||
resp = app.put('/api/export-import/bundle-import/', bundles[0])
|
||||
resp = app.post('/api/export-import/bundle-import/', upload_files=[('bundle', 'bundle.tar', bundles[0])])
|
||||
assert Application.objects.count() == 1
|
||||
assert ApplicationElement.objects.count() == 8
|
||||
|
||||
# no changes since last import
|
||||
resp = app.put('/api/export-import/bundle-check/', bundles[0])
|
||||
resp = app.post('/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', bundles[0])])
|
||||
assert resp.json == {
|
||||
'data': {
|
||||
'differences': [],
|
||||
|
@ -901,7 +924,7 @@ def test_bundle_check(app, admin_user):
|
|||
)
|
||||
|
||||
# and check
|
||||
resp = app.put('/api/export-import/bundle-check/', bundles[0])
|
||||
resp = app.post('/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', bundles[0])])
|
||||
assert resp.json == {
|
||||
'data': {
|
||||
'differences': [
|
||||
|
@ -993,10 +1016,10 @@ def test_bundle_check(app, admin_user):
|
|||
}
|
||||
|
||||
# update bundle
|
||||
resp = app.put('/api/export-import/bundle-import/', bundles[1])
|
||||
resp = app.post('/api/export-import/bundle-import/', upload_files=[('bundle', 'bundle.tar', bundles[1])])
|
||||
|
||||
# and check
|
||||
resp = app.put('/api/export-import/bundle-check/', bundles[1])
|
||||
resp = app.post('/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', bundles[1])])
|
||||
assert resp.json == {
|
||||
'data': {
|
||||
'differences': [],
|
||||
|
@ -1008,7 +1031,7 @@ def test_bundle_check(app, admin_user):
|
|||
|
||||
# snapshots without application info
|
||||
AgendaSnapshot.objects.update(application_slug=None, application_version=None)
|
||||
resp = app.put('/api/export-import/bundle-check/', bundles[1])
|
||||
resp = app.post('/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', bundles[1])])
|
||||
assert resp.json == {
|
||||
'data': {
|
||||
'differences': [],
|
||||
|
@ -1024,7 +1047,9 @@ def test_bundle_check(app, admin_user):
|
|||
}
|
||||
|
||||
# bad file format
|
||||
resp = app.put('/api/export-import/bundle-check/', b'garbage')
|
||||
resp = app.post(
|
||||
'/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', b'garbage')], status=400
|
||||
)
|
||||
assert resp.json['err']
|
||||
assert resp.json['err_desc'] == 'Invalid tar file'
|
||||
|
||||
|
@ -1035,6 +1060,10 @@ def test_bundle_check(app, admin_user):
|
|||
tarinfo = tarfile.TarInfo('foo.json')
|
||||
tarinfo.size = len(foo_fd.getvalue())
|
||||
tar.addfile(tarinfo, fileobj=foo_fd)
|
||||
resp = app.put('/api/export-import/bundle-check/', tar_io.getvalue())
|
||||
resp = app.post(
|
||||
'/api/export-import/bundle-check/',
|
||||
upload_files=[('bundle', 'bundle.tar', tar_io.getvalue())],
|
||||
status=400,
|
||||
)
|
||||
assert resp.json['err']
|
||||
assert resp.json['err_desc'] == 'Invalid tar file, missing manifest'
|
||||
|
|
|
@ -188,7 +188,7 @@ def test_bookings_api(app, user):
|
|||
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = app.get('/api/bookings/', params={'user_external_id': 'enfant-1234'})
|
||||
assert len(ctx.captured_queries) == 3
|
||||
assert len(ctx.captured_queries) == 6
|
||||
|
||||
assert resp.json['err'] == 0
|
||||
assert resp.json['data'] == [
|
||||
|
|
|
@ -44,9 +44,11 @@ def test_status(app, user):
|
|||
'err': 0,
|
||||
'id': 'event-slug',
|
||||
'slug': 'event-slug',
|
||||
'primary_event': None,
|
||||
'text': str(event),
|
||||
'label': '',
|
||||
'agenda_label': 'Foo bar',
|
||||
'agenda_slug': 'foo-bar',
|
||||
'date': localtime(event.start_datetime).strftime('%Y-%m-%d'),
|
||||
'datetime': localtime(event.start_datetime).strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'end_datetime': '',
|
||||
|
@ -84,9 +86,11 @@ def test_status(app, user):
|
|||
'err': 0,
|
||||
'id': 'event-slug',
|
||||
'slug': 'event-slug',
|
||||
'primary_event': None,
|
||||
'text': str(event),
|
||||
'label': '',
|
||||
'agenda_label': 'Foo bar',
|
||||
'agenda_slug': 'foo-bar',
|
||||
'date': localtime(event.start_datetime).strftime('%Y-%m-%d'),
|
||||
'datetime': localtime(event.start_datetime).strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'end_datetime': '',
|
||||
|
|
|
@ -57,7 +57,7 @@ def test_agenda_history(settings, app, admin_user):
|
|||
assert resp.text.count('<del>') == 0
|
||||
else:
|
||||
assert resp.text.count('diff_sub') == 1
|
||||
assert resp.text.count('diff_add') == 16
|
||||
assert resp.text.count('diff_add') == 17
|
||||
assert resp.text.count('diff_chg') == 0
|
||||
resp = app.get(
|
||||
'/manage/agendas/%s/history/compare/?version1=%s&version2=%s'
|
||||
|
@ -66,7 +66,7 @@ def test_agenda_history(settings, app, admin_user):
|
|||
assert 'Snapshot (%s)' % (snapshot1.pk) in resp
|
||||
assert 'Snapshot (%s) - (Version 42.0)' % (snapshot2.pk) in resp
|
||||
assert resp.text.count('diff_sub') == 1
|
||||
assert resp.text.count('diff_add') == 16
|
||||
assert resp.text.count('diff_add') == 17
|
||||
assert resp.text.count('diff_chg') == 0
|
||||
|
||||
# check compare on application version number
|
||||
|
@ -95,6 +95,11 @@ def test_agenda_history(settings, app, admin_user):
|
|||
assert 'Snapshot (%s) - (Version 41.0)' % snapshot1.pk in resp
|
||||
assert 'Snapshot (%s) - (Version 42.0)' % snapshot2.pk in resp
|
||||
|
||||
assert AgendaSnapshot.objects.update(user=admin_user)
|
||||
admin_user.delete()
|
||||
assert AgendaSnapshot.objects.count() == 2
|
||||
assert AgendaSnapshot.objects.filter(user__isnull=True).count() == 2
|
||||
|
||||
|
||||
def test_agenda_history_as_manager(app, manager_user):
|
||||
agenda = Agenda.objects.create(slug='foo', label='Foo')
|
||||
|
@ -195,6 +200,11 @@ def test_category_history(settings, app, admin_user):
|
|||
assert 'Snapshot (%s) - (Version 41.0)' % snapshot1.pk in resp
|
||||
assert 'Snapshot (%s) - (Version 42.0)' % snapshot2.pk in resp
|
||||
|
||||
assert CategorySnapshot.objects.update(user=admin_user)
|
||||
admin_user.delete()
|
||||
assert CategorySnapshot.objects.count() == 2
|
||||
assert CategorySnapshot.objects.filter(user__isnull=True).count() == 2
|
||||
|
||||
|
||||
def test_events_type_history(settings, app, admin_user):
|
||||
events_type = EventsType.objects.create(slug='foo', label='Foo')
|
||||
|
@ -273,6 +283,11 @@ def test_events_type_history(settings, app, admin_user):
|
|||
assert 'Snapshot (%s) - (Version 41.0)' % snapshot1.pk in resp
|
||||
assert 'Snapshot (%s) - (Version 42.0)' % snapshot2.pk in resp
|
||||
|
||||
assert EventsTypeSnapshot.objects.update(user=admin_user)
|
||||
admin_user.delete()
|
||||
assert EventsTypeSnapshot.objects.count() == 2
|
||||
assert EventsTypeSnapshot.objects.filter(user__isnull=True).count() == 2
|
||||
|
||||
|
||||
def test_resource_history(settings, app, admin_user):
|
||||
resource = Resource.objects.create(slug='foo', label='Foo')
|
||||
|
@ -347,6 +362,11 @@ def test_resource_history(settings, app, admin_user):
|
|||
assert 'Snapshot (%s) - (Version 41.0)' % snapshot1.pk in resp
|
||||
assert 'Snapshot (%s) - (Version 42.0)' % snapshot2.pk in resp
|
||||
|
||||
assert ResourceSnapshot.objects.update(user=admin_user)
|
||||
admin_user.delete()
|
||||
assert ResourceSnapshot.objects.count() == 2
|
||||
assert ResourceSnapshot.objects.filter(user__isnull=True).count() == 2
|
||||
|
||||
|
||||
def test_unavailability_calendar_history(settings, app, admin_user):
|
||||
unavailability_calendar = UnavailabilityCalendar.objects.create(slug='foo', label='Foo')
|
||||
|
@ -425,6 +445,11 @@ def test_unavailability_calendar_history(settings, app, admin_user):
|
|||
assert 'Snapshot (%s) - (Version 41.0)' % snapshot1.pk in resp
|
||||
assert 'Snapshot (%s) - (Version 42.0)' % snapshot2.pk in resp
|
||||
|
||||
assert UnavailabilityCalendarSnapshot.objects.update(user=admin_user)
|
||||
admin_user.delete()
|
||||
assert UnavailabilityCalendarSnapshot.objects.count() == 2
|
||||
assert UnavailabilityCalendarSnapshot.objects.filter(user__isnull=True).count() == 2
|
||||
|
||||
|
||||
def test_unavailability_calendar_history_as_manager(app, manager_user):
|
||||
unavailability_calendar = UnavailabilityCalendar.objects.create(slug='foo', label='Foo')
|
||||
|
|
|
@ -181,6 +181,25 @@ def test_import_export_bad_date_format(app):
|
|||
assert '%s' % excinfo.value == 'Bad datetime format "17-05-22 08:00:00"'
|
||||
|
||||
|
||||
def test_import_export_bad_end_time_format(app):
|
||||
agenda_events = Agenda.objects.create(label='Events Agenda', kind='events')
|
||||
Desk.objects.create(agenda=agenda_events, slug='_exceptions_holder')
|
||||
Event.objects.create(
|
||||
agenda=agenda_events,
|
||||
start_datetime=make_aware(datetime.datetime(2020, 7, 21, 16, 42, 35)),
|
||||
places=10,
|
||||
end_time=datetime.time(20, 00),
|
||||
)
|
||||
|
||||
output = get_output_of_command('export_site')
|
||||
payload = json.loads(output)
|
||||
assert len(payload['agendas']) == 1
|
||||
payload['agendas'][0]['events'][0]['end_time'] = 'xxx20:00'
|
||||
with pytest.raises(AgendaImportError) as excinfo:
|
||||
import_site(payload)
|
||||
assert '%s' % excinfo.value == 'Bad time format "xxx20:00"'
|
||||
|
||||
|
||||
def test_import_export_events_agenda_options(app):
|
||||
agenda = Agenda.objects.create(
|
||||
label='Foo Bar',
|
||||
|
@ -256,6 +275,7 @@ def test_import_export_event_details(app):
|
|||
publication_datetime=make_aware(datetime.datetime(2020, 5, 11)),
|
||||
places=42,
|
||||
start_datetime=now(),
|
||||
end_time=datetime.time(20, 00),
|
||||
duration=30,
|
||||
)
|
||||
# check event (agenda, slug) unicity
|
||||
|
@ -287,6 +307,7 @@ def test_import_export_event_details(app):
|
|||
assert str(first_imported_event.publication_datetime) == '2020-05-10 22:00:00+00:00'
|
||||
assert str(first_imported_event.publication_datetime.tzinfo) == 'UTC'
|
||||
assert first_imported_event.duration == 30
|
||||
assert first_imported_event.end_time == datetime.time(20, 00)
|
||||
assert Agenda.objects.get(label='Foo Bar 2').event_set.first().slug == 'event'
|
||||
|
||||
|
||||
|
@ -297,6 +318,7 @@ def test_import_export_recurring_event(app, freezer):
|
|||
event = Event.objects.create(
|
||||
agenda=agenda,
|
||||
start_datetime=now(),
|
||||
end_time=datetime.time(20, 00),
|
||||
recurrence_days=[now().isoweekday()],
|
||||
recurrence_week_interval=2,
|
||||
places=10,
|
||||
|
@ -353,6 +375,7 @@ def test_import_export_recurring_event(app, freezer):
|
|||
|
||||
event = Event.objects.get(slug='test')
|
||||
assert event.places == 42
|
||||
assert event.end_time == datetime.time(20, 00)
|
||||
assert Event.objects.filter(primary_event=event, places=42).count() == 1
|
||||
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@ def test_meeting_event_exclusion_constraint():
|
|||
)
|
||||
|
||||
|
||||
def test_clean_time_period_exceptions(transactional_db):
|
||||
def test_clean_time_period_exceptions():
|
||||
app = 'agendas'
|
||||
|
||||
migrate_from = [(app, '0065_unavailability_calendar')]
|
||||
|
@ -297,7 +297,7 @@ def test_clean_time_period_exceptions(transactional_db):
|
|||
|
||||
|
||||
@override_settings(LANGUAGE_CODE='fr-fr')
|
||||
def test_translate_holidays_exceptions(transactional_db):
|
||||
def test_translate_holidays_exceptions():
|
||||
app = 'agendas'
|
||||
|
||||
migrate_from = [(app, '0068_remove_timeperiodexception_external')]
|
||||
|
@ -344,7 +344,7 @@ def test_translate_holidays_exceptions(transactional_db):
|
|||
assert desk.timeperiodexception_set.filter(label='Jour de l’An').count() == 1
|
||||
|
||||
|
||||
def test_migration_convert_week_days(transactional_db):
|
||||
def test_migration_convert_week_days():
|
||||
app = 'agendas'
|
||||
|
||||
migrate_from = [(app, '0156_update_dow_index')]
|
||||
|
@ -392,7 +392,7 @@ def test_migration_convert_week_days(transactional_db):
|
|||
assert SharedCustodyRule.objects.get().days == [1, 5, 7]
|
||||
|
||||
|
||||
def test_migration_booking_check_data(transactional_db):
|
||||
def test_migration_booking_check_data():
|
||||
app = 'agendas'
|
||||
|
||||
migrate_from = [(app, '0161_add_booking_check_model')]
|
||||
|
|
Loading…
Reference in New Issue