Production Build Working
CI / scan_ruby (push) Failing after 37s
CI / lint (push) Failing after 39s

This commit is contained in:
Jason Jordan
2026-09-16 12:41:44 -04:00
parent 9853d58469
commit 1c80e642f5
51 changed files with 648 additions and 440 deletions
@@ -1,23 +0,0 @@
module Api
module V1
class AdminController < ApplicationController
include AuthorizeRequest
include AuthorizeRole
before_action :require_admin
# example admin-only endpoint
# GET /api/v1/admin/dashboard
def dashboard
render json: {
message: "Welcome to admin dashboard",
stats: {
total_users: User.count,
total_admins: User.admin.count,
total_moderators: User.moderator.count
}
}, status: :ok
end
end
end
end
-87
View File
@@ -1,87 +0,0 @@
module Api
module V1
class AuthController < ApplicationController
include AuthorizeRequest
skip_before_action :authorize_request, only: %i[signup login refresh]
# post /signup -> signup user and return jwt + refresh token
# I used strong params so no sql injection here (rails got your back)
def signup
user = User.new(user_params)
if user.save
tokens = generate_tokens(user)
render json: { **tokens, user: user.as_json(only: %i[id email role]) }, status: :created
else
render json: { errors: user.errors.full_messages }, status: :unprocessable_entity
end
end
# post /login -> login with email & password (keep it simple)
# if it matches, it gives you both access token and refresh token
def login
user = User.find_by(email: params[:email])
if user&.valid_password?(params[:password])
tokens = generate_tokens(user)
render json: { **tokens, user: user.as_json(only: %i[id email role]) }, status: :ok
else
render json: { error: "Invalid email or password" }, status: :unauthorized
end
end
# post /refresh -> exchange refresh token for new access token
# keeps users logged in without re-entering credentials
def refresh
refresh_token = RefreshToken.find_by(token: params[:refresh_token])
if refresh_token&.active?
user = refresh_token.user
access_token = JsonWebToken.encode(user_id: user.id)
render json: { access_token:, user: user.as_json(only: %i[id email role]) }, status: :ok
else
render json: { error: "Invalid or expired refresh token" }, status: :unauthorized
end
end
# post /logout -> NOW with real token retireing
# adds the current token to retire so it can't be used again
# authorize_request ensures @current_user and token are present
def logout
header = request.headers["Authorization"]
token = header.split(" ").last if header
decoded = JsonWebToken.decode(token)
RetiredToken.create!(
jti: decoded[:jti],
user_id: decoded[:user_id],
exp: Time.at(decoded[:exp])
)
# also revoke all refresh tokens for this user
@current_user.refresh_tokens.update_all(revoked: true)
render json: { message: "Successfully logged out. Token retired." }, status: :ok
rescue StandardError => e
render json: { error: "Logout failed: #{e.message}" }, status: :unprocessable_entity
end
private
# only allow what we actually need. nothing fancy, nothing extra. not need for require
def user_params
params.permit(:email, :password, :password_confirmation)
end
# generate both access and refresh tokens
def generate_tokens(user)
access_token = JsonWebToken.encode(user_id: user.id)
refresh_token = user.refresh_tokens.create!
{
access_token: access_token,
refresh_token: refresh_token.token,
expires_in: 1.hour.to_i
}
end
end
end
end
+5 -3
View File
@@ -1,12 +1,14 @@
module Api
module V1
class BrokersController < ApplicationController
# before_action :authenticate_user!
before_action :authenticate_user!
def employers_list
broker_id = params[:id]
broker = Baclight::Broker.find(broker_id)
employers = broker.baclight_employers.order(:name).map { |emp| {name: emp.name, entity_key: emp.pl_plan_key }}
@broker = Baclight::Broker.find(broker_id)
authorize @broker
employers = @broker.baclight_employers.order(:name).map { |emp| {name: emp.name, entity_key: emp.pl_plan_key }}
render json: employers, status: :ok
end
@@ -3,6 +3,16 @@ module Api
class CarriersController < ApplicationController
before_action :authenticate_user!
def employers_list
carrier_id = params[:id]
@carrier = Baclight::Carrier.find(carrier_id)
authorize @carrier
employers = @carrier.baclight_employers.order(:name).map { |emp| {name: emp.name, entity_key: emp.pl_plan_key }}
render json: employers, status: :ok
end
end
end
end
@@ -1,18 +0,0 @@
module Api
module V1
class ClaimsController < ApplicationController
def member_claims
pb_entity_key = params[:id]
member_claims = MemberClaimsService.new(pb_entity_key).call
if member_claims.present?
render json: member_claims, status: :ok
else
render json: { error: "Member Claims not found" }, status: :not_found
end
end
end
end
end
+62 -8
View File
@@ -1,23 +1,26 @@
module Api
module V1
class EmployersController < ApplicationController
# before_action :authenticate_user!
before_action :authenticate_user!
def id_cards
pl_plan_key = params[:id]
id_cards = EmployersService::IdCards.new(pl_plan_key).call
@employer = Baclight::Employer.find_by(pl_plan_key: pl_plan_key)
authorize @employer
id_cards = EmployersService::IdCards.new(@employer.pl_plan_key).call
if id_cards.code == 200
content_disposition = id_cards.headers['Content-Disposition']
filename = content_disposition[/filename="?([^"]*)"?/, 1]
# filename = params[:filename].presence || 'employer_idcards.zip'
response.headers['Access-Control-Expose-Headers'] = 'Content-Disposition'
send_data(
id_cards.body,
type: 'application/zip',
send_data id_cards.body,
filename: filename,
type: 'application/zip',
disposition: 'attachment'
)
else
render json: { error: "Employer not found" }, status: :not_found
end
@@ -25,12 +28,63 @@ module Api
def members_list
pl_plan_key = params[:id]
employer = Baclight::Employer.find_by(pl_plan_key: pl_plan_key)
members = employer.baclight_members.active.order(:name).map { |mem| {name: mem.name, entity_key: mem.pb_entity_key}}
@employer = Baclight::Employer.find_by(pl_plan_key: pl_plan_key)
authorize @employer
members = @employer.baclight_members.active.order(:name).map { |mem| {name: mem.name, entity_key: mem.pb_entity_key}}
render json: members, status: :ok
end
def coverage
pl_plan_key = params[:id]
@employer = Baclight::Employer.find_by(pl_plan_key: pl_plan_key)
authorize @employer
coverage = EmployersService::Coverage.new(@employer).call
if coverage.present?
render json: coverage, status: :ok
else
render json: { error: "Coverage not found" }, status: :not_found
end
end
def available_document_categories
pl_plan_key = params[:id]
@employer = Baclight::Employer.find_by(pl_plan_key: pl_plan_key)
authorize @employer
available_categories = Baclight::DocumentCategory.joins(:document_uploads).where(document_uploads: { pl_plan_key: pl_plan_key }).pluck(:id, :display_name).to_h
if available_categories.present?
render json: available_categories, status: :ok
else
render json: { }, status: :ok
end
end
def documents
pl_plan_key = params[:id]
category_id = params[:category_id]
@employer = Baclight::Employer.find_by(pl_plan_key: pl_plan_key)
authorize @employer
employer_document = Baclight::DocumentUpload.where(category_id: category_id, pl_plan_key: pl_plan_key).order(updated_at: :desc).first
if employer_document.present?
response.headers['Access-Control-Expose-Headers'] = 'Content-Disposition'
send_data employer_document.file_data,
filename: employer_document.filename,
type: employer_document.file_type,
disposition: "attachment"
else
render json: { error: "Document not found" }, status: :not_found
end
end
end
end
end
@@ -1,96 +0,0 @@
module Api
module V1
class IdCardsController < ApplicationController
def member_card
pb_entity_key = params[:id]
layout = params[:layout]
@member = Baclight::Member.find_by(pb_entity_key: pb_entity_key)
# authorize :id_cards, @member
url_components = {
host: ENV["BACLIGHT_SERVER_HOST"],
port: ENV["BACLIGHT_SERVER_PORT"],
path: "/api/v1/web_id_cards/member_card/#{pb_entity_key}/#{layout}"
}
response = HTTParty.get(
URI::HTTP.build(url_components),
headers: { 'Content-Type' => 'application/json', 'Accept' => 'application/pdf' },
stream_body: true
)
if response.code == 200
content_disposition = response.headers['Content-Disposition']
filename = content_disposition[/filename="?([^"]*)"?/, 1]
disposition = layout == "MobileDisplayCard" ? 'inline' : 'attachment'
send_data(
response.body,
type: 'application/pdf',
filename: filename,
disposition: disposition
)
else
render json: { error: "Member not found" }, status: :not_found
end
end
def member_benefits
pb_entity_key = params[:id]
@member = Baclight::Member.find_by(pb_entity_key: pb_entity_key)
plan_id = @member.id_card_plan_id
plan_benefits = Baclight::IdCardPlan.joins(:baclight_id_card_plan_benefits)
.select('id_card_plans.id, id_card_plans.title, id_card_plan_benefits.id, id_card_plan_benefits.sequence, id_card_plan_benefits.benefit, id_card_plan_benefits.benefit_desc')
.where(id: plan_id)
.distinct
if plan_benefits.present?
render json: plan_benefits, status: :ok
else
render json: { error: "Plan Benefits not found" }, status: :not_found
end
end
def employer_cards
pl_plan_key = params[:id]
@employer = Baclight::Employer.find_by(pl_plan_key: pl_plan_key)
# authorize :id_cards, @employer
url_components = {
host: ENV["BACLIGHT_SERVER_HOST"],
port: ENV["BACLIGHT_SERVER_PORT"],
path: "/api/v1/web_id_cards/employer_cards/#{pl_plan_key}"
}
# Send POST with params and enable streaming
response = HTTParty.get(
URI::HTTP.build(url_components),
headers: { 'Content-Type' => 'application/json', 'Accept' => 'application/zip' },
stream_body: true
)
if response.code == 200
content_disposition = response.headers['Content-Disposition']
filename = content_disposition[/filename="?([^"]*)"?/, 1]
# filename = params[:filename].presence || 'employer_idcards.zip'
send_data(
response.body,
type: 'application/zip',
filename: filename,
disposition: 'attachment'
)
else
render json: { error: "Employer not found" }, status: :not_found
end
end
end
end
end
+17 -13
View File
@@ -1,7 +1,7 @@
module Api
module V1
class MembersController < ApplicationController
# before_action :authenticate_user!
before_action :authenticate_user!
def initialize_dashboard
pb_entity_key = params[:id]
@@ -17,7 +17,7 @@ module Api
pb_entity_key = params[:id]
layout = params[:layout]
@member = Baclight::Member.find_by(pb_entity_key: pb_entity_key)
# authorize @member
authorize @member
generated_id_card = MembersService::IdCard.new(@member, layout).call
@@ -37,21 +37,24 @@ module Api
end
end
def network_provider
pl_plan_key = params[:id]
# def network_provider
# pl_plan_key = params[:id]
network_provider = Baclight::IdCardSetup.find_by(pl_plan_key: pl_plan_key).slice(:network_provider)
# network_provider = Baclight::IdCardSetup.find_by(pl_plan_key: pl_plan_key).slice(:network_provider)
if network_provider.present?
render json: network_provider, status: :ok
else
render json: { error: "Network Provider not found" }, status: :not_found
end
end
# if network_provider.present?
# render json: network_provider, status: :ok
# else
# render json: { error: "Network Provider not found" }, status: :not_found
# end
# end
def plan_benefits
pb_entity_key = params[:id]
plan_benefits = MembersService::PlanBenefits.new(pb_entity_key).call
@member = Baclight::Member.find_by(pb_entity_key: pb_entity_key)
authorize @member
plan_benefits = MembersService::PlanBenefits.new(@member).call
if plan_benefits.present?
render json: plan_benefits, status: :ok
@@ -60,9 +63,10 @@ module Api
end
end
def claims
def claims
pb_entity_key = params[:id]
@member = Baclight::Member.find_by(pb_entity_key: pb_entity_key)
authorize @member
recent_claims = MembersService::Claims.new(@member).call
@@ -1,19 +0,0 @@
module Api
module V1
class NetworkProviderController < ApplicationController
def employer_network_provider
pl_plan_key = params[:id]
network_provider = Baclight::IdCardSetup.find_by(pl_plan_key: pl_plan_key).slice(:network_provider)
if network_provider.present?
render json: network_provider, status: :ok
else
render json: { error: "Network Provider not found" }, status: :not_found
end
end
end
end
end
@@ -1,16 +0,0 @@
module Api
module V1
class ProfileController < ApplicationController
include AuthorizeRequest
# get /profile
# this is for getting current user who logged in
def show
render json: {
id: @current_user.id,
email: @current_user.email
}, status: :ok
end
end
end
end
@@ -1,14 +0,0 @@
module Api
module V1
class ProtectedController < ApplicationController
include AuthorizeRequest
def index
render json: {
message: "you are free to use this buddy",
user: @current_user.as_json(only: %(id email))
}
end
end
end
end
@@ -3,6 +3,21 @@ module Api
class ProvidersController < ApplicationController
before_action :authenticate_user!
def claims
tax_id = params[:id]
member_pb_entity_key = params[:pb_entity_key]
@member = Baclight::Member.find_by(pb_entity_key: member_pb_entity_key)
if @member.present?
provider_claims = MembersService::Claims.new(@member, tax_id).call
else
provider_claims = nil
end
render json: provider_claims, status: :ok
end
end
end
end
@@ -0,0 +1,22 @@
module Api
module V1
class PublicController < ApplicationController
def search_eligibility
member_number = params[:member_number]
dob = params[:dob]
date = Date.parse(dob)
formatted_date = date.strftime("%m/%d/%Y")
member = Vhcs::VwmbMember.find_by(pb_entity_key: member_number, date_of_birth: formatted_date)
unless member.present?
member_number = nil
end
render json: member_number, status: :ok
end
end
end
end
+21 -16
View File
@@ -1,25 +1,30 @@
# frozen_string_literal: true
class Users::PasswordsController < Devise::PasswordsController
# GET /resource/password/new
# def new
# super
# end
# POST /users/password
def create
self.resource = resource_class.send_reset_password_instructions(resource_params)
yield resource if block_given?
# POST /resource/password
# def create
# super
# end
if successfully_sent?(resource)
render json: { message: "Password reset instructions sent successfully." }, status: :ok
else
render json: { errors: resource.errors.full_messages }, status: :unprocessable_entity
end
end
# GET /resource/password/edit?reset_password_token=abcdef
# def edit
# super
# end
# PUT /users/password
def update
self.resource = resource_class.reset_password_by_token(resource_params)
yield resource if block_given?
# PUT /resource/password
# def update
# super
# end
if resource.errors.empty?
resource.unlock_access! if unlockable?(resource)
render json: { message: "Password updated successfully." }, status: :ok
else
render json: { errors: resource.errors.full_messages }, status: :unprocessable_entity
end
end
# protected