allscripts_api 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1b23ffb52309d9ea984d58c79f4395ec31c2da8f
4
+ data.tar.gz: eebeb6cefe1d8405f58c8d9d0dc879aca52d5691
5
+ SHA512:
6
+ metadata.gz: 001e96d778c6fae73d8ac958d5be9fb2c5734a0212420ee6d9932ba20d125ee36ab865062d79a04d5aa9dd6ce465bb4649cf67acc58137f8f30a5ab99c18ac9c
7
+ data.tar.gz: 35b052c6a01bd26cb9520e6aea5d9334dae1908d36b28250d7323f13e486640e93528a516c7a01700418a6f249b28efbcacc600d464ef43fce085af1a02d9ea5
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ .vscode/
14
+
15
+ /spec/fixtures/secrets.yml
data/.pryrc ADDED
@@ -0,0 +1,24 @@
1
+ require "allscripts_api"
2
+ require "yaml"
3
+
4
+ begin
5
+ loaded = ENV["app_name"] && ENV["app_password"] && ENV["unity_url"] && ENV["app_username"]
6
+ unless loaded
7
+ secrets = YAML.safe_load(File.read("spec/fixtures/secrets.yml"))
8
+ secrets.map { |key_name, secret| ENV[key_name] = secret }
9
+ end
10
+ rescue => exception
11
+ puts(exception)
12
+ end
13
+
14
+ def bc
15
+ client =
16
+ AllscriptsApi::Client.new(ENV["unity_url"],
17
+ ENV["app_name"],
18
+ ENV["app_username"],
19
+ ENV["app_password"])
20
+ client.get_token
21
+ client.get_user_authentication("jmedici", "password01")
22
+
23
+ client
24
+ end
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,22 @@
1
+ AllCops:
2
+ Exclude:
3
+ - "bin/*"
4
+ - .pryrc
5
+ - "spec/*"
6
+
7
+ Style/StringLiterals:
8
+ EnforcedStyle: double_quotes
9
+
10
+ Style/FrozenStringLiteralComment:
11
+ EnforcedStyle: always
12
+
13
+ Style/AccessorMethodName:
14
+ Exclude:
15
+ - "lib/allscripts_api/client.rb"
16
+
17
+ # Bumbing the max from 10 to 15 allows magic params to work nicely
18
+ Metrics/MethodLength:
19
+ Max: 15
20
+ # Bumbing the max from 5 to 7 allows magic params to work nicely
21
+ Metrics/ParameterLists:
22
+ Max: 7
data/.simplecov ADDED
@@ -0,0 +1,7 @@
1
+ require "simplecov"
2
+ require "coveralls"
3
+
4
+ SimpleCov.formatter = Coveralls::SimpleCov::Formatter
5
+ SimpleCov.start do
6
+ add_filter "spec/helper.rb"
7
+ end
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.5.0
5
+ - 2.4.2
6
+ - 2.3.6
7
+ before_install: gem install bundler -v 1.16.1
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in allscripts_api.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,123 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ allscripts_api (0.1.0)
5
+ faraday (>= 0.12.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ addressable (2.5.2)
11
+ public_suffix (>= 2.0.2, < 4.0)
12
+ ast (2.3.0)
13
+ coderay (1.1.2)
14
+ coveralls (0.8.21)
15
+ json (>= 1.8, < 3)
16
+ simplecov (~> 0.14.1)
17
+ term-ansicolor (~> 1.3)
18
+ thor (~> 0.19.4)
19
+ tins (~> 1.6)
20
+ crack (0.4.3)
21
+ safe_yaml (~> 1.0.0)
22
+ diff-lcs (1.3)
23
+ docile (1.1.5)
24
+ faraday (0.14.0)
25
+ multipart-post (>= 1.2, < 3)
26
+ gitlab (4.0.0)
27
+ httparty
28
+ terminal-table (= 1.7.1)
29
+ hashdiff (0.3.7)
30
+ httparty (0.14.0)
31
+ multi_xml (>= 0.5.2)
32
+ json (2.1.0)
33
+ method_source (0.9.0)
34
+ mini_portile2 (2.3.0)
35
+ multi_xml (0.5.5)
36
+ multipart-post (2.0.0)
37
+ nokogiri (1.8.2)
38
+ mini_portile2 (~> 2.3.0)
39
+ octokit (4.7.0)
40
+ sawyer (~> 0.8.0, >= 0.5.3)
41
+ parallel (1.12.1)
42
+ parser (2.4.0.0)
43
+ ast (~> 2.2)
44
+ powerpack (0.1.1)
45
+ pronto (0.9.3)
46
+ gitlab (~> 4.0, >= 4.0.0)
47
+ httparty (>= 0.13.7, < 0.15)
48
+ octokit (~> 4.7, >= 4.7.0)
49
+ rainbow (~> 2.1)
50
+ rugged (~> 0.24, >= 0.23.0)
51
+ thor (~> 0.19.0)
52
+ pronto-rubocop (0.9.0)
53
+ pronto (~> 0.9.0)
54
+ rubocop (~> 0.38, >= 0.35.0)
55
+ pry (0.11.3)
56
+ coderay (~> 1.1.0)
57
+ method_source (~> 0.9.0)
58
+ public_suffix (3.0.2)
59
+ rainbow (2.2.2)
60
+ rake
61
+ rake (10.5.0)
62
+ rspec (3.7.0)
63
+ rspec-core (~> 3.7.0)
64
+ rspec-expectations (~> 3.7.0)
65
+ rspec-mocks (~> 3.7.0)
66
+ rspec-core (3.7.1)
67
+ rspec-support (~> 3.7.0)
68
+ rspec-expectations (3.7.0)
69
+ diff-lcs (>= 1.2.0, < 2.0)
70
+ rspec-support (~> 3.7.0)
71
+ rspec-mocks (3.7.0)
72
+ diff-lcs (>= 1.2.0, < 2.0)
73
+ rspec-support (~> 3.7.0)
74
+ rspec-support (3.7.1)
75
+ rubocop (0.49.1)
76
+ parallel (~> 1.10)
77
+ parser (>= 2.3.3.1, < 3.0)
78
+ powerpack (~> 0.1)
79
+ rainbow (>= 1.99.1, < 3.0)
80
+ ruby-progressbar (~> 1.7)
81
+ unicode-display_width (~> 1.0, >= 1.0.1)
82
+ ruby-progressbar (1.9.0)
83
+ rugged (0.25.1.1)
84
+ safe_yaml (1.0.4)
85
+ sawyer (0.8.1)
86
+ addressable (>= 2.3.5, < 2.6)
87
+ faraday (~> 0.8, < 1.0)
88
+ simplecov (0.14.1)
89
+ docile (~> 1.1.0)
90
+ json (>= 1.8, < 3)
91
+ simplecov-html (~> 0.10.0)
92
+ simplecov-html (0.10.2)
93
+ term-ansicolor (1.6.0)
94
+ tins (~> 1.0)
95
+ terminal-table (1.7.1)
96
+ unicode-display_width (~> 1.1.1)
97
+ thor (0.19.4)
98
+ tins (1.16.0)
99
+ unicode-display_width (1.1.3)
100
+ webmock (3.3.0)
101
+ addressable (>= 2.3.6)
102
+ crack (>= 0.3.2)
103
+ hashdiff
104
+ yard (0.9.12)
105
+
106
+ PLATFORMS
107
+ ruby
108
+
109
+ DEPENDENCIES
110
+ allscripts_api!
111
+ bundler (~> 1.16)
112
+ coveralls
113
+ nokogiri
114
+ pronto
115
+ pronto-rubocop
116
+ pry
117
+ rake (~> 10.0)
118
+ rspec (~> 3.0)
119
+ webmock (~> 3.3)
120
+ yard (~> 0.9)
121
+
122
+ BUNDLED WITH
123
+ 1.16.1
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+
2
+ Copyright (c) 2018 Avhana Health, Inc
3
+
4
+ MIT License
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # AllscriptsApi, an Allscripts Unity Client
2
+
3
+ [![Coverage Status](https://coveralls.io/repos/github/Avhana/allscripts_api/badge.svg?branch=master)](https://coveralls.io/github/Avhana/allscripts_api?branch=master)
4
+ [![Build Status](https://travis-ci.org/Avhana/allscripts_api.svg?branch=master)](https://travis-ci.org/Avhana/allscripts_api)
5
+ [![Inline docs](http://inch-ci.org/github/Avhana/allscripts_api.svg?branch=master&style=shields)](http://inch-ci.org/github/Avhana/allscripts_api)
6
+ [![Dependency Status](https://gemnasium.com/badges/github.com/Avhana/allscripts_api.svg)](https://gemnasium.com/github.com/Avhana/allscripts_api)
7
+ [![Maintainability](https://api.codeclimate.com/v1/badges/9889f5255914a5fcbeb5/maintainability)](https://codeclimate.com/github/Avhana/allscripts_api/maintainability)
8
+ [![security](https://hakiri.io/github/Avhana/allscripts_api/master.svg)](https://hakiri.io/github/Avhana/allscripts_api/master)
9
+
10
+ AllscriptsApi is a simple ruby wrapper around the [Allscripts Unity API](https://developer.allscripts.com/APIReference/). This gem specifically focuses on the JSON
11
+ functionality of the API and will not support SOAP. Additionally, `allscripts_api` focuses on being simple
12
+ to use and understand. There are no DSLs, or behind the scenes magic. The code aims to be well documented,
13
+ readable, and straightforward to use in your own application. The docs are available [here](http://www.rubydoc.info/github/Avhana/allscripts_api/master/AllscriptsApi)
14
+
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ ```ruby
21
+ gem 'allscripts_api'
22
+ ```
23
+
24
+ And then execute:
25
+
26
+ $ bundle
27
+
28
+ Or install it yourself as:
29
+
30
+ $ gem install allscripts_api
31
+
32
+ ## Usage
33
+ The client can be used either with ahead of time configuration and instantiated with `AllscriptsApi.connect`, or by directly calling
34
+ `AllscriptsApi::Client.new`, and passing your applications credentials.
35
+ ### Optional Configuration
36
+
37
+ You may configure the client beforehand with the following config block. If you are using Rails,
38
+ this will go in `cofig/initializers`. However, the code does not rely on ActiveSupport and can
39
+ be configured ahead of time in and Ruby application.
40
+
41
+ ```ruby
42
+ AllscriptsApi.configure do |config|
43
+ config.app_name = 'YOUR_APP_NAME_HERE'
44
+ config.app_username = 'YOUR_APP_USERNAME_HERE'
45
+ config.app_password = 'YOUR_APP_PASSWORD_HERE'
46
+ config.unity_url = 'CHOSEN_UNITY_URL'
47
+ end
48
+ ```
49
+
50
+ If you have configured you application ahead of time, you can test your set up now.
51
+ ```ruby
52
+ client = AllscriptsApi.connect
53
+ client.get_token
54
+ ```
55
+
56
+ If this works, the client should set a token, and you should see it printed to the console. If it fails for any reason, it will raise [`GetTokenError`](https://github.com/Avhana/allscripts_api/blob/master/lib/allscripts_api.rb#L16), and dump the response body of the GetToken call to Unity.
57
+
58
+ Assuming a successful call to GetToken, next authenticate the test user to that token.
59
+
60
+ ```ruby
61
+ client.get_user_authentication("jmedici", "password01")
62
+ ```
63
+
64
+ This call will return a [`MagicError`](https://github.com/Avhana/allscripts_api/blob/master/lib/allscripts_api.rb#L12) if it fails.
65
+
66
+ ### Directly Building the Client
67
+ If you want to use the gem from the console, or without ahead of time configuration, you may do so as follows.
68
+ ```ruby
69
+ client =
70
+ AllscriptsApi::Client.new(unity_url, app_name, app_username, app_password)
71
+ client.get_token
72
+ client.get_user_authentication("jmedici", "password01")
73
+ ```
74
+ As you can see, after the initial call, usage is the same. That is because `AllscriptsApi.connect` returns an instance of `AllscriptsApi::Client`. You can find the documentation for `AllscriptsApi.connect` [here](http://www.rubydoc.info/github/Avhana/allscripts_api/master/AllscriptsApi/Client).
75
+
76
+
77
+ ## Code of Conduct
78
+ In order to have a more open and welcoming community of contributors and users, Avhana Health will enforce a [Code of Conduct](https://github.com/avhana/allscripts_api/blob/master/code-of-conduct.md), which follows v1.4 of the [Contributors Covenant](https://www.contributor-covenant.org/version/1/4/code-of-conduct.html).
79
+
80
+ ## Contributing
81
+
82
+ Bug reports and pull requests are welcome on GitHub at https://github.com/avhana/allscripts_api.
83
+
84
+ ## License
85
+
86
+ This gem is provided as is under the [MIT license](https://github.com/avhana/allscripts_api/blob/master/LICENSE), Copyright (c) 2018 Avhana Health, Inc.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,36 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "allscripts_api/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "allscripts_api"
8
+ spec.version = AllscriptsApi::VERSION
9
+ spec.authors = ["Chase"]
10
+ spec.email = ["chase.gilliam@gmail.com"]
11
+
12
+ spec.summary = "A simple, configurable wrapper around Allscripts APIs"
13
+ spec.description = %(The allscripts_api gem wraps a set of Allscripts APIs, including
14
+ but not limited to Unity. The gem focuses on JSON endpoints instead
15
+ of SOAP.)
16
+ spec.homepage = "https://github.com/Avhana/allscripts_api"
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+ spec.bindir = "exe"
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_dependency "faraday", ">= 0.12.2"
26
+ spec.add_development_dependency "bundler", "~> 1.16"
27
+ spec.add_development_dependency "coveralls"
28
+ spec.add_development_dependency "nokogiri"
29
+ spec.add_development_dependency "pronto"
30
+ spec.add_development_dependency "pronto-rubocop"
31
+ spec.add_development_dependency "pry"
32
+ spec.add_development_dependency "rake", "~> 10.0"
33
+ spec.add_development_dependency "rspec", "~> 3.0"
34
+ spec.add_development_dependency "yard", "~> 0.9"
35
+ spec.add_development_dependency "webmock", "~> 3.3"
36
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "allscripts_api"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,73 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ education, socio-economic status, nationality, personal appearance, race,
10
+ religion, or sexual identity and orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72
+
73
+ [homepage]: https://www.contributor-covenant.org
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "allscripts_api/configuration"
4
+ require "allscripts_api/magic_params"
5
+ require "allscripts_api/named_magic_methods"
6
+ require "allscripts_api/client"
7
+ require "allscripts_api/version"
8
+
9
+ # Entry point for the AllscriptsApi gem.
10
+ module AllscriptsApi
11
+ # Error wrapper of Unity or other Allscripts API errors.
12
+ class MagicError < RuntimeError
13
+ end
14
+
15
+ # Error raised whenever Unity's '/GetToken' call fails or returns an error.
16
+ class GetTokenError < RuntimeError
17
+ end
18
+
19
+ # Error raised if AllscriptsApi.connect is called without configuring
20
+ # the gem first
21
+ class NoConfigurationError < RuntimeError
22
+ # method to return a sample config block
23
+ #
24
+ # @return [String] a sample config block
25
+ def self.error_message
26
+ %(Please add the following to config/initializers and try again.
27
+ AllscriptsApi.configure do |config|
28
+ config.app_name = 'YOUR_APP_NAME_HERE'
29
+ config.app_username = 'YOUR_APP_USERNAME_HERE'
30
+ config.app_password = 'YOUR_APP_PASSWORD_HERE'
31
+ config.unity_url = 'CHOSEN_UNITY_URL'
32
+ end
33
+ )
34
+ end
35
+ end
36
+
37
+ class << self
38
+ attr_accessor :configuration
39
+ # a method that allows a configuration block to be passed
40
+ # to {AllscriptsApi::Configuration#new}
41
+ # @see AllscriptsApi::Configuration
42
+ def configure
43
+ self.configuration ||= AllscriptsApi::Configuration.new
44
+ yield(configuration)
45
+ end
46
+
47
+ # The main entry point for a pre-configured client
48
+ #
49
+ # @return [AllscriptsApi::Client, AllscriptsApi::NoConfigurationError]
50
+ # @see AllscriptsApi::Client
51
+ def connect
52
+ unless AllscriptsApi.configuration
53
+ raise NoConfigurationError, NoConfigurationError.error_message
54
+ end
55
+ unity_url = AllscriptsApi.configuration.unity_url
56
+ app_name = AllscriptsApi.configuration.app_name
57
+ app_username = AllscriptsApi.configuration.app_username
58
+ app_password = AllscriptsApi.configuration.app_password
59
+
60
+ Client.new(unity_url, app_name, app_username, app_password)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+ require "json"
5
+ module AllscriptsApi
6
+ # Client serves as an entry point for making calls
7
+ class Client
8
+ include AllscriptsApi::NamedMagicMethods
9
+ attr_reader :adapter, :unity_url, :app_name, :token
10
+ attr_writer :sso_token
11
+
12
+ # hardcoded to use the JSON endpoint
13
+ ENDPOINT = "/Unity/UnityService.svc/json".freeze
14
+
15
+ # Instantiation of the Client
16
+ #
17
+ # @param url [String] Allscripts URL to be used to make Unity API calls
18
+ # @param app_name [String] app name assigned by Allscripts
19
+ # @param app_username [String] the app username supplied by Allscripts
20
+ # @param app_password [String] the app password supplied by Allscripts
21
+ def initialize(url, app_name, app_username, app_password)
22
+ @unity_url = url
23
+ @app_name = app_name
24
+ @username = app_username
25
+ @password = app_password
26
+ @adapter = check_adapter
27
+ end
28
+
29
+ # Gets security token necessary in all workflows
30
+ # @return [String] security token
31
+ def get_token
32
+ full_path = build_request_path("/GetToken")
33
+ response = conn.post do |req|
34
+ req.url(full_path)
35
+ req.body = { Username: @username, Password: @password }.to_json
36
+ end
37
+
38
+ raise(GetTokenError, response.body) unless response.status == 200
39
+ @token = response.body
40
+ end
41
+
42
+ # Assign a security token from `get_token` to a specific Allscripts user.
43
+ # This creates a link on the Allscripts server that allows that token
44
+ # to be used in subsequent `magic` calls passed that user's username.
45
+ #
46
+ # @param username [String] the Allscripts user's username (from Allscripts)
47
+ # @param password [String] the Allscripts user's password (from Allscripts)
48
+ # @return [Hash] user permissions, etc.
49
+ def get_user_authentication(username, password)
50
+ @allscripts_username = username
51
+ params = MagicParams.format(user_id: username, parameter1: password)
52
+ response = magic("GetUserAuthentication", magic_params: params)
53
+ response["getuserauthenticationinfo"][0]
54
+ end
55
+
56
+ # Validate a token generated and passed by Allscripts during SSO
57
+ # Falls back and looks for sso_token on the client if not passed one
58
+ # Note that sso_token is not the token from `get_token``
59
+ #
60
+ # TODO: test and validate. Add error handling
61
+ #
62
+ # @param sso_token [String] the Allscripts SSO token (from Allscripts)
63
+ def validate_sso_token(sso_token = nil)
64
+ sso_token ||= @sso_token
65
+ params = MagicParams.format(parameter1: sso_token)
66
+ response = magic("GetTokenValidation", magic_params: params)
67
+ response["Table"][0]
68
+ end
69
+
70
+ # Main method for interacting with the Allscripts UNityAPI
71
+ #
72
+ # @param action [String] the API action to be performed
73
+ # @param magic_params [MagicParams] a params object
74
+ # used to build the Magic Action request body's user_id,
75
+ # patient_id, and magic parameters. The patient_id
76
+ # is sometimes oprional and the numbered
77
+ # params are generally optional, but must be sent
78
+ # as blank strings if unused.
79
+ # @return [Hash, MagicError] the parsed JSON response from Allscripts or
80
+ # a `MagicError` with the API error message(hopefully)
81
+ def magic(action, magic_params: MagicParams.format)
82
+ full_path = build_request_path("/MagicJson")
83
+ body = build_magic_body(action, magic_params)
84
+ response =
85
+ conn.post do |req|
86
+ req.url(full_path)
87
+ req.body = body
88
+ end
89
+
90
+ read_magic_response(response)
91
+ end
92
+
93
+ private
94
+
95
+ def check_adapter
96
+ @adapter ||=
97
+ if AllscriptsApi.configuration
98
+ AllscriptsApi.configuration.faraday_adapter
99
+ else
100
+ Faraday.default_adapter # make requests with Net::HTTP
101
+ end
102
+ end
103
+
104
+ def read_magic_response(response)
105
+ raise(MagicError, response.body) unless response.status == 200
106
+ response_body = JSON.parse(response.body)[0]
107
+ raise(MagicError, response_body["Error"]) if response_body.key?("Error")
108
+ response_body
109
+ end
110
+
111
+ def build_magic_body(action, params)
112
+ params.merge(
113
+ Action: action,
114
+ Appname: @app_name,
115
+ Token: @token
116
+ ).to_json
117
+ end
118
+
119
+ def build_request_path(path)
120
+ "#{ENDPOINT}#{path}"
121
+ end
122
+
123
+ def conn
124
+ @conn ||= Faraday.new(url: @unity_url) do |faraday|
125
+ faraday.headers["Content-Type"] = "application/json"
126
+ faraday.adapter(@adapter)
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AllscriptsApi
4
+ # Configuration class to allow configuration on application
5
+ # initialization. Configuration should look like the following.
6
+ #
7
+ # AllscriptsApi.configure do |config|
8
+ # config.app_name = 'YOUR_APP_NAME_HERE'
9
+ # config.app_username = 'YOUR_APP_USERNAME_HERE'
10
+ # config.app_password = 'YOUR_APP_PASSWORD_HERE'
11
+ # config.unity_url = 'CHOSEN_UNITY_URL'
12
+ # config.faraday_adapter = Faraday.some_adapter # default = Faraday.default_adapter
13
+ # end
14
+ class Configuration
15
+ attr_accessor :app_name, :app_password, :unity_url,
16
+ :app_username, :faraday_adapter
17
+ # The initialize method may be passed a block, but defaults to fetching
18
+ # data from the environment
19
+ #
20
+ # @return [AllscriptsApi:Configuration] new instance of the config class
21
+ def initialize
22
+ @app_name = ENV["app_name"]
23
+ @app_password = ENV["app_password"]
24
+ @unity_url = ENV["unity_url"]
25
+ @app_username = ENV["app_username"]
26
+ @faraday_adapter = Faraday.default_adapter
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AllscriptsApi
4
+ # A simple formatter for Magic Action's numbered perameters
5
+ class MagicParams
6
+ # A method for formatting data for the body of {AllscriptsApi::Client#magic}
7
+ # calls. Magic Actions require all arguments to be present in the HTTP call
8
+ # and in the correct order.
9
+ #
10
+ # @param user_id [String] id or user name of the App/User making the call
11
+ # @param patient_id [String, Nil] the optional id of a patient
12
+ # related to the Magic call
13
+ # @param parameter1 [String, Nil] the optional 1st argument of the Magic call
14
+ # @param parameter2 [String, Nil] the optional 2nd argument of the Magic call
15
+ # @param parameter3 [String, Nil] the optional 3rd argument of the Magic call
16
+ # @param parameter4 [String, Nil] the optional 4th argument of the Magic call
17
+ # @param parameter5 [String, Nil] the optional 5th argument of the Magic call
18
+ # @param parameter6 [String, Nil] the optional 6th argument of the Magic call
19
+ # @param data [Hash, Nil] the optional data argument of the Magic call
20
+ #
21
+ # @return [Hash] the method returns a formatted hash containing the
22
+ # passed parameters and empty values for unused params
23
+ # @example formatting params for SearchPatients as seen in {NamedMagicMethods#search_patients}
24
+ # MagicParams.format(user_id: "YOUR_APP_USERNAME, parameter1: "Smith")
25
+ # => {AppUserID: "YOUR_APP_USERNAME",
26
+ # PatientID: "",
27
+ # Parameter1: "Smith",
28
+ # Parameter2: "",
29
+ # Parameter3: "",
30
+ # Parameter4: "",
31
+ # Parameter5: "",
32
+ # Parameter6: "",
33
+ # Data: {}}
34
+ def self.format(user_id: "", patient_id: "", parameter1: "", parameter2: "", parameter3: "", parameter4: "", parameter5: "", parameter6: "", data: {})
35
+ {
36
+ AppUserID: user_id,
37
+ PatientID: patient_id,
38
+ Parameter1: parameter1,
39
+ Parameter2: parameter2,
40
+ Parameter3: parameter3,
41
+ Parameter4: parameter4,
42
+ Parameter5: parameter5,
43
+ Parameter6: parameter6,
44
+ Data: data
45
+ }
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AllscriptsApi
4
+ # A collection of named convenience methods that map
5
+ # to Allscripts magic actions. These methods are included
6
+ # in `AllscriptsApi::Client` and can be accessed from
7
+ # instances of that class.
8
+ module NamedMagicMethods
9
+ # a wrapper around SearchPatients
10
+ #
11
+ # @param search_string [String] may be a name, birthdate
12
+ # partial address, or other PHI
13
+ # @return [Array<Hash>, Array, MagicError] a list of found patients,
14
+ # an empty array, or an error
15
+ def search_patients(search_string)
16
+ params =
17
+ MagicParams.format(
18
+ user_id: @allscripts_username,
19
+ parameter1: search_string
20
+ )
21
+ results = magic("SearchPatients", magic_params: params)
22
+ results["searchpatientsinfo"]
23
+ end
24
+
25
+ # gets the CCDA documents for the specified patient and encounter
26
+ #
27
+ # @param patient_id [String] patient id
28
+ # @param encounter_id [String] encounter id from which to generate the CCDA
29
+ # @param org_id [String] specifies the organization, by default Unity
30
+ # uses the organization for the specified user
31
+ # @param app_group [String] defaults to "TouchWorks"
32
+ # @param referral_text [String] contents of ReferralText are appended
33
+ # @param site_id [String] site id
34
+ # @param document_type [String] document type defaults to CCDACCD,
35
+ # CCDACCD (Default) - Returns the Continuity of Care Document. This
36
+ # is the default behavior if nothing is passed in.
37
+ # CCDASOC - Returns the Summary of Care Document
38
+ # CCDACS - Returns the Clinical Summary Document (Visit Summary).
39
+ # @return [String, AllscriptsApi::MagicError] ccda for patient
40
+ def get_ccda(patient_id,
41
+ encounter_id,
42
+ org_id = nil,
43
+ app_group = nil,
44
+ referral_text = nil,
45
+ site_id = nil,
46
+ document_type = "CCDACCD")
47
+ params =
48
+ MagicParams.format(
49
+ user_id: @allscripts_username,
50
+ patient_id: patient_id,
51
+ parameter1: encounter_id,
52
+ parameter2: org_id,
53
+ parameter3: app_group,
54
+ parameter4: referral_text,
55
+ parameter5: site_id,
56
+ parameter6: document_type
57
+ )
58
+ results = magic("GetCCDA", magic_params: params)
59
+ results["getccdainfo"][0]["ccdaxml"]
60
+ end
61
+
62
+ # gets data elements of a patient's history
63
+ #
64
+ # @param patient_id [String] patient id
65
+ # @param section [String] section
66
+ # if no section is specified than all sections wt data are returned
67
+ # list multiple sections by using a pipe-delimited list ex. "Vitals|Alerts"
68
+ # @param encounter_id [String] internal identifier for the encounter
69
+ # the EncounterID can be acquired with GetEncounterList
70
+ # @param verbose [String] XMLDetail
71
+ # verbose column will be Y or blank, when Y is provided there will be a
72
+ # piece of XML data that is specific to that element of the patient's chart
73
+ # @return [String, AllscriptsApi::MagicError] clinical summary for patient
74
+ def get_clinical_summary(patient_id,
75
+ section = nil,
76
+ encounter_id = nil,
77
+ verbose = nil)
78
+ params =
79
+ MagicParams.format(
80
+ user_id: @allscripts_username,
81
+ patient_id: patient_id,
82
+ parameter1: section,
83
+ parameter2: encounter_id,
84
+ parameter3: verbose
85
+ )
86
+ results = magic("GetClinicalSummary", magic_params: params)
87
+ results["getclinicalsummaryinfo"]
88
+ end
89
+
90
+ # gets patient's demographic info, insurance, guarantor, and PCP info
91
+ #
92
+ # @param patient_id [String] patient id
93
+ # @param patient_number [String] PM patient number
94
+ # @return [String, AllscriptsApi::MagicError] patient demographics
95
+ def get_patient(patient_id,
96
+ patient_number = nil)
97
+ params =
98
+ MagicParams.format(
99
+ user_id: @allscripts_username,
100
+ patient_id: patient_id,
101
+ parameter1: patient_number
102
+ )
103
+ results = magic("GetPatient", magic_params: params)
104
+ results["getpatientinfo"]
105
+ end
106
+
107
+ # a wrapper around GetPatientProblems
108
+ #
109
+ # @param patient_id [String] patient id
110
+ # @param show_by_encounter [String] Y or N (defaults to `N`)
111
+ # @param assessed [String]
112
+ # @param encounter_id [String] id for a specific patient encounter
113
+ # @param filter_on_id [String]
114
+ # @param display_in_progress [String]
115
+ # @return [Array<Hash>, Array, MagicError] a list of found problems,
116
+ # an empty array, or an error
117
+ def get_patient_problems(patient_id,
118
+ show_by_encounter = "N",
119
+ assessed = nil,
120
+ encounter_id = nil,
121
+ filter_on_id = nil,
122
+ display_in_progress = nil)
123
+ params = MagicParams.format(
124
+ user_id: @allscripts_username,
125
+ patient_id: patient_id,
126
+ parameter1: show_by_encounter,
127
+ parameter2: assessed,
128
+ parameter3: encounter_id,
129
+ parameter4: filter_on_id,
130
+ parameter5: display_in_progress
131
+ )
132
+ results = magic("GetPatientProblems", magic_params: params)
133
+ results["getpatientproblemsinfo"]
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AllscriptsApi
4
+ # gem version declaration
5
+ VERSION = "0.1.0".freeze
6
+ end
metadata ADDED
@@ -0,0 +1,220 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: allscripts_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Chase
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-03-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.12.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.12.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.16'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.16'
41
+ - !ruby/object:Gem::Dependency
42
+ name: coveralls
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: nokogiri
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pronto
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pronto-rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '10.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '10.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: yard
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.9'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.9'
153
+ - !ruby/object:Gem::Dependency
154
+ name: webmock
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '3.3'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '3.3'
167
+ description: "The allscripts_api gem wraps a set of Allscripts APIs, including\n but
168
+ not limited to Unity. The gem focuses on JSON endpoints instead \n of
169
+ SOAP."
170
+ email:
171
+ - chase.gilliam@gmail.com
172
+ executables: []
173
+ extensions: []
174
+ extra_rdoc_files: []
175
+ files:
176
+ - ".gitignore"
177
+ - ".pryrc"
178
+ - ".rspec"
179
+ - ".rubocop.yml"
180
+ - ".simplecov"
181
+ - ".travis.yml"
182
+ - Gemfile
183
+ - Gemfile.lock
184
+ - LICENSE
185
+ - README.md
186
+ - Rakefile
187
+ - allscripts_api.gemspec
188
+ - bin/console
189
+ - bin/setup
190
+ - code-of-conduct.md
191
+ - lib/allscripts_api.rb
192
+ - lib/allscripts_api/client.rb
193
+ - lib/allscripts_api/configuration.rb
194
+ - lib/allscripts_api/magic_params.rb
195
+ - lib/allscripts_api/named_magic_methods.rb
196
+ - lib/allscripts_api/version.rb
197
+ homepage: https://github.com/Avhana/allscripts_api
198
+ licenses: []
199
+ metadata: {}
200
+ post_install_message:
201
+ rdoc_options: []
202
+ require_paths:
203
+ - lib
204
+ required_ruby_version: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ required_rubygems_version: !ruby/object:Gem::Requirement
210
+ requirements:
211
+ - - ">="
212
+ - !ruby/object:Gem::Version
213
+ version: '0'
214
+ requirements: []
215
+ rubyforge_project:
216
+ rubygems_version: 2.6.14
217
+ signing_key:
218
+ specification_version: 4
219
+ summary: A simple, configurable wrapper around Allscripts APIs
220
+ test_files: []