feat(catalog): creation - #14
Conversation
…sts for applications, openings, employee testimonials, email configuration, email templates, news categories, resources, and memberships; enhance navigation and API integration for improved content administration
PR Summary by QodoAdd end-to-end catalog management for ten content domains
AI Description
Diagram
High-Level Assessment
Files changed (93)
|
Code Review by Qodo
1. Draft applicants leak publicly
|
| applications=[ | ||
| public_application(link.application) for link in row.application_links if link.application |
There was a problem hiding this comment.
1. Draft applicants leak publicly 🐞 Bug ⛨ Security
A published opening serializes every linked application without checking the application's status, so draft applicants and their resume key, contact details, compensation, and free-form information become anonymously readable. This bypasses the public catalog rule that drafts must not appear on public routes.
Agent Prompt
## Issue description
Published openings currently expose every linked application, including drafts and sensitive applicant fields.
## Issue Context
Only applications with `ContentStatus.publish` may be included by a public opening response; preferably minimize the public applicant schema as well.
## Fix Focus Areas
- apps/Backend/src/flycatch_api/services/catalog_service.py[447-462]
- apps/Backend/src/flycatch_api/schemas/public_catalog.py[11-27]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| def list_published(self, db: Session, q: str | None, page: int, per_page: int) -> PublicEmployeeTestimonialList: | ||
| query = db.query(EmployeeTestimonialRow).filter(EmployeeTestimonialRow.status == ContentStatus.publish) | ||
| page, per_page, rows, total = _paginate( | ||
| query.order_by(EmployeeTestimonialRow.sort_order.asc()), page, per_page |
There was a problem hiding this comment.
2. Unlisted testimonials remain public 🐞 Bug ≡ Correctness
list_published filters only by row status and therefore returns testimonials whose listed publish checkbox is false. Administrators cannot actually hide such testimonials from the public list using the new visibility control.
Agent Prompt
## Issue description
The public testimonial list includes rows with `listed=false`, despite `listed` being the testimonial Publish checkbox.
## Issue Context
Keep row `status` and `listed` independent, but require both published status and listed visibility for public listing; clarify whether public detail should apply the same visibility rule.
## Fix Focus Areas
- apps/Backend/src/flycatch_api/services/catalog_service.py[601-619]
- specs/025-admin-employee-testimonials/spec.md[46-50]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| def list_published(self, db: Session, q: str | None, page: int, per_page: int) -> PublicEmployeeTestimonialList: | ||
| query = db.query(EmployeeTestimonialRow).filter(EmployeeTestimonialRow.status == ContentStatus.publish) | ||
| page, per_page, rows, total = _paginate( | ||
| query.order_by(EmployeeTestimonialRow.sort_order.asc()), page, per_page |
There was a problem hiding this comment.
3. Testimonial search is ignored 🐞 Bug ≡ Correctness
The public testimonial endpoint accepts and passes q, but EmployeeTestimonialService.list_published never applies it. Searches return the unfiltered page and an incorrect unfiltered total.
Agent Prompt
## Issue description
Public testimonial searches ignore the supplied `q` parameter.
## Issue Context
Apply the same appropriate name/designation/review filtering before pagination so both items and total reflect the query.
## Fix Focus Areas
- apps/Backend/src/flycatch_api/services/catalog_service.py[601-608]
- apps/Backend/src/flycatch_api/api/catalog.py[108-115]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| def list_published(self, db: Session, q: str | None, page: int, per_page: int) -> PublicEmailConfigurationList: | ||
| query = db.query(EmailConfigurationRow).filter(EmailConfigurationRow.status == ContentStatus.publish) | ||
| page, per_page, rows, total = _paginate(query.order_by(EmailConfigurationRow.created_at.desc()), page, per_page) |
There was a problem hiding this comment.
4. Email configuration search ignored 🐞 Bug ≡ Correctness
The public email-configuration endpoint accepts q, but EmailConfigurationService.list_published paginates a status-only query. Every search therefore returns unfiltered records and totals.
Agent Prompt
## Issue description
Public email-configuration searches ignore the supplied `q` parameter.
## Issue Context
Filter the published query by the relevant email fields before pagination.
## Fix Focus Areas
- apps/Backend/src/flycatch_api/services/catalog_service.py[714-719]
- apps/Backend/src/flycatch_api/api/catalog.py[108-115]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| def list_published(self, db: Session, q: str | None, page: int, per_page: int) -> PublicEmailTemplateList: | ||
| query = db.query(EmailTemplateRow).filter(EmailTemplateRow.status == ContentStatus.publish) | ||
| page, per_page, rows, total = _paginate(query.order_by(EmailTemplateRow.slug.asc()), page, per_page) |
There was a problem hiding this comment.
5. Email template search ignored 🐞 Bug ≡ Correctness
The public email-template endpoint accepts q, but EmailTemplateService.list_published never filters by it. Searches return the complete published template set and unfiltered totals.
Agent Prompt
## Issue description
Public email-template searches ignore the supplied `q` parameter.
## Issue Context
Filter published templates by slug, subject, and/or type before pagination, consistently with the admin search.
## Fix Focus Areas
- apps/Backend/src/flycatch_api/services/catalog_service.py[807-812]
- apps/Backend/src/flycatch_api/api/catalog.py[149-163]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| def list_published(self, db: Session, q: str | None, page: int, per_page: int) -> PublicMembershipList: | ||
| query = db.query(MembershipRow).filter(MembershipRow.status == ContentStatus.publish) | ||
| page, per_page, rows, total = _paginate(query.order_by(MembershipRow.created_at.desc()), page, per_page) | ||
| return PublicMembershipList(items=[self._public(row) for row in rows], page=page, per_page=per_page, total=total) |
There was a problem hiding this comment.
6. Membership search is ignored 🐞 Bug ≡ Correctness
The public membership endpoint accepts q, but MembershipService.list_published does not use it. Searches always return the unfiltered published page and total.
Agent Prompt
## Issue description
Public membership searches ignore the supplied `q` parameter.
## Issue Context
Filter published memberships by title and description before pagination, matching the admin search behavior.
## Fix Focus Areas
- apps/Backend/src/flycatch_api/services/catalog_service.py[1231-1234]
- apps/Backend/src/flycatch_api/api/catalog.py[108-115]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| <h2>{t(`${ns}.title`)}</h2> | ||
| <button type="button" className="primary" onClick={onAdd}> | ||
| {t(`${ns}.add`)} |
There was a problem hiding this comment.
7. Read-only users see mutations 🐞 Bug ≡ Correctness
Catalog navigation is granted with only <resource>.read, but every catalog list unconditionally exposes Add, Edit, and Delete controls and routes into writable forms. Read-only administrators can therefore enter mutation flows that inevitably fail at the backend permission checks.
Agent Prompt
## Issue description
Read-only catalog users are shown create, update, publish, and delete UI they are not authorized to use.
## Issue Context
Pass resource action permissions into catalog list/form components, hide or disable each mutation control, and prevent direct form navigation when the matching grant is absent.
## Fix Focus Areas
- apps/Administration-FE/src/components/CatalogList.tsx[20-71]
- apps/Administration-FE/src/components/CatalogList.tsx[168-181]
- apps/Administration-FE/src/components/CatalogForm.tsx[431-445]
- apps/Administration-FE/src/components/AdminShell.tsx[1370-1392]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Changes
Reviewer
@bprahul017 & @Sinoj-flycatch