diff --git a/Dockerfile b/Dockerfile index c1f1260..428339d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,36 +1,39 @@ # syntax = docker/dockerfile:1 -# This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand: -# docker build -t my-app . -# docker run -d -p 80:80 -p 443:443 --name my-app -e RAILS_MASTER_KEY= my-app - -# Make sure RUBY_VERSION matches the Ruby version in .ruby-version +# 1. Base Stage: Common dependencies ARG RUBY_VERSION=3.3.1 -FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base +FROM ruby:$RUBY_VERSION-slim as base -# Rails app lives here -WORKDIR app - -# Install base packages -RUN apt-get update -qq && \ - apt-get install --no-install-recommends -y curl libjemalloc2 libvips postgresql-client && \ - rm -rf /var/lib/apt/lists /var/cache/apt/archives - -# Set production environment +WORKDIR /rails ENV RAILS_ENV="production" \ BUNDLE_DEPLOYMENT="1" \ BUNDLE_PATH="/usr/local/bundle" \ - BUNDLE_WITHOUT="development" + BUNDLE_WITHOUT="development:test" -# Throw-away build stage to reduce size of final image -FROM base AS build - -# Install packages needed to build gems +# Install base packages (libvips for Active Storage, curl for healthchecks) RUN apt-get update -qq && \ - apt-get install --no-install-recommends -y build-essential git libpq-dev pkg-config && \ + apt-get install --no-install-recommends -y \ + build-essential \ + curl \ + git \ + libvips \ + freetds-bin \ + freetds-dev \ + libjemalloc2 \ + ruby-dev \ + dos2unix && \ + rm -rf /var/lib/apt/lists /var/cache/apt/archives + +# 2. Build Stage: Gems and Assets +FROM base as build + +# Install packages needed to build gems and precompile assets +RUN apt-get update -qq && \ + apt-get install --no-install-recommends -y build-essential pkg-config less && \ rm -rf /var/lib/apt/lists /var/cache/apt/archives # Install application gems +RUN bundle config set --local frozen false COPY Gemfile Gemfile.lock ./ RUN bundle install && \ rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \ @@ -39,28 +42,26 @@ RUN bundle install && \ # Copy application code COPY . . -# Precompile bootsnap code for faster boot times -RUN bundle exec bootsnap precompile app/ lib/ +RUN bundle exec bootsnap precompile app/ - - - -# Final stage for app image +# 3. Final Stage: Lean Runtime FROM base -# Copy built artifacts: gems, application -COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}" -COPY --from=build /app /app +# Copy built artifacts: gems and precompiled assets +# COPY --from=build /rails/public /rails/public +# COPY --from=build /rails/app/javascript /rails/app/javascript +# COPY --from=build /rails/config/importmap.rb /rails/config/importmap.rb +COPY --from=build /usr/local/bundle /usr/local/bundle +COPY --from=build /rails /rails -# Run and own only the runtime files as a non-root user for security -RUN groupadd --system --gid 1000 rails && \ - useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \ - chown -R rails:rails db log storage tmp -USER 1000:1000 +# Run as a non-privileged user for security +RUN useradd -ms /bin/bash rails +RUN chown -R rails:rails /rails +USER rails:rails # Entrypoint prepares the database. -ENTRYPOINT ["/app/bin/docker-entrypoint"] +ENTRYPOINT ["/rails/bin/docker-entrypoint"] -# Start the server by default, this can be overwritten at runtime -EXPOSE 3000 -CMD ["./bin/rails", "server"] +# Start the server +EXPOSE 3005 +CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"] diff --git a/Dockerfile.old b/Dockerfile.old new file mode 100644 index 0000000..c1f1260 --- /dev/null +++ b/Dockerfile.old @@ -0,0 +1,66 @@ +# syntax = docker/dockerfile:1 + +# This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand: +# docker build -t my-app . +# docker run -d -p 80:80 -p 443:443 --name my-app -e RAILS_MASTER_KEY= my-app + +# Make sure RUBY_VERSION matches the Ruby version in .ruby-version +ARG RUBY_VERSION=3.3.1 +FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base + +# Rails app lives here +WORKDIR app + +# Install base packages +RUN apt-get update -qq && \ + apt-get install --no-install-recommends -y curl libjemalloc2 libvips postgresql-client && \ + rm -rf /var/lib/apt/lists /var/cache/apt/archives + +# Set production environment +ENV RAILS_ENV="production" \ + BUNDLE_DEPLOYMENT="1" \ + BUNDLE_PATH="/usr/local/bundle" \ + BUNDLE_WITHOUT="development" + +# Throw-away build stage to reduce size of final image +FROM base AS build + +# Install packages needed to build gems +RUN apt-get update -qq && \ + apt-get install --no-install-recommends -y build-essential git libpq-dev pkg-config && \ + rm -rf /var/lib/apt/lists /var/cache/apt/archives + +# Install application gems +COPY Gemfile Gemfile.lock ./ +RUN bundle install && \ + rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \ + bundle exec bootsnap precompile --gemfile + +# Copy application code +COPY . . + +# Precompile bootsnap code for faster boot times +RUN bundle exec bootsnap precompile app/ lib/ + + + + +# Final stage for app image +FROM base + +# Copy built artifacts: gems, application +COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}" +COPY --from=build /app /app + +# Run and own only the runtime files as a non-root user for security +RUN groupadd --system --gid 1000 rails && \ + useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \ + chown -R rails:rails db log storage tmp +USER 1000:1000 + +# Entrypoint prepares the database. +ENTRYPOINT ["/app/bin/docker-entrypoint"] + +# Start the server by default, this can be overwritten at runtime +EXPOSE 3000 +CMD ["./bin/rails", "server"] diff --git a/app/controllers/api/v1/admin_controller.rb b/app/controllers/api/v1/admin_controller.rb deleted file mode 100644 index 5a56fcd..0000000 --- a/app/controllers/api/v1/admin_controller.rb +++ /dev/null @@ -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 diff --git a/app/controllers/api/v1/auth_controller.rb b/app/controllers/api/v1/auth_controller.rb deleted file mode 100644 index e365f49..0000000 --- a/app/controllers/api/v1/auth_controller.rb +++ /dev/null @@ -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 diff --git a/app/controllers/api/v1/brokers_controller.rb b/app/controllers/api/v1/brokers_controller.rb index 0bed621..fa905dc 100644 --- a/app/controllers/api/v1/brokers_controller.rb +++ b/app/controllers/api/v1/brokers_controller.rb @@ -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 diff --git a/app/controllers/api/v1/carriers_controller.rb b/app/controllers/api/v1/carriers_controller.rb index bb810a7..fca7500 100644 --- a/app/controllers/api/v1/carriers_controller.rb +++ b/app/controllers/api/v1/carriers_controller.rb @@ -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 \ No newline at end of file diff --git a/app/controllers/api/v1/claims_controller.rb b/app/controllers/api/v1/claims_controller.rb deleted file mode 100644 index cc68222..0000000 --- a/app/controllers/api/v1/claims_controller.rb +++ /dev/null @@ -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 \ No newline at end of file diff --git a/app/controllers/api/v1/employers_controller.rb b/app/controllers/api/v1/employers_controller.rb index 67a9e76..378dc44 100644 --- a/app/controllers/api/v1/employers_controller.rb +++ b/app/controllers/api/v1/employers_controller.rb @@ -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 \ No newline at end of file diff --git a/app/controllers/api/v1/id_cards_controller.rb b/app/controllers/api/v1/id_cards_controller.rb deleted file mode 100644 index 0d31093..0000000 --- a/app/controllers/api/v1/id_cards_controller.rb +++ /dev/null @@ -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 diff --git a/app/controllers/api/v1/members_controller.rb b/app/controllers/api/v1/members_controller.rb index 1954cce..5539afe 100644 --- a/app/controllers/api/v1/members_controller.rb +++ b/app/controllers/api/v1/members_controller.rb @@ -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 diff --git a/app/controllers/api/v1/network_provider_controller.rb b/app/controllers/api/v1/network_provider_controller.rb deleted file mode 100644 index 902772b..0000000 --- a/app/controllers/api/v1/network_provider_controller.rb +++ /dev/null @@ -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 \ No newline at end of file diff --git a/app/controllers/api/v1/profile_controller.rb b/app/controllers/api/v1/profile_controller.rb deleted file mode 100644 index 7d74dfe..0000000 --- a/app/controllers/api/v1/profile_controller.rb +++ /dev/null @@ -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 diff --git a/app/controllers/api/v1/protected_controller.rb b/app/controllers/api/v1/protected_controller.rb deleted file mode 100644 index 574d02a..0000000 --- a/app/controllers/api/v1/protected_controller.rb +++ /dev/null @@ -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 diff --git a/app/controllers/api/v1/providers_controller.rb b/app/controllers/api/v1/providers_controller.rb index 7950501..74e5d0d 100644 --- a/app/controllers/api/v1/providers_controller.rb +++ b/app/controllers/api/v1/providers_controller.rb @@ -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 \ No newline at end of file diff --git a/app/controllers/api/v1/public_controller.rb b/app/controllers/api/v1/public_controller.rb new file mode 100644 index 0000000..7ffe1f7 --- /dev/null +++ b/app/controllers/api/v1/public_controller.rb @@ -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 diff --git a/app/controllers/users/passwords_controller.rb b/app/controllers/users/passwords_controller.rb index 259dbb0..c667eec 100644 --- a/app/controllers/users/passwords_controller.rb +++ b/app/controllers/users/passwords_controller.rb @@ -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 diff --git a/app/models/baclight/carrier.rb b/app/models/baclight/carrier.rb index 7290fc4..6dc3d14 100644 --- a/app/models/baclight/carrier.rb +++ b/app/models/baclight/carrier.rb @@ -6,10 +6,10 @@ module Baclight has_many :baclight_brokers, class_name: "Baclight::Broker", foreign_key: "carrier_id", primary_key: "id" has_many :baclight_employers, through: :baclight_brokers, - source: :baclight_employer + source: :baclight_employers has_many :baclight_members, through: :baclight_employers, - source: :baclight_member + source: :baclight_members alias_attribute :id, :id alias_attribute :name, :name diff --git a/app/models/baclight/document_category.rb b/app/models/baclight/document_category.rb new file mode 100644 index 0000000..81bd58a --- /dev/null +++ b/app/models/baclight/document_category.rb @@ -0,0 +1,15 @@ +module Baclight + class DocumentCategory < BaclightRecord + + self.table_name = 'document_categories' + + alias_attribute :id, :id + alias_attribute :display_name, :display_name + alias_attribute :created_at, :created_at + alias_attribute :updated_at, :updated_at + + has_many :document_uploads, class_name: "Baclight::DocumentUpload", foreign_key: "category_id", primary_key: "id" + + + end +end \ No newline at end of file diff --git a/app/models/baclight/document_upload.rb b/app/models/baclight/document_upload.rb new file mode 100644 index 0000000..7d355b2 --- /dev/null +++ b/app/models/baclight/document_upload.rb @@ -0,0 +1,19 @@ +module Baclight + class DocumentUpload < BaclightRecord + + self.table_name = 'document_uploads' + + alias_attribute :id, :id + alias_attribute :filename, :filename + alias_attribute :file_type, :file_type + alias_attribute :file_data, :file_data + alias_attribute :pl_plan_key, :pl_plan_key + alias_attribute :active, :active + alias_attribute :category_id, :category_id + alias_attribute :created_at, :created_at + alias_attribute :updated_at, :updated_at + + belongs_to :document_category, class_name: "Baclight::DocumentUpload", foreign_key: "category_id" + + end +end \ No newline at end of file diff --git a/app/models/baclight/employer.rb b/app/models/baclight/employer.rb index 47f33c3..9437d5a 100644 --- a/app/models/baclight/employer.rb +++ b/app/models/baclight/employer.rb @@ -3,22 +3,27 @@ module Baclight self.table_name = 'Employers' + has_one :baclight_carrier, through: :baclight_broker belongs_to :baclight_broker, class_name: "Baclight::Broker", foreign_key: "broker_id" has_many :baclight_members, class_name: "Baclight::Member", foreign_key: "employer_id", primary_key: "id" - alias_attribute :id, :id - alias_attribute :name, :name - alias_attribute :slug, :slug - alias_attribute :pl_plan_key, :pl_plan_key - alias_attribute :company_pb_entity_key, :company_pb_entity_key - alias_attribute :plan_id, :plan_id - alias_attribute :group_number, :group_number - alias_attribute :effective_date, :effective_date - alias_attribute :active, :active - alias_attribute :initialized, :initialized - alias_attribute :broker_id, :broker_id - alias_attribute :created_at, :created_at - alias_attribute :updated_at, :updated_at + # alias_attribute :id, :id + # alias_attribute :name, :name + # alias_attribute :slug, :slug + # alias_attribute :pl_plan_key, :pl_plan_key + # alias_attribute :company_pb_entity_key, :company_pb_entity_key + # alias_attribute :plan_id, :plan_id + # alias_attribute :group_number, :group_number + # alias_attribute :effective_date, :effective_date + # alias_attribute :active, :active + # alias_attribute :initialized, :initialized + # alias_attribute :broker_id, :broker_id + # alias_attribute :created_at, :created_at + # alias_attribute :updated_at, :updated_at + + def carrier_id + self.baclight_broker.carrier_id + end def belongs_to_levels self.joins(baclight_broker: :baclight_carrier).select( diff --git a/app/models/baclight/id_card_plan.rb b/app/models/baclight/id_card_plan.rb index 9b73676..e466fd8 100644 --- a/app/models/baclight/id_card_plan.rb +++ b/app/models/baclight/id_card_plan.rb @@ -5,14 +5,14 @@ module Baclight has_many :baclight_id_card_plan_benefits, class_name: "Baclight::IdCardPlanBenefit", foreign_key: "plan_id", primary_key: "id" - alias_attribute :id, :id - alias_attribute :title, :title - alias_attribute :pb_product_key, :pb_product_key - alias_attribute :pl_plan_key, :pl_plan_key - alias_attribute :template, :template - alias_attribute :setup_id, :setup_id - alias_attribute :created_at, :created_at - alias_attribute :updated_at, :updated_at + # alias_attribute :id, :id + # alias_attribute :title, :title + # alias_attribute :pb_product_key, :pb_product_key + # alias_attribute :pl_plan_key, :pl_plan_key + # alias_attribute :template, :template + # alias_attribute :setup_id, :setup_id + # alias_attribute :created_at, :created_at + # alias_attribute :updated_at, :updated_at end end \ No newline at end of file diff --git a/app/models/baclight/member.rb b/app/models/baclight/member.rb index 8d0e0be..bdab285 100644 --- a/app/models/baclight/member.rb +++ b/app/models/baclight/member.rb @@ -6,7 +6,7 @@ module Baclight belongs_to :baclight_employer, class_name: "Baclight::Employer", foreign_key: "employer_id" scope :active, -> { - where(active: true) + where(active: true) } # alias_attribute :id, :id @@ -40,5 +40,19 @@ module Baclight baclight_employer&.baclight_broker&.carrier_id end + def eff_date + participation = Vhcs::PbProductParticipation.joins('INNER JOIN "PBCoveredEntities" ON "PBProductParticipation"."PBProductParticipationKey" = "PBCoveredEntities"."PBProductParticipationKey"').where('"PBCoveredEntities"."PBEntityKey" = ?', pb_entity_key).order(out_of_effect: :desc).first + eff_date = nil + if participation + in_effect = participation.in_effect + out_of_effect = participation.out_of_effect + + if in_effect <= (Date.today + 90.days) && (out_of_effect - 1.day) > Date.today && out_of_effect > in_effect + eff_date = in_effect.strftime("%m/%d/%Y") + end + end + eff_date + end + end end \ No newline at end of file diff --git a/app/models/user.rb b/app/models/user.rb index 2f2415f..9f7c763 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -2,7 +2,7 @@ class User < ApplicationRecord include Devise::JWT::RevocationStrategies::JTIMatcher devise :database_authenticatable, :registerable, - :validatable, :jwt_authenticatable, jwt_revocation_strategy: self + :validatable, :recoverable, :jwt_authenticatable, jwt_revocation_strategy: self # Include default devise modules. Others available are: # :recoverable, :rememberable, :confirmable, :lockable, :timeoutable, :trackable and :omniauthable @@ -30,46 +30,34 @@ class User < ApplicationRecord @keychain ||= case role when "member" if role_entity.present? - # belongs_to = { - # employer_id: role_entity.employer_id, - # broker_id: role_entity&.baclight_employer.broker_id, - # carrier_id:role_entity&.baclight_employer&.baclight_broker&.carrier_id - # } - keys = role_entity.attributes.with_indifferent_access.slice( - :id, :name, :family_id, :mb_member_key, :pb_entity_key, :pl_plan_key + role_entity.attributes.with_indifferent_access.slice( + :id, :name, :family_id, :mb_member_key, :pb_entity_key, :pl_plan_key, :employer_id ) - - keys #.merge(belongs_to) end when "employer" if role_entity.present? - belongs_to = role_entity.joins(broker: :carrier).select( - 'brokers.id AS broker_id', - 'carriers.id AS carrier_id' + role_entity.attributes.with_indifferent_access.slice( + :id, :name, :pl_plan_key, :company_pb_entity_key, :plan_id, :group_number ) - - keys = role_entity.attributes.with_indifferent_access.slice( - :name, :pl_plan_key, :company_pb_entity_key, :plan_id, :group_number - ) - - keys.merge(belongs_to) end when "broker" if role_entity.present? - belongs_to = role_entity.joins(:carrier).select( - 'carriers.id AS carrier_id' - ) role_entity.attributes.with_indifferent_access.slice( :name, :id - ).merge(belongs_to) - end - when "provider" - if role_entity.present? - role_entity.attributes.with_indifferent_access.slice( - :name, :pb_entity_key, :tax_id, :family_id ) end + when "provider" + { + id: self.id, + name: self.name, + tax_id: self.role_id + } + # if role_entity.present? + # role_entity.attributes.with_indifferent_access.slice( + # :id, :name, :pb_entity_key, :tax_id, :family_id + # ) + # end when "carrier" if role_entity.present? role_entity.attributes.with_indifferent_access.slice( @@ -77,6 +65,11 @@ class User < ApplicationRecord ) end # when "admin" + # if role_entity.present? + # role_entity.attributes.with_indifferent_access.slice( + # :name, :id + # ) + # end end end @@ -91,33 +84,37 @@ class User < ApplicationRecord find_initial_member end when "employer" - Baclight::Employer.find_by(company_pb_entity_key: role_id) + Baclight::Employer.find_by(pl_plan_key: role_id) when "broker" - Baclight::Broker.find_by(broker_id: role_id) + Baclight::Broker.find_by(id: role_id) when "provider" Baclight::Provider.find_by(tax_id: role_id) when "carrier" - Baclight::Carrier.find_by(carrier_id: role_id) + Baclight::Carrier.find_by(id: role_id) # when "admin" end end def sync_role_entity - if role == "member" - self.name = role_entity.name.split(",").reverse.join(" ").squish - else - self.name = role_entity.name + unless role == "provider" + if role == "member" + self.name = role_entity.name.split(",").reverse.join(" ").squish + else + self.name = role_entity.name + end end end def role_entity_exists - if role_entity.blank? - errors.add(:role, "#{role} with id #{role_id} was not found.") - end - if role == "member" - dob = Vhcs::VwmbMember.find_by(pb_entity_key: role_id).date_of_birth - unless dob == date_of_birth - errors.add(:role, "#{role} with id #{role_id} and #{date_of_birth} was not found.") + unless role == "provider" + if role_entity.blank? + errors.add(:role, "#{role} with id #{role_id} was not found.") + end + if role == "member" + dob = Vhcs::VwmbMember.find_by(pb_entity_key: role_id).date_of_birth + unless dob == date_of_birth + errors.add(:role, "#{role} with id #{role_id} and #{date_of_birth} was not found.") + end end end end diff --git a/app/models/vhcs/pb_product_participation.rb b/app/models/vhcs/pb_product_participation.rb new file mode 100644 index 0000000..a6bdef9 --- /dev/null +++ b/app/models/vhcs/pb_product_participation.rb @@ -0,0 +1,55 @@ +module Vhcs + class PbProductParticipation < VhcsRecord + + self.table_name = 'PbProductParticipation' + + alias_attribute :pb_product_participation_key, :PBProductParticipationKey + alias_attribute :pb_affiliation_key, :PBAffiliationKey + alias_attribute :pb_product_availability_key, :PBProductAvailabilityKey + alias_attribute :coverage_type_code, :CoverageTypeCode + alias_attribute :optional_amount, :OptionalAmount + alias_attribute :in_effect, :InEffect + alias_attribute :out_of_effect, :OutOfEffect + alias_attribute :in_effect_reason_code, :InEffectReasonCode + alias_attribute :out_of_effect_reason_code, :OutOfEffectReasonCode + alias_attribute :when_last_changed, :WhenLastChanged + alias_attribute :who_last_changed, :WhoLastChanged + alias_attribute :user_defined_rate_criteria_value_1, :UserDefinedRateCriteriaValue1 + alias_attribute :user_defined_rate_criteria_value_2, :UserDefinedRateCriteriaValue2 + alias_attribute :user_defined_rate_criteria_value_3, :UserDefinedRateCriteriaValue3 + alias_attribute :user_defined_rate_criteria_record_id_1, :UserDefinedRateCriteriaRecordID1 + alias_attribute :user_defined_rate_criteria_record_id_2, :UserDefinedRateCriteriaRecordID2 + alias_attribute :user_defined_rate_criteria_record_id_3, :UserDefinedRateCriteriaRecordID3 + alias_attribute :optional_amount_record_id, :OptionalAmountRecordID + alias_attribute :primary_pb_affiliation_key, :PrimaryPBAffiliationKey + alias_attribute :payment_type_record_id_g_1_7_7, :PaymentTypeRecordID_G177 + + def attributes + rails_like = { + pb_product_participation_key: self.pb_product_participation_key, + pb_affiliation_key: self.pb_affiliation_key, + pb_product_availability_key: self.pb_product_availability_key, + coverage_type_code: self.coverage_type_code, + optional_amount: self.optional_amount, + in_effect: self.in_effect, + out_of_effect: self.out_of_effect, + in_effect_reason_code: self.in_effect_reason_code, + out_of_effect_reason_code: self.out_of_effect_reason_code, + when_last_changed: self.when_last_changed, + who_last_changed: self.who_last_changed, + user_defined_rate_criteria_value_1: self.user_defined_rate_criteria_value_1, + user_defined_rate_criteria_value_2: self.user_defined_rate_criteria_value_2, + user_defined_rate_criteria_value_3: self.user_defined_rate_criteria_value_3, + user_defined_rate_criteria_record_id_1: self.user_defined_rate_criteria_record_id_1, + user_defined_rate_criteria_record_id_2: self.user_defined_rate_criteria_record_id_2, + user_defined_rate_criteria_record_id_3: self.user_defined_rate_criteria_record_id_3, + optional_amount_record_id: self.optional_amount_record_id, + primary_pb_affiliation_key: self.primary_pb_affiliation_key, + payment_type_record_id_g_1_7_7: self.payment_type_record_id_g_1_7_7, + } + super.merge(rails_like) + end + + + end +end \ No newline at end of file diff --git a/app/policies/baclight/broker_policy.rb b/app/policies/baclight/broker_policy.rb index 9c7d56e..e281a9a 100644 --- a/app/policies/baclight/broker_policy.rb +++ b/app/policies/baclight/broker_policy.rb @@ -1,12 +1,12 @@ class Baclight::BrokerPolicy < ApplicationPolicy - def employers_list?; true; end + def employers_list?; broker_rule?; end private def broker_rule? user.admin? || - (user.broker? && record.broker_id == user.keychain[:id]) || + (user.broker? && record.id == user.keychain[:id]) || (user.carrier? && record.carrier_id == user.keychain[:id]) end diff --git a/app/policies/baclight/carrier_policy.rb b/app/policies/baclight/carrier_policy.rb new file mode 100644 index 0000000..1ea9f07 --- /dev/null +++ b/app/policies/baclight/carrier_policy.rb @@ -0,0 +1,12 @@ +class Baclight::CarrierPolicy < ApplicationPolicy + + def employers_list?; carrier_rule?; end + + private + + def carrier_rule? + user.admin? || + (user.carrier? && record.id == user.keychain[:id]) + end + +end \ No newline at end of file diff --git a/app/policies/baclight/employer_policy.rb b/app/policies/baclight/employer_policy.rb index 4723141..eddf0dc 100644 --- a/app/policies/baclight/employer_policy.rb +++ b/app/policies/baclight/employer_policy.rb @@ -1,13 +1,24 @@ class Baclight::EmployerPolicy < ApplicationPolicy def id_cards?; employer_rule?; end - def members_list?; true; end + def members_list?; employer_rule?; end + def coverage?; employer_rule?; end + def available_document_categories?; member_employer_rule?; end + def documents?; member_employer_rule?; end private + def member_employer_rule? + user.admin? || + (user.member? && record.id == user.keychain[:employer_id]) || + (user.employer? && record.id == user.keychain[:id]) || + (user.broker? && record.broker_id == user.keychain[:id]) || + (user.carrier? && record.carrier_id == user.keychain[:id]) + end + def employer_rule? user.admin? || - (user.employer? && record.employer_id == user.keychain[:id]) || + (user.employer? && record.id == user.keychain[:id]) || (user.broker? && record.broker_id == user.keychain[:id]) || (user.carrier? && record.carrier_id == user.keychain[:id]) end diff --git a/app/policies/baclight/member_policy.rb b/app/policies/baclight/member_policy.rb index 3e19828..8982364 100644 --- a/app/policies/baclight/member_policy.rb +++ b/app/policies/baclight/member_policy.rb @@ -2,6 +2,7 @@ class Baclight::MemberPolicy < ApplicationPolicy def initialize_dashboard?; member_rule?; end def id_card?; member_rule?; end + def plan_benefits?; member_rule?; end def claims? user.admin? || @@ -12,7 +13,7 @@ class Baclight::MemberPolicy < ApplicationPolicy private def member_rule? - user.admin? || + user.admin? || user.provider? || (user.member? && record.id == user.keychain[:id]) || (user.employer? && record.employer_id == user.keychain[:id]) || (user.broker? && record.broker_id == user.keychain[:id]) || diff --git a/app/policies/baclight/provider_policy.rb b/app/policies/baclight/provider_policy.rb new file mode 100644 index 0000000..8b9d89e --- /dev/null +++ b/app/policies/baclight/provider_policy.rb @@ -0,0 +1,11 @@ +class Baclight::ProviderPolicy < ApplicationPolicy + + def claims?; provider_rule?; end + + private + + def provider_rule? + user.admin? || user.provider? + end + +end \ No newline at end of file diff --git a/app/services/employers_service/coverage.rb b/app/services/employers_service/coverage.rb new file mode 100644 index 0000000..70e7503 --- /dev/null +++ b/app/services/employers_service/coverage.rb @@ -0,0 +1,29 @@ +module EmployersService + class Coverage + + def initialize(employer) + @employer = employer + end + + def call + employer_plans = Baclight::IdCardPlan.where(pl_plan_key: @employer.pl_plan_key).to_a + employer_members = @employer.baclight_members.active.order(:name).to_a + employer_members.map! do |member| + eff_date = member.eff_date + if eff_date + plan_title = employer_plans.select { |plan| plan.id == member.id_card_plan_id }&.first&.title + { + name: member.name, + pb_entity_key: member.pb_entity_key, + plan_title: plan_title, + effective_date: eff_date, + dependents: JSON.parse(member.dependents) + } + else + nil + end + end + employer_members.compact + end + end +end diff --git a/app/services/members_service/claims.rb b/app/services/members_service/claims.rb index 0ba71b9..58010b7 100644 --- a/app/services/members_service/claims.rb +++ b/app/services/members_service/claims.rb @@ -1,7 +1,7 @@ module MembersService class Claims - def initialize(entity, recent = false) + def initialize(entity, provider_tax_id = "", recent = false) if entity.is_a?(Integer) @member = Baclight::Member.find_by(pb_entity_key: entity) else @@ -10,6 +10,7 @@ module MembersService if @member.present? @pl_plan_key = @member.pl_plan_key @family_id = @member.family_id + @provider_tax_id = provider_tax_id @recent = recent else raise ArgumentError, "Member not found." @@ -21,7 +22,7 @@ module MembersService args = { PLPlanKey: @pl_plan_key, FamilyId: @family_id, - ProviderTaxId: "", + ProviderTaxId: @provider_tax_id, UserID: "JASONJ" } claims_headers = CallStoredProc.new("CPFindClaim", args).call diff --git a/app/services/members_service/initialize_dashboard.rb b/app/services/members_service/initialize_dashboard.rb index 09beda8..1e2468f 100644 --- a/app/services/members_service/initialize_dashboard.rb +++ b/app/services/members_service/initialize_dashboard.rb @@ -12,7 +12,7 @@ module MembersService def call plan_benefits = MembersService::PlanBenefits.new(@member).call network_provider = MembersService::NetworkProvider.new(@member).call - recent_claims = MembersService::Claims.new(@member, true).call + recent_claims = MembersService::Claims.new(@member, "", true).call { network_provider: network_provider, diff --git a/app/services/members_service/plan_benefits.rb b/app/services/members_service/plan_benefits.rb index b0ed8fb..760b409 100644 --- a/app/services/members_service/plan_benefits.rb +++ b/app/services/members_service/plan_benefits.rb @@ -11,10 +11,16 @@ module MembersService end def call - Baclight::IdCardPlan.joins(:baclight_id_card_plan_benefits) + plan_details = 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 + { + plan_details: plan_details, + coverage_type: @member.coverage_class, + effective_date: @member.eff_date, + dependents: JSON.parse(@member.dependents) + } end end end diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb new file mode 100644 index 0000000..dc55f64 --- /dev/null +++ b/app/views/devise/mailer/confirmation_instructions.html.erb @@ -0,0 +1,5 @@ +

Welcome <%= @email %>!

+ +

You can confirm your account email through the link below:

+ +

<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>

diff --git a/app/views/devise/mailer/email_changed.html.erb b/app/views/devise/mailer/email_changed.html.erb new file mode 100644 index 0000000..32f4ba8 --- /dev/null +++ b/app/views/devise/mailer/email_changed.html.erb @@ -0,0 +1,7 @@ +

Hello <%= @email %>!

+ +<% if @resource.try(:unconfirmed_email?) %> +

We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.

+<% else %> +

We're contacting you to notify you that your email has been changed to <%= @resource.email %>.

+<% end %> diff --git a/app/views/devise/mailer/password_change.html.erb b/app/views/devise/mailer/password_change.html.erb new file mode 100644 index 0000000..b41daf4 --- /dev/null +++ b/app/views/devise/mailer/password_change.html.erb @@ -0,0 +1,3 @@ +

Hello <%= @resource.email %>!

+ +

We're contacting you to notify you that your password has been changed.

diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb new file mode 100644 index 0000000..021f222 --- /dev/null +++ b/app/views/devise/mailer/reset_password_instructions.html.erb @@ -0,0 +1,8 @@ +

Hello <%= @resource.email %>!

+ +

Someone has requested a link to change your password. You can do this through the link below.

+ +

<%= link_to 'Change my password', "http://localhost:3001/account/password-reset?token=#{@token}" %>

+ +

If you didn't request this, please ignore this email.

+

Your password won't change until you access the link above and create a new one.

diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb new file mode 100644 index 0000000..41e148b --- /dev/null +++ b/app/views/devise/mailer/unlock_instructions.html.erb @@ -0,0 +1,7 @@ +

Hello <%= @resource.email %>!

+ +

Your account has been locked due to an excessive number of unsuccessful sign in attempts.

+ +

Click the link below to unlock your account:

+ +

<%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>

diff --git a/app/views/devise/shared/_error_messages.html.erb b/app/views/devise/shared/_error_messages.html.erb new file mode 100644 index 0000000..cabfe30 --- /dev/null +++ b/app/views/devise/shared/_error_messages.html.erb @@ -0,0 +1,15 @@ +<% if resource.errors.any? %> +
+

+ <%= I18n.t("errors.messages.not_saved", + count: resource.errors.count, + resource: resource.class.model_name.human.downcase) + %> +

+
    + <% resource.errors.full_messages.each do |message| %> +
  • <%= message %>
  • + <% end %> +
+
+<% end %> diff --git a/app/views/devise/shared/_links.html.erb b/app/views/devise/shared/_links.html.erb new file mode 100644 index 0000000..7a75304 --- /dev/null +++ b/app/views/devise/shared/_links.html.erb @@ -0,0 +1,25 @@ +<%- if controller_name != 'sessions' %> + <%= link_to "Log in", new_session_path(resource_name) %>
+<% end %> + +<%- if devise_mapping.registerable? && controller_name != 'registrations' %> + <%= link_to "Sign up", new_registration_path(resource_name) %>
+<% end %> + +<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> + <%= link_to "Forgot your password?", new_password_path(resource_name) %>
+<% end %> + +<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> + <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
+<% end %> + +<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> + <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
+<% end %> + +<%- if devise_mapping.omniauthable? %> + <%- resource_class.omniauth_providers.each do |provider| %> + <%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false } %>
+ <% end %> +<% end %> diff --git a/bin/docker-entrypoint b/bin/docker-entrypoint index d1fa779..90699d0 100644 --- a/bin/docker-entrypoint +++ b/bin/docker-entrypoint @@ -5,9 +5,10 @@ if [ -z "${LD_PRELOAD+x}" ] && [ -f /usr/lib/*/libjemalloc.so.2 ]; then export LD_PRELOAD="$(echo /usr/lib/*/libjemalloc.so.2)" fi -# If running the rails server then create or migrate existing database -if [ "${1}" == "./bin/rails" ] && [ "${2}" == "server" ]; then - ./bin/rails db:prepare +# If running the rails server then migrate existing database +if [ "${1}" == "bundle" ] && [ "${2}" == "exec" ] && [ "${3}" == "puma" ]; then + echo "running migrations..." + ./bin/rails db:migrate fi rm -f /usr/src/app/tmp/pids/server.pid diff --git a/bin/docker-entrypoint.baclight b/bin/docker-entrypoint.baclight new file mode 100644 index 0000000..ccc5be3 --- /dev/null +++ b/bin/docker-entrypoint.baclight @@ -0,0 +1,32 @@ +#!/bin/bash -e +set -e + +# Enable jemalloc for reduced memory usage and latency. +if [ -z "${LD_PRELOAD+x}" ] && [ -f /usr/lib/*/libjemalloc.so.2 ]; then + export LD_PRELOAD="$(echo /usr/lib/*/libjemalloc.so.2)" +fi + +# This prevents "A server is already running" errors if a previous container crashed. +if [ -f tmp/pids/server.pid ]; then + rm -f tmp/pids/server.pid +fi + +rm -rf /usr/local/bundle/cache/*.gem + +echo "bundle install..." +bundle check || bundle install --jobs 4 + +# NOTE: Enable this as you need to get migrations working in your deployed +# (i.e. Production) environments. Match the condition check to what you have in +# the Dockerfile CMD. I use puma in the production.Dockerfile as that's the +# recommended option by the Puma team (https://github.com/puma/puma#rails), but +# the default Rails Dockerfile uses `./bin/rails server` + +echo "starting puma server..." + +# If running the rails server then create or migrate existing database +if [ "${1}" == "bundle" ] && [ "${2}" == "exec" ] && [ "${3}" == "puma" ]; then + ./bin/rails db:migrate +fi + +exec "${@}" diff --git a/config/application.rb b/config/application.rb index 9bf9054..52e3c7e 100644 --- a/config/application.rb +++ b/config/application.rb @@ -26,7 +26,7 @@ module RailsApiAuthTemplate # Please, add to the `ignore` list any other `lib` subdirectories that do # not contain `.rb` files, or that should not be reloaded or eager loaded. # Common ones are `templates`, `generators`, or `middleware`, for example. - config.autoload_lib(ignore: %w[assets tasks]) + config.autoload_lib(ignore: %w[assets tasks generators]) # Configuration for the application, engines, and railties goes here. # diff --git a/config/environments/development.rb b/config/environments/development.rb index 246a2a3..d3c4240 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -40,7 +40,7 @@ Rails.application.configure do # caching is enabled. config.action_mailer.perform_caching = false - config.action_mailer.default_url_options = { host: "localhost", port: 3000 } + config.action_mailer.default_url_options = { host: "localhost", port: 3002 } # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log diff --git a/config/environments/production.rb b/config/environments/production.rb index 02c59e3..8bb6c99 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -42,7 +42,7 @@ Rails.application.configure do # config.assume_ssl = true # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - config.force_ssl = true + config.force_ssl = false # Skip http-to-https redirect for the default health check endpoint. # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index bee8b06..00ce3fb 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -19,10 +19,10 @@ Devise.setup do |config| config.jwt do |jwt| jwt.secret = ENV['DEVISE_JWT_SECRET_KEY'] # Or Rails.application.credentials.devise_jwt_secret_key! jwt.dispatch_requests = [ - ['POST', %r{^/login$}] + ['POST', %r{^/signin$}] ] jwt.revocation_requests = [ - ['DELETE', %r{^/logout$}] + ['DELETE', %r{^/signout$}] ] jwt.expiration_time = 30.minutes.to_i end diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb index 1e7382e..43175f2 100644 --- a/config/initializers/rack_attack.rb +++ b/config/initializers/rack_attack.rb @@ -23,7 +23,7 @@ class Rack::Attack end # why not tell them politely if they try too much - self.throttled_response = lambda do |_env| + self.throttled_responder = lambda do |_env| [ 429, { "Content-Type" => "application/json" }, diff --git a/config/puma.rb b/config/puma.rb index 03c166f..802cc42 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -24,7 +24,7 @@ threads_count = ENV.fetch("RAILS_MAX_THREADS", 3) threads threads_count, threads_count # Specifies the `port` that Puma will listen on to receive requests; default is 3000. -port ENV.fetch("PORT", 3000) +port ENV.fetch("PORT", 3005) # Allow puma to be restarted by `bin/rails restart` command. plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb index dc2e1f7..1456459 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -6,11 +6,13 @@ Rails.application.routes.draw do path_names: { sign_in: 'signin', sign_out: 'signout', - registration: 'signup' + registration: 'signup', + password: 'forgot_password' }, controllers: { sessions: 'users/sessions', - registrations: 'users/registrations' + registrations: 'users/registrations', + passwords: 'users/passwords' } # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html @@ -44,6 +46,7 @@ Rails.application.routes.draw do get 'initialize_dashboard' get 'id_card/:layout', to: 'members#id_card' get 'claims' + get 'plan_benefits' end end resources :employers do @@ -51,6 +54,9 @@ Rails.application.routes.draw do get 'initialize_dashboard' get 'id_cards' get 'members_list' + get 'coverage' + get 'available_document_categories' + get 'documents/:category_id', to: 'employers#documents' end end resources :brokers do @@ -58,6 +64,21 @@ Rails.application.routes.draw do get 'employers_list' end end + resources :carriers do + member do + get 'employers_list' + end + end + resources :providers do + member do + get 'claims/:pb_entity_key', to: 'providers#claims' + end + end + resources :public do + collection do + get 'search_eligibility' + end + end end end end diff --git a/docker-compose.yaml b/docker-compose.yaml index 3260bbc..d27b99f 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -3,6 +3,7 @@ services: build: context: ./ dockerfile: development.Dockerfile + # dockerfile: Dockerfile container_name: web_api volumes: - .:/usr/src/app @@ -12,6 +13,7 @@ services: environment: - HISTFILE=/usr/src/app/log/.bash_history - RAILS_ENV=development + # - RAILS_ENV=production - BACLIGHT_SERVER_HOST=baclight - BACLIGHT_SERVER_PORT=3002 - PUID=1000 diff --git a/lib/json_web_token.rb b/lib/json_web_token.rb index cda7b35..626bcd5 100644 --- a/lib/json_web_token.rb +++ b/lib/json_web_token.rb @@ -8,7 +8,7 @@ class JsonWebToken # secret key used to sign the token # make sure to keep this secret in .env (never hardcode and check before pushing to github) # will crash if JWT_SECRET_KEY is not set - this is intentional for security - SECRET_KEY = ENV.fetch("JWT_SECRET_KEY") + SECRET_KEY = ENV.fetch("DEVISE_JWT_SECRET_KEY") # encode payload into a jwt # payload is usually like: { user_id: 1 }