symgate 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: 4b8844223c94a355ea8ad0d294d75bfa31127a27
4
+ data.tar.gz: 822d5a227b81ac8e4e22c6a62b07d5c813b40640
5
+ SHA512:
6
+ metadata.gz: d1e6978cf81fb2f10922d9fdb3eb13c86163cc5e95a5b75e428363ecd4fe6435bbd02809c66074a8fa8df5849b82f627af7f03a87caa54286105dff6ad8a1a9b
7
+ data.tar.gz: a4f344a61d6cd9d6c08a7e7f3d2bc0b82a4641dc26a1cc7a2da28504e5e45b5075093e1b11ce1d632ae4c08da238e61276ab9632e586a8461b5db835e6e7af61
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.junit/*.xml
11
+ /.idea/
12
+ /.chef/
13
+ /local-mode-cache/
14
+ /nodes/
15
+ /.vagrant/
16
+ /Berksfile.lock
17
+ /vendor/
18
+ /coverage/
19
+ /coverage.zip
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "symboliser-vagrant"]
2
+ path = symboliser-vagrant
3
+ url = https://git.widgit.com/scm/online/symboliser-vagrant.git
data/.junit/.git-keep ADDED
File without changes
data/.rubocop.yml ADDED
@@ -0,0 +1,19 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.2
3
+ Exclude:
4
+ - 'vendor/**/*'
5
+ - '.chef/**/*'
6
+ - 'local-mode-cache/**/*'
7
+ - 'symboliser-vagrant/**/*'
8
+
9
+ Metrics/LineLength:
10
+ Max: 100
11
+
12
+ Metrics/MethodLength:
13
+ Max: 12
14
+
15
+ Style/NumericLiterals:
16
+ MinDigits: 6
17
+
18
+ Metrics/ClassLength:
19
+ Max: 120
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.2.1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in symgate-gem.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # Symgate::Gem
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/symgate/gem`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'symgate-gem'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install symgate-gem
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ 1. Fork it ( https://github.com/[my-github-username]/symgate-gem/fork )
36
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
37
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
38
+ 4. Push to the branch (`git push origin my-new-feature`)
39
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,100 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ # rubocop:disable Lint/RescueException
4
+
5
+ begin
6
+ require 'rspec/core/rake_task'
7
+ RSpec::Core::RakeTask.new(:spec) do |spec|
8
+ spec.pattern = 'test/spec/**/*_spec.rb'
9
+ end
10
+ desc 'Run RSpec integration tests against vagrant symboliser'
11
+ RSpec::Core::RakeTask.new('spec:integration') do |spec|
12
+ spec.pattern = 'test/integration/**/*_spec.rb'
13
+ end
14
+
15
+ desc 'Run RSpec code examples with junit output'
16
+ RSpec::Core::RakeTask.new('teamcity:spec') do |spec|
17
+ spec.rspec_opts = '-f RspecJunitFormatter -o .junit/rspec.xml'
18
+ spec.pattern = 'test/spec/**/*_spec.rb'
19
+ end
20
+
21
+ desc 'Run RSpec integration tests against vagrant symboliser with junit output'
22
+ RSpec::Core::RakeTask.new('teamcity:spec:integration') do |spec|
23
+ spec.rspec_opts = '-f RspecJunitFormatter -o .junit/integration.xml'
24
+ spec.pattern = 'test/integration/**/*_spec.rb'
25
+ end
26
+ rescue LoadError
27
+ $stderr.puts 'Unable to find rspec gem'
28
+ end
29
+
30
+ desc 'Runs the rubocop linting tool'
31
+ task :rubocop do
32
+ raise 'rubocop failed' unless system 'bundle exec rubocop -D -E -S'
33
+ end
34
+
35
+ desc 'Run all tests'
36
+ task test: [:rubocop, :spec]
37
+
38
+ namespace :teamcity do
39
+ desc 'Runs rubocop with junit output'
40
+ task :rubocop do
41
+ raise 'rubocop failed' unless system 'bundle exec rubocop ' \
42
+ '--no-color --require rubocop/formatter/junit_formatter ' \
43
+ '--format RuboCop::Formatter::JUnitFormatter --out .junit/rubocop.xml ' \
44
+ '-D -E -S'
45
+ end
46
+
47
+ desc 'Archives coverage html report into a zip'
48
+ task :zip_coverage do
49
+ Dir.chdir('coverage') do
50
+ system 'zip ../coverage.zip -r *'
51
+ end
52
+ end
53
+
54
+ desc 'Run all tests with junit output'
55
+ task :test do
56
+ first_exception = nil
57
+
58
+ %w(teamcity:rubocop
59
+ teamcity:spec
60
+ teamcity:zip_coverage
61
+ teamcity:spec:integration).each do |task_name|
62
+ begin
63
+ Rake::Task[task_name].invoke
64
+ rescue Exception => e
65
+ first_exception = e if first_exception.nil?
66
+ end
67
+ end
68
+
69
+ raise first_exception if first_exception
70
+ end
71
+ end
72
+
73
+ namespace :test do
74
+ task teamcity: 'teamcity:test'
75
+ end
76
+
77
+ namespace :vagrant do
78
+ desc 'Boot the symboliser virtual machine'
79
+ task :up do
80
+ Bundler.with_clean_env do
81
+ system 'bundle install --path vendor/bundle', chdir: 'symboliser-vagrant'
82
+ system 'RUBYLIB= NOEXEC_DISABLE=1 vagrant up',
83
+ chdir: 'symboliser-vagrant'
84
+ end
85
+ end
86
+
87
+ desc 'Destroy the symboliser virtual machine'
88
+ task :destroy do
89
+ Bundler.with_clean_env do
90
+ system 'RUBYLIB= NOEXEC_DISABLE=1 vagrant destroy --force',
91
+ chdir: 'symboliser-vagrant'
92
+ end
93
+ end
94
+
95
+ desc 'Halt the symboliser virtual machine for later use'
96
+ task :halt do
97
+ system 'RUBYLIB= NOEXEC_DISABLE=1 vagrant halt --force',
98
+ chdir: 'symboliser-vagrant'
99
+ end
100
+ end
@@ -0,0 +1,151 @@
1
+ require 'symgate/client'
2
+ require 'symgate/auth/user'
3
+
4
+ module Symgate
5
+ module Auth
6
+ # client for the Symgate authentication system
7
+ class Client < Symgate::Client
8
+ # returns a list of groups for the current symgate account
9
+ def enumerate_groups
10
+ Symgate::Client.savon_array(
11
+ savon_request(:enumerate_groups).body[:enumerate_groups_response],
12
+ :groupid
13
+ )
14
+ end
15
+
16
+ # creates a new group
17
+ def create_group(group_id)
18
+ savon_request(:create_group, returns_error_string: true) do |soap|
19
+ soap.message(groupid: group_id)
20
+ end
21
+ end
22
+
23
+ # destroys an existing group
24
+ def destroy_group(group_id)
25
+ savon_request(:destroy_group, returns_error_string: true) do |soap|
26
+ soap.message(groupid: group_id)
27
+ end
28
+ end
29
+
30
+ # renames a group
31
+ def rename_group(old_group_id, new_group_id)
32
+ savon_request(:rename_group, returns_error_string: true) do |soap|
33
+ soap.message(old_groupid: old_group_id, new_groupid: new_group_id)
34
+ end
35
+ end
36
+
37
+ # returns a list of users for the specified group
38
+ def enumerate_users(group_id)
39
+ resp = savon_request(:enumerate_users) { |soap| soap.message(groupid: group_id) }
40
+
41
+ Symgate::Client.savon_array(
42
+ resp.body[:enumerate_users_response],
43
+ :user,
44
+ Symgate::Auth::User
45
+ )
46
+ end
47
+
48
+ # creates a new user from a Symgate::Auth::User, with the specified password
49
+ def create_user(user, password)
50
+ savon_request(:create_user, returns_error_string: true) do |soap|
51
+ soap.message(password: password)
52
+ user.to_soap(soap[:message])
53
+ end
54
+ end
55
+
56
+ # updates a user (sets the is_group_admin member)
57
+ def update_user(user)
58
+ savon_request(:update_user, returns_error_string: true) do |soap|
59
+ soap.message({})
60
+ user.to_soap(soap[:message])
61
+ end
62
+ end
63
+
64
+ # renames a user (must be within the same group)
65
+ def rename_user(old_user_id, new_user_id)
66
+ savon_request(:rename_user, returns_error_string: true) do |soap|
67
+ soap.message(old_user_id: old_user_id, new_user_id: new_user_id)
68
+ end
69
+ end
70
+
71
+ # moves a user between groups
72
+ def move_user(old_user_id, new_user_id)
73
+ savon_request(:move_user, returns_error_string: true) do |soap|
74
+ soap.message(old_user_id: old_user_id, new_user_id: new_user_id)
75
+ end
76
+ end
77
+
78
+ # sets the password for a user
79
+ def set_user_password(user_id, password)
80
+ savon_request(:set_user_password, returns_error_string: true) do |soap|
81
+ soap.message(userid: user_id, password: password)
82
+ end
83
+ end
84
+
85
+ # destroys a user
86
+ def destroy_user(user_id)
87
+ savon_request(:destroy_user, returns_error_string: true) do |soap|
88
+ soap.message(userid: user_id)
89
+ end
90
+ end
91
+
92
+ # authenticates a user and returns a token, optionally with a user to impersonate
93
+ def authenticate(user_to_impersonate = nil)
94
+ r = savon_request(:authenticate) do |soap|
95
+ soap.message(userid: user_to_impersonate) if user_to_impersonate
96
+ end.body[:authenticate_response]
97
+
98
+ r ? r[:authtoken] : nil
99
+ end
100
+
101
+ # adds a language to the specified group and returns 'OK' if successful or
102
+ # 'Exists' if the language is already assigned to the account
103
+ def add_group_language(group, language)
104
+ savon_request(:add_group_language) do |soap|
105
+ soap.message(groupid: group, language: language)
106
+ end.body[:add_group_language_response]
107
+ end
108
+
109
+ # removes a language from the specified group and returns 'OK' if successful or
110
+ # 'NotExist' if the language is not assigned to the account
111
+ def remove_group_language(group, language)
112
+ savon_request(:remove_group_language) do |soap|
113
+ soap.message(groupid: group, language: language)
114
+ end.body[:remove_group_language_response]
115
+ end
116
+
117
+ # lists the languages assigned to a group
118
+ def enumerate_group_languages(group_id)
119
+ resp = savon_request(:enumerate_group_languages) { |soap| soap.message(groupid: group_id) }
120
+
121
+ Symgate::Client.savon_array(
122
+ resp.body[:enumerate_group_languages_response],
123
+ :language
124
+ )
125
+ end
126
+
127
+ # queries whether a language is available for a group
128
+ def query_group_language(group_id, language)
129
+ savon_request(:query_group_language) do |soap|
130
+ soap.message(groupid: group_id, language: language)
131
+ end.body[:query_group_language_response]
132
+ end
133
+
134
+ # lists the language for the currently authenticated user
135
+ def enumerate_languages
136
+ resp = savon_request(:enumerate_languages)
137
+
138
+ Symgate::Client.savon_array(
139
+ resp.body[:enumerate_languages_response],
140
+ :language
141
+ )
142
+ end
143
+
144
+ # queries whether a language is available for the currently authenticated user
145
+ def query_language(language)
146
+ savon_request(:query_language) { |soap| soap.message(language: language) }
147
+ .body[:query_language_response]
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,37 @@
1
+ require 'symgate/type'
2
+
3
+ module Symgate
4
+ module Auth
5
+ # defines a symgate user
6
+ class User < Symgate::Type
7
+ def initialize(opts = {})
8
+ super(opts)
9
+ @is_group_admin = opts[:is_group_admin] || false
10
+ end
11
+
12
+ def self.from_soap(hash)
13
+ Symgate::Auth::User.new(
14
+ user_id: hash[:@id],
15
+ is_group_admin: hash[:@is_group_admin] == 'true'
16
+ )
17
+ end
18
+
19
+ def to_soap(hash)
20
+ hash[:'auth:user'] = ''
21
+ hash[:attributes!] = {} unless hash.include? :attributes!
22
+ hash[:attributes!][:'auth:user'] = { id: @user_id }
23
+ hash[:attributes!][:'auth:user'][:isGroupAdmin] = @is_group_admin if @is_group_admin
24
+ end
25
+
26
+ def to_s
27
+ @user_id + (@is_group_admin ? '(admin)' : '')
28
+ end
29
+
30
+ protected
31
+
32
+ def attributes
33
+ %i(user_id is_group_admin)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,2 @@
1
+ require 'symgate/auth/user'
2
+ require 'symgate/auth/client'
@@ -0,0 +1,142 @@
1
+ require 'savon'
2
+ require 'symgate/error'
3
+ require 'symgate/namespaces'
4
+
5
+ module Symgate
6
+ # A generic client for the Symgate API.
7
+ # See the WSDL for full documentation
8
+ class Client
9
+ attr_accessor :wsdl, :endpoint, :user, :password, :token, :account, :key, :savon_opts
10
+ attr_reader :savon_client
11
+
12
+ # Constructs a new client with the provided options
13
+ def initialize(opts = {})
14
+ @wsdl = 'https://ws.widgitonline.com/schema/symboliser.wsdl'
15
+ @endpoint = 'https://ws.widgitonline.com/'
16
+ @savon_opts = {}
17
+ opts.each { |k, v| instance_variable_set("@#{k}", v) }
18
+
19
+ validate_client_options
20
+ create_savon_client
21
+ end
22
+
23
+ # returns an array from 0 or more items when an array is expected.
24
+ # (savon returns a single value for things that can be a sequence of multiple objects)
25
+ # expects a hash, and a key for the array within that hash.
26
+ # if classname is specified, the method will return an array of objects initialised
27
+ # by the hash contents
28
+ def self.savon_array(hash, key, classname = nil)
29
+ if hash && hash.include?(key)
30
+ [hash[key]].flatten
31
+ else
32
+ []
33
+ end.map { |v| classname ? classname.from_soap(v) : v }
34
+ end
35
+
36
+ protected
37
+
38
+ # ensures enough information has been passed to the client
39
+ def validate_client_options
40
+ validate_has_account
41
+ validate_has_key_or_user
42
+ validate_is_passwordy
43
+ end
44
+
45
+ def validate_has_account
46
+ raise Symgate::Error, 'No account specified' if @account.nil?
47
+ end
48
+
49
+ def validate_has_key_or_user
50
+ raise Symgate::Error, 'No key or user specified' if @key.nil? && @user.nil?
51
+ raise Symgate::Error, 'Both key and user were specified' if @key && @user
52
+ end
53
+
54
+ def validate_is_passwordy
55
+ unless [@key, @password, @token].one?
56
+ raise Symgate::Error, 'You must supply one of key, password or token'
57
+ end
58
+ end
59
+
60
+ def create_savon_client
61
+ @savon_client = Savon.client(savon_opts.merge(wsdl: @wsdl, endpoint: @endpoint)) do
62
+ endpoint(@endpoint) if @endpoint
63
+ namespaces(Symgate::NAMESPACES)
64
+ end
65
+ end
66
+
67
+ # builds a credentials object - required for all requests
68
+ def savon_creds
69
+ creds = { 'auth:account': @account }
70
+ creds[:'auth:key'] = @key if @key
71
+ creds[:'auth:user'] = savon_user if @user
72
+
73
+ { 'auth:creds': creds }
74
+ end
75
+
76
+ def savon_user
77
+ user = { 'auth:id': @user }
78
+ user[:'auth:password'] = @password if @password
79
+ user[:'auth:authtoken'] = @token if @token
80
+
81
+ user
82
+ end
83
+
84
+ # sends a request to the server and yields a soap block for defining the
85
+ # message body
86
+ def savon_request(method, opts = {})
87
+ r = @savon_client.call(method) do |soap|
88
+ yield soap if block_given?
89
+ soap.message({}) if soap[:message].nil?
90
+ soap[:message].merge!(savon_creds)
91
+ end
92
+
93
+ raise_error_on_string_response(r, "#{method}_response".to_sym) if opts[:returns_error_string]
94
+ r
95
+ rescue Savon::SOAPFault => e
96
+ raise Symgate::Error.from_savon(e)
97
+ end
98
+
99
+ def raise_error_on_string_response(response, response_type)
100
+ e = response.body[response_type]
101
+ raise Symgate::Error, e unless e.to_s == ''
102
+ end
103
+
104
+ def arrayize_option(singular, plural, opts)
105
+ if opts.include? singular # else nothing to do
106
+ if opts.include? plural
107
+ raise Symgate::Error, "Options can't include both #{singular} and #{plural}"
108
+ end
109
+
110
+ opts[plural] = [opts[singular]]
111
+ opts.delete(singular)
112
+ end
113
+ end
114
+
115
+ def check_option_is_array_of(classname, key, opts)
116
+ if opts.include? key
117
+ raise Symgate::Error, "#{key} must be an array" unless opts[key].is_a? Array
118
+ check_array_for_type(opts[key], classname)
119
+ end
120
+ end
121
+
122
+ def check_for_unknown_opts(keys, opts)
123
+ opts.keys.each do |k|
124
+ raise Symgate::Error, "Unknown option: #{k}" unless keys.include? k
125
+ end
126
+ end
127
+
128
+ def check_array_for_type(ary, type_name)
129
+ raise Symgate::Error, "#{ary.class.name} is not an array" unless ary.is_a? Array
130
+
131
+ ary.each do |item|
132
+ unless item.is_a? type_name
133
+ raise Symgate::Error, "'#{item.class.name}' is not a #{type_name.name}"
134
+ end
135
+ end
136
+ end
137
+
138
+ def check_for_multiple_opts(keys, opts)
139
+ raise Symgate::Error, "Supply only one of 'match' or 'entry'" if keys.all? { |k| opts.key? k }
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,48 @@
1
+ require 'symgate/type'
2
+
3
+ module Symgate
4
+ module Cml
5
+ # defines the cml symbol information for a concept
6
+ class Symbol < Symgate::Type
7
+ def self.from_soap(hash)
8
+ Symgate::Cml::Symbol.new(
9
+ symset: hash_value_with_optional_namespace(:cml, :symset, hash),
10
+ main: hash_value_with_optional_namespace(:cml, :main, hash),
11
+ top_left: hash_value_with_optional_namespace(:cml, :top_left, hash),
12
+ top_right: hash_value_with_optional_namespace(:cml, :top_right, hash),
13
+ bottom_left: hash_value_with_optional_namespace(:cml, :bottom_left, hash),
14
+ bottom_right: hash_value_with_optional_namespace(:cml, :bottom_right, hash),
15
+ full_left: hash_value_with_optional_namespace(:cml, :full_left, hash),
16
+ full_right: hash_value_with_optional_namespace(:cml, :full_right, hash),
17
+ top: hash_value_with_optional_namespace(:cml, :top, hash),
18
+ extra: hash_value_with_optional_namespace(:cml, :extra, hash)
19
+ )
20
+ end
21
+
22
+ def to_soap
23
+ {
24
+ 'cml:symset': symset,
25
+ 'cml:main': main,
26
+ 'cml:top_left': top_left,
27
+ 'cml:top_right': top_right,
28
+ 'cml:bottom_left': bottom_left,
29
+ 'cml:bottom_right': bottom_right,
30
+ 'cml:full_left': full_left,
31
+ 'cml:full_right': full_right,
32
+ 'cml:top': top,
33
+ 'cml:extra': extra
34
+ }.delete_if { |_, v| v.nil? }
35
+ end
36
+
37
+ def to_s
38
+ "Symbol: #{@main}"
39
+ end
40
+
41
+ protected
42
+
43
+ def attributes
44
+ %i(symset main top_left top_right bottom_left bottom_right full_left full_right top extra)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1 @@
1
+ require 'symgate/cml/symbol'
@@ -0,0 +1,33 @@
1
+ require 'savon'
2
+
3
+ module Symgate
4
+ # Defines a symgate-specific error so this can be caught by the caller
5
+ class Error < StandardError
6
+ attr_reader :original_error, :detail
7
+
8
+ # Initialises a symgate error from either a string or a savon error
9
+ def initialize(message)
10
+ super(message)
11
+ end
12
+
13
+ def self.from_savon(error)
14
+ e = Symgate::Error.new(message_from_savon_error(error))
15
+
16
+ e.original_error = error
17
+ e
18
+ end
19
+
20
+ def original_error=(error)
21
+ @original_error = error
22
+ @detail = error.to_hash[:fault][:detail]
23
+ end
24
+
25
+ def self.message_from_savon_error(error)
26
+ "#{error.message}. #{error.to_hash[:fault][:detail]}"
27
+ rescue
28
+ # :nocov:
29
+ error.message
30
+ # :nocov:
31
+ end
32
+ end
33
+ end