manager: inspect views (#87751)
This commit is contained in:
parent
ecf0ffd96e
commit
bd06f2b82f
|
@ -10,6 +10,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AddField(
|
||||
model_name='agenda',
|
||||
name='desk_simple_management',
|
||||
field=models.BooleanField(default=False),
|
||||
field=models.BooleanField(default=False, verbose_name='Global desk management'),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -62,13 +62,14 @@ from django.template import (
|
|||
VariableDoesNotExist,
|
||||
engines,
|
||||
)
|
||||
from django.template.defaultfilters import yesno
|
||||
from django.urls import reverse
|
||||
from django.utils import functional
|
||||
from django.utils.dates import WEEKDAYS
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.formats import date_format
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.html import escape
|
||||
from django.utils.html import escape, linebreaks
|
||||
from django.utils.module_loading import import_string
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.text import slugify
|
||||
|
@ -177,12 +178,35 @@ def booking_template_validator(value):
|
|||
pass
|
||||
|
||||
|
||||
class WithInspectMixin:
|
||||
def get_inspect_fields(self, keys=None):
|
||||
keys = keys or self.get_inspect_keys()
|
||||
for key in keys:
|
||||
field = self._meta.get_field(key)
|
||||
get_value_method = 'get_%s_inspect_value' % key
|
||||
get_display_method = 'get_%s_display' % key
|
||||
if hasattr(self, get_value_method):
|
||||
value = getattr(self, get_value_method)()
|
||||
elif hasattr(self, get_display_method):
|
||||
value = getattr(self, get_display_method)()
|
||||
else:
|
||||
value = getattr(self, key)
|
||||
if value in [None, '']:
|
||||
continue
|
||||
if isinstance(value, bool):
|
||||
value = yesno(value)
|
||||
if isinstance(field, models.TextField):
|
||||
value = mark_safe(linebreaks(value))
|
||||
yield (field.verbose_name, value)
|
||||
|
||||
|
||||
TimeSlot = collections.namedtuple(
|
||||
'TimeSlot', ['start_datetime', 'end_datetime', 'full', 'desk', 'booked_for_external_user']
|
||||
)
|
||||
|
||||
|
||||
class Agenda(WithSnapshotMixin, WithApplicationMixin, models.Model):
|
||||
# pylint: disable=too-many-public-methods
|
||||
class Agenda(WithSnapshotMixin, WithApplicationMixin, WithInspectMixin, models.Model):
|
||||
# mark temporarily restored snapshots
|
||||
snapshot = models.ForeignKey(
|
||||
AgendaSnapshot, on_delete=models.CASCADE, null=True, related_name='temporary_instance'
|
||||
|
@ -250,7 +274,7 @@ class Agenda(WithSnapshotMixin, WithApplicationMixin, models.Model):
|
|||
booking_form_url = models.CharField(
|
||||
_('Booking form URL'), max_length=200, blank=True, validators=[django_template_validator]
|
||||
)
|
||||
desk_simple_management = models.BooleanField(default=False)
|
||||
desk_simple_management = models.BooleanField(_('Global desk management'), default=False)
|
||||
mark_event_checked_auto = models.BooleanField(
|
||||
_('Automatically mark event as checked when all bookings have been checked'), default=False
|
||||
)
|
||||
|
@ -625,6 +649,62 @@ class Agenda(WithSnapshotMixin, WithApplicationMixin, models.Model):
|
|||
|
||||
return created, agenda
|
||||
|
||||
def get_inspect_keys(self):
|
||||
keys = ['label', 'slug', 'kind', 'category', 'anonymize_delay', 'default_view']
|
||||
if self.kind == 'events':
|
||||
keys += ['booking_form_url', 'events_type']
|
||||
elif self.kind == 'meetings':
|
||||
keys += ['desk_simple_management']
|
||||
return keys
|
||||
|
||||
def get_permissions_inspect_fields(self):
|
||||
yield from self.get_inspect_fields(keys=['edit_role', 'view_role'])
|
||||
|
||||
def get_display_inspect_fields(self):
|
||||
keys = []
|
||||
if self.kind == 'events':
|
||||
keys += ['event_display_template']
|
||||
keys += [
|
||||
'booking_user_block_template',
|
||||
]
|
||||
yield from self.get_inspect_fields(keys=keys)
|
||||
|
||||
def get_booking_check_inspect_fields(self):
|
||||
keys = [
|
||||
'booking_check_filters',
|
||||
'mark_event_checked_auto',
|
||||
'disable_check_update',
|
||||
'enable_check_for_future_events',
|
||||
'booking_extra_user_block_template',
|
||||
]
|
||||
yield from self.get_inspect_fields(keys=keys)
|
||||
|
||||
def get_invoicing_inspect_fields(self):
|
||||
keys = ['invoicing_unit', 'invoicing_tolerance']
|
||||
yield from self.get_inspect_fields(keys=keys)
|
||||
|
||||
def get_notifications_inspect_fields(self):
|
||||
if hasattr(self, 'notifications_settings'):
|
||||
yield from self.notifications_settings.get_inspect_fields()
|
||||
return []
|
||||
|
||||
def get_reminder_inspect_fields(self):
|
||||
if hasattr(self, 'reminder_settings'):
|
||||
yield from self.reminder_settings.get_inspect_fields()
|
||||
return []
|
||||
|
||||
def get_booking_delays_inspect_fields(self):
|
||||
keys = [
|
||||
'minimal_booking_delay',
|
||||
'minimal_booking_delay_in_working_days',
|
||||
'maximal_booking_delay',
|
||||
'minimal_booking_time',
|
||||
]
|
||||
yield from self.get_inspect_fields(keys=keys)
|
||||
|
||||
def get_kind_inspect_value(self):
|
||||
return self.get_real_kind_display()
|
||||
|
||||
def duplicate(self, label=None):
|
||||
# clone current agenda
|
||||
new_agenda = copy.deepcopy(self)
|
||||
|
@ -1761,7 +1841,7 @@ WEEK_CHOICES = [
|
|||
]
|
||||
|
||||
|
||||
class TimePeriod(models.Model):
|
||||
class TimePeriod(WithInspectMixin, models.Model):
|
||||
weekday = models.IntegerField(_('Week day'), choices=WEEKDAYS_LIST, null=True)
|
||||
weekday_indexes = ArrayField(
|
||||
models.IntegerField(choices=WEEK_CHOICES),
|
||||
|
@ -1828,6 +1908,15 @@ class TimePeriod(models.Model):
|
|||
'end_time': self.end_time.strftime('%H:%M'),
|
||||
}
|
||||
|
||||
def get_inspect_keys(self):
|
||||
return [
|
||||
'weekday',
|
||||
'weekday_indexes',
|
||||
'date',
|
||||
'start_time',
|
||||
'end_time',
|
||||
]
|
||||
|
||||
def duplicate(self, desk_target=None, agenda_target=None):
|
||||
# clone current period
|
||||
new_period = copy.deepcopy(self)
|
||||
|
@ -2035,7 +2124,7 @@ class SharedTimePeriod:
|
|||
start_datetime += datetime.timedelta(days=7)
|
||||
|
||||
|
||||
class MeetingType(models.Model):
|
||||
class MeetingType(WithInspectMixin, models.Model):
|
||||
agenda = models.ForeignKey(Agenda, on_delete=models.CASCADE)
|
||||
label = models.CharField(_('Label'), max_length=150)
|
||||
slug = models.SlugField(_('Identifier'), max_length=160)
|
||||
|
@ -2072,6 +2161,13 @@ class MeetingType(models.Model):
|
|||
'duration': self.duration,
|
||||
}
|
||||
|
||||
def get_inspect_keys(self):
|
||||
return [
|
||||
'label',
|
||||
'slug',
|
||||
'duration',
|
||||
]
|
||||
|
||||
def duplicate(self, agenda_target=None):
|
||||
new_meeting_type = copy.deepcopy(self)
|
||||
new_meeting_type.pk = None
|
||||
|
@ -2093,7 +2189,7 @@ class MeetingType(models.Model):
|
|||
)
|
||||
|
||||
|
||||
class Event(models.Model):
|
||||
class Event(WithInspectMixin, models.Model):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
INTERVAL_CHOICES = [
|
||||
(1, _('Every week')),
|
||||
|
@ -2661,6 +2757,23 @@ class Event(models.Model):
|
|||
'duration': self.duration,
|
||||
}
|
||||
|
||||
def get_inspect_keys(self):
|
||||
return [
|
||||
'label',
|
||||
'slug',
|
||||
'description',
|
||||
'start_datetime',
|
||||
'duration',
|
||||
'recurrence_days',
|
||||
'recurrence_week_interval',
|
||||
'recurrence_end_date',
|
||||
'publication_datetime',
|
||||
'places',
|
||||
'waiting_list_places',
|
||||
'url',
|
||||
'pricing',
|
||||
]
|
||||
|
||||
def duplicate(self, agenda_target=None, primary_event=None, label=None, start_datetime=None):
|
||||
new_event = copy.deepcopy(self)
|
||||
new_event.pk = None
|
||||
|
@ -2845,7 +2958,7 @@ class Event(models.Model):
|
|||
return custom_fields
|
||||
|
||||
|
||||
class EventsType(WithSnapshotMixin, WithApplicationMixin, models.Model):
|
||||
class EventsType(WithSnapshotMixin, WithApplicationMixin, WithInspectMixin, models.Model):
|
||||
# mark temporarily restored snapshots
|
||||
snapshot = models.ForeignKey(
|
||||
EventsTypeSnapshot, on_delete=models.CASCADE, null=True, related_name='temporary_instance'
|
||||
|
@ -2918,6 +3031,9 @@ class EventsType(WithSnapshotMixin, WithApplicationMixin, models.Model):
|
|||
'custom_fields': self.custom_fields,
|
||||
}
|
||||
|
||||
def get_inspect_keys(self):
|
||||
return ['label', 'slug']
|
||||
|
||||
|
||||
class BookingColor(models.Model):
|
||||
COLOR_COUNT = 8
|
||||
|
@ -3312,7 +3428,7 @@ class BookingCheck(models.Model):
|
|||
OpeningHour = collections.namedtuple('OpeningHour', ['begin', 'end'])
|
||||
|
||||
|
||||
class Desk(models.Model):
|
||||
class Desk(WithInspectMixin, models.Model):
|
||||
agenda = models.ForeignKey(Agenda, on_delete=models.CASCADE)
|
||||
label = models.CharField(_('Label'), max_length=150)
|
||||
slug = models.SlugField(_('Identifier'), max_length=160)
|
||||
|
@ -3375,6 +3491,12 @@ class Desk(models.Model):
|
|||
'unavailability_calendars': [{'slug': x.slug} for x in self.unavailability_calendars.all()],
|
||||
}
|
||||
|
||||
def get_inspect_keys(self):
|
||||
return [
|
||||
'label',
|
||||
'slug',
|
||||
]
|
||||
|
||||
def duplicate(self, label=None, agenda_target=None, reset_slug=True):
|
||||
# clone current desk
|
||||
new_desk = copy.deepcopy(self)
|
||||
|
@ -3476,7 +3598,7 @@ class Desk(models.Model):
|
|||
).delete() # source was not in settings anymore
|
||||
|
||||
|
||||
class Resource(WithSnapshotMixin, WithApplicationMixin, models.Model):
|
||||
class Resource(WithSnapshotMixin, WithApplicationMixin, WithInspectMixin, models.Model):
|
||||
# mark temporarily restored snapshots
|
||||
snapshot = models.ForeignKey(
|
||||
ResourceSnapshot, on_delete=models.CASCADE, null=True, related_name='temporary_instance'
|
||||
|
@ -3539,8 +3661,11 @@ class Resource(WithSnapshotMixin, WithApplicationMixin, models.Model):
|
|||
'description': self.description,
|
||||
}
|
||||
|
||||
def get_inspect_keys(self):
|
||||
return ['label', 'slug', 'description']
|
||||
|
||||
class Category(WithSnapshotMixin, WithApplicationMixin, models.Model):
|
||||
|
||||
class Category(WithSnapshotMixin, WithApplicationMixin, WithInspectMixin, models.Model):
|
||||
# mark temporarily restored snapshots
|
||||
snapshot = models.ForeignKey(
|
||||
CategorySnapshot, on_delete=models.CASCADE, null=True, related_name='temporary_instance'
|
||||
|
@ -3595,12 +3720,15 @@ class Category(WithSnapshotMixin, WithApplicationMixin, models.Model):
|
|||
'slug': self.slug,
|
||||
}
|
||||
|
||||
def get_inspect_keys(self):
|
||||
return ['label', 'slug']
|
||||
|
||||
|
||||
def ics_directory_path(instance, filename):
|
||||
return f'ics/{str(uuid.uuid4())}/{filename}'
|
||||
|
||||
|
||||
class TimePeriodExceptionSource(models.Model):
|
||||
class TimePeriodExceptionSource(WithInspectMixin, models.Model):
|
||||
desk = models.ForeignKey(Desk, on_delete=models.CASCADE, null=True)
|
||||
unavailability_calendar = models.ForeignKey('UnavailabilityCalendar', on_delete=models.CASCADE, null=True)
|
||||
ics_filename = models.CharField(null=True, max_length=256)
|
||||
|
@ -3871,8 +3999,18 @@ class TimePeriodExceptionSource(models.Model):
|
|||
'enabled': self.enabled,
|
||||
}
|
||||
|
||||
def get_inspect_keys(self):
|
||||
return [
|
||||
'ics_filename',
|
||||
'ics_file',
|
||||
'ics_url',
|
||||
'settings_slug',
|
||||
'settings_label',
|
||||
'enabled',
|
||||
]
|
||||
|
||||
class UnavailabilityCalendar(WithSnapshotMixin, WithApplicationMixin, models.Model):
|
||||
|
||||
class UnavailabilityCalendar(WithSnapshotMixin, WithApplicationMixin, WithInspectMixin, models.Model):
|
||||
# mark temporarily restored snapshots
|
||||
snapshot = models.ForeignKey(
|
||||
UnavailabilityCalendarSnapshot, on_delete=models.CASCADE, null=True, related_name='temporary_instance'
|
||||
|
@ -3980,6 +4118,12 @@ class UnavailabilityCalendar(WithSnapshotMixin, WithApplicationMixin, models.Mod
|
|||
|
||||
return created, unavailability_calendar
|
||||
|
||||
def get_inspect_keys(self):
|
||||
return ['label', 'slug']
|
||||
|
||||
def get_permissions_inspect_fields(self):
|
||||
yield from self.get_inspect_fields(keys=['edit_role', 'view_role'])
|
||||
|
||||
|
||||
class TimePeriodExceptionGroup(models.Model):
|
||||
unavailability_calendar = models.ForeignKey(UnavailabilityCalendar, on_delete=models.CASCADE)
|
||||
|
@ -3994,7 +4138,7 @@ class TimePeriodExceptionGroup(models.Model):
|
|||
return self.label
|
||||
|
||||
|
||||
class TimePeriodException(models.Model):
|
||||
class TimePeriodException(WithInspectMixin, models.Model):
|
||||
desk = models.ForeignKey(Desk, on_delete=models.CASCADE, null=True)
|
||||
unavailability_calendar = models.ForeignKey(UnavailabilityCalendar, on_delete=models.CASCADE, null=True)
|
||||
source = models.ForeignKey(TimePeriodExceptionSource, on_delete=models.CASCADE, null=True)
|
||||
|
@ -4108,6 +4252,13 @@ class TimePeriodException(models.Model):
|
|||
'update_datetime': export_datetime(self.update_datetime),
|
||||
}
|
||||
|
||||
def get_inspect_keys(self):
|
||||
return [
|
||||
'label',
|
||||
'start_datetime',
|
||||
'end_datetime',
|
||||
]
|
||||
|
||||
def duplicate(self, desk_target=None, source_target=None):
|
||||
# clone current exception
|
||||
new_exception = copy.deepcopy(self)
|
||||
|
@ -4199,7 +4350,7 @@ class NotificationType:
|
|||
return self.settings._meta.get_field(self.name).verbose_name
|
||||
|
||||
|
||||
class AgendaNotificationsSettings(models.Model):
|
||||
class AgendaNotificationsSettings(WithInspectMixin, models.Model):
|
||||
EMAIL_FIELD = 'use-email-field'
|
||||
VIEW_ROLE = 'view-role'
|
||||
EDIT_ROLE = 'edit-role'
|
||||
|
@ -4263,6 +4414,13 @@ class AgendaNotificationsSettings(models.Model):
|
|||
'cancelled_event_emails': self.cancelled_event_emails,
|
||||
}
|
||||
|
||||
def get_inspect_keys(self):
|
||||
return [
|
||||
'almost_full_event',
|
||||
'full_event',
|
||||
'cancelled_event',
|
||||
]
|
||||
|
||||
def duplicate(self, agenda_target):
|
||||
new_settings = copy.deepcopy(self)
|
||||
new_settings.pk = None
|
||||
|
@ -4271,7 +4429,7 @@ class AgendaNotificationsSettings(models.Model):
|
|||
return new_settings
|
||||
|
||||
|
||||
class AgendaReminderSettings(models.Model):
|
||||
class AgendaReminderSettings(WithInspectMixin, models.Model):
|
||||
ONE_DAY_BEFORE = 1
|
||||
TWO_DAYS_BEFORE = 2
|
||||
THREE_DAYS_BEFORE = 3
|
||||
|
@ -4360,6 +4518,14 @@ class AgendaReminderSettings(models.Model):
|
|||
'sms_extra_info': self.sms_extra_info,
|
||||
}
|
||||
|
||||
def get_inspect_keys(self):
|
||||
return [
|
||||
'days_before_email',
|
||||
'days_before_sms',
|
||||
'email_extra_info',
|
||||
'sms_extra_info',
|
||||
]
|
||||
|
||||
def duplicate(self, agenda_target):
|
||||
new_settings = copy.deepcopy(self)
|
||||
new_settings.pk = None
|
||||
|
|
|
@ -0,0 +1,326 @@
|
|||
{% extends "chrono/manager_agenda_settings.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans 'Inspect' %}</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'chrono-manager-agenda-inspect' pk=agenda.pk %}">{% trans "Inspect" %}</a>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class="pk-tabs">
|
||||
<div class="pk-tabs--tab-list" role="tablist">
|
||||
<button aria-controls="panel-information" aria-selected="true" id="tab-information" role="tab" tabindex="0">{% trans "Information" %}</button>
|
||||
<button aria-controls="panel-settings" aria-selected="false" id="tab-settings" role="tab" tabindex="-1">{% trans "Settings" %}</button>
|
||||
<button aria-controls="panel-permissions" aria-selected="false" id="tab-permissions" role="tab" tabindex="-1">{% trans "Permissions" %}</button>
|
||||
{% if object.kind == 'events' %}
|
||||
<button aria-controls="panel-events" aria-selected="false" id="tab-events" role="tab" tabindex="-1">{% trans "Events" %}</button>
|
||||
<button aria-controls="panel-exceptions" aria-selected="false" id="tab-exceptions" role="tab" tabindex="-1">{% trans "Recurrence exceptions" %}</button>
|
||||
{% elif object.kind == 'meetings' %}
|
||||
<button aria-controls="panel-meeting-types" aria-selected="false" id="tab-meeting-types" role="tab" tabindex="-1">{% trans "Meeting Types" %}</button>
|
||||
<button aria-controls="panel-desks" aria-selected="false" id="tab-desks" role="tab" tabindex="-1">{% trans "Desks" %}</button>
|
||||
<button aria-controls="panel-resources" aria-selected="false" id="tab-resources" role="tab" tabindex="-1">{% trans "Resources" %}</button>
|
||||
{% elif object.kind == 'virtual' %}
|
||||
<button aria-controls="panel-agendas" aria-selected="false" id="tab-agendas" role="tab" tabindex="-1">{% trans "Included Agendas" %}</button>
|
||||
<button aria-controls="panel-time-periods" aria-selected="false" id="tab-time-periods" role="tab" tabindex="-1">{% trans "Exception Periods" %}</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="pk-tabs--container">
|
||||
|
||||
<div aria-labelledby="tab-information" id="panel-information" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
<ul>
|
||||
{% for label, value in object.get_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-labelledby="tab-settings" hidden id="panel-settings" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
|
||||
{% if object.kind != 'virtual' %}
|
||||
<h4>{% trans "Display options" %}</h4>
|
||||
<ul>
|
||||
{% for label, value in object.get_display_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% if object.kind == 'events' %}
|
||||
<h4>{% trans "Booking check options" %}</h4>
|
||||
<ul>
|
||||
{% for label, value in object.get_booking_check_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% if object.kind == 'events' %}
|
||||
{% if agenda.partial_bookings %}
|
||||
<h4>{% trans "Invoicing options" %}</h4>
|
||||
<ul>
|
||||
{% for label, value in object.get_invoicing_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<h4>{% trans "Management notifications" %}</h4>
|
||||
<ul>
|
||||
{% for label, value in object.get_notifications_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if object.kind != 'virtual' and not object.partial_bookings %}
|
||||
<h4>{% trans "Booking reminders" %}</h4>
|
||||
<ul>
|
||||
{% for label, value in object.get_reminder_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
<h4>{% trans "Booking Delays" %}</h4>
|
||||
<ul>
|
||||
{% for label, value in object.get_booking_delays_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-labelledby="tab-permissions" hidden id="panel-permissions" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
<ul>
|
||||
{% for label, value in object.get_permissions_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if object.kind == 'events' %}
|
||||
|
||||
<div aria-labelledby="tab-events" hidden id="panel-events" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
{% for event in object.event_set.all %}
|
||||
<h4>{{ event }}</h4>
|
||||
<ul>
|
||||
{% for label, value in event.get_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-labelledby="tab-exceptions" hidden id="panel-exceptions" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
{% for desk in object.desk_set.all %}{% if desk.slug == '_exceptions_holder' %}
|
||||
<h4>{% trans "Unavailability calendars" %}</h4>
|
||||
<ul>
|
||||
{% for unavailability_calendar in desk.unavailability_calendars.all %}
|
||||
<li class="parameter-unavailability-calendar }}">
|
||||
{{ unavailability_calendar }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<h4>{% trans "Exception sources" %}</h4>
|
||||
{% for source in desk.timeperiodexceptionsource_set.all %}
|
||||
<h5>{{ source }}</h5>
|
||||
<ul>
|
||||
{% for label, value in source.get_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
|
||||
<h4>{% trans "Exceptions" %}</h4>
|
||||
{% for exception in desk.timeperiodexception_set.all %}
|
||||
<h5>{{ exception }}</h5>
|
||||
<ul>
|
||||
{% for label, value in exception.get_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
{% endif %}{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% elif object.kind == 'meetings' %}
|
||||
|
||||
<div aria-labelledby="tab-meeting-types" hidden id="panel-meeting-types" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
{% for meeting_type in object.meetingtype_set.all %}
|
||||
<h4>{{ meeting_type }}</h4>
|
||||
<ul>
|
||||
{% for label, value in meeting_type.get_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-labelledby="tab-desks" hidden id="panel-desks" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
{% for desk in object.desk_set.all %}
|
||||
<h4>{{ desk }}</h4>
|
||||
<ul>
|
||||
{% for label, value in desk.get_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<h5>{% trans "Opening hours" %}</h5>
|
||||
{% for time_period in desk.timeperiod_set.all %}
|
||||
<h6>{{ time_period }}</h6>
|
||||
<ul>
|
||||
{% for label, value in time_period.get_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
|
||||
<h5>{% trans "Unavailability calendars" %}</h5>
|
||||
<ul>
|
||||
{% for unavailability_calendar in desk.unavailability_calendars.all %}
|
||||
<li class="parameter-unavailability-calendar }}">
|
||||
{{ unavailability_calendar }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<h5>{% trans "Exception sources" %}</h5>
|
||||
{% for source in desk.timeperiodexceptionsource_set.all %}
|
||||
<h6>{{ source }}</h6>
|
||||
<ul>
|
||||
{% for label, value in source.get_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
|
||||
<h5>{% trans "Exceptions" %}</h5>
|
||||
{% for exception in desk.timeperiodexception_set.all %}
|
||||
<h6>{{ exception }}</h6>
|
||||
<ul>
|
||||
{% for label, value in exception.get_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-labelledby="tab-resources" hidden id="panel-resources" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
<ul>
|
||||
{% for resource in object.resources.all %}
|
||||
<li class="parameter-resource }}">
|
||||
{{ resource }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% elif object.kind == "virtual" %}
|
||||
|
||||
<div aria-labelledby="tab-agendas" hidden id="panel-agendas" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
<ul>
|
||||
{% for agenda in object.real_agendas.all %}
|
||||
<li class="parameter-agenda }}">
|
||||
{{ agenda }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-labelledby="tab-time-periods" hidden id="panel-time-periods" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
{% for time_period in object.excluded_timeperiods.all %}
|
||||
<h4>{{ time_period }}</h4>
|
||||
<ul>
|
||||
{% for label, value in time_period.get_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% endblock %}
|
|
@ -120,10 +120,11 @@
|
|||
<a class="button button-paragraph" rel="popup" class="action-duplicate" href="{% url 'chrono-manager-agenda-duplicate' pk=object.pk %}">{% trans 'Duplicate' %}</a>
|
||||
{% endif %}
|
||||
|
||||
<h3>{% trans "Navigation" %}</h3>
|
||||
{% if show_history %}
|
||||
<h3>{% trans "Navigation" %}</h3>
|
||||
<a class="button button-paragraph" href="{% url 'chrono-manager-agenda-history' pk=agenda.pk %}">{% trans 'History' %}</a>
|
||||
{% endif %}
|
||||
<a class="button button-paragraph" href="{% url 'chrono-manager-agenda-inspect' pk=agenda.pk %}">{% trans 'Inspect' %}</a>
|
||||
{% block agenda-extra-navigation-actions %}{% endblock %}
|
||||
|
||||
{% url 'chrono-manager-homepage' as object_list_url %}
|
||||
|
|
|
@ -20,9 +20,12 @@
|
|||
{% else %}
|
||||
<h2>{% trans "New Category" %}</h2>
|
||||
{% endif %}
|
||||
{% if show_history and category %}
|
||||
{% if category %}
|
||||
<span class="actions">
|
||||
<a href="{% url 'chrono-manager-category-history' pk=category.pk %}">{% trans 'History' %}</a>
|
||||
<a href="{% url 'chrono-manager-category-inspect' pk=category.pk %}">{% trans 'Inspect' %}</a>
|
||||
{% if show_history %}
|
||||
<a href="{% url 'chrono-manager-category-history' pk=category.pk %}">{% trans 'History' %}</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
{% extends "chrono/manager_category_form.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans 'Inspect' %}</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'chrono-manager-category-inspect' pk=category.pk %}">{% trans "Inspect" %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="pk-tabs">
|
||||
<div class="pk-tabs--tab-list" role="tablist">
|
||||
<button aria-controls="panel-information" aria-selected="true" id="tab-information" role="tab" tabindex="0">{% trans "Information" %}</button>
|
||||
</div>
|
||||
<div class="pk-tabs--container">
|
||||
|
||||
<div aria-labelledby="tab-information" id="panel-information" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
<ul>
|
||||
{% for label, value in object.get_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% endblock %}
|
|
@ -8,9 +8,6 @@
|
|||
|
||||
{% block agenda-extra-navigation-actions %}
|
||||
{% with lingo_url=object.get_lingo_url %}{% if lingo_url %}
|
||||
{% if not show_history %}
|
||||
<h3>{% trans "Navigation" %}</h3>
|
||||
{% endif %}
|
||||
<a class="button button-paragraph" href="{{ lingo_url }}">{% trans 'Pricing' context 'pricing' %}</a>
|
||||
{% endif %}{% endwith %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -20,9 +20,12 @@
|
|||
{% else %}
|
||||
<h2>{% trans "New events type" %}</h2>
|
||||
{% endif %}
|
||||
{% if show_history and object.pk %}
|
||||
{% if object.pk %}
|
||||
<span class="actions">
|
||||
<a href="{% url 'chrono-manager-events-type-history' pk=object.pk %}">{% trans 'History' %}</a>
|
||||
<a href="{% url 'chrono-manager-events-type-inspect' pk=object.pk %}">{% trans 'Inspect' %}</a>
|
||||
{% if show_history %}
|
||||
<a href="{% url 'chrono-manager-events-type-history' pk=object.pk %}">{% trans 'History' %}</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
{% extends "chrono/manager_events_type_form.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans 'Inspect' %}</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'chrono-manager-events-type-inspect' pk=events_type.pk %}">{% trans "Inspect" %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="pk-tabs">
|
||||
<div class="pk-tabs--tab-list" role="tablist">
|
||||
<button aria-controls="panel-information" aria-selected="true" id="tab-information" role="tab" tabindex="0">{% trans "Information" %}</button>
|
||||
<button aria-controls="panel-custom-fields" aria-selected="false" id="tab-custom-fields" role="tab" tabindex="-1">{% trans "Custom fields" %}</button>
|
||||
</div>
|
||||
<div class="pk-tabs--container">
|
||||
|
||||
<div aria-labelledby="tab-information" id="panel-information" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
<ul>
|
||||
{% for label, value in object.get_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-labelledby="tab-custom-fields" hidden id="panel-custom-fields" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
{% for value in object.get_custom_fields %}
|
||||
<h4>{{ value.label }}</h4>
|
||||
<ul>
|
||||
<li class="parameter-varname">
|
||||
<span class="parameter">{% trans "Field slug:" %}</span>
|
||||
{{ value.varname }}
|
||||
</li>
|
||||
<li class="parameter-label">
|
||||
<span class="parameter">{% trans "Field label:" %}</span>
|
||||
{{ value.label }}
|
||||
</li>
|
||||
<li class="parameter-field-type">
|
||||
<span class="parameter">{% trans "Field type:" %}</span>
|
||||
{% if value.field_type == 'text' %}{% trans "Text" %}{% endif %}
|
||||
{% if value.field_type == 'textarea' %}{% trans "Textarea" %}{% endif %}
|
||||
{% if value.field_type == 'textbool' %}{% trans "Boolean" %}{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% endblock %}
|
|
@ -63,8 +63,9 @@
|
|||
<a class="button button-paragraph" rel="popup" href="{% url 'chrono-manager-resource-edit' pk=resource.pk %}">{% trans 'Edit' %}</a>
|
||||
{% endif %}
|
||||
|
||||
<h3>{% trans "Navigation" %}</h3>
|
||||
<a class="button button-paragraph" href="{% url 'chrono-manager-resource-inspect' pk=resource.pk %}">{% trans 'Inspect' %}</a>
|
||||
{% if show_history %}
|
||||
<h3>{% trans "Navigation" %}</h3>
|
||||
<a class="button button-paragraph" href="{% url 'chrono-manager-resource-history' pk=resource.pk %}">{% trans 'History' %}</a>
|
||||
{% endif %}
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
{% extends "chrono/manager_resource_detail.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans 'Inspect' %}</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'chrono-manager-resource-inspect' pk=resource.pk %}">{% trans "Inspect" %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="pk-tabs">
|
||||
<div class="pk-tabs--tab-list" role="tablist">
|
||||
<button aria-controls="panel-information" aria-selected="true" id="tab-information" role="tab" tabindex="0">{% trans "Information" %}</button>
|
||||
</div>
|
||||
<div class="pk-tabs--container">
|
||||
|
||||
<div aria-labelledby="tab-information" id="panel-information" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
<ul>
|
||||
{% for label, value in object.get_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% endblock %}
|
|
@ -0,0 +1,69 @@
|
|||
{% extends "chrono/manager_unavailability_calendar_settings.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans 'Inspect' %}</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'chrono-manager-unavailability-calendar-inspect' pk=unavailability_calendar.pk %}">{% trans "Inspect" %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="pk-tabs">
|
||||
<div class="pk-tabs--tab-list" role="tablist">
|
||||
<button aria-controls="panel-information" aria-selected="true" id="tab-information" role="tab" tabindex="0">{% trans "Information" %}</button>
|
||||
<button aria-controls="panel-permissions" aria-selected="false" id="tab-permissions" role="tab" tabindex="-1">{% trans "Permissions" %}</button>
|
||||
<button aria-controls="panel-exceptions" aria-selected="false" id="tab-exceptions" role="tab" tabindex="-1">{% trans "Exceptions" %}</button>
|
||||
</div>
|
||||
<div class="pk-tabs--container">
|
||||
|
||||
<div aria-labelledby="tab-information" id="panel-information" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
<ul>
|
||||
{% for label, value in object.get_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-labelledby="tab-permissions" hidden id="panel-permissions" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
<ul>
|
||||
{% for label, value in object.get_permissions_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-labelledby="tab-exceptions" hidden id="panel-exceptions" role="tabpanel" tabindex="0">
|
||||
<div class="section">
|
||||
{% for exception in object.timeperiodexception_set.all %}
|
||||
<h4>{{ exception }}</h4>
|
||||
<ul>
|
||||
{% for label, value in exception.get_inspect_fields %}
|
||||
<li class="parameter-{{ label|slugify }}">
|
||||
<span class="parameter">{% blocktrans %}{{ label }}:{% endblocktrans %}</span>
|
||||
{{ value }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% endblock %}
|
|
@ -54,10 +54,11 @@
|
|||
<a class="button button-paragraph" rel="popup" href="{% url 'chrono-manager-unavailability-calendar-delete' pk=unavailability_calendar.id %}">{% trans 'Delete' %}</a>
|
||||
{% endif %}
|
||||
|
||||
<h3>{% trans "Navigation" %}</h3>
|
||||
{% if show_history %}
|
||||
<h3>{% trans "Navigation" %}</h3>
|
||||
<a class="button button-paragraph" href="{% url 'chrono-manager-unavailability-calendar-history' pk=unavailability_calendar.pk %}">{% trans 'History' %}</a>
|
||||
{% endif %}
|
||||
<a class="button button-paragraph" href="{% url 'chrono-manager-unavailability-calendar-inspect' pk=unavailability_calendar.pk %}">{% trans 'Inspect' %}</a>
|
||||
|
||||
{% url 'chrono-manager-unavailability-calendar-list' as object_list_url %}
|
||||
{% include 'chrono/includes/application_detail_fragment.html' %}
|
||||
|
|
|
@ -65,6 +65,11 @@ urlpatterns = [
|
|||
views.unavailability_calendar_import_unavailabilities,
|
||||
name='chrono-manager-unavailability-calendar-import-unavailabilities',
|
||||
),
|
||||
path(
|
||||
'unavailability-calendar/<int:pk>/inspect/',
|
||||
views.unavailability_calendar_inspect,
|
||||
name='chrono-manager-unavailability-calendar-inspect',
|
||||
),
|
||||
path(
|
||||
'unavailability-calendar/<int:pk>/history/',
|
||||
views.unavailability_calendar_history,
|
||||
|
@ -100,6 +105,7 @@ urlpatterns = [
|
|||
),
|
||||
path('resource/<int:pk>/edit/', views.resource_edit, name='chrono-manager-resource-edit'),
|
||||
path('resource/<int:pk>/delete/', views.resource_delete, name='chrono-manager-resource-delete'),
|
||||
path('resource/<int:pk>/inspect/', views.resource_inspect, name='chrono-manager-resource-inspect'),
|
||||
path('resource/<int:pk>/history/', views.resource_history, name='chrono-manager-resource-history'),
|
||||
path(
|
||||
'resource/<int:pk>/history/compare/',
|
||||
|
@ -110,6 +116,7 @@ urlpatterns = [
|
|||
path('category/add/', views.category_add, name='chrono-manager-category-add'),
|
||||
path('category/<int:pk>/edit/', views.category_edit, name='chrono-manager-category-edit'),
|
||||
path('category/<int:pk>/delete/', views.category_delete, name='chrono-manager-category-delete'),
|
||||
path('category/<int:pk>/inspect/', views.category_inspect, name='chrono-manager-category-inspect'),
|
||||
path('category/<int:pk>/history/', views.category_history, name='chrono-manager-category-history'),
|
||||
path(
|
||||
'category/<int:pk>/history/compare/',
|
||||
|
@ -124,6 +131,9 @@ urlpatterns = [
|
|||
views.events_type_delete,
|
||||
name='chrono-manager-events-type-delete',
|
||||
),
|
||||
path(
|
||||
'events-type/<int:pk>/inspect/', views.events_type_inspect, name='chrono-manager-events-type-inspect'
|
||||
),
|
||||
path(
|
||||
'events-type/<int:pk>/history/', views.events_type_history, name='chrono-manager-events-type-history'
|
||||
),
|
||||
|
@ -479,6 +489,7 @@ urlpatterns = [
|
|||
views.agenda_import_events_sample_csv,
|
||||
name='chrono-manager-sample-events-csv',
|
||||
),
|
||||
path('agendas/<int:pk>/inspect/', views.agenda_inspect, name='chrono-manager-agenda-inspect'),
|
||||
path('agendas/<int:pk>/history/', views.agenda_history, name='chrono-manager-agenda-history'),
|
||||
path(
|
||||
'agendas/<int:pk>/history/compare/',
|
||||
|
|
|
@ -30,7 +30,7 @@ from django.conf import settings
|
|||
from django.contrib import messages
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db import IntegrityError, models, transaction
|
||||
from django.db.models import BooleanField, Count, ExpressionWrapper, F, Func, Max, Min, Q, Value
|
||||
from django.db.models import BooleanField, Count, ExpressionWrapper, F, Func, Max, Min, Prefetch, Q, Value
|
||||
from django.db.models.deletion import ProtectedError
|
||||
from django.db.models.functions import Cast
|
||||
from django.http import Http404, HttpResponse, HttpResponseForbidden, HttpResponseRedirect
|
||||
|
@ -800,6 +800,19 @@ class ResourceDeleteView(DeleteView):
|
|||
resource_delete = ResourceDeleteView.as_view()
|
||||
|
||||
|
||||
class ResourceInspectView(DetailView):
|
||||
template_name = 'chrono/manager_resource_inspect.html'
|
||||
model = Resource
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not request.user.is_staff:
|
||||
raise PermissionDenied()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
resource_inspect = ResourceInspectView.as_view()
|
||||
|
||||
|
||||
class ResourceHistoryView(InstanceWithSnapshotHistoryView):
|
||||
template_name = 'chrono/manager_resource_history.html'
|
||||
model = ResourceSnapshot
|
||||
|
@ -918,6 +931,19 @@ class CategoryDeleteView(DeleteView):
|
|||
category_delete = CategoryDeleteView.as_view()
|
||||
|
||||
|
||||
class CategoryInspectView(DetailView):
|
||||
template_name = 'chrono/manager_category_inspect.html'
|
||||
model = Category
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not request.user.is_staff:
|
||||
raise PermissionDenied()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
category_inspect = CategoryInspectView.as_view()
|
||||
|
||||
|
||||
class CategoryHistoryView(InstanceWithSnapshotHistoryView):
|
||||
template_name = 'chrono/manager_category_history.html'
|
||||
model = CategorySnapshot
|
||||
|
@ -1092,6 +1118,20 @@ class EventsTypeDeleteView(DeleteView):
|
|||
events_type_delete = EventsTypeDeleteView.as_view()
|
||||
|
||||
|
||||
class EventsTypeInspectView(DetailView):
|
||||
template_name = 'chrono/manager_events_type_inspect.html'
|
||||
model = EventsType
|
||||
context_object_name = 'events_type'
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not request.user.is_staff:
|
||||
raise PermissionDenied()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
events_type_inspect = EventsTypeInspectView.as_view()
|
||||
|
||||
|
||||
class EventsTypeHistoryView(InstanceWithSnapshotHistoryView):
|
||||
template_name = 'chrono/manager_events_type_history.html'
|
||||
model = EventsTypeSnapshot
|
||||
|
@ -4155,6 +4195,37 @@ class TimePeriodExceptionSourceRefreshView(ManagedTimePeriodExceptionMixin, Deta
|
|||
time_period_exception_source_refresh = TimePeriodExceptionSourceRefreshView.as_view()
|
||||
|
||||
|
||||
class AgendaInspectView(ManagedAgendaMixin, DetailView):
|
||||
template_name = 'chrono/manager_agenda_inspect.html'
|
||||
model = Agenda
|
||||
|
||||
def set_agenda(self, **kwargs):
|
||||
self.agenda = get_object_or_404(
|
||||
Agenda.objects.select_related(
|
||||
'category', 'events_type', 'edit_role', 'view_role'
|
||||
).prefetch_related(
|
||||
'resources',
|
||||
Prefetch(
|
||||
'desk_set',
|
||||
queryset=Desk.objects.prefetch_related(
|
||||
'timeperiod_set',
|
||||
'timeperiodexception_set',
|
||||
'timeperiodexceptionsource_set',
|
||||
'unavailability_calendars',
|
||||
),
|
||||
),
|
||||
Prefetch('event_set', queryset=Event.objects.filter(primary_event__isnull=True)),
|
||||
),
|
||||
id=kwargs.get('pk'),
|
||||
)
|
||||
|
||||
def get_object(self):
|
||||
return self.agenda
|
||||
|
||||
|
||||
agenda_inspect = AgendaInspectView.as_view()
|
||||
|
||||
|
||||
class AgendaHistoryView(ManagedAgendaMixin, InstanceWithSnapshotHistoryView):
|
||||
template_name = 'chrono/manager_agenda_history.html'
|
||||
model = AgendaSnapshot
|
||||
|
@ -4792,6 +4863,23 @@ class UnavailabilityCalendarImportUnavailabilitiesView(ManagedUnavailabilityCale
|
|||
unavailability_calendar_import_unavailabilities = UnavailabilityCalendarImportUnavailabilitiesView.as_view()
|
||||
|
||||
|
||||
class UnavailabilityCalendarInspectView(ManagedUnavailabilityCalendarMixin, DetailView):
|
||||
template_name = 'chrono/manager_unavailability_calendar_inspect.html'
|
||||
model = UnavailabilityCalendar
|
||||
context_object_name = 'unavailability_calendar'
|
||||
|
||||
def set_unavailability_calendar(self, **kwargs):
|
||||
self.unavailability_calendar = get_object_or_404(
|
||||
UnavailabilityCalendar.objects.select_related('edit_role', 'view_role'), pk=kwargs.get('pk')
|
||||
)
|
||||
|
||||
def get_object(self):
|
||||
return self.unavailability_calendar
|
||||
|
||||
|
||||
unavailability_calendar_inspect = UnavailabilityCalendarInspectView.as_view()
|
||||
|
||||
|
||||
class UnavailabilityCalendarHistoryView(ManagedUnavailabilityCalendarMixin, InstanceWithSnapshotHistoryView):
|
||||
template_name = 'chrono/manager_unavailability_calendar_history.html'
|
||||
model = UnavailabilityCalendarSnapshot
|
||||
|
|
|
@ -13,14 +13,17 @@ from django.test.utils import CaptureQueriesContext
|
|||
|
||||
from chrono.agendas.models import (
|
||||
Agenda,
|
||||
AgendaNotificationsSettings,
|
||||
AgendaReminderSettings,
|
||||
Booking,
|
||||
Desk,
|
||||
Event,
|
||||
EventsType,
|
||||
MeetingType,
|
||||
Resource,
|
||||
TimePeriod,
|
||||
TimePeriodException,
|
||||
TimePeriodExceptionSource,
|
||||
UnavailabilityCalendar,
|
||||
VirtualMember,
|
||||
)
|
||||
|
@ -800,6 +803,78 @@ def test_options_agenda_as_manager(app, manager_user):
|
|||
assert '<h2>Settings' in resp.text
|
||||
|
||||
|
||||
def test_inspect_agenda(app, admin_user):
|
||||
meetings_agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
|
||||
meetings_agenda.resources.add(Resource.objects.create(slug='foo', label='Foo'))
|
||||
desk = Desk.objects.create(slug='foo', label='Foo', agenda=meetings_agenda)
|
||||
unavailability_calendar = UnavailabilityCalendar.objects.create(slug='foo', label='Foo')
|
||||
desk.unavailability_calendars.add(unavailability_calendar)
|
||||
MeetingType.objects.create(agenda=meetings_agenda, label='Meeting Type', duration=30)
|
||||
tpx_start = make_aware(datetime.datetime(2017, 5, 22, 8, 0))
|
||||
tpx_end = make_aware(datetime.datetime(2017, 5, 22, 12, 30))
|
||||
TimePeriodException.objects.create(desk=desk, start_datetime=tpx_start, end_datetime=tpx_end)
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, weekday=2, start_time=tpx_start.time(), end_time=tpx_end.time(), weekday_indexes=[1, 3]
|
||||
)
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, date=datetime.date(2022, 10, 24), start_time=tpx_start.time(), end_time=tpx_end.time()
|
||||
)
|
||||
TimePeriodExceptionSource.objects.create(desk=desk, ics_url='http://example.com/sample.ics')
|
||||
AgendaNotificationsSettings.objects.create(
|
||||
agenda=meetings_agenda,
|
||||
full_event=AgendaNotificationsSettings.EMAIL_FIELD,
|
||||
full_event_emails=['hop@entrouvert.com', 'top@entrouvert.com'],
|
||||
)
|
||||
AgendaReminderSettings.objects.create(agenda=meetings_agenda, days_before_email=1, email_extra_info='top')
|
||||
|
||||
events_agenda = Agenda.objects.create(label='Events', kind='events')
|
||||
Event.objects.create(
|
||||
agenda=events_agenda, start_datetime=make_aware(datetime.datetime(2020, 7, 21, 16, 42, 35)), places=10
|
||||
)
|
||||
exceptions_desk = Desk.objects.create(agenda=events_agenda, slug='_exceptions_holder')
|
||||
tpx_start = make_aware(datetime.datetime(2017, 5, 22, 8, 0))
|
||||
tpx_end = make_aware(datetime.datetime(2017, 5, 22, 12, 30))
|
||||
TimePeriodException.objects.create(desk=exceptions_desk, start_datetime=tpx_start, end_datetime=tpx_end)
|
||||
exceptions_desk.unavailability_calendars.add(unavailability_calendar)
|
||||
|
||||
virtual_agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
||||
VirtualMember.objects.create(virtual_agenda=virtual_agenda, real_agenda=meetings_agenda)
|
||||
TimePeriod.objects.create(
|
||||
agenda=virtual_agenda, weekday=1, start_time=datetime.time(10, 0), end_time=datetime.time(11, 0)
|
||||
)
|
||||
|
||||
app = login(app)
|
||||
|
||||
resp = app.get('/manage/agendas/%s/settings' % meetings_agenda.pk)
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = resp.click('Inspect')
|
||||
assert len(ctx.captured_queries) == 12
|
||||
|
||||
resp = app.get('/manage/agendas/%s/settings' % events_agenda.pk)
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = resp.click('Inspect')
|
||||
assert len(ctx.captured_queries) == 12
|
||||
|
||||
resp = app.get('/manage/agendas/%s/settings' % virtual_agenda.pk)
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = resp.click('Inspect')
|
||||
assert len(ctx.captured_queries) == 8
|
||||
|
||||
|
||||
def test_inspect_agenda_as_manager(app, manager_user):
|
||||
agenda = Agenda.objects.create(slug='foo', label='Foo')
|
||||
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
||||
|
||||
app = login(app, username='manager', password='manager')
|
||||
agenda.view_role = manager_user.groups.all()[0]
|
||||
agenda.save()
|
||||
app.get('/manage/agendas/%s/inspect/' % agenda.pk, status=403)
|
||||
|
||||
agenda.edit_role = manager_user.groups.all()[0]
|
||||
agenda.save()
|
||||
app.get('/manage/agendas/%s/inspect/' % agenda.pk, status=200)
|
||||
|
||||
|
||||
@mock.patch('chrono.agendas.models.Agenda.is_available_for_simple_management')
|
||||
def test_agenda_options_desk_simple_management(available_mock, app, admin_user):
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import pytest
|
||||
from django.db import connection
|
||||
from django.test.utils import CaptureQueriesContext
|
||||
|
||||
from chrono.agendas.models import Agenda, Category
|
||||
from chrono.apps.snapshot.models import CategorySnapshot
|
||||
|
@ -84,3 +86,14 @@ def test_delete_category_as_manager(app, manager_user):
|
|||
category = Category.objects.create(label='Foo bar')
|
||||
app = login(app, username='manager', password='manager')
|
||||
app.get('/manage/category/%s/delete/' % category.pk, status=403)
|
||||
|
||||
|
||||
def test_inspect_category(app, admin_user):
|
||||
category = Category.objects.create(label='Foo bar')
|
||||
|
||||
app = login(app)
|
||||
|
||||
resp = app.get('/manage/category/%s/edit/' % category.pk)
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = resp.click('Inspect')
|
||||
assert len(ctx.captured_queries) == 3
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import pytest
|
||||
from django.db import connection
|
||||
from django.test.utils import CaptureQueriesContext
|
||||
|
||||
from chrono.agendas.models import Agenda, EventsType
|
||||
from chrono.apps.snapshot.models import EventsTypeSnapshot
|
||||
|
@ -212,3 +214,14 @@ def test_delete_events_type_as_manager(app, manager_user):
|
|||
events_type = EventsType.objects.create(label='Foo bar')
|
||||
app = login(app, username='manager', password='manager')
|
||||
app.get('/manage/events-type/%s/delete/' % events_type.pk, status=403)
|
||||
|
||||
|
||||
def test_inspect_events_type(app, admin_user):
|
||||
events_type = EventsType.objects.create(label='Foo bar')
|
||||
|
||||
app = login(app)
|
||||
|
||||
resp = app.get('/manage/events-type/%s/edit/' % events_type.pk)
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = resp.click('Inspect')
|
||||
assert len(ctx.captured_queries) == 3
|
||||
|
|
|
@ -1043,3 +1043,14 @@ def test_resource_today_button(app, admin_user):
|
|||
|
||||
resp = app.get('/manage/resource/%s/week/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day))
|
||||
assert 'Today' not in resp.pyquery('a.active').text()
|
||||
|
||||
|
||||
def test_inspect_resource(app, admin_user):
|
||||
resource = Resource.objects.create(label='Foo bar')
|
||||
|
||||
app = login(app)
|
||||
|
||||
resp = app.get('/manage/resource/%s/' % resource.pk)
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = resp.click('Inspect')
|
||||
assert len(ctx.captured_queries) == 3
|
||||
|
|
|
@ -3,6 +3,8 @@ import os
|
|||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from django.db import connection
|
||||
from django.test.utils import CaptureQueriesContext
|
||||
from webtest import Upload
|
||||
|
||||
from chrono.agendas.models import (
|
||||
|
@ -709,3 +711,32 @@ def test_unavailability_calendar_delete_unavailability_permissions(app, manager_
|
|||
unavailability_calendar.edit_role = group
|
||||
unavailability_calendar.save()
|
||||
app.get(url)
|
||||
|
||||
|
||||
def test_inspect_unavailability_calendar(app, admin_user):
|
||||
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar 1')
|
||||
TimePeriodException.objects.create(
|
||||
unavailability_calendar=unavailability_calendar,
|
||||
start_datetime=now() - datetime.timedelta(days=2),
|
||||
end_datetime=now() - datetime.timedelta(days=1),
|
||||
)
|
||||
|
||||
app = login(app)
|
||||
|
||||
resp = app.get('/manage/unavailability-calendar/%s/settings' % unavailability_calendar.pk)
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = resp.click('Inspect')
|
||||
assert len(ctx.captured_queries) == 4
|
||||
|
||||
|
||||
def test_inspect_unavailability_calendar_as_manager(app, manager_user):
|
||||
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar 1')
|
||||
|
||||
app = login(app, username='manager', password='manager')
|
||||
unavailability_calendar.view_role = manager_user.groups.all()[0]
|
||||
unavailability_calendar.save()
|
||||
app.get('/manage/unavailability-calendar/%s/inspect/' % unavailability_calendar.pk, status=403)
|
||||
|
||||
unavailability_calendar.edit_role = manager_user.groups.all()[0]
|
||||
unavailability_calendar.save()
|
||||
app.get('/manage/unavailability-calendar/%s/inspect/' % unavailability_calendar.pk, status=200)
|
||||
|
|
Loading…
Reference in New Issue