-
Notifications
You must be signed in to change notification settings - Fork 0
Client #93: Coach role pages #102
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
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
eab8c2b
chore: add shadcn dialog primitives and server error helper
FadyGergesRezk 7228c58
feat: show coach's team on the dashboard
FadyGergesRezk 015366a
feat: add event create/edit/delete and scope attendance status to tra…
FadyGergesRezk 4a3bfa2
fix: include trainer-coached teams in my teams
FadyGergesRezk c505141
fix: scope member filter options to the viewer's teams
FadyGergesRezk e0b387f
feat: add coach feedback compose, coverage tracking, and mock persist…
FadyGergesRezk 6f2424b
fix: confirm before deleting a development report
FadyGergesRezk f4042da
fix: address coderabbit review findings on PR #102
FadyGergesRezk 1b0145b
Merge remote-tracking branch 'origin/main' into client/93-coach-role-…
FadyGergesRezk 8f00d52
feat: add coach team edit and letters compose UI
FadyGergesRezk 8bc756b
fix: unify letters mock switch with shared mockOr pattern
FadyGergesRezk c0f205c
fix: enforce documented role scoping on event creation
raphael-frank 7f9a647
Merge branch 'main' into client/93-coach-role-pages
raphael-frank File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
40 changes: 40 additions & 0 deletions
40
services/spring-event/src/main/java/tum/devoops/eventservice/entity/DirectorEntity.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| package tum.devoops.eventservice.entity; | ||
|
|
||
| import java.io.Serializable; | ||
| import java.util.UUID; | ||
|
|
||
| import jakarta.persistence.Column; | ||
| import jakarta.persistence.Embeddable; | ||
| import jakarta.persistence.EmbeddedId; | ||
| import jakarta.persistence.Entity; | ||
| import jakarta.persistence.Table; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.Data; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
|
|
||
| /** | ||
| * Read-only shadow of {@code organization.directors}, owned by the organization service. | ||
| */ | ||
| @Entity | ||
| @Table(schema = "organization", name = "directors") | ||
| @Getter | ||
| @NoArgsConstructor | ||
| public class DirectorEntity { | ||
|
|
||
| // Composite PK: (sport_id, member_id). | ||
| @EmbeddedId | ||
| private Id id; | ||
|
|
||
| @Embeddable | ||
| @Data | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| public static class Id implements Serializable { | ||
| @Column(name = "sport_id", nullable = false) | ||
| private UUID sportId; | ||
|
|
||
| @Column(name = "member_id", nullable = false) | ||
| private UUID memberId; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
services/spring-event/src/main/java/tum/devoops/eventservice/entity/TrainerEntity.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| package tum.devoops.eventservice.entity; | ||
|
|
||
| import java.io.Serializable; | ||
| import java.util.UUID; | ||
|
|
||
| import jakarta.persistence.Column; | ||
| import jakarta.persistence.Embeddable; | ||
| import jakarta.persistence.EmbeddedId; | ||
| import jakarta.persistence.Entity; | ||
| import jakarta.persistence.Table; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.Data; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
|
|
||
| /** | ||
| * Read-only shadow of {@code organization.trainers}, owned by the organization service. | ||
| */ | ||
| @Entity | ||
| @Table(schema = "organization", name = "trainers") | ||
| @Getter | ||
| @NoArgsConstructor | ||
| public class TrainerEntity { | ||
|
|
||
| // Composite PK: (team_id, member_id). | ||
| @EmbeddedId | ||
| private Id id; | ||
|
|
||
| @Embeddable | ||
| @Data | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| public static class Id implements Serializable { | ||
| @Column(name = "team_id", nullable = false) | ||
| private UUID teamId; | ||
|
|
||
| @Column(name = "member_id", nullable = false) | ||
| private UUID memberId; | ||
| } | ||
| } |
8 changes: 8 additions & 0 deletions
8
...es/spring-event/src/main/java/tum/devoops/eventservice/repository/DirectorRepository.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package tum.devoops.eventservice.repository; | ||
|
|
||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
|
|
||
| import tum.devoops.eventservice.entity.DirectorEntity; | ||
|
|
||
| public interface DirectorRepository extends JpaRepository<DirectorEntity, DirectorEntity.Id> { | ||
| } |
8 changes: 8 additions & 0 deletions
8
...ces/spring-event/src/main/java/tum/devoops/eventservice/repository/TrainerRepository.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package tum.devoops.eventservice.repository; | ||
|
|
||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
|
|
||
| import tum.devoops.eventservice.entity.TrainerEntity; | ||
|
|
||
| public interface TrainerRepository extends JpaRepository<TrainerEntity, TrainerEntity.Id> { | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| import { act } from 'react' | ||
| import { createRoot, type Root } from 'react-dom/client' | ||
| import { MemoryRouter } from 'react-router-dom' | ||
| import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' | ||
|
|
||
| vi.mock('@/features/auth', async () => { | ||
| const { MOCK_PERSONAS } = await import('@/mocks/personas') | ||
|
|
||
| return { | ||
| useAuth: () => ({ user: MOCK_PERSONAS.coach }), | ||
| } | ||
| }) | ||
|
|
||
| vi.mock('@/app/pages/api/dashboardQueries', async () => { | ||
| const { dashboardFixtures } = await import('@/mocks/fixtures/dashboard') | ||
|
|
||
| return { | ||
| useDashboard: () => ({ | ||
| data: dashboardFixtures.coach, | ||
| isLoading: false, | ||
| error: null, | ||
| }), | ||
| } | ||
| }) | ||
|
|
||
| vi.mock('@/features/sport-events/api/queries', async () => { | ||
| const { eventSummaryFixtures } = await import('@/mocks/fixtures') | ||
| const { MOCK_PERSONAS } = await import('@/mocks/personas') | ||
| const { scopeEvents } = await import('@/mocks/scope') | ||
|
|
||
| return { | ||
| useEventsList: () => ({ | ||
| data: scopeEvents(eventSummaryFixtures, MOCK_PERSONAS.coach), | ||
| isLoading: false, | ||
| error: null, | ||
| }), | ||
| } | ||
| }) | ||
|
|
||
| vi.mock('@/features/organization/api/queries', () => ({ | ||
| useSportsList: () => ({ | ||
| data: [], | ||
| isLoading: false, | ||
| error: null, | ||
| }), | ||
| useTeamsList: () => ({ | ||
| data: [], | ||
| isLoading: false, | ||
| error: null, | ||
| }), | ||
| })) | ||
|
|
||
| const { DashboardPage } = await import('@/app/pages/DashboardPage') | ||
| const { dashboardFixtures } = await import('@/mocks/fixtures/dashboard') | ||
|
|
||
| describe('DashboardPage', () => { | ||
| let container: HTMLDivElement | ||
| let root: Root | ||
|
|
||
| beforeEach(() => { | ||
| vi.clearAllMocks() | ||
| document.body.innerHTML = '<div id="root"></div>' | ||
| container = document.getElementById('root') as HTMLDivElement | ||
| root = createRoot(container) | ||
| }) | ||
|
|
||
| afterEach(async () => { | ||
| await act(async () => { | ||
| root.unmount() | ||
| }) | ||
| document.body.innerHTML = '' | ||
| }) | ||
|
|
||
| async function render() { | ||
| await act(async () => { | ||
| root.render( | ||
| <MemoryRouter> | ||
| <DashboardPage /> | ||
| </MemoryRouter>, | ||
| ) | ||
| }) | ||
| } | ||
|
|
||
| it('renders the coach team and roster size from the dashboard fixture', async () => { | ||
| const dashboard = dashboardFixtures.coach | ||
|
|
||
| expect(dashboard.role).toBe('trainer') | ||
|
|
||
| await render() | ||
|
|
||
| if (dashboard.role === 'trainer') { | ||
| expect(container.textContent).toContain(dashboard.team.name) | ||
| expect(container.textContent).toContain(`${dashboard.total_members} roster members`) | ||
| } | ||
| }) | ||
| }) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: AET-DevOps26/team-devoops
Length of output: 10170
🏁 Script executed:
Repository: AET-DevOps26/team-devoops
Length of output: 18727
Check every linked team/sport before allowing create
services/spring-event/src/main/java/tum/devoops/eventservice/service/EventService.java:195-215accepts the request if the requester matches any one linked team or any sport in the combined set. That lets a trainer/director mix one authorized link with unauthorized teams/sports and still create the event with the full payload. Add coverage for mixed authorized/unauthorized links and require each linked team/sport to be individually in scope.🤖 Prompt for AI Agents