zaikio-directory 0.0.1

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
+ SHA256:
3
+ metadata.gz: 4ec062a81b127383211acdf2bc5e4f060fdae2ddd0c933d5e637e18d41b742eb
4
+ data.tar.gz: '0813f75186da07996059c404b4e376aecb4eb8173658e885aadbdb88b4f24a72'
5
+ SHA512:
6
+ metadata.gz: 5757766b6d07f3ee23407c7fd100f53ab8f9fd65c76f13d384dfcfc1696771b15d1e6f109a18379e5b9f57d34a49dc6aa6b985762c8bd09def293a970c98893c
7
+ data.tar.gz: 0efbe9f1c86caf1a79ef1cd5c45ec5fc9d78bcc131cbbb3989e540726fd77804e8a26bccca0228f3aa6839527a4799cde1ddabc87b8cb5850d98dc4656bd2d44
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2020 Zaikio GmbH
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,108 @@
1
+ # Zaikio::Directory
2
+
3
+ Ruby API Client for Zaikio's Directory.
4
+
5
+ ## Installation
6
+
7
+ ### 1. Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'zaikio-directory'
11
+ ```
12
+
13
+ And then execute:
14
+ ```bash
15
+ $ bundle
16
+ ```
17
+
18
+ Or install it yourself as:
19
+ ```bash
20
+ $ gem install zaikio-directory
21
+ ```
22
+
23
+ ### 2. Configure the gem:
24
+
25
+ ```rb
26
+ # config/initializers/zaikio_directory.rb
27
+
28
+ Zaikio::Directory.configure do |config|
29
+ config.host :production # sandbox or production
30
+ end
31
+ ```
32
+
33
+
34
+ ## Usage
35
+
36
+ The Directory Client has an ORM like design. However, we distinguish between the contexts of the organization and the person.
37
+
38
+ For the requests to work, a valid JSON Web token with the correct OAuth Scopes must always be provided. Please refer to [zakio-oauth_client](#todo).
39
+
40
+ If you want to know which actions are available and which scopes are required, please refer to the [Directory API Reference](https://docs.zaikio.com/api/directory/directory.html).
41
+
42
+ ### As an organization
43
+
44
+ ```rb
45
+ token = "..." # Your valid JWT for an organization
46
+ Zaikio::Directory.with_token(token) do
47
+ organization = Zaikio::Directory::CurrentOrganization.new
48
+
49
+ # Fetch Data
50
+ organization.memberships.find('abc')
51
+ organization.members.all
52
+ organization.machines.all
53
+ organization.software.all
54
+ organization.sites.all
55
+ organization.sites.find('123')
56
+ organization.business_relationships.all
57
+ organization.fetch
58
+ organization.name
59
+
60
+ # Create new resources
61
+ organization.business_relationships.create(target_id: "abcd-efgh", kind: "printer", reference: "a-123")
62
+ organization.machines.create(name: "Speedmaster 2020", manufacturer: "heidelberg", kind: "sheetfed_digital_press", serial_number: "HDB1337", site_id: "d6308910-f5ae-58c0-aba7-d099947845c6")
63
+ organization.sites.create(name: "Mainz", address_attributes: {
64
+ addressee: "Crispy Mountain GmbH",
65
+ text: "Emmerich-Josef-Straße 1A, 55116 Mainz"
66
+ })
67
+
68
+ # Delete resources
69
+ organization.machines.first.destroy
70
+ end
71
+ ```
72
+
73
+ ### As a person
74
+
75
+ ```rb
76
+ token = "..." # Your valid JWT for a person
77
+ Zaikio::Directory.with_token(token) do
78
+ person = Zaikio::Directory::CurrentPerson.new
79
+
80
+ # Fetch Data
81
+ person.organizations
82
+ person.organization_memberships
83
+ person.fetch
84
+ person.full_name
85
+
86
+ organization = person.admin_organizations.find(&:connected?)
87
+ organization.machines.all
88
+ organization.sites.all
89
+
90
+ # Update details
91
+ person.update(first_name: "Lisa", name: "Simpson", pronoun: "She/Her")
92
+ end
93
+ ```
94
+
95
+ ### Other Use Cases
96
+
97
+ ```rb
98
+ Zaikio::Directory.with_basic_auth(client_id, client_secret) do
99
+ connections = Zaikio::Directory::Connection.all
100
+ end
101
+
102
+ roles = Zaikio::Directory::Role.all
103
+ revoked_access_tokens = Zaikio::Directory::RevokedAccessToken.all
104
+
105
+ Zaikio::Directory.with_token(token) do
106
+ Zaikio::Directory::RevokedAccessToken.create
107
+ end
108
+ ```
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+ require 'rubocop/rake_task'
9
+
10
+ RDoc::Task.new(:rdoc) do |rdoc|
11
+ rdoc.rdoc_dir = 'rdoc'
12
+ rdoc.title = 'Zaikio::Directory'
13
+ rdoc.options << '--line-numbers'
14
+ rdoc.rdoc_files.include('README.md')
15
+ rdoc.rdoc_files.include('lib/**/*.rb')
16
+ end
17
+
18
+ require 'bundler/gem_tasks'
19
+
20
+ require 'rake/testtask'
21
+
22
+ Rake::TestTask.new(:test) do |t|
23
+ t.libs << 'test'
24
+ t.pattern = 'test/**/*_test.rb'
25
+ t.verbose = false
26
+ end
27
+
28
+ task default: :test
29
+
30
+ namespace :test do
31
+ desc 'Runs RuboCop on specified directories'
32
+ RuboCop::RakeTask.new(:rubocop) do |task|
33
+ task.fail_on_error = false
34
+ end
35
+ end
36
+
37
+ Rake::Task[:test].enhance ['test:rubocop']
@@ -0,0 +1,25 @@
1
+ require "faraday"
2
+ require "jwt"
3
+
4
+ module Zaikio
5
+ module Directory
6
+ class AuthorizationMiddleware < Faraday::Middleware
7
+ def self.reset_token
8
+ @token = nil
9
+ end
10
+
11
+ def self.token(token = nil)
12
+ @token = token || @token
13
+ end
14
+
15
+ def call(request_env)
16
+ if self.class.token
17
+ request_env[:request_headers]["Authorization"] = "Bearer #{self.class.token}"
18
+ end
19
+
20
+ @app.call(request_env).on_complete do |response_env|
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,7 @@
1
+ module Zaikio
2
+ module Directory
3
+ class Base < Spyke::Base
4
+ self.callback_methods = { create: :post, update: :patch }.freeze
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Zaikio
2
+ module Directory
3
+ class BusinessRelationship < Base
4
+ uri "organization/business_relationships(/:id)"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,40 @@
1
+ require "logger"
2
+
3
+ module Zaikio
4
+ module Directory
5
+ class Configuration
6
+ HOSTS = {
7
+ development: "http://directory.zaikio.test",
8
+ test: "http://directory.zaikio.test",
9
+ staging: "https://directory.staging.zaikio.com",
10
+ sandbox: "https://directory.sandbox.zaikio.com",
11
+ production: "https://directory.zaikio.com"
12
+ }.freeze
13
+
14
+ attr_accessor :host
15
+ attr_reader :environment
16
+ attr_writer :logger
17
+
18
+ def initialize
19
+ @environment = :sandbox
20
+ end
21
+
22
+ def logger
23
+ @logger ||= Logger.new(STDOUT)
24
+ end
25
+
26
+ def environment=(env)
27
+ @environment = env.to_sym
28
+ @host = host_for(environment)
29
+ end
30
+
31
+ private
32
+
33
+ def host_for(environment)
34
+ HOSTS.fetch(environment) do
35
+ raise StandardError.new, "Invalid Zaikio::Directory environment '#{environment}'"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,33 @@
1
+ module Zaikio
2
+ module Directory
3
+ class CurrentOrganization < Base
4
+ self.primary_key = nil
5
+ include_root_in_json :organization
6
+ uri "organization"
7
+
8
+ def self.find
9
+ all.find_one
10
+ end
11
+
12
+ # Associations
13
+ has_many :memberships, class_name: "Zaikio::Directory::Membership",
14
+ uri: "organization/memberships"
15
+ has_many :business_relationships, class_name: "Zaikio::Directory::BusinessRelationship",
16
+ uri: "organization/business_relationships"
17
+ has_many :software, class_name: "Zaikio::Directory::Software",
18
+ uri: "software"
19
+ has_many :machines, class_name: "Zaikio::Directory::Machine",
20
+ uri: "machines"
21
+ has_many :sites, class_name: "Zaikio::Directory::Site",
22
+ uri: "sites"
23
+
24
+ def fetch
25
+ self.attributes = get
26
+ end
27
+
28
+ def members
29
+ memberships.map(&:person)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ module Zaikio
2
+ module Directory
3
+ class CurrentPerson < Base
4
+ self.primary_key = nil
5
+ include_root_in_json :person
6
+ uri "person"
7
+
8
+ def self.find
9
+ all.find_one
10
+ end
11
+
12
+ # Associations
13
+ has_many :organization_memberships, class_name: "Zaikio::Directory::OrganizationMembership",
14
+ uri: nil
15
+
16
+ def fetch
17
+ self.attributes = get
18
+ end
19
+
20
+ def organizations
21
+ organization_memberships.map(&:organization)
22
+ end
23
+
24
+ def admin_organizations
25
+ organization_memberships.map do |m|
26
+ m.organization if m.roles.include?("admin") || m.roles.include?("owner")
27
+ end.compact
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,16 @@
1
+ require "multi_json"
2
+
3
+ module Zaikio
4
+ module Directory
5
+ class JSONParser < Faraday::Response::Middleware
6
+ def parse(body)
7
+ json = MultiJson.load(body, symbolize_keys: true)
8
+ {
9
+ data: json,
10
+ metadata: {},
11
+ errors: json.is_a?(Hash) ? json[:errors] : {}
12
+ }
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ module Zaikio
2
+ module Directory
3
+ class Machine < Base
4
+ uri "machines(/:id)"
5
+ include_root_in_json :machine
6
+
7
+ # Callbacks
8
+ after_create :make_organization_owner
9
+
10
+ def make_organization_owner
11
+ if Zaikio::Directory.current_token_data.subject_type == "Organization"
12
+ self.class.request(:post, "machines/#{id}/machine_ownership")
13
+ else
14
+ org_path = "person/organizations/#{organization_id}"
15
+ self.class.request(:post, "#{org_path}/machines/#{id}/machine_ownership")
16
+ end
17
+ end
18
+
19
+ def destroy
20
+ if Zaikio::Directory.current_token_data.subject_type == "Organization"
21
+ self.class.request(:delete, "machines/#{id}/machine_ownership")
22
+ else
23
+ org_path = "person/organizations/#{owner_id || organization_id}"
24
+ self.class.request(:delete, "#{org_path}/machines/#{id}/machine_ownership")
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,8 @@
1
+ module Zaikio
2
+ module Directory
3
+ class Membership < Base
4
+ include_root_in_json :membership
5
+ has_one :person, uri: nil, class_name: "Zaikio::Directory::Person"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,19 @@
1
+ module Zaikio
2
+ module Directory
3
+ class Organization < Base
4
+ uri "person/organizations"
5
+
6
+ include_root_in_json :organization
7
+
8
+ # Associations
9
+ has_many :memberships, class_name: "Zaikio::Directory::Membership",
10
+ uri: "person/organizations/:organization_id/memberships"
11
+ has_many :software, class_name: "Zaikio::Directory::Software",
12
+ uri: "person/organizations/:organization_id/software"
13
+ has_many :machines, class_name: "Zaikio::Directory::Machine",
14
+ uri: "person/organizations/:organization_id/machines"
15
+ has_many :sites, class_name: "Zaikio::Directory::Site",
16
+ uri: "person/organizations/:organization_id/sites"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ module Zaikio
2
+ module Directory
3
+ class OrganizationMembership < Base
4
+ uri "person/organization_memberships"
5
+
6
+ include_root_in_json :organization_membership
7
+
8
+ # Associations
9
+ has_one :organization, class_name: "Zaikio::Directory::Organization"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ module Zaikio
2
+ module Directory
3
+ class Person < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ module Zaikio
2
+ module Directory
3
+ class RevokedAccessToken < Base
4
+ uri "blacklisted_access_tokens"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ module Zaikio
2
+ module Directory
3
+ class Role < Base
4
+ uri "roles"
5
+
6
+ include_root_in_json :role
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ module Zaikio
2
+ module Directory
3
+ class Site < Base
4
+ uri "sites(/:id)"
5
+ include_root_in_json :site
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,29 @@
1
+ module Zaikio
2
+ module Directory
3
+ class Software < Base
4
+ uri "software(/:id)"
5
+ include_root_in_json :software
6
+
7
+ # Callbacks
8
+ after_create :make_organization_owner
9
+
10
+ def make_organization_owner
11
+ if Zaikio::Directory.current_token_data.subject_type == "Organization"
12
+ self.class.request(:post, "software/#{id}/software_ownership")
13
+ else
14
+ org_path = "person/organizations/#{organization_id}"
15
+ self.class.request(:post, "#{org_path}/software/#{id}/software_ownership")
16
+ end
17
+ end
18
+
19
+ def destroy
20
+ if Zaikio::Directory.current_token_data.subject_type == "Organization"
21
+ self.class.request(:delete, "software/#{id}/software_ownership")
22
+ else
23
+ org_path = "person/organizations/#{owner_id || organization_id}"
24
+ self.class.request(:delete, "#{org_path}/software/#{id}/software_ownership")
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ module Zaikio
2
+ module Directory
3
+ VERSION = "0.0.1".freeze
4
+ end
5
+ end
@@ -0,0 +1,73 @@
1
+ require "faraday"
2
+ require "spyke"
3
+ require "zaikio/directory/configuration"
4
+ require "zaikio/directory/json_parser"
5
+ require "zaikio/directory/authorization_middleware"
6
+
7
+ # Models
8
+ require "zaikio/directory/base"
9
+ require "zaikio/directory/organization_membership"
10
+ require "zaikio/directory/business_relationship"
11
+ require "zaikio/directory/organization"
12
+ require "zaikio/directory/person"
13
+ require "zaikio/directory/machine"
14
+ require "zaikio/directory/software"
15
+ require "zaikio/directory/site"
16
+ require "zaikio/directory/membership"
17
+ require "zaikio/directory/current_person"
18
+ require "zaikio/directory/current_organization"
19
+ require "zaikio/directory/role"
20
+ require "zaikio/directory/revoked_access_token"
21
+
22
+ module Zaikio
23
+ module Directory
24
+ class << self
25
+ attr_accessor :configuration
26
+
27
+ def configure
28
+ @connection = nil
29
+ self.configuration ||= Configuration.new
30
+ yield(configuration)
31
+
32
+ Base.connection = connection
33
+ end
34
+
35
+ def with_token(token)
36
+ AuthorizationMiddleware.token token
37
+ yield
38
+ ensure
39
+ AuthorizationMiddleware.reset_token
40
+ end
41
+
42
+ def current_token_data
43
+ return {} unless AuthorizationMiddleware.token
44
+
45
+ payload = JWT.decode(AuthorizationMiddleware.token, nil, false).first
46
+
47
+ create_token_data(payload)
48
+ end
49
+
50
+ def connection
51
+ @connection ||= Faraday.new(url: "#{configuration.host}/api/v1") do |c|
52
+ c.request :json
53
+ c.response :logger, configuration&.logger
54
+ c.use JSONParser
55
+ c.use AuthorizationMiddleware
56
+ c.adapter Faraday.default_adapter
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def create_token_data(payload)
63
+ subjects = payload["sub"].split(">")
64
+
65
+ OpenStruct.new(
66
+ on_behalf_of_id: subjects.first.split("/").last,
67
+ subject_id: subjects.last.split("/").last,
68
+ subject_type: subjects.last.split("/").first
69
+ )
70
+ end
71
+ end
72
+ end
73
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: zaikio-directory
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Zaikio GmbH
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-04-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jwt
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.2.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.2.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: multi_json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.14.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.14.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: oj
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.10.5
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.10.5
55
+ - !ruby/object:Gem::Dependency
56
+ name: spyke
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 5.3.4
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 5.3.4
69
+ description: Ruby API Client for Zaikio's Directory
70
+ email:
71
+ - js@crispymtn.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - MIT-LICENSE
77
+ - README.md
78
+ - Rakefile
79
+ - lib/zaikio/directory.rb
80
+ - lib/zaikio/directory/authorization_middleware.rb
81
+ - lib/zaikio/directory/base.rb
82
+ - lib/zaikio/directory/business_relationship.rb
83
+ - lib/zaikio/directory/configuration.rb
84
+ - lib/zaikio/directory/current_organization.rb
85
+ - lib/zaikio/directory/current_person.rb
86
+ - lib/zaikio/directory/json_parser.rb
87
+ - lib/zaikio/directory/machine.rb
88
+ - lib/zaikio/directory/membership.rb
89
+ - lib/zaikio/directory/organization.rb
90
+ - lib/zaikio/directory/organization_membership.rb
91
+ - lib/zaikio/directory/person.rb
92
+ - lib/zaikio/directory/revoked_access_token.rb
93
+ - lib/zaikio/directory/role.rb
94
+ - lib/zaikio/directory/site.rb
95
+ - lib/zaikio/directory/software.rb
96
+ - lib/zaikio/directory/version.rb
97
+ homepage: https://www.zaikio.com/
98
+ licenses:
99
+ - MIT
100
+ metadata: {}
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubygems_version: 3.1.2
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: Ruby API Client for Zaikio's Directory
120
+ test_files: []