Class: SM::Client

Inherits:
Common::Client::Base show all
Includes:
Common::Client::Concerns::MHVSessionBasedClient
Defined in:
lib/sm/client.rb

Overview

Core class responsible for SM API interface operations

Constant Summary collapse

MHV_MAXIMUM_PER_PAGE =
250
CONTENT_DISPOSITION =
'attachment; filename='
STATSD_KEY_PREFIX =
if instance_of? SM::Client
  'api.sm'
else
  'mobile.sm'
end

Constants included from Common::Client::Concerns::MhvLockedSessionClient

Common::Client::Concerns::MhvLockedSessionClient::LOCK_RETRY_DELAY, Common::Client::Concerns::MhvLockedSessionClient::RETRY_ATTEMPTS

Instance Attribute Summary

Attributes included from Common::Client::Concerns::MHVSessionBasedClient

#session

Attributes included from Common::Client::Concerns::MhvLockedSessionClient

#session

Preferences collapse

Folders collapse

Message Drafts collapse

Messages collapse

Triage Teams collapse

StatsD collapse

Instance Method Summary collapse

Methods included from Common::Client::Concerns::MHVSessionBasedClient

#auth_headers, #get_session, #get_session_tagged, #invalid?, #session_config_key, #token_headers, #user_key

Methods included from SentryLogging

#log_exception_to_sentry, #log_message_to_sentry, #non_nil_hash?, #normalize_level, #rails_logger, #set_sentry_metadata

Methods included from Common::Client::Concerns::MhvLockedSessionClient

#authenticate, #initialize, #invalid?, #lock_and_get_session, #obtain_redis_lock, #refresh_session, #release_redis_lock

Methods inherited from Common::Client::Base

#config, configuration, #connection, #delete, #get, #perform, #post, #put, #raise_backend_exception, #raise_not_authenticated, #request, #sanitize_headers!, #service_name

Instance Method Details

#append_requires_oh_messages_query(path, requires_oh_messages = nil) ⇒ Object (private)



534
535
536
537
538
539
540
# File 'lib/sm/client.rb', line 534

def append_requires_oh_messages_query(path, requires_oh_messages = nil)
  if requires_oh_messages == '1'
    separator = path.include?('?') ? '&' : '?'
    path += "#{separator}requiresOHMessages=#{requires_oh_messages}"
  end
  path
end

#delete_folder(id) ⇒ Fixnum

Delete a Folder

Parameters:

  • id (Fixnum)

    id of the Folder

Returns:

  • (Fixnum)

    the status code of the response



138
139
140
141
# File 'lib/sm/client.rb', line 138

def delete_folder(id)
  response = perform(:delete, "folder/#{id}", nil, token_headers)
  response&.status
end

#delete_message(id) ⇒ Fixnum

Delete a message

Parameters:

  • id (Fixnum)

    id of message to be deleted

Returns:

  • (Fixnum)

    the response status code



416
417
418
419
420
421
# File 'lib/sm/client.rb', line 416

def delete_message(id)
  custom_headers = token_headers.merge('Content-Type' => 'application/json')
  response = perform(:post, "message/#{id}", nil, custom_headers)

  response&.status
end

#get_all_triage_teams(user_uuid, use_cache, requires_oh = nil) ⇒ Common::Collection[AllTriageTeams]

Get a collection of all triage team recipients, including blocked with detailed attributes per each team including a total tally of associated and locked teams



463
464
465
466
467
468
469
470
471
472
473
474
475
476
# File 'lib/sm/client.rb', line 463

def get_all_triage_teams(user_uuid, use_cache, requires_oh = nil)
  cache_key = "#{user_uuid}-all-triage-teams"
  get_cached_or_fetch_data(use_cache, cache_key, AllTriageTeams) do
    path = 'alltriageteams'
    if requires_oh == '1'
      separator = path.include?('?') ? '&' : '?'
      path += "#{separator}requiresOHTriageGroup=#{requires_oh}"
    end
    json = perform(:get, path, nil, token_headers).body
    data = Common::Collection.new(AllTriageTeams, **json)
    AllTriageTeams.set_cached(cache_key, data)
    data
  end
end

#get_attachment(message_id, attachment_id) ⇒ Hash

Retrieve a message attachment

Parameters:

  • message_id (Fixnum)

    the message id

  • attachment_id (Fixnum)

    the attachment id

Returns:

  • (Hash)

    an object with attachment response details



430
431
432
433
434
435
436
# File 'lib/sm/client.rb', line 430

def get_attachment(message_id, attachment_id)
  path = "message/#{message_id}/attachment/#{attachment_id}"

  response = perform(:get, path, nil, token_headers)
  filename = response.response_headers['content-disposition'].gsub(CONTENT_DISPOSITION, '').gsub(/%22|"/, '')
  { body: response.body, filename: }
end

#get_cached_or_fetch_data(use_cache, cache_key, model) ⇒ Object



493
494
495
496
497
498
499
500
501
502
503
504
505
506
# File 'lib/sm/client.rb', line 493

def get_cached_or_fetch_data(use_cache, cache_key, model)
  data = nil
  data = model.get_cached(cache_key) if use_cache

  if data
    Rails.logger.info("secure messaging #{model} cache fetch", cache_key)
    statsd_cache_hit
    Common::Collection.new(model, data:)
  else
    Rails.logger.info("secure messaging #{model} service fetch", cache_key)
    statsd_cache_miss
    yield
  end
end

#get_categoriesCategory

Get message categories

Returns:



267
268
269
270
271
272
# File 'lib/sm/client.rb', line 267

def get_categories
  path = 'message/category'

  json = perform(:get, path, nil, token_headers).body
  Category.new(json)
end

#get_folder(id, requires_oh_messages = nil) ⇒ Folder

Get a single Folder

Returns:



101
102
103
104
105
106
107
# File 'lib/sm/client.rb', line 101

def get_folder(id, requires_oh_messages = nil)
  path = "folder/#{id}"
  path = append_requires_oh_messages_query(path, requires_oh_messages)

  json = perform(:get, path, nil, token_headers).body
  Folder.new(json)
end

#get_folder_messages(user_uuid, folder_id, use_cache) ⇒ Common::Collection

Get a collection of Messages

Returns:



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/sm/client.rb', line 148

def get_folder_messages(user_uuid, folder_id, use_cache)
  cache_key = "#{user_uuid}-folder-messages-#{folder_id}"
  get_cached_or_fetch_data(use_cache, cache_key, Message) do
    page = 1
    json = { data: [], errors: {}, metadata: {} }

    loop do
      path = "folder/#{folder_id}/message/page/#{page}/pageSize/#{MHV_MAXIMUM_PER_PAGE}"
      page_data = perform(:get, path, nil, token_headers).body
      json[:data].concat(page_data[:data])
      json[:metadata].merge(page_data[:metadata])
      break unless page_data[:data].size == MHV_MAXIMUM_PER_PAGE

      page += 1
    end
    messages = Common::Collection.new(Message, **json)
    Message.set_cached(cache_key, messages)
    messages
  end
end

#get_folder_threads(folder_id, params) ⇒ Common::Collection

Get a collection of Threads

Parameters:

  • folder_id (Fixnum)

    id of the user’s folder (0 Inbox, -1 Sent, -2 Drafts, -3 Deleted, > 0 for custom folder)

  • page_start (Fixnum)

    Pagination start numbering

  • page_end (Fixnum)

    Pagination end numbering (max: 100)

  • sort_field (String)

    field to sort results by (SENDER_NAME or RECIPIENT_NAME or SENT_DATE or DRAFT_DATE)

  • sort_order (String)

    order to sort results by (ASC for Ascending or DESC for Descending)

Returns:



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/sm/client.rb', line 180

def get_folder_threads(folder_id, params)
  base_path = "folder/threadlistview/#{folder_id}"
  query_params = [
    "pageSize=#{params[:page_size]}",
    "pageNumber=#{params[:page_number]}",
    "sortField=#{params[:sort_field]}",
    "sortOrder=#{params[:sort_order]}"
  ].join('&')
  path = "#{base_path}?#{query_params}"
  path = append_requires_oh_messages_query(path, params[:requires_oh_messages])

  json = perform(:get, path, nil, token_headers).body

  Common::Collection.new(MessageThread, **json)
end

#get_folders(user_uuid, use_cache, requires_oh_messages = nil) ⇒ Common::Collection[Folder]

Get a collection of Folders



83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/sm/client.rb', line 83

def get_folders(user_uuid, use_cache, requires_oh_messages = nil)
  path = 'folder'
  path = append_requires_oh_messages_query(path, requires_oh_messages)

  cache_key = "#{user_uuid}-folders"
  get_cached_or_fetch_data(use_cache, cache_key, Folder) do
    json = perform(:get, path, nil, token_headers).body
    data = Common::Collection.new(Folder, **json)
    Folder.set_cached(cache_key, data)
    data
  end
end

#get_full_messages_for_thread(id, requires_oh_messages = nil) ⇒ Common::Collection[MessageThreadDetails]

Get a message thread with full body and attachments

Parameters:

  • id (Fixnum)

    message id

Returns:



318
319
320
321
322
323
# File 'lib/sm/client.rb', line 318

def get_full_messages_for_thread(id, requires_oh_messages = nil)
  path = "message/#{id}/allmessagesforthread/1"
  path = append_requires_oh_messages_query(path, requires_oh_messages)
  json = perform(:get, path, nil, token_headers).body
  Common::Collection.new(MessageThreadDetails, **json)
end

#get_message(id) ⇒ Message

Get a message

Parameters:

  • id (Fixnum)

    message id

Returns:



280
281
282
283
284
# File 'lib/sm/client.rb', line 280

def get_message(id)
  path = "message/#{id}/read"
  json = perform(:get, path, nil, token_headers).body
  Message.new(json)
end

#get_message_history(id) ⇒ Common::Collection[Message]

Get a message thread old api

Parameters:

  • id (Fixnum)

    message id

Returns:



292
293
294
295
296
# File 'lib/sm/client.rb', line 292

def get_message_history(id)
  path = "message/#{id}/history"
  json = perform(:get, path, nil, token_headers).body
  Common::Collection.new(Message, **json)
end

#get_messages_for_thread(id, requires_oh_messages = nil) ⇒ Common::Collection[MessageThread]

Get a message thread

Parameters:

  • id (Fixnum)

    message id

Returns:



304
305
306
307
308
309
310
# File 'lib/sm/client.rb', line 304

def get_messages_for_thread(id, requires_oh_messages = nil)
  path = "message/#{id}/messagesforthread"
  path = append_requires_oh_messages_query(path, requires_oh_messages)

  json = perform(:get, path, nil, token_headers).body
  Common::Collection.new(MessageThreadDetails, **json)
end

#get_preferencesMessagingPreference

Fetch the current email settings, including address and frequency

Returns:



42
43
44
45
46
47
# File 'lib/sm/client.rb', line 42

def get_preferences
  json = perform(:get, 'preferences/notification', nil, token_headers).body
  frequency = MessagingPreference::FREQUENCY_GET_MAP[json[:data][:notify_me]]
  MessagingPreference.new(email_address: json[:data][:email_address],
                          frequency:)
end

#get_preferences_frequency_listHash

Fetch the list of available constant values for email frequency

Returns:

  • (Hash)

    an object containing the body of the response



33
34
35
# File 'lib/sm/client.rb', line 33

def get_preferences_frequency_list
  perform(:get, 'preferences/notification/list', nil, token_headers).body
end

#get_signatureSting

Fetch current message signature

Returns:

  • (Sting)

    json response



71
72
73
# File 'lib/sm/client.rb', line 71

def get_signature
  perform(:get, 'preferences/signature', nil, token_headers).body
end

#get_triage_teams(user_uuid, use_cache) ⇒ Common::Collection[TriageTeam]

Get a collection of triage team recipients



446
447
448
449
450
451
452
453
454
# File 'lib/sm/client.rb', line 446

def get_triage_teams(user_uuid, use_cache)
  cache_key = "#{user_uuid}-triage-teams"
  get_cached_or_fetch_data(use_cache, cache_key, TriageTeam) do
    json = perform(:get, 'triageteam', nil, token_headers).body
    data = Common::Collection.new(TriageTeam, **json)
    TriageTeam.set_cached(cache_key, data)
    data
  end
end

#post_create_folder(name) ⇒ Folder

Create a Folder

Parameters:

  • name (String)

    name for the folder

Returns:



115
116
117
118
# File 'lib/sm/client.rb', line 115

def post_create_folder(name)
  json = perform(:post, 'folder', { 'name' => name }, token_headers).body
  Folder.new(json)
end

#post_create_message(args = {}) ⇒ Message

Create a message

Parameters:

  • args (Hash) (defaults to: {})

    a hash of message arguments

Returns:

Raises:



332
333
334
335
336
337
# File 'lib/sm/client.rb', line 332

def post_create_message(args = {})
  validate_create_context(args)

  json = perform(:post, 'message', args.to_h, token_headers).body
  Message.new(json)
end

#post_create_message_draft(args = {}) ⇒ MessageDraft

Create and update a new message draft

Parameters:

  • args (Hash) (defaults to: {})

    arguments for the message draft

Returns:

Raises:



229
230
231
232
233
234
235
236
237
# File 'lib/sm/client.rb', line 229

def post_create_message_draft(args = {})
  # Prevent call if this is a reply draft, otherwise reply-to message suject can change.
  validate_draft(args)

  json = perform(:post, 'message/draft', args, token_headers).body
  draft = MessageDraft.new(json)
  draft.body = draft.original_attributes[:body]
  draft
end

#post_create_message_draft_reply(id, args = {}) ⇒ MessageDraft

Create and update a new message draft reply

Parameters:

  • id (Fixnum)

    id of the message for which the reply is directed

  • args (Hash) (defaults to: {})

    arguments for the message draft reply

Returns:

Raises:



247
248
249
250
251
252
253
254
255
256
257
# File 'lib/sm/client.rb', line 247

def post_create_message_draft_reply(id, args = {})
  # prevent call if this an existing draft with no association to a reply-to message
  validate_reply_draft(args)

  json = perform(:post, "message/#{id}/replydraft", args, token_headers).body
  json[:data][:has_message] = true

  draft = MessageDraft.new(json)
  draft.body = draft.original_attributes[:body]
  draft.as_reply
end

#post_create_message_reply(id, args = {}) ⇒ Message

Create a message reply

Parameters:

  • args (Hash) (defaults to: {})

    a hash of message arguments

Returns:

Raises:



376
377
378
379
380
381
# File 'lib/sm/client.rb', line 376

def post_create_message_reply(id, args = {})
  validate_reply_context(args)

  json = perform(:post, "message/#{id}/reply", args.to_h, token_headers).body
  Message.new(json)
end

#post_create_message_reply_with_attachment(id, args = {}) ⇒ Message

Create a message reply with an attachment

Parameters:

  • args (Hash) (defaults to: {})

    a hash of message arguments

Returns:

Raises:



361
362
363
364
365
366
367
# File 'lib/sm/client.rb', line 361

def post_create_message_reply_with_attachment(id, args = {})
  validate_reply_context(args)

  custom_headers = token_headers.merge('Content-Type' => 'multipart/form-data')
  json = perform(:post, "message/#{id}/reply/attach", args.to_h, custom_headers).body
  Message.new(json)
end

#post_create_message_with_attachment(args = {}) ⇒ Message

Create a message with an attachment

Parameters:

  • args (Hash) (defaults to: {})

    a hash of message arguments

Returns:

Raises:



346
347
348
349
350
351
352
# File 'lib/sm/client.rb', line 346

def post_create_message_with_attachment(args = {})
  validate_create_context(args)

  custom_headers = token_headers.merge('Content-Type' => 'multipart/form-data')
  json = perform(:post, 'message/attach', args.to_h, custom_headers).body
  Message.new(json)
end

#post_move_message(id, folder_id) ⇒ Fixnum

Move a message to a given folder

Parameters:

  • id (Fixnum)

    the Message id

  • folder_id (Fixnum)

    the Folder id

Returns:

  • (Fixnum)

    the response status code



390
391
392
393
394
395
# File 'lib/sm/client.rb', line 390

def post_move_message(id, folder_id)
  custom_headers = token_headers.merge('Content-Type' => 'application/json')
  response = perform(:post, "message/#{id}/move/tofolder/#{folder_id}", nil, custom_headers)

  response&.status
end

#post_move_thread(id, folder_id) ⇒ Fixnum

Move a thread to a given folder

Parameters:

  • id (Fixnum)

    the thread id

  • folder_id (Fixnum)

    the Folder id

Returns:

  • (Fixnum)

    the response status code



404
405
406
407
408
# File 'lib/sm/client.rb', line 404

def post_move_thread(id, folder_id)
  custom_headers = token_headers.merge('Content-Type' => 'application/json')
  response = perform(:post, "message/#{id}/movethreadmessages/tofolder/#{folder_id}", nil, custom_headers)
  response&.status
end

#post_preferences(params) ⇒ MessagingPreference

Set the email address and frequency for getting emails.

Examples:

client.post_preferences(email_address: '[email protected]', frequency: 'daily')

Parameters:

  • params (Hash)

    a hash of parameter objects

Returns:

Raises:



60
61
62
63
64
# File 'lib/sm/client.rb', line 60

def post_preferences(params)
  mhv_params = MessagingPreference.new(params).mhv_params
  perform(:post, 'preferences/notification', mhv_params, token_headers)
  get_preferences
end

#post_rename_folder(folder_id, name) ⇒ Folder

Rename a Folder

Parameters:

  • folder_id (Fixnum)

    id of the Folder

  • name (String)

    new name for the folder

Returns:



127
128
129
130
# File 'lib/sm/client.rb', line 127

def post_rename_folder(folder_id, name)
  json = perform(:post, "folder/#{folder_id}/rename", { 'folderName' => name }, token_headers).body
  Folder.new(json)
end

#post_search_folder(folder_id, page_num, page_size, args = {}, requires_oh_messages = nil) ⇒ Common::Collection

Run a search of messages in the given folder

Parameters:

  • folder_id (Fixnum)

    id of the folder to search

  • page_num (Fixnum)

    page number of results to return

  • page_size (Fixnum)

    number of messages per page

  • args (Hash) (defaults to: {})

    arguments for the message search

Returns:



205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/sm/client.rb', line 205

def post_search_folder(folder_id, page_num, page_size, args = {}, requires_oh_messages = nil)
  page_num ||= 1
  page_size ||= MHV_MAXIMUM_PER_PAGE

  path = "folder/#{folder_id}/searchMessage/page/#{page_num}/pageSize/#{page_size}"
  path = append_requires_oh_messages_query(path, requires_oh_messages)

  json_data = perform(:post,
                      path,
                      args.to_h,
                      token_headers).body
  Common::Collection.new(Message, **json_data)
end

#reply_draft?(id) ⇒ Boolean (private)

Returns:

  • (Boolean)


510
511
512
# File 'lib/sm/client.rb', line 510

def reply_draft?(id)
  get_message_history(id).data.present?
end

#statsd_cache_hitObject (private)

Report stats of secure messaging events



556
557
558
# File 'lib/sm/client.rb', line 556

def statsd_cache_hit
  StatsD.increment("#{STATSD_KEY_PREFIX}.cache.hit")
end

#statsd_cache_missObject (private)



560
561
562
# File 'lib/sm/client.rb', line 560

def statsd_cache_miss
  StatsD.increment("#{STATSD_KEY_PREFIX}.cache.miss")
end

#update_triage_team_preferences(updated_triage_teams_list) ⇒ Fixnum

Update preferredTeam value for a patient’s list of triage teams

with triage_team_id and preferred_team values

Parameters:

  • updated_triage_teams_list (Array)

    an array of objects

Returns:

  • (Fixnum)

    the response status code



486
487
488
489
490
# File 'lib/sm/client.rb', line 486

def update_triage_team_preferences(updated_triage_teams_list)
  custom_headers = token_headers.merge('Content-Type' => 'application/json')
  response = perform(:post, 'preferences/patientpreferredtriagegroups', updated_triage_teams_list, custom_headers)
  response&.status
end

#validate_create_context(args) ⇒ Object (private)



526
527
528
529
530
531
532
# File 'lib/sm/client.rb', line 526

def validate_create_context(args)
  if args[:id].present? && reply_draft?(args[:id])
    draft = MessageDraft.new(args.merge(has_message: true)).as_reply
    draft.errors.add(:base, 'attempted to use reply draft in send message')
    raise Common::Exceptions::ValidationErrors, draft
  end
end

#validate_draft(args) ⇒ Object (private)



514
515
516
517
518
# File 'lib/sm/client.rb', line 514

def validate_draft(args)
  draft = MessageDraft.new(args)
  draft.as_reply if args[:id] && reply_draft?(args[:id])
  raise Common::Exceptions::ValidationErrors, draft unless draft.valid?
end

#validate_reply_context(args) ⇒ Object (private)



542
543
544
545
546
547
548
# File 'lib/sm/client.rb', line 542

def validate_reply_context(args)
  if args[:id].present? && !reply_draft?(args[:id])
    draft = MessageDraft.new(args)
    draft.errors.add(:base, 'attempted to use plain draft in send reply')
    raise Common::Exceptions::ValidationErrors, draft
  end
end

#validate_reply_draft(args) ⇒ Object (private)



520
521
522
523
524
# File 'lib/sm/client.rb', line 520

def validate_reply_draft(args)
  draft = MessageDraft.new(args).as_reply
  draft.has_message = !args[:id] || reply_draft?(args[:id])
  raise Common::Exceptions::ValidationErrors, draft unless draft.valid?
end