diff --git a/CHANGES.rst b/CHANGES.rst index e1a8451e14d..0b4b8d644a0 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -11,6 +11,7 @@ Improvements ^^^^^^^^^^^^ - Display program codes in 'My contributions' (:pr:`5573`) +- Warn when a user cannot create an event in the current category (:pr:`5572`) Bugfixes ^^^^^^^^ diff --git a/indico/modules/categories/fields.py b/indico/modules/categories/fields.py index 7ab5f265f2c..51924dd05d3 100644 --- a/indico/modules/categories/fields.py +++ b/indico/modules/categories/fields.py @@ -25,7 +25,7 @@ class CategoryField(HiddenField): widget = JinjaWidget('forms/category_picker_widget.html') def __init__(self, *args, **kwargs): - self.navigator_category_id = 0 + self.navigator_category_id = None self.require_event_creation_rights = kwargs.pop('require_event_creation_rights', False) super().__init__(*args, **kwargs) diff --git a/indico/modules/events/client/js/creation.js b/indico/modules/events/client/js/creation.js index d527d9d5896..58fc0187489 100644 --- a/indico/modules/events/client/js/creation.js +++ b/indico/modules/events/client/js/creation.js @@ -33,7 +33,10 @@ import {camelizeKeys} from 'indico/utils/case'; const messages = $($.parseHTML($('#event-creation-protection-messages').html())); const protectionMessage = $('
', {class: 'form-group', css: {marginTop: '5px'}}); const listingMessage = $($.parseHTML($('#event-listing-message').html())); + const eventCreationMessage = $($.parseHTML($('#event-creation-message').html())); + const $form = options.categoryField.closest('form'); + const $submitBtn = $form.find('input[type="submit"]').first(); const $createBooking = $('#event-creation-create_booking'); const $availableMessage = $('#room-available'); const $availablePrebookMessage = $('#room-available-prebook'); @@ -55,8 +58,30 @@ import {camelizeKeys} from 'indico/utils/case'; let multipleOccurrences = false; protectionMessage.appendTo(options.protectionModeFields.closest('.form-field')); + eventCreationMessage.insertAfter($('#category-warning-event-creation-category')); listingMessage.appendTo($listingField.closest('.form-field')); + $submitBtn.prop('disabled', true); + $form.on('change input', updateSubmitBtn); + + function canCreateInSelectedCategory() { + return ( + options.canCreateEvents || + // unlisted events or no default category + !currentCategory || + // categories other than the initial one cannot be selected unless the user can create events in them + currentCategory?.id !== options.initialCategory?.id + ); + } + + // like disabled-until-change but also disables submit when the user + // does not have the rights to create events in the selected category + function updateSubmitBtn() { + const untouched = $.param($form.serializeArray(), true) === $form.data('initialData'); + const disabled = untouched || !canCreateInSelectedCategory(); + $submitBtn.prop('disabled', disabled); + } + function updateProtectionMessage() { if (!currentCategory) { protectionMessage.html(''); @@ -71,11 +96,9 @@ import {camelizeKeys} from 'indico/utils/case'; protectionMessage.html(elem); } - function updateWarningMessage() { - $(`#category-warning-event-creation-category`).toggleClass( - 'hidden', - (currentCategory && currentCategory.has_events) || !currentCategory - ); + // Display a warning if the user does not have the rights to create events in the selected category + function updateEventCreationMessage() { + eventCreationMessage.toggleClass('hidden', canCreateInSelectedCategory()); } options.categoryField.on('indico:categorySelected', (evt, cat) => { @@ -90,6 +113,8 @@ import {camelizeKeys} from 'indico/utils/case'; } currentCategory = cat; updateProtectionMessage(); + updateEventCreationMessage(); + updateSubmitBtn(); }); $listingField.on('change', evt => { @@ -108,9 +133,8 @@ import {camelizeKeys} from 'indico/utils/case'; options.categoryField.trigger('indico:categorySelected', []); } - // update listing and warning message boxes + // update listing listingMessage.toggleClass('hidden', JSON.parse($listingField.val())); - updateWarningMessage(); }); options.protectionModeFields.on('change', function() { diff --git a/indico/modules/events/controllers/creation.py b/indico/modules/events/controllers/creation.py index e631551d9a0..29c26f98a77 100644 --- a/indico/modules/events/controllers/creation.py +++ b/indico/modules/events/controllers/creation.py @@ -156,10 +156,13 @@ def _process(self): return jsonify_data(flash=False, redirect=url_for('event_management.settings', event)) check_room_availability = rb_check_user_access(session.user) and config.ENABLE_ROOMBOOKING rb_excluded_categories = [c.id for c in rb_settings.get('excluded_categories')] + category = self._default_category + can_create_events = category.can_create_events(session.user) if category else True return jsonify_template('events/forms/event_creation_form.html', form=form, fields=form._field_order, event_type=self.event_type.name, single_category=(not self.root_category.has_children), check_room_availability=check_room_availability, rb_excluded_categories=rb_excluded_categories, + can_create_events=can_create_events, can_create_unlisted_events=can_create_unlisted_events(session.user)) diff --git a/indico/modules/events/templates/forms/event_creation_form.html b/indico/modules/events/templates/forms/event_creation_form.html index c47f4f741fc..848e148d68a 100644 --- a/indico/modules/events/templates/forms/event_creation_form.html +++ b/indico/modules/events/templates/forms/event_creation_form.html @@ -2,7 +2,8 @@ {% set category = {'id': form.category.data.id, 'is_protected': form.category.data.is_protected, 'title': form.category.data.title, - 'has_events': form.category.data.has_events} if form.category.data else none %} + 'has_events': form.category.data.has_events, + 'has_children': form.category.data.has_children} if form.category.data else none %} {{ form_header(form, action=url_for('events.create', event_type=event_type)) }} {% if can_create_unlisted_events %} @@ -16,8 +17,7 @@ {% endcall %} {% endif %} {% call form_footer(form) %} - + {% endcall %} @@ -110,11 +110,25 @@
+ +