allscripts_api 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []