-
Notifications
You must be signed in to change notification settings - Fork 130
feat(badges): add categories support for badge layouts and filtering #834
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: enext
Are you sure you want to change the base?
Conversation
Reviewer's GuideThis PR introduces category support for badge layouts, enabling automatic layout assignment per item category by extending the data model, forms, views, templates, exporters, and API, with the necessary migration and minor dev settings updates. Sequence diagram for badge rendering with category-based layout assignmentsequenceDiagram
participant System
participant BadgeRenderer
participant Item
participant BadgeLayout
participant ItemCategory
System->>BadgeRenderer: Request badge for Item
BadgeRenderer->>Item: Get item details
BadgeRenderer->>BadgeLayout: Check for item-specific layout
alt No item-specific layout
BadgeRenderer->>ItemCategory: Get item's category
BadgeRenderer->>BadgeLayout: Check for category-specific layout
alt No category-specific layout
BadgeRenderer->>BadgeLayout: Use default layout
end
end
BadgeRenderer-->>System: Return rendered badge
Class diagram for updated BadgeLayout modelclassDiagram
class BadgeLayout {
+id: int
+name: str
+default: bool
+layout: str
+category: ItemCategory
}
class ItemCategory {
+id: int
+name: str
}
BadgeLayout --> ItemCategory : category
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there - I've reviewed your changes and they look great!
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `src/pretix/plugins/badges/exporters.py:184` </location>
<code_context>
for bi in BadgeItem.objects.select_related('layout').filter(item__event=event)
}
+
+ # Build category-based renderer map
+ category_renderermap = {}
+ for layout in event.badge_layouts.filter(category__isnull=False).select_related('category'):
+ category_renderermap[layout.category_id] = _renderer(event, layout)
+
</code_context>
<issue_to_address>
Consider handling duplicate category assignments for badge layouts.
Currently, assigning multiple layouts to the same category will result in only the last one being used. Consider adding validation or documenting which layout should take precedence.
</issue_to_address>
<suggested_fix>
<<<<<<< SEARCH
# Build category-based renderer map
category_renderermap = {}
for layout in event.badge_layouts.filter(category__isnull=False).select_related('category'):
category_renderermap[layout.category_id] = _renderer(event, layout)
=======
# Build category-based renderer map
category_renderermap = {}
for layout in event.badge_layouts.filter(category__isnull=False).select_related('category'):
if layout.category_id in category_renderermap:
# Validation: Multiple layouts assigned to the same category
raise ValueError(
f"Duplicate badge layout assignment for category ID {layout.category_id}. "
"Each category should have only one badge layout assigned."
)
category_renderermap[layout.category_id] = _renderer(event, layout)
# Note: If you want to allow duplicates and document precedence, comment out the raise and add a comment:
# "If multiple layouts are assigned to the same category, the last one will take precedence."
>>>>>>> REPLACE
</suggested_fix>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Screen.Recording.2025-08-16.at.12.18.57.AM.mov |
mariobehling
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make this PR against the enext branch.
98441f3 to
40eaac2
Compare
|
Thanks @mariobehling, works as shown in video. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces category-based filtering and assignment capabilities for badge layouts, enabling automatic application of badge designs based on product categories. The changes also include a namespace migration from 'pretix' to 'eventyay' throughout the badges plugin.
Key Changes:
- Added a
categoryForeignKey field to BadgeLayout model linking to ProductCategory - Created a new LayoutEdit view for editing badge metadata (name and category)
- Updated the badge layout listing UI to display category information and separate metadata/design editing actions
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| app/eventyay/plugins/badges/models.py | Added category field to BadgeLayout with SET_NULL cascade; enhanced save method with robust error handling for PDF background processing |
| app/eventyay/plugins/badges/forms.py | Extended BadgeLayoutForm to include category field with event-scoped queryset filtering |
| app/eventyay/plugins/badges/views.py | Added LayoutEdit UpdateView for metadata editing; updated plugin namespace checks and log actions from 'pretix' to 'eventyay'; fixed prefetch from item_assignments to product_assignments |
| app/eventyay/plugins/badges/templates/pretixplugins/badges/index.html | Added category column to layout table; split edit functionality into separate metadata and design buttons; adjusted action column width from 2 to 3 |
| app/eventyay/plugins/badges/api.py | Added category field to BadgeLayoutSerializer for API exposure |
Comments suppressed due to low confidence (1)
app/eventyay/plugins/badges/models.py:66
- 'except' clause does nothing but pass and there is no explanatory comment.
except Exception:
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <strong> | ||
| <a href="{% url "plugins:badges:edit" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}"> | ||
| {{ l.name }} | ||
| </a></strong> | ||
| </a> | ||
| </strong> |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The badge layout name now links to the design editor for all users (line 52), but there's no permission check for can_change_event_settings. This could allow users without the proper permissions to access the editor, though the view itself should have permission checks.
Consider wrapping the link in a permission check or removing the link for users without edit permissions:
{% if "can_change_event_settings" in request.eventpermset %}
<strong>
<a href="{% url "plugins:badges:edit" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}">
{{ l.name }}
</a>
</strong>
{% else %}
<strong>{{ l.name }}</strong>
{% endif %}| <td class="text-right flip"> | ||
| {% if "can_change_event_settings" in request.eventpermset %} | ||
| <a href="{% url "plugins:badges:edit" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}" class="btn btn-default btn-sm"><i class="fa fa-edit"></i></a> | ||
| <a href="{% url "plugins:badges:edit_metadata" organizer=request.event.organizer.slug event=request.event.slug layout=l.id %}" class="btn btn-default btn-sm" title="{% trans "Edit metadata" %}" data-toggle="tooltip"><i class="fa fa-edit"></i></a> |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The template references a URL pattern named plugins:badges:edit_metadata, but this URL pattern is not defined in the urls.py file. The LayoutEdit view has been created, but it needs to be imported and mapped to a URL pattern.
Add the following to urls.py:
- Import
LayoutEditin the imports section (line 11-18) - Add a URL pattern like:
url(
r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/badges/(?P<layout>\d+)/edit_metadata$',
LayoutEdit.as_view(),
name='edit_metadata',
),| class LayoutEdit(BadgePluginEnabledMixin, EventPermissionRequiredMixin, UpdateView): | ||
| model = BadgeLayout | ||
| form_class = BadgeLayoutForm | ||
| template_name = 'pretixplugins/badges/edit.html' |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The template name 'pretixplugins/badges/edit.html' is used by the LayoutEdit view, which should display and allow editing of the category field that's now part of the BadgeLayoutForm. However, the template may need to be updated to render the category field. Verify that the template includes {% bootstrap_field form.category layout="control" %} or similar to render the category field, otherwise users won't be able to set the category when editing badge layouts.
| if event: | ||
| # Filter categories to only those belonging to this event | ||
| self.fields['category'].queryset = event.categories.all() | ||
| self.fields['category'].required = False |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When event is None or not provided, the category field's queryset won't be set, which could cause the form to show all categories across all events instead of an empty queryset. This could be a security/data leakage issue.
Consider updating the logic to:
if event:
# Filter categories to only those belonging to this event
self.fields['category'].queryset = event.categories.all()
else:
# If no event is provided, ensure no categories are shown
from eventyay.base.models import ProductCategory
self.fields['category'].queryset = ProductCategory.objects.none()
self.fields['category'].required = False| except Exception: | ||
| pass |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bare except Exception: pass statement silently swallows all exceptions during PDF background processing, which could hide legitimate errors and make debugging difficult. Consider logging the exception or being more specific about which exceptions to catch (e.g., PDF-related exceptions only).
For example:
except Exception as e:
import logging
logger = logging.getLogger(__name__)
logger.warning(f'Failed to process badge background PDF: {e}')| category = models.ForeignKey( | ||
| 'base.ProductCategory', | ||
| on_delete=models.SET_NULL, | ||
| related_name='badge_layouts', | ||
| null=True, | ||
| blank=True, | ||
| verbose_name=_('Category'), | ||
| help_text=_('If set, this badge layout will be automatically applied to items in this category.'), | ||
| ) |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Consider adding model-level validation to ensure the category belongs to the same event as the BadgeLayout. While the form filters categories by event, direct model saves or future API write operations could potentially assign a category from a different event.
Add a clean method or override save:
def clean(self):
super().clean()
if self.category and self.category.event_id != self.event_id:
from django.core.exceptions import ValidationError
raise ValidationError({'category': _('Category must belong to the same event as the badge layout.')})
mariobehling
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please respond to AI comments.
mariobehling
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please respond to AI comments.
Fixes #833
Summary by Sourcery
Introduce item category support for badge layouts and integrate category-based filtering and rendering throughout check-in and badge exports
New Features:
Enhancements:
Build:
Chores: