-
Notifications
You must be signed in to change notification settings - Fork 176
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Registration V2 API Routes to the monolith (#10022)
* add new models * add job to create a new registration * make Competing lane it's own module and run rubocop * add v2 api files * add error codes and WIP registration_checker * migrate Registration checker * add new registration error and use validations for guests and comments * move routes back to the monolith * migrate create route * remove dynamoid error handling * fix registration show * fix registration list_admin * fix registration list * make update work * run rubocop * more complex rubocop changes * fix migration merge * fix create after merge * remove double render from update * fix typo for bulk_update * suppress logging in tests * use allow_registration_self_delete_after_acceptance * refactor update in competing lane * get payment working * add payment history entry and add has_paid boolean for frontend * make refunds work * rub rubocop * implement qualifications * run rubocop * removed log level change * added skip for before(:suite) block * WIP checker specs * WIP checker specs * working with JWT tokens now * rubocop * comp qualifications factory working * all checker create tests passing * added update tests * rubocop * basic update status tests done' * rubocop * checker update status tests completed * event update checks * final updates and bulk update requests now passing * rubocop * minor corrections * bulk update tests :) * ruboocp * list admin working * triggering tests * fix for competition factory * trying to trigger test * removed whitespace * busy trying to figure out routes.js.erb issues * fixing webpacker issues * rubocop * fixed comp factory * fixed weird event limit reliance * trying to fix cases where we want to add qualificatiosn later * fix view test errors * lol checking present without safe accessing * oops * please work * move breaking changes into another PR * wcif statuses and comments * more comments and re-enabled random test order * rubocop fix * added tests against wcif statuses * Unlocalized bulk update error * rubocop * refactor validate_jwt_token * remove rescues * add prepare task * add TODO about @competition * use existing method for other_series_ids * run rubocop * rename to payment_statuses * Hallucinate an admin to set WCIF events * remove unverified_wcif_events * renamed low_event_limit trait * remove duplicate competition factory property * moved to admin factory * changed mock user to competition organizer * move all string registration statuses to constants * move send_status_change_email check out of the method * renamed user fields to current_user and target_user * flip check in organizer_modifying_own_registration? * use Qualification class for competitor_qualifies_for_event? * missing commas * fix guests being string * fix constant access * fix guests string in create_registration * fix typo * forgot status waiting list oops * add :with_organizers for tests * got request tests working * rubocop * fixed tests and added local check for disabled tag * defining event ids separately from events in reg factory * added TODO comment * renamed with_low_event_limit * More efficient series check * Make events_held? more concise to read * Make 'guest_limit_exceeded?' more readable * switch competing_status from hardcoded strings to constants defined in registration helper * quick refactor fixes * simplified events_held --------- Co-authored-by: Duncan <duncanonthejob@gmail.com> Co-authored-by: Duncan <52967253+dunkOnIT@users.noreply.github.com> Co-authored-by: Gregor Billing <gbilling@worldcubeassociation.org>
- Loading branch information
1 parent
7b785b0
commit 4405901
Showing
33 changed files
with
3,959 additions
and
93 deletions.
There are no files selected for viewing
This file contains 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 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,37 @@ | ||
# frozen_string_literal: true | ||
|
||
class Api::V1::ApiController < ActionController::API | ||
prepend_before_action :validate_jwt_token | ||
|
||
# Manually include new Relic because we don't derive from ActionController::Base | ||
include NewRelic::Agent::Instrumentation::ControllerInstrumentation if Rails.env.production? | ||
|
||
def validate_jwt_token | ||
auth_header = request.headers['Authorization'] | ||
if auth_header.blank? | ||
return render json: { error: Registrations::ErrorCodes::MISSING_AUTHENTICATION }, status: :unauthorized | ||
end | ||
token = auth_header.split[1] | ||
begin | ||
decode_result = JWT.decode token, AppSecrets.JWT_KEY, true, { algorithm: 'HS256' } | ||
decoded_token = decode_result[0] | ||
@current_user = User.find(decoded_token['user_id'].to_i) | ||
rescue JWT::VerificationError, JWT::InvalidJtiError | ||
render json: { error: Registrations::ErrorCodes::INVALID_TOKEN }, status: :unauthorized | ||
rescue JWT::ExpiredSignature | ||
render json: { error: Registrations::ErrorCodes::EXPIRED_TOKEN }, status: :unauthorized | ||
end | ||
end | ||
|
||
def render_error(http_status, error, data = nil) | ||
if data.present? | ||
render json: { error: error, data: data }, status: http_status | ||
else | ||
render json: { error: error }, status: http_status | ||
end | ||
end | ||
|
||
rescue_from ActionController::ParameterMissing do |e| | ||
render json: { error: Registrations::ErrorCodes::INVALID_REQUEST_DATA }, status: :bad_request | ||
end | ||
end |
156 changes: 156 additions & 0 deletions
156
app/controllers/api/v1/registrations/registrations_controller.rb
This file contains 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,156 @@ | ||
# frozen_string_literal: true | ||
|
||
class Api::V1::Registrations::RegistrationsController < Api::V1::ApiController | ||
skip_before_action :validate_jwt_token, only: [:list] | ||
# The order of the validations is important to not leak any non public info via the API | ||
# That's why we should always validate a request first, before taking any other before action | ||
# before_actions are triggered in the order they are defined | ||
before_action :validate_create_request, only: [:create] | ||
before_action :validate_show_registration, only: [:show] | ||
before_action :validate_list_admin, only: [:list_admin] | ||
before_action :validate_update_request, only: [:update] | ||
before_action :validate_bulk_update_request, only: [:bulk_update] | ||
before_action :validate_payment_ticket_request, only: [:payment_ticket] | ||
|
||
rescue_from ActiveRecord::RecordNotFound do | ||
render json: {}, status: :not_found | ||
end | ||
|
||
rescue_from WcaExceptions::RegistrationError do |e| | ||
# TODO: Figure out what the best way to log errors in development is | ||
Rails.logger.debug { "Create was rejected with error #{e.error} at #{e.backtrace[0]}" } | ||
render_error(e.status, e.error, e.data) | ||
end | ||
|
||
rescue_from WcaExceptions::BulkUpdateError do |e| | ||
Rails.logger.debug { "Bulk update was rejected with error #{e.errors} at #{e.backtrace[0]}" } | ||
render_error(e.status, e.errors) | ||
end | ||
|
||
def validate_show_registration | ||
@user_id, @competition_id = show_params | ||
@competition = Competition.find(@competition_id) | ||
render_error(:unauthorized, ErrorCodes::USER_INSUFFICIENT_PERMISSIONS) unless @current_user.id == @user_id.to_i || @current_user.can_manage_competition?(@competition) | ||
end | ||
|
||
def show | ||
registration = Registration.find_by!(user_id: @user_id, competition_id: @competition_id) | ||
render json: registration.to_v2_json(admin: true, history: true) | ||
end | ||
|
||
def create | ||
# Currently we only have one lane | ||
if params[:competing] | ||
competing_params = params.permit(:guests, competing: [:status, :comment, { event_ids: [] }, :admin_comment]) | ||
|
||
user_id = registration_params['user_id'] | ||
competition_id = registration_params['competition_id'] | ||
|
||
AddRegistrationJob.prepare_task(user_id, competition_id) | ||
.perform_later("competing", competition_id, user_id, competing_params) | ||
return render json: { status: 'accepted', message: 'Started Registration Process' }, status: :accepted | ||
end | ||
|
||
render json: { status: 'bad request', message: 'You need to supply at least one lane' }, status: :bad_request | ||
end | ||
|
||
def validate_create_request | ||
Registrations::RegistrationChecker.create_registration_allowed!(params, @current_user) | ||
end | ||
|
||
def update | ||
if params[:competing] | ||
updated_registration = Registrations::Lanes::Competing.update!(params, @current_user.id) | ||
return render json: { status: 'ok', registration: updated_registration.to_v2_json(admin: true, history: true) }, status: :ok | ||
end | ||
render json: { status: 'bad request', message: 'You need to supply at least one lane' }, status: :bad_request | ||
end | ||
|
||
def validate_update_request | ||
Registrations::RegistrationChecker.update_registration_allowed!(params, @current_user) | ||
end | ||
|
||
def bulk_update | ||
updated_registrations = {} | ||
update_requests = params[:requests] | ||
update_requests.each do |update| | ||
updated_registrations[update['user_id']] = Registrations::Lanes::Competing.update!(update, @current_user) | ||
end | ||
|
||
render json: { status: 'ok', updated_registrations: updated_registrations } | ||
end | ||
|
||
def validate_bulk_update_request | ||
Registrations::RegistrationChecker.bulk_update_allowed!(params, @current_user) | ||
end | ||
|
||
def list | ||
competition_id = list_params | ||
registrations = Registration.where(competition_id: competition_id) | ||
render json: registrations.map { |r| r.to_v2_json } | ||
end | ||
|
||
# To list Registrations in the admin view you need to be able to administer the competition | ||
def validate_list_admin | ||
competition_id = list_params | ||
# TODO: Do we set this as an instance variable here so we can use it below? | ||
@competition = Competition.find(competition_id) | ||
unless @current_user.can_manage_competition?(@competition) | ||
render_error(:unauthorized, ErrorCodes::USER_INSUFFICIENT_PERMISSIONS) | ||
end | ||
end | ||
|
||
def list_admin | ||
registrations = Registration.where(competition: @competition) | ||
render json: registrations.map { |r| r.to_v2_json(admin: true, history: true, pii: true) } | ||
end | ||
|
||
def validate_payment_ticket_request | ||
competition_id = params[:competition_id] | ||
@competition = Competition.find(competition_id) | ||
render_error(:forbidden, ErrorCodes::PAYMENT_NOT_ENABLED) unless @competition.using_payment_integrations? | ||
|
||
@registration = Registration.find_by(user: @current_user, competition: @competition) | ||
render_error(:forbidden, ErrorCodes::PAYMENT_NOT_READY) if @registration.nil? | ||
end | ||
|
||
def payment_ticket | ||
donation = params[:donation_iso].to_i || 0 | ||
amount_iso = @competition.base_entry_fee_lowest_denomination | ||
currency_iso = @competition.currency_code | ||
payment_account = @competition.payment_account_for(:stripe) | ||
payment_intent = payment_account.prepare_intent(@registration, amount_iso + donation, currency_iso, @current_user) | ||
render json: { client_secret: payment_intent.client_secret } | ||
end | ||
|
||
private | ||
|
||
def action_type(request) | ||
self_updating = request[:user_id] == @current_user | ||
status = request.dig('competing', 'status') | ||
if status == 'cancelled' | ||
return self_updating ? 'Competitor delete' : 'Admin delete' | ||
end | ||
self_updating ? 'Competitor update' : 'Admin update' | ||
end | ||
|
||
def registration_params | ||
params.require([:user_id, :competition_id]) | ||
params.require(:competing).require(:event_ids) | ||
params | ||
end | ||
|
||
def show_params | ||
user_id, competition_id = params.require([:user_id, :competition_id]) | ||
[user_id.to_i, competition_id] | ||
end | ||
|
||
def update_params | ||
params.require([:user_id, :competition_id]) | ||
params.permit(:guests, competing: [:status, :comment, { event_ids: [] }, :admin_comment]) | ||
end | ||
|
||
def list_params | ||
params.require(:competition_id) | ||
end | ||
end |
This file contains 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 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 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 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
Oops, something went wrong.