mirror of https://github.com/docusealco/docuseal
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
77 lines
2.6 KiB
77 lines
2.6 KiB
# frozen_string_literal: true
|
|
|
|
module Api
|
|
module V1
|
|
module Admin
|
|
# InvitationAcceptanceController
|
|
# Handles token validation and invitation acceptance
|
|
# Implements single-use token enforcement with Redis
|
|
class InvitationAcceptanceController < ApiBaseController
|
|
# Skip authentication for token acceptance (user may not be logged in yet)
|
|
skip_before_action :authenticate_user!, only: [:create]
|
|
|
|
# POST /api/v1/admin/invitation_acceptance
|
|
def create
|
|
# Layer 1: Extract and validate token
|
|
raw_token = params[:token]
|
|
email = params[:email]
|
|
|
|
unless raw_token.present? && email.present?
|
|
return render json: { error: 'Token and email are required' }, status: :bad_request
|
|
end
|
|
|
|
# Layer 2: Find user by email (or create if needed)
|
|
user = User.find_by(email: email)
|
|
|
|
unless user
|
|
# In a real implementation, you might want to create the user
|
|
# or require them to register first
|
|
return render json: { error: 'User account not found. Please register first.' }, status: :not_found
|
|
end
|
|
|
|
# Layer 3: Use InvitationService for secure acceptance
|
|
invitation = InvitationService.accept_invitation(raw_token, user)
|
|
|
|
if invitation
|
|
# Layer 4: Return success with institution info
|
|
render json: {
|
|
message: 'Invitation accepted successfully',
|
|
institution: {
|
|
id: invitation.institution.id,
|
|
name: invitation.institution.name
|
|
},
|
|
role: invitation.role,
|
|
next_steps: 'You can now access the institution dashboard'
|
|
}
|
|
else
|
|
# Security event already logged by service
|
|
render json: { error: 'Invalid or expired token' }, status: :unprocessable_entity
|
|
end
|
|
end
|
|
|
|
# GET /api/v1/admin/invitation_acceptance/validate
|
|
# Pre-validate token before showing acceptance form
|
|
def validate
|
|
raw_token = params[:token]
|
|
preview = raw_token[0..7] + '...'
|
|
|
|
invitation = CohortAdminInvitation.active.find_by(token_preview: preview)
|
|
|
|
if invitation
|
|
render json: {
|
|
valid: true,
|
|
institution_name: invitation.institution.name,
|
|
role: invitation.role,
|
|
expires_at: invitation.expires_at
|
|
}
|
|
else
|
|
render json: {
|
|
valid: false,
|
|
error: 'Invitation not found or expired'
|
|
}, status: :not_found
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end |