CSC/ECE 517 Fall 2025 - E2565. Integration of JoinTeamRequests: Difference between revisions
No edit summary |
No edit summary |
||
| Line 9: | Line 9: | ||
Currently, Expertiza supports teammate advertisements for assignments with topics. Topic holders can create advertisements on the "Your Team" page. However, the complete flow for responding to advertisements and managing join team requests is not fully integrated. The following gaps exist: | Currently, Expertiza supports teammate advertisements for assignments with topics. Topic holders can create advertisements on the "Your Team" page. However, the complete flow for responding to advertisements and managing join team requests is not fully integrated. The following gaps exist: | ||
1. The join_team_requests_controller has action privilege checks scattered across methods instead of using a centralized `action_allowed?` method | |||
2. There is no frontend UI for viewing advertisements on the Signup Sheet page | |||
3. There is no UI for creating join team requests when responding to advertisements | |||
4. The "Received Requests" section is missing from the StudentTeamView page | |||
5. There is no method to accept join team requests (only decline exists) | |||
6. The controller needs better integration with the frontend | |||
=== Goals === | === Goals === | ||
1. Refactor the join_team_requests_controller to use a single `action_allowed?` method for privilege checking | |||
2. Add a trumpet icon on the Signup Sheet page to indicate when advertisements exist for topics | |||
3. Create a frontend UI for viewing advertisements and creating join team requests | |||
4. Add a "Received Requests" section to StudentTeamView.tsx for managing incoming join team requests | |||
5. Implement an accept method for join team requests | |||
6. Ensure proper validation that teams cannot accept requests when full | |||
7. Conduct comprehensive testing of the entire flow | |||
== Design == | == Design == | ||
| Line 370: | Line 381: | ||
=== Phase 1: Backend Refactoring === | === Phase 1: Backend Refactoring === | ||
1. '''Refactor action_allowed? method''' | |||
a. Update `Api::V1::JoinTeamRequestsController#action_allowed?` to handle all actions | |||
b. Remove individual privilege checks from `index` method | |||
c. Ensure all actions go through the centralized check | |||
2. '''Add accept method''' | |||
a. Implement `accept` method with team full validation | |||
b. Add transaction handling for atomic operations | |||
c. Update request status to ACCEPTED | |||
d. Add participant to team using `team.add_member` | |||
3. '''Add team_requests method''' | |||
a. Implement method to fetch requests for a team | |||
b. Add authorization check (user must be team member) | |||
c. Include participant and user data in response | |||
4. '''Add advertisements method to SignedUpTeamsController''' | |||
a. Implement method to fetch all advertisements for an assignment | |||
b. Join with teams and sign_up_topics | |||
c. Return formatted advertisement data | |||
5. '''Update JoinTeamRequest model''' | |||
a. Add `belongs_to :team` association | |||
b. Add scopes for filtering | |||
c. Update validations | |||
6. '''Update routes''' | |||
a. Add routes for new endpoints | |||
b. Ensure RESTful conventions | |||
=== Phase 2: Frontend - Signup Sheet === | === Phase 2: Frontend - Signup Sheet === | ||
1. '''Create SignupSheet component (if not exists)''' | |||
a. Display topics for an assignment | |||
b. Fetch advertisements for the assignment | |||
c. Map advertisements to topics | |||
d. Display trumpet icon for topics with advertisements | |||
2. '''Create JoinTeamRequestModal component''' | |||
a. Design modal UI | |||
b. Implement form with comments field | |||
c. Add submit handler | |||
d. Handle success/error states | |||
3. '''Integrate modal with SignupSheet''' | |||
a. Add click handler for topics with advertisements | |||
b. Open modal with advertisement details | |||
c. Handle modal close | |||
=== Phase 3: Frontend - StudentTeamView === | === Phase 3: Frontend - StudentTeamView === | ||
1. '''Add Received Requests section''' | |||
a. Create section similar to "Received Invitations" | |||
b. Fetch join team requests for current team | |||
c. Display requests in table format | |||
2. '''Implement approve/decline functionality''' | |||
a. Add approve button handler | |||
b. Add decline button handler | |||
c. Check team full status before allowing approve | |||
d. Update UI after actions | |||
3. '''Add useJoinTeamRequest hook''' | |||
a. Create hook file | |||
b. Implement all API methods | |||
c. Export hook for use in components | |||
=== Phase 4: Integration and Testing === | === Phase 4: Integration and Testing === | ||
1. '''End-to-end testing''' | |||
a. Test advertisement creation → request creation → approval flow | |||
b. Test decline flow | |||
c. Test team full validation | |||
d. Test authorization checks | |||
2. '''Unit testing''' | |||
a. Test controller methods | |||
b. Test model validations | |||
c. Test frontend components | |||
3. '''Integration testing''' | |||
a. Test API endpoints | |||
b. Test frontend-backend integration | |||
c. Test error handling | |||
== Files Changed/Added == | == Files Changed/Added == | ||
| Line 492: | Line 492: | ||
==== Unit Tests ==== | ==== Unit Tests ==== | ||
1. '''JoinTeamRequestsController Tests''' | |||
a. Test action_allowed? for different actions and user roles | |||
b. Test accept method with valid request | |||
c. Test accept method when team is full | |||
d. Test accept method when participant already on team | |||
e. Test team_requests method authorization | |||
f. Test team_requests method returns correct data | |||
2. '''SignedUpTeamsController Tests''' | |||
a. Test advertisements method returns correct data | |||
b. Test advertisements method filters correctly | |||
3. '''JoinTeamRequest Model Tests''' | |||
a. Test associations | |||
b. Test validations | |||
c. Test scopes | |||
==== Integration Tests ==== | ==== Integration Tests ==== | ||
1. '''End-to-End Flow Tests''' | |||
a. Create advertisement → Create join request → Accept request | |||
b. Create advertisement → Create join request → Decline request | |||
c. Test team full validation prevents acceptance | |||
d. Test authorization prevents unauthorized access | |||
=== Frontend Testing === | === Frontend Testing === | ||
| Line 521: | Line 519: | ||
==== Component Tests ==== | ==== Component Tests ==== | ||
1. '''SignUpSheet Component''' | |||
a. Test advertisement indicators display correctly | |||
b. Test modal opens on click | |||
c. Test data fetching | |||
2. '''JoinTeamRequestModal Component''' | |||
a. Test form submission | |||
b. Test validation | |||
c. Test success/error handling | |||
3. '''StudentTeamView Component''' | |||
a. Test Received Requests section displays | |||
b. Test approve functionality | |||
c. Test decline functionality | |||
d. Test team full validation | |||
==== Integration Tests ==== | ==== Integration Tests ==== | ||
1. '''API Integration''' | |||
a. Test all API calls work correctly | |||
b. Test error handling | |||
c. Test loading states | |||
== Edge Cases and Error Handling == | == Edge Cases and Error Handling == | ||
| Line 548: | Line 544: | ||
=== Backend Edge Cases === | === Backend Edge Cases === | ||
1. '''Team Full Validation''' | |||
- Check team capacity before accepting request | - Check team capacity before accepting request | ||
- Return appropriate error message | - Return appropriate error message | ||
- Prevent race conditions with database transactions | - Prevent race conditions with database transactions | ||
2. '''Authorization''' | |||
- Verify user is team member before showing requests | |||
- Verify user is team member before showing requests | - Verify user is student before creating requests | ||
- Verify user is student before creating requests | - Verify user is administrator before viewing all requests | ||
- Verify user is administrator before viewing all requests | 3. '''Duplicate Requests''' | ||
- Prevent creating duplicate requests from same participant | |||
- Handle case where participant already on team | |||
- Prevent creating duplicate requests from same participant | 4. '''Concurrent Modifications''' | ||
- Handle case where participant already on team | - Use transactions for atomic operations | ||
- Handle race conditions in team membership updates | |||
- Use transactions for atomic operations | |||
- Handle race conditions in team membership updates | |||
=== Frontend Edge Cases === | === Frontend Edge Cases === | ||
1. '''Network Errors''' | |||
- Display appropriate error messages | - Display appropriate error messages | ||
- Handle timeout scenarios | - Handle timeout scenarios | ||
- Provide retry mechanisms | - Provide retry mechanisms | ||
2. '''Empty States''' | |||
- Show appropriate messages when no advertisements exist | |||
- Show appropriate messages when no advertisements exist | - Show appropriate messages when no requests exist | ||
- Show appropriate messages when no requests exist | 3. '''Loading States''' | ||
- Display loading indicators during API calls | |||
- Prevent multiple simultaneous requests | |||
- Display loading indicators during API calls | 4. '''Form Validation''' | ||
- Prevent multiple simultaneous requests | - Validate required fields | ||
- Provide user feedback for errors | |||
- Validate required fields | |||
- Provide user feedback for errors | |||
== Security Considerations == | == Security Considerations == | ||
1. '''Authorization Checks''' | |||
- All endpoints must verify user permissions | - All endpoints must verify user permissions | ||
- Team members can only see requests for their team | - Team members can only see requests for their team | ||
- Students can only create requests for themselves | - Students can only create requests for themselves | ||
2. '''Input Validation''' | |||
- Sanitize all user inputs | |||
- Sanitize all user inputs | - Validate team_id and assignment_id parameters | ||
- Validate team_id and assignment_id parameters | - Prevent SQL injection through parameterized queries | ||
- Prevent SQL injection through parameterized queries | 3. '''Rate Limiting''' | ||
- Consider rate limiting for request creation | |||
- Prevent spam requests | |||
- Consider rate limiting for request creation | |||
- Prevent spam requests | |||
== References == | == References == | ||
Latest revision as of 02:43, 11 November 2025
E2565. Integration of JoinTeamRequests
Overview
This document describes the design and implementation plan for integrating JoinTeamRequests functionality in Expertiza. The feature enables students to respond to teammate advertisements by creating join team requests, which topic holders can then approve or decline. This integration will complete the teammate advertisement workflow by connecting the advertisement creation (already implemented) with the join team request flow.
Problem Statement
Currently, Expertiza supports teammate advertisements for assignments with topics. Topic holders can create advertisements on the "Your Team" page. However, the complete flow for responding to advertisements and managing join team requests is not fully integrated. The following gaps exist:
1. The join_team_requests_controller has action privilege checks scattered across methods instead of using a centralized `action_allowed?` method
2. There is no frontend UI for viewing advertisements on the Signup Sheet page
3. There is no UI for creating join team requests when responding to advertisements
4. The "Received Requests" section is missing from the StudentTeamView page
5. There is no method to accept join team requests (only decline exists)
6. The controller needs better integration with the frontend
Goals
1. Refactor the join_team_requests_controller to use a single `action_allowed?` method for privilege checking
2. Add a trumpet icon on the Signup Sheet page to indicate when advertisements exist for topics
3. Create a frontend UI for viewing advertisements and creating join team requests
4. Add a "Received Requests" section to StudentTeamView.tsx for managing incoming join team requests
5. Implement an accept method for join team requests
6. Ensure proper validation that teams cannot accept requests when full
7. Conduct comprehensive testing of the entire flow
Design
Backend Design
Controller Refactoring
The `Api::V1::JoinTeamRequestsController` currently has privilege checks scattered across methods:
- `index` method checks for administrator role directly - `action_allowed?` only checks if user is a student
Refactored Design:
The `action_allowed?` method will be enhanced to handle different actions based on the action being performed:
def action_allowed?
case action_name.to_sym
when :index
@current_user.administrator?
when :create, :show, :update, :destroy, :decline, :accept
@current_user.student?
else
false
end
end
All methods will rely on this centralized privilege check, removing individual checks from methods like `index`.
New Methods
1. Accept Method
Add a new `accept` method to handle accepting join team requests:
# PATCH/PUT api/v1/join_team_requests/:id/accept
# Accepts a join team request and adds the participant to the team
def accept
team = @join_team_request.team
# Check if team is full
if team.full?
return render json: { error: 'This team is full.' }, status: :unprocessable_entity
end
# Check if participant is already on the team
if team.participants.include?(@join_team_request.participant)
return render json: { error: 'Participant already belongs to the team' }, status: :unprocessable_entity
end
ActiveRecord::Base.transaction do
# Add participant to team
result = team.add_member(@join_team_request.participant)
if result[:success]
# Update request status
@join_team_request.update!(reply_status: ACCEPTED)
render json: { message: 'JoinTeamRequest accepted successfully', join_team_request: @join_team_request }, status: :ok
else
render json: { error: result[:error] }, status: :unprocessable_entity
raise ActiveRecord::Rollback
end
end
rescue => e
render json: { error: "Failed to accept request: #{e.message}" }, status: :unprocessable_entity
end
2. Get Join Team Requests for Team
Add a method to fetch all join team requests for a specific team (for the "Received Requests" section):
# GET api/v1/join_team_requests/team/:team_id
# Gets all join team requests for a specific team
def team_requests
team = Team.find(params[:team_id])
# Verify current user is a member of the team
unless team.participants.exists?(user_id: @current_user.id)
return render json: { error: 'Unauthorized' }, status: :unauthorized
end
join_team_requests = JoinTeamRequest.where(team_id: params[:team_id])
.includes(:participant => :user)
.order(created_at: :desc)
render json: join_team_requests, status: :ok
end
3. Get Advertisements for Assignment
Add a method to fetch all advertisements for an assignment (for the Signup Sheet page):
# GET api/v1/signed_up_teams/advertisements/:assignment_id
# Gets all advertisements for an assignment
def advertisements
assignment = Assignment.find(params[:assignment_id])
signed_up_teams = SignedUpTeam.joins(:team, :sign_up_topic)
.where(sign_up_topics: { assignment_id: params[:assignment_id] })
.where(advertise_for_partner: true)
.includes(:team, :sign_up_topic)
advertisements = signed_up_teams.map do |sut|
{
id: sut.id,
team_id: sut.team_id,
team_name: sut.team.name,
topic_id: sut.sign_up_topic_id,
topic_name: sut.sign_up_topic.topic_name,
comments_for_advertisement: sut.comments_for_advertisement,
created_at: sut.created_at
}
end
render json: advertisements, status: :ok
end
Model Updates
The `JoinTeamRequest` model needs to establish proper associations:
class JoinTeamRequest < ApplicationRecord
belongs_to :team
belongs_to :participant
ACCEPTED_STATUSES = %w[ACCEPTED DECLINED PENDING]
validates :reply_status, inclusion: { in: ACCEPTED_STATUSES }
scope :pending, -> { where(reply_status: 'PENDING') }
scope :for_team, ->(team_id) { where(team_id: team_id) }
end
Routes Updates
Add new routes for the additional endpoints:
resources :join_team_requests do
collection do
get 'team/:team_id', to: 'join_team_requests#team_requests'
post 'decline/:id', to: 'join_team_requests#decline'
post 'accept/:id', to: 'join_team_requests#accept'
end
end
resources :signed_up_teams do
collection do
get 'advertisements/:assignment_id', to: 'signed_up_teams#advertisements'
end
member do
post :create_advertisement
patch :update_advertisement
delete :remove_advertisement
end
end
Frontend Design
Signup Sheet Page Enhancement
Create a new component or enhance existing signup sheet to display advertisements:
Component: SignupSheet.tsx
This component will:
- Display all topics for an assignment - Show a trumpet icon (🔔) next to topics that have advertisements - Allow users to click on topics with advertisements to view details - Provide a modal/dialog to view advertisement details and create a join team request
interface Advertisement {
id: number;
team_id: number;
team_name: string;
topic_id: number;
topic_name: string;
comments_for_advertisement: string;
created_at: string;
}
interface SignUpTopic {
id: number;
topic_name: string;
topic_identifier: string;
max_choosers: number;
description?: string;
has_advertisement?: boolean;
advertisement?: Advertisement;
}
The UI will show:
- A table/list of topics - Trumpet icon indicator for topics with advertisements - Click handler to open advertisement details modal
Join Team Request Modal
Create a modal component for creating join team requests:
Component: JoinTeamRequestModal.tsx
This modal will:
- Display advertisement details (team name, topic, desired qualifications) - Provide a text area for comments (optional) - Show a "Send Request" button - Handle form submission and API calls
interface JoinTeamRequestModalProps {
show: boolean;
onHide: () => void;
advertisement: Advertisement;
assignmentId: number;
onSuccess: () => void;
}
StudentTeamView Enhancement
Add a "Received Requests" section to `StudentTeamView.tsx`:
Section: Received Join Team Requests
This section will:
- Display all pending join team requests for the current team - Show request details: requester name, email, comments, date - Provide "Approve" and "Decline" buttons for each request - Disable approve button if team is full - Show status for non-pending requests
interface JoinTeamRequest {
id: number;
participant_id: number;
team_id: number;
comments: string;
reply_status: 'PENDING' | 'ACCEPTED' | 'DECLINED';
created_at: string;
participant: {
id: number;
user: {
id: number;
name: string;
full_name: string;
email: string;
};
};
}
The UI structure will be similar to the existing "Received Invitations" section, with:
- Table displaying request information - Action buttons (Approve/Decline) for pending requests - Status display for processed requests
API Hooks
Create or extend hooks for join team requests:
File: hooks/useJoinTeamRequest.ts
export const useJoinTeamRequest = () => {
const createRequestAPI = useAPI();
const acceptRequestAPI = useAPI();
const declineRequestAPI = useAPI();
const fetchTeamRequestsAPI = useAPI();
const fetchAdvertisementsAPI = useAPI();
const createJoinTeamRequest = (teamId: number, assignmentId: number, comments?: string) =>
createRequestAPI.sendRequest({
url: `/join_team_requests`,
method: 'POST',
data: { team_id: teamId, assignment_id: assignmentId, comments }
});
const acceptJoinTeamRequest = (requestId: number) =>
acceptRequestAPI.sendRequest({
url: `/join_team_requests/accept/${requestId}`,
method: 'POST'
});
const declineJoinTeamRequest = (requestId: number) =>
declineRequestAPI.sendRequest({
url: `/join_team_requests/decline/${requestId}`,
method: 'POST'
});
const fetchTeamRequests = (teamId: number) =>
fetchTeamRequestsAPI.sendRequest({
url: `/join_team_requests/team/${teamId}`
});
const fetchAdvertisements = (assignmentId: number) =>
fetchAdvertisementsAPI.sendRequest({
url: `/signed_up_teams/advertisements/${assignmentId}`
});
return {
createJoinTeamRequest,
acceptJoinTeamRequest,
declineJoinTeamRequest,
fetchTeamRequests,
fetchAdvertisements,
createRequestAPI,
acceptRequestAPI,
declineRequestAPI,
fetchTeamRequestsAPI,
fetchAdvertisementsAPI
};
};
Implementation Plan
Phase 1: Backend Refactoring
1. Refactor action_allowed? method
a. Update `Api::V1::JoinTeamRequestsController#action_allowed?` to handle all actions b. Remove individual privilege checks from `index` method c. Ensure all actions go through the centralized check
2. Add accept method
a. Implement `accept` method with team full validation b. Add transaction handling for atomic operations c. Update request status to ACCEPTED d. Add participant to team using `team.add_member`
3. Add team_requests method
a. Implement method to fetch requests for a team b. Add authorization check (user must be team member) c. Include participant and user data in response
4. Add advertisements method to SignedUpTeamsController
a. Implement method to fetch all advertisements for an assignment b. Join with teams and sign_up_topics c. Return formatted advertisement data
5. Update JoinTeamRequest model
a. Add `belongs_to :team` association b. Add scopes for filtering c. Update validations
6. Update routes
a. Add routes for new endpoints b. Ensure RESTful conventions
Phase 2: Frontend - Signup Sheet
1. Create SignupSheet component (if not exists)
a. Display topics for an assignment b. Fetch advertisements for the assignment c. Map advertisements to topics d. Display trumpet icon for topics with advertisements
2. Create JoinTeamRequestModal component
a. Design modal UI b. Implement form with comments field c. Add submit handler d. Handle success/error states
3. Integrate modal with SignupSheet
a. Add click handler for topics with advertisements b. Open modal with advertisement details c. Handle modal close
Phase 3: Frontend - StudentTeamView
1. Add Received Requests section
a. Create section similar to "Received Invitations" b. Fetch join team requests for current team c. Display requests in table format
2. Implement approve/decline functionality
a. Add approve button handler b. Add decline button handler c. Check team full status before allowing approve d. Update UI after actions
3. Add useJoinTeamRequest hook
a. Create hook file b. Implement all API methods c. Export hook for use in components
Phase 4: Integration and Testing
1. End-to-end testing
a. Test advertisement creation → request creation → approval flow b. Test decline flow c. Test team full validation d. Test authorization checks
2. Unit testing
a. Test controller methods b. Test model validations c. Test frontend components
3. Integration testing
a. Test API endpoints b. Test frontend-backend integration c. Test error handling
Files Changed/Added
Backend Files
Modified:
- `app/controllers/api/v1/join_team_requests_controller.rb` - Refactor action_allowed?, add accept and team_requests methods - `app/controllers/api/v1/signed_up_teams_controller.rb` - Add advertisements method - `app/models/join_team_request.rb` - Add associations and scopes - `config/routes.rb` - Add new routes
Added:
- `spec/requests/api/v1/join_team_requests_spec.rb` - Request specs for new methods - `spec/models/join_team_request_spec.rb` - Model specs
Frontend Files
Modified:
- `src/pages/Student Teams/StudentTeamView.tsx` - Add Received Requests section - `src/hooks/useStudentTeam.ts` - Add join team request methods (or create new hook)
Added:
- `src/pages/SignUpSheet/SignUpSheet.tsx` - Signup sheet component with advertisement indicators - `src/pages/SignUpSheet/JoinTeamRequestModal.tsx` - Modal for creating join team requests - `src/hooks/useJoinTeamRequest.ts` - Hook for join team request API calls - `src/pages/SignUpSheet/SignUpSheet.module.css` - Styles for signup sheet - `src/pages/SignUpSheet/JoinTeamRequestModal.module.css` - Styles for modal
Testing Plan
Backend Testing
Unit Tests
1. JoinTeamRequestsController Tests
a. Test action_allowed? for different actions and user roles b. Test accept method with valid request c. Test accept method when team is full d. Test accept method when participant already on team e. Test team_requests method authorization f. Test team_requests method returns correct data
2. SignedUpTeamsController Tests
a. Test advertisements method returns correct data b. Test advertisements method filters correctly
3. JoinTeamRequest Model Tests
a. Test associations b. Test validations c. Test scopes
Integration Tests
1. End-to-End Flow Tests
a. Create advertisement → Create join request → Accept request b. Create advertisement → Create join request → Decline request c. Test team full validation prevents acceptance d. Test authorization prevents unauthorized access
Frontend Testing
Component Tests
1. SignUpSheet Component
a. Test advertisement indicators display correctly b. Test modal opens on click c. Test data fetching
2. JoinTeamRequestModal Component
a. Test form submission b. Test validation c. Test success/error handling
3. StudentTeamView Component
a. Test Received Requests section displays b. Test approve functionality c. Test decline functionality d. Test team full validation
Integration Tests
1. API Integration
a. Test all API calls work correctly b. Test error handling c. Test loading states
Edge Cases and Error Handling
Backend Edge Cases
1. Team Full Validation
- Check team capacity before accepting request - Return appropriate error message - Prevent race conditions with database transactions
2. Authorization
- Verify user is team member before showing requests - Verify user is student before creating requests - Verify user is administrator before viewing all requests
3. Duplicate Requests
- Prevent creating duplicate requests from same participant - Handle case where participant already on team
4. Concurrent Modifications
- Use transactions for atomic operations - Handle race conditions in team membership updates
Frontend Edge Cases
1. Network Errors
- Display appropriate error messages - Handle timeout scenarios - Provide retry mechanisms
2. Empty States
- Show appropriate messages when no advertisements exist - Show appropriate messages when no requests exist
3. Loading States
- Display loading indicators during API calls - Prevent multiple simultaneous requests
4. Form Validation
- Validate required fields - Provide user feedback for errors
Security Considerations
1. Authorization Checks
- All endpoints must verify user permissions - Team members can only see requests for their team - Students can only create requests for themselves
2. Input Validation
- Sanitize all user inputs - Validate team_id and assignment_id parameters - Prevent SQL injection through parameterized queries
3. Rate Limiting
- Consider rate limiting for request creation - Prevent spam requests
References
- Expertiza Wiki: E2252. Refactor auth controller.rb & password retrieval controller.rb - Rails API Documentation - React Router Documentation - Expertiza Codebase: Existing invitation and team management implementations



