Development

Application Controller Code needed for workspace and status callback

include QualtricsInterface (for example in helpers/shut/study_helper.rb)

Set environment variables

ENV['API_URL'}                      ||= 'http://api-assessment.bhtcloud.org/'
ENV['QUALTRICS_ID']                 =  'a qualtrics api token'
ENV['QUALTRICS_LIBRARY']            =  'a qualtrics library id'
ENV['STUDY_WORKSPACE_NAME']         =  'a unique name for the study on a specific deploy'

Interface

Controller

    get_participant_state participant_id, survey_name
        - returns 'not started', 'in progress', 'responded'
    get_participant_link(participant_id, survey_name)['unique_link']
        - returns link to qualtrics
    get_results(participant_id, survey_name)['answers']
        - returns a hash of question=>respose values  

Usage

Participants have activities thru the activity_participants join record.   Typical activities are:
  interest
  consent
  phone (phone assessment)
  time_1  (pre)
  time_2  (post)
  time_3  (post_6)
  time_4  (post_12)

The survey name referenced in the interface is: 
survey_name = ENV['STUDY_WORKSPACE_NAME'] + '-' + activity

#### app/helpers/shuti/study_helper.rb (see git blame for lines 40-70)

    There is a horrific method called main_btn_state that governs the appearance
    of the big yellow button on the landing page for the intervention.


    Here is an extension of that code.   Style Notes:  the ruby multiple assignment syntax is used:
     a,b= something.  Obviously this code could be refactored 


      include QualtricsInterface
      def assessment_status assessment_key
        main_button=[]
        @participant = Participant.find(@participant.id)
        assessment_uuid = Activity.find_by(key: assessment_key).uuid
        if @participant.assessment_available_or_in_progress?(assessment_key[-1])
          survey_name = ENV['STUDY_WORKSPACE_NAME'] + '-' + assessment_key
          main_button[0] = activities_path(survey_name: survey_name, activity_uuid: assessment_uuid)
          state = get_participant_state(@participant.id, survey_name)
          main_button[1] = "#{state == 'not started' ? 'Start' : 'Continue'} #{assessment_key.humanize} Survey"
          if state == 'responded'
            #STALE CACHE WORKAROUND
            raise StaleAASMException unless @participant.activity(assessment_key).in_progress?
            @participant.activity(assessment_key).complete!
          end
        end
        [@participant.assessment_available_or_in_progress?(assessment_key[-1]), main_button]
      end

      def main_btn_state
        unless @main_btn_state
          @main_btn_state = []
          if ['Experimental', 'Control'].include?(@participant.participant_type)
            assessment_active, @main_btn_state = assessment_status 'time_4'
            return @main_btn_state if assessment_active && @participant.study_phase == 'time_4'
            assessment_active, @main_btn_state = assessment_status 'time_3'
            return @main_btn_state if assessment_active && @participant.study_phase == 'time_3'
            assessment_active, @main_btn_state = assessment_status 'time_2'
            return @main_btn_state if assessment_active && @participant.study_phase == 'time_2'
            assessment_active, @main_btn_state = assessment_status 'time_1'
            return @main_btn_state if assessment_active && @participant.study_phase == 'time_1'
          end

#### app/controllers/activities/assessments_controller.rb

    The assessment links are accessed by a redirect from the main button state.  We redirect to the start route
    in the Assesments controller to set the in progress state.

    We redirect from Qualtrics to the complete route in order to update the assessment to complete.

        class Activities::AssessmentsController < ApplicationController
          include QualtricsInterface

          prepend_before_action only: [:complete] { request.env["devise.skip_timeout"] = true }

          def start
            survey_name = params['survey_name']
            activity_key = Activity.uuid_to_key(params['activity_uuid'])
            participant = current_user.participant
            activity = participant.activity(activity_key)
            activity.start! unless activity.in_progress?
            #STALE CACHE WORKAROUND
            raise StaleAASMException unless activity.in_progress?
            link = get_participant_link(participant.id, survey_name)['unique_link']
            redirect_to link
          end

          def complete
            participant = current_user.participant
            activity_key = Activity.uuid_to_key(params['assessment_uuid'])
            participant.activity(activity_key).complete!
            redirect_to root_path
          end

#### app/controllers/activities/consents_controller.rb

   The consent links are accessed by a similar controller.

        class Activities::ConsentsController < ActionController::Base
          include QualtricsInterface

          before_action :init_session

          def init_session
            session[:init] = true
          end

          def start
            uuid=params[:uuid]
            survey_name = ENV['STUDY_WORKSPACE_NAME'] + '-' + 'consent'
            participant = User.find_by(uuid: uuid).participant
            link = get_participant_link(participant.id, survey_name)['unique_link']
            activity = participant.activity('consent')
            activity.start! unless activity.in_progress?
            redirect_to link
          end

          def complete
            CompleteConsentWorker.new.perform
            redirect_to consent_thanks_path
          end

          def download
            send_file(
                "#{Rails.root}/consent_forms/pid_#{params[:id]}_consent_form.pdf",
                filename: "pid_#{params[:id]}_consent_form.pdf",
                type: 'application/pdf'
            )
          end
        end

        The actual Consent completion process is handled by 

###### app/workers/complete_consent_worker.rb The actual Consent completion process invoked by the complete function. This worker synchronously updates the status of the Participant, allowing the study to proceed.

###### app/workers/generate_consent_pdf_worker.rb The Consent form PDF generation invoked with perform_async by the Consent completion worker. It should be possible for this worker to fail and be retried by Sidekiq. When this succeeds it also sends an email with the PDF.

Qualtrics callbacks

       The Qualtrics callback for a survey is build with the UUID of an activity.   This
       callback is found under Survey Options on Qualtrics.  Near the bottom of the options
       is an option to enter a Redirect URL.

       Here's a example for localhost testing.

       http://localhost:3000/activities/assessments/complete/045939cd-7ede-47c3-9ae9-3022521c11d

       This is routed to a completion endpoint.
       which converts that UUID into a activity, like time_1.   
       Then it updates the status of the current participant. 

       These UUIDs are in db/seeds/activities.seeds.rb.

       Here is what the consent form callback URL looks like for localhost.

       http://localhost:3000/activities/consents/complete