Class: HealthCards::Payload

Inherits:
Object
  • Object
show all
Extended by:
PayloadTypes
Includes:
AttributeFilters
Defined in:
lib/health_cards/payload.rb

Overview

A Payload which implements the credential claims specified by https://smarthealth.cards/

Direct Known Subclasses

COVIDPayload, MonkeypoxPayload

Constant Summary collapse

FHIR_REF_REGEX =
%r{((http|https)://([A-Za-z0-9\-\\.:%$]*/)+)?(
Account|ActivityDefinition|AdverseEvent|AllergyIntolerance|Appointment|AppointmentResponse|AuditEvent|Basic|
Binary|BiologicallyDerivedProduct|BodyStructure|Bundle|CapabilityStatement|CarePlan|CareTeam|CatalogEntry|
ChargeItem|ChargeItemDefinition|Claim|ClaimResponse|ClinicalImpression|CodeSystem|Communication|
CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition|Consent|Contract|Coverage|
CoverageEligibilityRequest|CoverageEligibilityResponse|DetectedIssue|Device|DeviceDefinition|DeviceMetric
|DeviceRequest|DeviceUseStatement|DiagnosticReport|DocumentManifest|DocumentReference|EffectEvidenceSynthesis|
Encounter|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|EventDefinition|Evidence|EvidenceVariable|
ExampleScenario|ExplanationOfBenefit|FamilyMemberHistory|Flag|Goal|GraphDefinition|Group|GuidanceResponse|
HealthcareService|ImagingStudy|Immunization|ImmunizationEvaluation|ImmunizationRecommendation|
ImplementationGuide|InsurancePlan|Invoice|Library|Linkage|List|Location|Measure|MeasureReport|Media|Medication|
MedicationAdministration|MedicationDispense|MedicationKnowledge|MedicationRequest|MedicationStatement|
MedicinalProduct|MedicinalProductAuthorization|MedicinalProductContraindication|MedicinalProductIndication|
MedicinalProductIngredient|MedicinalProductInteraction|MedicinalProductManufactured|MedicinalProductPackaged|
MedicinalProductPharmaceutical|MedicinalProductUndesirableEffect|MessageDefinition|MessageHeader|
MolecularSequence|NamingSystem|NutritionOrder|Observation|ObservationDefinition|OperationDefinition|
OperationOutcome|Organization|OrganizationAffiliation|Patient|PaymentNotice|PaymentReconciliation|Person|
PlanDefinition|Practitioner|PractitionerRole|Procedure|Provenance|Questionnaire|QuestionnaireResponse|
RelatedPerson|RequestGroup|ResearchDefinition|ResearchElementDefinition|ResearchStudy|ResearchSubject|
RiskAssessment|RiskEvidenceSynthesis|Schedule|SearchParameter|ServiceRequest|Slot|Specimen|SpecimenDefinition|
StructureDefinition|StructureMap|Subscription|Substance|SubstanceNucleicAcid|SubstancePolymer|SubstanceProtein|
SubstanceReferenceInformation|SubstanceSourceMaterial|SubstanceSpecification|SupplyDelivery|SupplyRequest|Task|
TerminologyCapabilities|TestReport|TestScript|ValueSet|VerificationResult|VisionPrescription)/
[A-Za-z0-9\-.]{1,64}(/_history/[A-Za-z0-9\-.]{1,64})?}x.freeze

Constants included from AttributeFilters

AttributeFilters::ALL_FHIR_RESOURCES

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from PayloadTypes

additional_types, supports_type?, types

Methods included from AttributeFilters

#handle_allowable, #handle_disallowable, included

Constructor Details

#initialize(bundle:, issuer: nil) ⇒ Payload

Create a Payload



113
114
115
116
117
118
# File 'lib/health_cards/payload.rb', line 113

def initialize(bundle:, issuer: nil)
  raise InvalidPayloadError unless bundle.is_a?(FHIR::Bundle) # && bundle.valid?

  @issuer = issuer
  @bundle = bundle
end

Instance Attribute Details

#bundle ⇒ Object (readonly)

Returns the value of attribute bundle.



40
41
42
# File 'lib/health_cards/payload.rb', line 40

def bundle
  @bundle
end

#issuer ⇒ Object (readonly)

Returns the value of attribute issuer.



40
41
42
# File 'lib/health_cards/payload.rb', line 40

def issuer
  @issuer
end

#nbf ⇒ Object (readonly)

Returns the value of attribute nbf.



40
41
42
# File 'lib/health_cards/payload.rb', line 40

def nbf
  @nbf
end

Class Method Details

.compress_payload(payload) ⇒ Object

Compress an arbitrary payload, useful for debugging



79
80
81
# File 'lib/health_cards/payload.rb', line 79

def compress_payload(payload)
  Zlib::Deflate.new(nil, -Zlib::MAX_WBITS).deflate(payload.to_s, Zlib::FINISH)
end

.decompress_payload(payload) ⇒ Hash

Decompress an arbitrary payload, useful for debugging



71
72
73
74
# File 'lib/health_cards/payload.rb', line 71

def decompress_payload(payload)
  inf = Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate(payload)
  JSON.parse(inf)
end

.extract_bundle(payload) ⇒ FHIR::Bundle

Extract a bundle from a compressed payload



59
60
61
62
63
64
65
66
# File 'lib/health_cards/payload.rb', line 59

def extract_bundle(payload)
  json = decompress_payload(payload)
  bundle_hash = json.dig('vc', 'credentialSubject', 'fhirBundle')

  raise HealthCards::InvalidCredentialError unless bundle_hash

  FHIR::Bundle.new(bundle_hash)
end

.fhir_version(ver = nil) ⇒ String

Sets/Gets the fhir version that will be passed through to the credential created by an instnace of this Payload (sub)class will only return the current value value (used as a getter)



89
90
91
92
93
94
95
96
# File 'lib/health_cards/payload.rb', line 89

def fhir_version(ver = nil)
  if @fhir_version.nil? && ver.nil?
    @fhir_version = superclass.fhir_version unless self == HealthCards::Payload
  elsif ver
    @fhir_version = ver
  end
  @fhir_version
end

.from_payload(payload) ⇒ HealthCards::Payload

Create a Payload from a compressed payload



46
47
48
49
50
51
52
53
54
# File 'lib/health_cards/payload.rb', line 46

def from_payload(payload)
  json = decompress_payload(payload)
  bundle_hash = json.dig('vc', 'credentialSubject', 'fhirBundle')

  raise HealthCards::InvalidCredentialError unless bundle_hash

  bundle = extract_bundle(payload)
  new(issuer: json['iss'], bundle: bundle)
end

Instance Method Details

#strip_fhir_bundle ⇒ Hash

Processes the bundle according to https://smarthealth.cards/#health-cards-are-small and returns a Hash with equivalent values to SMART Health Cards framework and any constraints created by subclasses



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/health_cards/payload.rb', line 156

def strip_fhir_bundle
  return [] unless bundle.entry

  new_bundle = duplicate_bundle
  url_map = redefine_uris(new_bundle)

  new_bundle.entry.each do |entry|
    entry.each_element do |value, , _|
      case ['type']
      when 'Reference'
        value.reference = process_reference(url_map, entry, value)
      when 'Resource'
        value.meta = nil unless value.meta&.security
      end

      handle_allowable(value)
      handle_disallowable(value)
    end
  end

  new_bundle
end

#to_hash(filter: true) ⇒ Hash



124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/health_cards/payload.rb', line 124

def to_hash(filter: true)
  fhir_bundle = filter ? strip_fhir_bundle : bundle
  {
    iss: issuer,
    nbf: Time.now.to_i,
    vc: {
      type: self.class.types,
      credentialSubject: {
        fhirVersion: self.class.fhir_version,
        fhirBundle: fhir_bundle.to_hash
      }
    }
  }
end

#to_json(*args) ⇒ String



148
149
150
# File 'lib/health_cards/payload.rb', line 148

def to_json(*args)
  to_hash.to_json(*args)
end

#to_s ⇒ Object

A compressed version of the FHIR::Bundle based on the SMART Health Cards frame work and any other constraints defined by a subclass



142
143
144
# File 'lib/health_cards/payload.rb', line 142

def to_s
  Payload.compress_payload(to_json)
end