symgate 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: 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