-
Notifications
You must be signed in to change notification settings - Fork 136
chore(enext): move api app from talk component to enext #1335
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 GuideMigrates the talk API functionality into the eventyay enext app by wiring up submissions/schedule/talk-related endpoints under the main API, updating imports and models to use eventyay.* modules, aligning permission and rule names, and adding support libraries for flexible DRF serializers and schema generation. Sequence diagram for talks to submissions redirect in the APIsequenceDiagram
actor "Client" as Client
participant "DjangoRouter" as DjangoRouter
participant "talks_to_submissions_redirect" as TalksToSubmissionsRedirect
participant "SubmissionViewSet" as SubmissionViewSet
"Client"->>"DjangoRouter": "GET /api/events/<event>/talks/<subpath>?q=1"
"DjangoRouter"->>"TalksToSubmissionsRedirect": "Dispatch request"
"TalksToSubmissionsRedirect"->>"TalksToSubmissionsRedirect": "Build new path by replacing '/talks/' with '/submissions/' and preserving query string"
"TalksToSubmissionsRedirect"-->>"Client": "301 Moved Permanently to /api/events/<event>/submissions/<subpath>?q=1"
"Client"->>"DjangoRouter": "GET /api/events/<event>/submissions/<subpath>?q=1" "(follow redirect)"
"DjangoRouter"->>"SubmissionViewSet": "Dispatch to appropriate SubmissionViewSet action"
"SubmissionViewSet"-->>"Client": "200 OK with submission data"
Sequence diagram for managing submission favourites via new endpointssequenceDiagram
actor "AuthenticatedUser" as AuthenticatedUser
participant "DjangoRouter" as DjangoRouter
participant "SubmissionFavouriteDeprecatedView" as SubmissionFavouriteDeprecatedView
participant "favourites_view" as FavouritesView
participant "favourite_view" as FavouriteView
rect rgb(235, 248, 255)
note over "AuthenticatedUser","DjangoRouter": "List favourite submissions"
"AuthenticatedUser"->>"DjangoRouter": "GET /api/events/<event>/submissions/favourites/"
"DjangoRouter"->>"FavouritesView": "Dispatch favourites_view"
"FavouritesView"->>"FavouritesView": "Check 'base.list_schedule' permission and collect favourites"
"FavouritesView"-->>"AuthenticatedUser": "200 OK with favourite submission codes"
end
rect rgb(235, 255, 235)
note over "AuthenticatedUser","DjangoRouter": "Toggle favourite on a single submission"
"AuthenticatedUser"->>"DjangoRouter": "POST /api/events/<event>/submissions/<code>/favourite/"
"DjangoRouter"->>"FavouriteView": "Dispatch favourite_view"
"FavouriteView"->>"FavouriteView": "Check 'base.list_schedule' permission and update favourite state"
"FavouriteView"-->>"AuthenticatedUser": "200 OK with updated favourite status"
end
rect rgb(255, 245, 235)
note over "AuthenticatedUser","DjangoRouter": "Use deprecated favourite-talk endpoint"
"AuthenticatedUser"->>"DjangoRouter": "POST /api/events/<event>/favourite-talk/"
"DjangoRouter"->>"SubmissionFavouriteDeprecatedView": "Dispatch deprecated view"
"SubmissionFavouriteDeprecatedView"-->>"AuthenticatedUser": "Response using legacy handling"
end
Updated class diagram for core talk-related API viewsets and serializersclassDiagram
class SubmissionViewSet {
+"queryset"
+"serializer_class"
+"get_legacy_queryset()"
+"get_legacy_serializer_class()"
+"get_legacy_serializer()"
+"get_unversioned_serializer_class()"
+"get_serializer()"
+"is_orga"
}
class SpeakerViewSet {
+"queryset"
+"serializer_class"
+"get_legacy_serializer_class()"
+"get_legacy_queryset()"
+"get_serializer()"
+"is_orga"
}
class QuestionViewSet {
+"queryset"
+"serializer_class"
+"filterset_fields"
+"search_fields"
+"get_queryset()"
}
class TalkSlotViewSet {
+"queryset"
+"serializer_class"
+"filterset_fields"
+"is_orga"
+"get_unversioned_serializer_class()"
}
class RoomViewSet {
+"queryset"
+"serializer_class"
+"filter_backends"
+"pagination_class"
}
class SubmissionSerializer {
+"Meta.model = Submission"
+"Meta.expandable_fields: submission_type, tags, track, resources"
+"Meta.extra_expandable_fields: slots, answers, speakers"
+"get_answers(obj)"
}
class SpeakerSerializer {
+"Meta.model = SpeakerProfile"
+"Meta.expandable_fields: submissions"
+"Meta.extra_expandable_fields: answers, submissions"
+"get_answers(obj)"
}
class QuestionSerializer {
+"Meta.model = TalkQuestion"
+"Meta.expandable_fields: options, tracks, submission_types"
}
class AnswerSerializer {
+"Meta.model = Answer"
+"Meta.expandable_fields: question, options, person"
}
class AnswerCreateSerializer {
+"question: PrimaryKeyRelatedField(queryset=TalkQuestion.objects.none())"
+"validate(data)"
}
class AnswerOptionSerializer {
+"Meta.model = AnswerOption"
+"Meta.expandable_fields: question"
}
class AnswerOptionCreateSerializer {
+"question: PrimaryKeyRelatedField(queryset=TalkQuestion.objects.none())"
+"__init__(*args, **kwargs)"
}
class ScheduleSerializer {
+"Meta.model = Schedule"
+"Meta.extra_expandable_fields: slots"
}
class TalkSlotSerializer {
+"Meta.model = TalkSlot"
+"Meta.expandable_fields: submission, schedule, room"
}
class RoomSerializer {
+"Meta.model = Room"
}
class TeamViewSet {
+"get_queryset()"
+"perform_update(serializer)"
+"perform_destroy(instance)"
+"delete_invite(request, invite_id)"
+"remove_member(request)"
}
class TeamSerializer {
+"Meta.model = Team"
+"Meta.expandable_fields: limit_tracks, members, invites"
}
class TeamInviteSerializer {
+"Meta.model = TeamInvite"
}
class User {
+"email"
+"is_active"
}
class Submission {
+"code"
+"state"
}
class SpeakerProfile {
+"user"
+"event"
}
class TalkQuestion {
+"event"
+"target: TalkQuestionTarget"
+"variant: TalkQuestionVariant"
}
class Answer {
+"question: TalkQuestion"
+"submission: Submission"
+"person: SpeakerProfile"
}
class AnswerOption {
+"question: TalkQuestion"
+"position"
}
class Schedule {
+"event"
+"version"
}
class TalkSlot {
+"submission: Submission"
+"schedule: Schedule"
+"room: Room"
}
class Room {
+"name"
+"capacity"
}
class Team {
+"organizer"
+"members: User[*]"
}
class TeamInvite {
+"team: Team"
+"email"
}
SubmissionViewSet --> SubmissionSerializer : uses
SpeakerViewSet --> SpeakerSerializer : uses
QuestionViewSet --> QuestionSerializer : uses
TalkSlotViewSet --> TalkSlotSerializer : uses
RoomViewSet --> RoomSerializer : uses
SubmissionSerializer --> Submission : serializes
SpeakerSerializer --> SpeakerProfile : serializes
QuestionSerializer --> TalkQuestion : serializes
AnswerSerializer --> Answer : serializes
AnswerOptionSerializer --> AnswerOption : serializes
ScheduleSerializer --> Schedule : serializes
TalkSlotSerializer --> TalkSlot : serializes
RoomSerializer --> Room : serializes
TeamSerializer --> Team : serializes
TeamInviteSerializer --> TeamInvite : serializes
Submission --> TalkSlot : has many slots
Submission --> Answer : has many answers
TalkQuestion --> Answer : has many answers
TalkQuestion --> AnswerOption : has many options
Schedule --> TalkSlot : has many slots
Room --> TalkSlot : hosts many slots
SpeakerProfile --> Answer : provides many answers
Team --> TeamInvite : has many invites
Team --> User : has many members
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 - here's some feedback:
- In talks_to_submissions_redirect, consider building the target URL via reverse/resolve rather than string replace on request.path to avoid edge cases (e.g., unexpected extra 'talks' segments or future URL changes) and to let Django handle URL construction.
- There are many hard-coded permission codename strings (e.g., 'base.orga_list_submission', 'base.list_schedule'); centralising these in a shared constants module or helper would make future permission refactors less error-prone and help keep backend and rules in sync.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In talks_to_submissions_redirect, consider building the target URL via reverse/resolve rather than string replace on request.path to avoid edge cases (e.g., unexpected extra 'talks' segments or future URL changes) and to let Django handle URL construction.
- There are many hard-coded permission codename strings (e.g., 'base.orga_list_submission', 'base.list_schedule'); centralising these in a shared constants module or helper would make future permission refactors less error-prone and help keep backend and rules in sync.
## Individual Comments
### Comment 1
<location> `app/eventyay/api/urls.py:47-49` </location>
<code_context>
def talks_to_submissions_redirect(request, event, subpath):
"""
Redirects requests from /events/.../talks/... to /events/.../submissions/...
preserving the subpath and query parameters.
"""
new_path = request.path.replace("/talks/", "/submissions/", 1)
query_string = request.META.get('QUERY_STRING', '')
if query_string:
new_path += '?' + query_string
return HttpResponsePermanentRedirect(new_path)
</code_context>
<issue_to_address>
**suggestion (code-quality):** We've found these issues:
- Use named expression to simplify assignment and conditional ([`use-named-expression`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/use-named-expression/))
- Use f-string instead of string concatenation ([`use-fstring-for-concatenation`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/use-fstring-for-concatenation/))
```suggestion
if query_string := request.META.get('QUERY_STRING', ''):
new_path += f'?{query_string}'
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| query_string = request.META.get('QUERY_STRING', '') | ||
| if query_string: | ||
| new_path += '?' + query_string |
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.
suggestion (code-quality): We've found these issues:
- Use named expression to simplify assignment and conditional (
use-named-expression) - Use f-string instead of string concatenation (
use-fstring-for-concatenation)
| query_string = request.META.get('QUERY_STRING', '') | |
| if query_string: | |
| new_path += '?' + query_string | |
| if query_string := request.META.get('QUERY_STRING', ''): | |
| new_path += f'?{query_string}' |
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 migrates the talks/submissions API from the legacy talk component into the main eventyay (enext) application. The migration includes porting API views, serializers, filters, permissions, and routing from the old pretalx-based module structure to the eventyay namespace.
Key changes:
- Add drf-flex-fields and drf-spectacular as dependencies for flexible serializers and API schema generation
- Update all import paths from
pretalx.*toeventyay.* - Rename models and permission codes (e.g.,
organiser→organizer,Question→TalkQuestion) - Wire submission-related endpoints into the main event router with permanent redirects from legacy
/talks/URLs to/submissions/
Reviewed changes
Copilot reviewed 32 out of 38 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| app/pyproject.toml | Added drf-flex-fields and drf-spectacular dependencies |
| app/uv.lock | Lock file updates for new dependencies including inflection and uritemplate |
| app/eventyay/common/auth.py | Updated UserApiToken import path to eventyay namespace |
| app/eventyay/api/views/team.py | Updated imports and changed organiser → organizer terminology |
| app/eventyay/api/views/submission.py | Migrated submission view imports and updated permission codes |
| app/eventyay/api/views/speaker*.py | Updated speaker and speaker_information view imports |
| app/eventyay/api/views/schedule.py | Updated schedule and slot view imports |
| app/eventyay/api/views/room*.py | Updated room view imports |
| app/eventyay/api/views/review.py | Updated review view imports |
| app/eventyay/api/views/question.py | Updated question view imports and Question → TalkQuestion renaming |
| app/eventyay/api/views/mail.py | Updated mail template view imports |
| app/eventyay/api/views/access_code.py | Updated access code view imports |
| app/eventyay/api/urls.py | Added submission-related endpoints and legacy redirect logic |
| app/eventyay/api/templates/rest_framework/api.html | New template for API browsable interface |
| app/eventyay/api/serializers/*.py | Updated all serializer imports and expandable field paths |
| app/eventyay/api/permissions.py | Updated permission object getter to use organizer |
| app/eventyay/api/pagination.py | New pagination classes supporting legacy API fallback |
| app/eventyay/api/mixins.py | Updated version utility imports |
| app/eventyay/api/filters/*.py | Updated filter model imports |
| app/eventyay/api/exceptions.py | New API exception handler with logging |
| app/eventyay/api/documentation.py | Updated documentation with organizer terminology |
| talk/src/pretalx/api/views/upload.py | Removed legacy upload view file |
Comments suppressed due to low confidence (3)
app/eventyay/api/serializers/team.py:9
- The
Teammodel is imported twice from different modules (line 6 fromeventyay.base.models.eventand line 7 fromeventyay.base.models.organizer). This creates ambiguity about which Team model is being used. Remove the duplicate import and keep only the correct one.
app/eventyay/api/documentation.py:81 - Corrected 'Organisers' to 'organizers' but inconsistently capitalized - should be 'Organizers' to match the sentence structure.
app/eventyay/api/serializers/speaker.py:11 - The import of
ModelSerializerwas removed but this appears to be a cleanup of an unused import. Verify that no code in this file actually requires ModelSerializer.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Add api app from talk component to enext.
Summary by Sourcery
Integrate the talks/submissions API from the legacy talk component into the core eventyay API and wire it into the main event routing.
New Features:
Enhancements:
Build: