Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
fbbe467
Pending changes exported from your codespace
vihar2712 Jun 24, 2025
755012e
grades controller finished
vihar2712 Aug 5, 2025
a1878ad
Merged main branch into join-team-requests-and-invitations
vihar2712 Aug 11, 2025
cd798c6
team hierarchy still unresolved. authorization module included.
vihar2712 Aug 21, 2025
65bf36b
/api/v1 removed
vihar2712 Oct 1, 2025
61e8698
modified invitation model
vihar2712 Oct 1, 2025
8985131
modified student_teams controller - made use of serializer, sending c…
vihar2712 Oct 6, 2025
04e31e6
methods inside student_teams added
vihar2712 Oct 12, 2025
9f8d758
retract, accept, reject invitation working
vihar2712 Oct 13, 2025
f0ebf63
added authorization inside invitations controller
vihar2712 Oct 17, 2025
4c80523
modified invitations controller
vihar2712 Oct 27, 2025
61a437b
added invitations sent by participant route and method
vihar2712 Oct 29, 2025
ec90caa
added methods for performing crud operations on advertisement inside …
vihar2712 Nov 5, 2025
4d25216
Advertisements and JoinTeamRequests (#248)
vihar2712 Dec 25, 2025
bf50188
Pending changes exported from your codespace
vihar2712 Jun 24, 2025
981c8af
grades controller finished
vihar2712 Aug 5, 2025
de27c99
team hierarchy still unresolved. authorization module included.
vihar2712 Aug 21, 2025
82583d1
/api/v1 removed
vihar2712 Oct 1, 2025
5f68a47
modified invitation model
vihar2712 Oct 1, 2025
384d4b6
modified student_teams controller - made use of serializer, sending c…
vihar2712 Oct 6, 2025
68724ad
methods inside student_teams added
vihar2712 Oct 12, 2025
fc5388c
retract, accept, reject invitation working
vihar2712 Oct 13, 2025
e765e2e
added authorization inside invitations controller
vihar2712 Oct 17, 2025
5316440
modified invitations controller
vihar2712 Oct 27, 2025
eca90c3
added invitations sent by participant route and method
vihar2712 Oct 29, 2025
e2750cf
added methods for performing crud operations on advertisement inside …
vihar2712 Nov 5, 2025
eb826b5
Merge branch 'advertisements' of https://github.com/expertiza/reimple…
vihar2712 Dec 26, 2025
0eee19c
synced to all the updated changes of main
vihar2712 Dec 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ RUN bundle install
EXPOSE 3002

# Set the entry point
ENTRYPOINT ["/app/setup.sh"]
ENTRYPOINT ["/app/setup.sh"]
2 changes: 1 addition & 1 deletion app/controllers/bookmarks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class BookmarksController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :not_found

def action_allowed?
has_privileges_of?('Student')
current_user_has_student_privileges?
end
# Index method returns the list of JSON objects of the bookmark
# GET on /bookmarks
Expand Down
23 changes: 4 additions & 19 deletions app/controllers/concerns/authorization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def authorize

# Check if all actions are allowed
def all_actions_allowed?
return true if has_privileges_of?('Super Administrator')
return true if current_user_has_super_admin_privileges?
action_allowed?
end

Expand All @@ -27,25 +27,13 @@ def action_allowed?
true
end

# Checks if current user has the required role or higher privileges
# @param required_role [Role, String] The minimum role required (can be Role object or role name)
# @return [Boolean] true if user has required role or higher privileges
# @example
# has_privileges_of?('Administrator') # checks if user is an admin or higher
# has_privileges_of?(Role::INSTRUCTOR) # checks if user is an instructor or higher
def has_privileges_of?(required_role)
required_role = Role.find_by_name(required_role) if required_role.is_a?(String)
current_user&.role&.all_privileges_of?(required_role) || false
end

# Unlike has_privileges_of? which checks for role hierarchy and privilege levels,
# this method checks if the user has exactly the specified role
# @param role_name [String, Role] The exact role to check for
# @return [Boolean] true if user has exactly this role, false otherwise
# @example
# has_role?('Student') # true only if user is exactly a student
# has_role?(Role::INSTRUCTOR) # true only if user is exactly an instructor
def has_role?(required_role)
# current_user_has_role?('Student') # true only if user is exactly a student
# current_user_has_role?(Role::INSTRUCTOR) # true only if user is exactly an instructor
def current_user_has_role?(required_role)
required_role = required_role.name if required_role.is_a?(Role)
current_user&.role&.name == required_role
end
Expand Down Expand Up @@ -240,9 +228,6 @@ def current_user_has_all_heatgrid_data_privileges?(assignment)
# Let the Role model define this logic for the sake of DRY
# If there is no currently logged-in user simply return false
def current_user_has_privileges_of?(role_name)
# puts current_user_and_role_exist?
# puts current_user
# puts current_user.role.all_privileges_of?(Role.find_by(name: role_name))
current_user_and_role_exist? && current_user.role.all_privileges_of?(Role.find_by(name: role_name))
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/courses_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class CoursesController < ApplicationController
rescue_from ActionController::ParameterMissing, with: :parameter_missing

def action_allowed?
has_privileges_of?('Instructor')
current_user_has_instructor_privileges?
end

# GET /courses
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/institutions_controller.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
class InstitutionsController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :institution_not_found
def action_allowed?
has_role?('Instructor')
current_user_has_role?('Instructor')
end
# GET /institutions
def index
Expand Down
244 changes: 157 additions & 87 deletions app/controllers/invitations_controller.rb
Original file line number Diff line number Diff line change
@@ -1,87 +1,157 @@
class InvitationsController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :invite_not_found

# GET /invitations
def index
@invitations = Invitation.all
render json: @invitations, status: :ok
end

# POST /invitations/
def create
params[:invitation][:reply_status] ||= InvitationValidator::WAITING_STATUS
@invitation = Invitation.invitation_factory(invite_params)
if @invitation.save
@invitation.send_invite_email
render json: @invitation, status: :created
else
render json: { error: @invitation.errors }, status: :unprocessable_entity
end
end

# GET /invitations/:id
def show
@invitation = Invitation.find(params[:id])
render json: @invitation, status: :ok
end

# PATCH /invitations/:id
def update
@invitation = Invitation.find(params[:id])
case params[:reply_status]
when InvitationValidator::ACCEPT_STATUS
@invitation.accept_invitation(nil)
render json: @invitation, status: :ok
when InvitationValidator::REJECT_STATUS
@invitation.decline_invitation(nil)
render json: @invitation, status: :ok
else
render json: @invitation.errors, status: :unprocessable_entity
end

end

# DELETE /invitations/:id
def destroy
@invitation = Invitation.find(params[:id])
@invitation.retract_invitation(nil)
render nothing: true, status: :no_content
end

# GET /invitations/:user_id/:assignment_id
def invitations_for_user_assignment
begin
@user = User.find(params[:user_id])
rescue ActiveRecord::RecordNotFound => e
render json: { error: e.message }, status: :not_found
return
end

begin
@assignment = Assignment.find(params[:assignment_id])
rescue ActiveRecord::RecordNotFound => e
render json: { error: e.message }, status: :not_found
return
end

@invitations = Invitation.where(to_id: @user.id).where(assignment_id: @assignment.id)
render json: @invitations, status: :ok
end

private

# This method will check if the invited user is a participant in the assignment.
# Currently there is no association between assignment and users therefore this method is not implemented yet.
def check_participant_before_invitation; end

# only allow a list of valid invite params
def invite_params
params.require(:invitation).permit(:id, :assignment_id, :from_id, :to_id, :reply_status)
end

# helper method used when invite is not found
def invite_not_found
render json: { error: "Invitation with id #{params[:id]} not found" }, status: :not_found
end

end
class InvitationsController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :invite_not_found
before_action :set_invitation, only: %i[show update destroy]
before_action :invitee_participant, only: %i[create]

def action_allowed?
case params[:action]
when 'invitations_sent_to_participant'
@participant = AssignmentParticipant.find(params[:participant_id])
unless current_user_has_id?(@participant.user_id)
render json: { error: "You do not have permission to perform this action." }, status: :forbidden
end
return true
else
return true
end
end

# GET /invitations
def index
@invitations = Invitation.all
render json: @invitations, status: :ok
end

# POST /invitations/
def create
params[:invitation][:reply_status] ||= InvitationValidator::WAITING_STATUS
@invitation = Invitation.invitation_factory(invite_params)
if @invitation.save
@invitation.send_invite_email
render json: { success: true, message: "Invitation successfully sent to #{params[:username]}", invitation: @invitation}, status: :created
else
render json: { error: @invitation.errors[:base].first}, status: :unprocessable_entity
end
end

# GET /invitations/:id
def show
render json: @invitation, status: :ok
end

# PATCH /invitations/:id
def update
case params[:reply_status]
when InvitationValidator::ACCEPT_STATUS
# if the current invitation status is either accepted/rejected/retracted then the invitation is no longer valid.
unless @invitation.reply_status.eql?(InvitationValidator::WAITING_STATUS)
render json: { error: "Sorry, the invitation is no longer valid" }, status: :unprocessable_entity
return
end
result = @invitation.accept_invitation
if result[:success]
render json: { success: true, message: result[:message], invitation: @invitation}, status: :ok
else
render json: { error: result[:error] }, status: :unprocessable_entity
end
when InvitationValidator::DECLINED_STATUS
@invitation.decline_invitation
render json: { success: true, message: "Invitation rejected successfully", invitation: @invitation}, status: :ok
when InvitationValidator::RETRACT_STATUS
@invitation.retract_invitation
render json: { success: true, message: "Invitation retracted successfully", invitation: @invitation}, status: :ok
else
render json: @invitation.errors, status: :unprocessable_entity
end
end

# DELETE /invitations/:id
def destroy
@invitation.destroy!
render json: { success:true, message: "Invitation deleted successfully." }, status: :ok

rescue ActiveRecord::RecordNotFound
render json: { error: "Invitation not found." }, status: :not_found
rescue ActiveRecord::RecordNotDestroyed => e
render json: { error: "Failed to retract invitation: #{e.record.errors.full_messages.to_sentence}" },
status: :unprocessable_entity
rescue => e
render json: { error: "Unexpected error: #{e.message}" }, status: :internal_server_error
end

def invitations_sent_to_participant
begin
rescue ActiveRecord::RecordNotFound => e
render json: { message: e.message, success:false }, status: :not_found
return
end

@invitations = Invitation.where(to_id: @participant.id, assignment_id: @participant.parent_id)
render json: @invitations, status: :ok
end

def invitations_sent_by_team
begin
team = AssignmentTeam.find(params[:team_id])
rescue ActiveRecord::RecordNotFound => e
render json: { message: e.message, success: false }, status: :not_found
return
end

@invitations = Invitation.where(from_id: team.id, assignment_id: team.parent_id)
render json: @invitations, status: :ok
end

def invitations_sent_by_participant
begin
participant = AssignmentParticipant.find(params[:participant_id])
rescue ActiveRecord::RecordNotFound => e
render json: { message: e.message, success: false }, status: :not_found
return
end

@invitations = Invitation.where(participant_id: participant.id, assignment_id: participant.parent_id)
render json: @invitations, status: :ok
end


private

# only allow a list of valid invite params
def invite_params
params.require(:invitation).permit(:id, :assignment_id, :reply_status).merge(from_team: inviter_team, to_participant: invitee_participant, from_participant: inviter_participant)
end

# helper method used when invite is not found
def invite_not_found
render json: { error: "Invitation not found" }, status: :not_found
end

# helper method used to fetch invitation from its id
def set_invitation
@invitation = Invitation.find(params[:id])
end

def inviter_participant
AssignmentParticipant.find_by(user: current_user)
end

# the team of the inviter at the time of sending invitation
def inviter_team
inviter_participant.team
end

def invitee_participant
invitee_user = User.find_by(name: params[:username])
unless invitee_user
render json: { error: "Participant with username #{params[:username]} not found" }, status: :not_found
return
end
invitee = AssignmentParticipant.find_by(parent_id: params[:assignment_id], user: invitee_user)
unless invitee
render json: { error: "Participant with username #{params[:username]} not found" }, status: :not_found
return
end
invitee
end
end
Loading
Loading