GospelToolbox/Labs

View on GitHub
app/controllers/api/teamschedule/v1/schedule_controller.rb

Summary

Maintainability
B
6 hrs
Test Coverage
require 'json'
require 'oauth2'
require 'pco_api'
require 'json-api-vanilla'

class Api::Teamschedule::V1::ScheduleController < ApiController
  TOKEN_EXPIRATION_PADDING = 300

  def show
    org_schedule = Apps::TeamSchedule::Schedule.find_by(organization_id: params[:organization_id]) ||
                   Apps::TeamSchedule::Schedule.create(organization_id: params[:organization_id])

    render json: org_schedule.schedule
  end

  def refresh
    schedule = {
      service_types: {},
      service_type_teams: {},
      records: {},
      schedule_dates: Set.new,
      team_positions: {},
      team_names: {}
    }

    service_types = JSON::Api::Vanilla.build(api.services.v2.service_types.get)

    service_types.data.each do |service_type|
      # Set properties for our schedule cache
      schedule[:service_types][service_type.id] = service_type.name
      schedule[:service_type_teams][service_type.id] = Set.new
      schedule[:records][service_type.id] = {}

      # Load the plans for this service type
      service_type_endpoint = api.services.v2.service_types[service_type.id.to_i]
      plans = JSON::Api::Vanilla.build(service_type_endpoint.plans.get(filter: 'future'))

      plans.data.each do |plan|
        next if plan.last_time_at.nil?

        plan_date = Date.parse(plan.last_time_at).to_s

        schedule[:schedule_dates].add(plan_date)

        # Load the people for this plan
        plan_endpoint = service_type_endpoint.plans[plan.id.to_i]
        plan_people = JSON::Api::Vanilla.build(plan_endpoint.team_members.get(include: %w[team person]))

        plan_people.data.each do |person|
          team = person.team

          unless schedule[:records][service_type.id].key?(team.id)
            schedule[:records][service_type.id][team.id] = {}
          end

          schedule[:team_names][team.id] = team.name
          schedule[:service_type_teams][service_type.id].add(team.id)

          unless schedule[:team_positions].key?(team.id)
            schedule[:team_positions][team.id] = Set.new
          end

          position = person.team_position_name || '(Other)'

          unless schedule[:records][service_type.id][team.id].key?(position)
            schedule[:records][service_type.id][team.id][position] = {}
          end

          schedule[:team_positions][team.id].add(position)

          unless schedule[:records][service_type.id][team.id][position].key?(plan_date)
            schedule[:records][service_type.id][team.id][position][plan_date] = Set.new
          end

          schedule[:records][service_type.id][team.id][position][plan_date].add(
            name: person.name,
            status: person.status,
            notification_sent: !person.notification_sent_at.nil?
          )
        end
      end
    end

    # Cache schedule
    org_schedule = Apps::TeamSchedule::Schedule.find_by(organization_id: params[:organization_id])
    org_schedule ||= Apps::TeamSchedule::Schedule.create(organization_id: params[:organization_id])

    org_schedule.schedule = schedule.to_json
    org_schedule.last_updated = Time.now

    org_schedule.save
  end

  private

  def api
    PCO::API.new(oauth_access_token: token.token)
  end

  def token
    @token_container ||= PlanningCenterToken.find_by(organization_id: params[:organization_id])
    return if @token_container.nil?

    token_hash = JSON.parse(@token_container.token)
    token_hash['access_token']

    token = OAuth2::AccessToken.from_hash(client, token_hash.dup)

    if token.expires? && (token.expires_at < Time.now.to_i + TOKEN_EXPIRATION_PADDING) && token.refresh_token
      token = token.refresh!
      @token_container.token = token.to_json
      @token_container.save
    end

    token
  end

  def client
    OAuth2::Client.new(
      ENV['pco_client_id'],
      ENV['pco_secret'],
      site: 'https://api.planningcenteronline.com'
    )
 end
end