platforms-core 0.1.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: 0d9a611c46fa4c038a9db473fea02df69b9edd694ab55c16a67aeef414ac9781
4
+ data.tar.gz: b7b810c1215f79251ba3b3aa5fe765492a1ba1d2a8e654a0fa1ea8f143ecefa9
5
+ SHA512:
6
+ metadata.gz: e4a25cf6f11910d9b9779356e669c88714de557efa3c3ecaa69a7ba3e9ea389afe9d31aafcb68ee5f2c38d0991ef8e4f57aabf167117f5df1800669bac95763b
7
+ data.tar.gz: f3ed523de72afb35712e71ac52df053a0522d10e6261a758b2513cdca710e2c488ffb16510199c60989e001676617f4279023c3c653e3ffffb3e302d1bd12dde
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2020 Benjamin Elias
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,106 @@
1
+ # Platforms::Core
2
+ This is a Ruby library which brings together open source and (at least
3
+ initially) Microsoft platforms. There are various gems out there to
4
+ do OAuth2 authentication, REST calls, and so on. However, this brings
5
+ everything together in one easy-to-use package.
6
+
7
+ The goal is to create a minimal representation of the external data service in order to build fuller integrations.
8
+ There is no particular integration in mind, so Platforms::Core should be as generic as possible to enable
9
+ different platforms together.
10
+
11
+ ## Usage
12
+
13
+ The Core gem is typically not used on its own. Instead use it in conjunction with one (or more!) platform-specific
14
+ libraries. Those should require Platforms::Core themselves.
15
+
16
+ ## Installation
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'platforms-core'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ ```bash
26
+ $ bundle
27
+ ```
28
+
29
+ Or install it yourself as:
30
+
31
+ ```bash
32
+ $ gem install platforms-core
33
+ ```
34
+
35
+ Once the gem is installed, from your Rails directory you will need to install the gem's migrations:
36
+
37
+ ```bash
38
+ $ rake platforms_core:install:migrations
39
+ ```
40
+
41
+ ## Configuration
42
+
43
+ REST-based APIs require authentication to get started. Please refer to
44
+ your platform for instructions on how to do this.
45
+
46
+ The gem assumes that you have a class called `User` and a class called `Network` which might look something like the following:
47
+
48
+ ```ruby
49
+ class User < ApplicationRecord
50
+
51
+ # A User belongs to a Platforms::User
52
+ belongs_to :platforms_user,
53
+ class_name: "Platforms::User",
54
+ inverse_of: :app_user
55
+
56
+ # Ensure a User only maps to one Platforms::User
57
+ validates :platforms_user_id, uniqueness: true
58
+ end
59
+ ```
60
+ and Network:
61
+
62
+ ```ruby
63
+ class Network < ApplicationRecord
64
+
65
+ # A Network belongs to a Platforms::Network
66
+ belongs_to :platforms_network,
67
+ class_name: "Platforms::Network",
68
+ inverse_of: :app_network
69
+
70
+ # Ensure a Network only maps to one Platforms::Network
71
+ validates :platforms_network_id, uniqueness: true
72
+ end
73
+ ```
74
+
75
+ If you need the User and Network classes to be named differently,
76
+ use configurations:
77
+
78
+ ```ruby
79
+ # config/initializers/platforms.rb
80
+
81
+ Platforms::Core.configure do |config|
82
+ config.network_class = "SampleNetwork"
83
+ config.user_class = "SampleUser"
84
+ end
85
+ ```
86
+
87
+ ## Documentation
88
+
89
+ You can generate the documentation by running
90
+
91
+ ```bash
92
+ $ rake yard
93
+ ```
94
+
95
+ If not everything is documented, check this with:
96
+ ```bash
97
+ $ yard stats --list-undoc
98
+ ```
99
+
100
+
101
+ ## Contributing
102
+
103
+ Please see [CONTRIBUTING.md](CONTRIBUTING.md).
104
+
105
+ ## License
106
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,18 @@
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 'yard'
8
+ YARD::Rake::YardocTask.new do |t|
9
+ end
10
+
11
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
12
+ load 'rails/tasks/engine.rake'
13
+
14
+ load 'rails/tasks/statistics.rake'
15
+
16
+ require 'bundler/gem_tasks'
17
+
18
+ task :default => ["app:spec"]
@@ -0,0 +1,8 @@
1
+ module Platforms
2
+ # An abstract class for the Platform models to inherit from
3
+ # Note that these are not namespaced to Platforms::Core, for
4
+ # convenience of the Engine's parent application.
5
+ class ApplicationRecord < ActiveRecord::Base
6
+ self.abstract_class = true
7
+ end
8
+ end
@@ -0,0 +1,41 @@
1
+ module Platforms
2
+ # Stores customer-specific certificates for authentication
3
+ class Certificate < ApplicationRecord
4
+
5
+ self.table_name = "platforms_certificates"
6
+
7
+ # OmniAuth::OAuth2 client ID must exist
8
+ validates :client_id, presence: true
9
+
10
+ # OmniAuth::OAuth2 client secret must exist
11
+ validates :client_secret, presence: true
12
+
13
+ # The strategy, according to OmniAuth. This allows a customer to
14
+ # have multiple vendor platforms.
15
+ validates :strategy, presence: true
16
+
17
+ # Name must exist and be unique
18
+ validates :name, presence: true, uniqueness: true
19
+
20
+ validates :strategy, 'platforms/product' => true
21
+
22
+ # Show a redacted client_secret for admin purposes.
23
+ # If the client_secret is too short, redacts entirely.
24
+ # Otherwise shows the last 3 characters.
25
+ # @return [String] redacted client_secret
26
+ def client_secret_privacy
27
+ return nil if client_secret.nil?
28
+ return "*****" if client_secret.length < 10
29
+ "*****#{client_secret.last(3)}"
30
+ end
31
+
32
+ # Credentials formatted for OmniAuth
33
+ # @return [Hash] with keys of client_id and client_secret
34
+ def credentials
35
+ {
36
+ client_id: client_id,
37
+ client_secret: client_secret
38
+ }
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,26 @@
1
+ module Platforms
2
+ # Used to define a collection of {Platforms::User}, at a level below
3
+ # a {Platforms::Network}. This a group, community, team, etc.
4
+ #
5
+ # @author Benjamin Elias
6
+ # @since 0.1.0
7
+ class Group < ApplicationRecord
8
+
9
+ self.table_name = "platforms_groups"
10
+
11
+ has_many :platforms_group_members,
12
+ class_name: "Platforms::GroupMember",
13
+ inverse_of: :platforms_group,
14
+ dependent: :destroy
15
+
16
+ # A group must belong to a {Platforms::Network}
17
+ belongs_to :platforms_network, class_name: "Platforms::Network"
18
+
19
+ # Name, Platform ID, and {Platforms::Network} must exist
20
+ validates :name, :platform_id, :platforms_network, presence: true
21
+
22
+ # Platform ID is unique, for that {Platforms::Network}
23
+ validates :platform_id, uniqueness: { scope: :platforms_network }
24
+
25
+ end
26
+ end
@@ -0,0 +1,54 @@
1
+ module Platforms
2
+ # Join table between {Platforms::Group} and {Platforms::User},
3
+ # to indicate membership.
4
+ #
5
+ # Includes a role, to indicate more specific membership as defined by
6
+ # the platform.
7
+ class GroupMember < ApplicationRecord
8
+
9
+ self.table_name = "platforms_group_members"
10
+
11
+ # Belongs to a {Platforms::User}
12
+ belongs_to :platforms_user, class_name: "Platforms::User"
13
+
14
+ # Belongs to a {Platforms::Group}
15
+ belongs_to :platforms_group, class_name: "Platforms::Group"
16
+
17
+ # Require valid {Platforms::User}
18
+ validates :platforms_user, presence: true
19
+
20
+ # Require valid {Platforms::Group}
21
+ validates :platforms_group, presence: true
22
+
23
+ # Require role to exist, must be in the following enum:
24
+ # * member 0
25
+ # * admin 1
26
+ # * read-only 2
27
+ validates :role, presence: true
28
+
29
+ # Ensure [{Platforms::User}, {Platforms::Group}] keys are unique
30
+ validates :platforms_user, uniqueness: {scope: :platforms_group}
31
+
32
+ # Network of #platforms_user is equal to that of #platforms_group
33
+ validate :platforms_network_match
34
+
35
+ # Role indicates admin rights
36
+ enum role: { member: 0, admin: 1, read_only: 2 }
37
+
38
+ private
39
+
40
+ # {Network} of {#platforms_user} is equal to that of #platforms_group
41
+ #
42
+ # Checks the {Network} of platforms_user against the {Network} of
43
+ # platforms_group and confirms they are the same.
44
+ def platforms_network_match
45
+ delegated = platforms_user.platforms_network_id rescue nil
46
+ alternate = platforms_group.platforms_network_id rescue nil
47
+
48
+ unless delegated == alternate and !delegated.nil?
49
+ errors.add(:network, "IDs not equal")
50
+ end
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,49 @@
1
+ module Platforms
2
+ # The basic network concept for a platform. Users are grouped together on
3
+ # within an information boundary. Could be a 'tenant'.
4
+ class Network < ApplicationRecord
5
+
6
+ self.table_name = "platforms_networks"
7
+
8
+ # Has a Network from the parent app
9
+ has_one :app_network,
10
+ class_name: Platforms::Core.configuration.network_class,
11
+ foreign_key: "platforms_network_id"
12
+
13
+ # {Platforms::Group} belong to this network
14
+ has_many :platforms_groups, class_name: "Platforms::Group"
15
+
16
+ # {Platforms::User} belong to this network
17
+ has_many :platforms_users, class_name: "Platforms::User"
18
+
19
+ # {Platforms::Tag} belong to this network
20
+ has_many :platforms_tags, class_name: "Platforms::Tag"
21
+
22
+ # Name of a network must exist.
23
+ validates :name, presence: true
24
+
25
+ # Permalink of the network must exist. Mostly for Yammer, but
26
+ # also applicable to Office 365. Should default to name if
27
+ # no concept is defined by the platform.
28
+ validates :permalink, presence: true
29
+
30
+ # Must have a platform type, which is effectively the Engine
31
+ # that the network should authenticated against.
32
+ validates :platform_type, presence: true
33
+
34
+ # Do not require app_network to exist, as that is created after
35
+ # Do not require certificate to exist, as the Certificate may not be
36
+ # saved in the database (if it is the default).
37
+
38
+ # Platform exists and is unique for each platform
39
+ validates :platform_id,
40
+ presence: true,
41
+ uniqueness: { scope: :platform_type }
42
+
43
+ # Trial exists as boolean
44
+ validates :trial, inclusion: { in: [true, false] }
45
+
46
+ # Platform is known (can be extended if the Platforms::NewProduct exists)
47
+ validates :platform_type, 'platforms/product' => true
48
+ end
49
+ end
@@ -0,0 +1,51 @@
1
+ module Platforms
2
+ # A Tag within a {Platforms::Network}. Typically a hashtag or similar,
3
+ # which may not be used in some platforms.
4
+ class Tag < ApplicationRecord
5
+ include Twitter::TwitterText::Extractor
6
+
7
+ self.table_name = "platforms_tags"
8
+
9
+ # Do not use the same strategy as Network/User here
10
+ # as a Platforms::Tag does not need to has_one (or has_many)
11
+ # Application-level tags.
12
+
13
+ # Belongs to a {Platforms::Network}
14
+ belongs_to :platforms_network, class_name: "Platforms::Network"
15
+
16
+ # Must have an identifying name
17
+ validates :name, presence: true
18
+
19
+ # The {Platforms::Network} must exist
20
+ validates :platforms_network, presence: true
21
+
22
+ # Does not need to validate platform_id, as it could be nil on
23
+ # the first insert (when creating it as part of some content, for example)
24
+
25
+ # platform_id is unique to the {Platforms::Network}. Should be able to have
26
+ # the same tag on different Networks, and not cause validation errors.
27
+ validates :platform_id,
28
+ uniqueness: {scope: :platforms_network},
29
+ allow_nil: true
30
+
31
+ # name is unique to the {Platforms::Network}. Should be able to have
32
+ # the same tag on different Networks, and not cause validation errors.
33
+ validates :name,
34
+ uniqueness: {scope: :platforms_network},
35
+ allow_nil: true
36
+
37
+ # Hashtag syntax is actually quite complicated. Stick to Twitter rules.
38
+ validate :tag_syntax
39
+
40
+ # Minimum of 2 characters (including "#")
41
+ validates :name, length: {minimum: 2}
42
+
43
+ private
44
+ def tag_syntax
45
+ expected = [self.name.sub(/\A#/, '')]
46
+ errors.add(:name, :format_hashtag) unless \
47
+ extract_hashtags(name) == expected
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,49 @@
1
+ module Platforms
2
+ # A User in a {Platforms::Network}. Serves the purpose of a colleague,
3
+ # but also for authentication identity.
4
+ class User < ApplicationRecord
5
+
6
+ self.table_name = "platforms_users"
7
+
8
+ # Has a User from the parent app
9
+ # Do not require parent app's User to exist, as that is created after.
10
+ has_one :app_user,
11
+ class_name: Platforms::Core.configuration.user_class,
12
+ foreign_key: "platforms_user_id"
13
+
14
+ # Belongs to a {Platforms::Network}
15
+ belongs_to :platforms_network,
16
+ class_name: "Platforms::Network"
17
+
18
+ # Links to Groups through {Platforms::GroupMember}.
19
+ has_many :platforms_group_members,
20
+ class_name: "Platforms::GroupMember",
21
+ inverse_of: :platforms_user,
22
+ dependent: :destroy
23
+
24
+ # Name must exist for display
25
+ validates :name, presence: true
26
+
27
+ # An identifier on the platform, does not have to be numeric.
28
+ validates :platform_id, presence: true
29
+
30
+ # The user's thumbnail photo as a URL
31
+ validates :thumbnail_url, presence: true
32
+
33
+ # A URL related to the user
34
+ validates :web_url, presence: true
35
+
36
+ # Must have some contact details
37
+ validates :email, presence: true
38
+
39
+ # Has a related {Platforms::Network}
40
+ validates :platforms_network, presence: true
41
+
42
+ # Platform ID must be unique
43
+ validates :platform_id, uniqueness: { scope: :platforms_network_id }
44
+
45
+ # Must record whether the user is an admin on the platform
46
+ validates :admin, inclusion: { in: [true, false] }
47
+
48
+ end
49
+ end
@@ -0,0 +1,54 @@
1
+ module Platforms
2
+
3
+ # Checks if a record includes an attribute with value blah, and
4
+ # the Platforms::Blah namespace includes a class which inherits
5
+ # from Rails::Engine. That is usually called Platforms::Blah::Engine.
6
+ #
7
+ # Adds a validation error if:
8
+ # * Platforms::Blah does not exist
9
+ # * Platforms::Blah does not have a class that inherits from Rails::Engine
10
+ #
11
+ class ProductValidator < ActiveModel::EachValidator
12
+
13
+ # Validate record includes an attribute with the value of a known Engine.
14
+ #
15
+ # Checks if a record includes an attribute with value blah, and
16
+ # the Platforms::Blah namespace includes a class which inherits
17
+ # from Rails::Engine. That is usually called Platforms::Blah::Engine.
18
+ #
19
+ # If Platforms::Blah does not include a known Engine, add an error.
20
+ #
21
+ # Also requires that value is lowercase.
22
+ #
23
+ # @param [ActiveModel] record being validated
24
+ # @param [Symbol] attribute name of record
25
+ # @param [Object] value of record.attribute
26
+ # @return no suitable return value, just adds errors to record.
27
+ def validate_each(record, attribute, value)
28
+ return if value.blank?
29
+
30
+ unless value == value.downcase
31
+ record.errors.add(attribute, "should be lower case")
32
+ return
33
+ end
34
+
35
+ kamel = value.camelize
36
+
37
+ begin
38
+ klass = Platforms.const_get(kamel)
39
+ children = klass.constants(false)
40
+ children.select! do |k|
41
+ # Do not allow non-Class looking things like String constants
42
+ next unless klass.const_get(k).respond_to? :ancestors
43
+ klass.const_get(k).ancestors.include? Rails::Engine
44
+ end
45
+ unless children.length == 1
46
+ record.errors.add(attribute, "Platforms::#{kamel} is not a Rails::Engine")
47
+ end
48
+ rescue NameError => e
49
+ record.errors.add(attribute, e)
50
+ return
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,16 @@
1
+ class CreatePlatformsNetworks < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :platforms_networks, force: :cascade do |t|
4
+ t.string :platform_id
5
+ t.string :platform_type
6
+ t.string :name
7
+ t.string :permalink
8
+ t.boolean :trial
9
+
10
+ t.timestamps
11
+ end
12
+ add_index :platforms_networks, :platform_id
13
+ add_index :platforms_networks, [:platform_id, :platform_type],
14
+ name: "platforms_ids"
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ class CreatePlatformsUsers < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :platforms_users do |t|
4
+ t.string :platform_id
5
+ t.string :name
6
+ t.string :thumbnail_url
7
+ t.boolean :admin
8
+ t.string :web_url
9
+ t.string :email
10
+ t.integer :platforms_network_id
11
+
12
+ t.timestamps
13
+ end
14
+ add_index :platforms_users, [:platform_id, :platforms_network_id]
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ class CreatePlatformsTags < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :platforms_tags do |t|
4
+ t.string :platform_id
5
+ t.string :name
6
+ t.integer :platforms_network_id
7
+
8
+ t.timestamps
9
+ end
10
+ add_index :platforms_tags, [:platform_id, :platforms_network_id]
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ class CreatePlatformsGroups < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :platforms_groups do |t|
4
+ t.string :platform_id
5
+ t.string :name
6
+ t.integer :platforms_network_id
7
+ t.string :web_url
8
+
9
+ t.timestamps
10
+ end
11
+ add_index :platforms_groups, [:platform_id, :platforms_network_id]
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class CreatePlatformsGroupMembers < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :platforms_group_members do |t|
4
+ t.integer :platforms_group_id
5
+ t.integer :platforms_user_id
6
+ t.integer :role
7
+
8
+ t.timestamps
9
+ end
10
+ add_index :platforms_group_members, [:platforms_group_id, :platforms_user_id],
11
+ name: "platforms_group_members_index"
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ class CreatePlatformsCertificates < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :platforms_certificates do |t|
4
+ t.string :client_id
5
+ t.string :client_secret
6
+ t.string :name
7
+ t.string :strategy
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,42 @@
1
+ module Platforms
2
+ module Core
3
+
4
+ # Configuration pattern for Rails, allows defaults and initializers to
5
+ # override those defaults.
6
+ # @see https://stackoverflow.com/a/24151439 Stack Overflow
7
+ class << self
8
+
9
+ # Get the configuration
10
+ # @return [Platforms::Configuration] the current configuration
11
+ def configuration
12
+ @configuration ||= Configuration.new
13
+ end
14
+
15
+ # Used by initializers to set the configuration
16
+ # @yield [configuration] provides the configuration context
17
+ def configure
18
+ yield configuration
19
+ end
20
+ end
21
+
22
+ # The class which stores the gem's configuration
23
+ # Should only store core configuration, not related to each product.
24
+ class Configuration
25
+ include ActiveSupport::Configurable
26
+
27
+ ##
28
+ # The default name for the main application's user class.
29
+ # @see Platforms::User
30
+ # (defaults: ::User)
31
+ config_accessor(:user_class) { "::User" }
32
+
33
+
34
+ ##
35
+ # The default name for the main application's network class.
36
+ # @see Platforms::Network
37
+ # (defaults: ::Network)
38
+ config_accessor(:network_class) { "::Network" }
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,26 @@
1
+ require 'twitter-text'
2
+
3
+ module Platforms
4
+ module Core
5
+ # Isolated Rails Engine
6
+ # @see https://guides.rubyonrails.org/engines.html
7
+ class Engine < ::Rails::Engine
8
+ isolate_namespace Platforms::Core
9
+
10
+ config.generators do |g|
11
+ g.test_framework :rspec
12
+ g.fixture_replacement :factory_bot
13
+ g.factory_bot dir: 'spec/factories'
14
+ end
15
+
16
+ initializer "platforms.factories", :after => "factory_bot.set_factory_paths" do
17
+ FactoryBot.definition_file_paths << File.expand_path('../../../spec/factories', __FILE__) if defined?(FactoryBot)
18
+
19
+ end
20
+
21
+ # https://tanzu.vmware.com/content/blog/leave-your-migrations-in-your-rails-engines
22
+ # Note: This is problematic for Travis CI, which runs migrations in rake and not rails
23
+ # This has therefore been removed.
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,29 @@
1
+ module Platforms
2
+ module Core
3
+
4
+ # This is a module for common authentication methods, across multiple
5
+ # platforms.
6
+ # @todo extract out the common functionality.
7
+ module OAuth2
8
+ extend ActiveSupport::Concern
9
+
10
+ # Get the token from the OmniAuth credentials store
11
+ # A convenience method.
12
+ # @return the OmniAuth auth token
13
+ def token
14
+ request.env["omniauth.auth"].credentials.token
15
+ end
16
+
17
+ # Sometimes the return value is a string "true", while others it is
18
+ # cast as a boolean. This normalises that behaviour to true or false.
19
+ # Any non-"true" String value should return false.
20
+ # @param val [Object] value to convert
21
+ # @return boolean equivalent
22
+ def bool_safe val
23
+ return val == "true" if val.is_a? String
24
+ val.eql?(true)
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,53 @@
1
+ module Platforms
2
+ module Core
3
+
4
+ # Handles the dynamic insertion of client ID and Client Secret
5
+ # into the OmniAuth regime.
6
+ #
7
+ # @author Benjamin Elias
8
+ # @since 0.1.0
9
+ # @see https://www.createdbypete.com/dynamic-omniauth-provider-setup/ Dynamic providers.
10
+ # @see https://github.com/omniauth/omniauth/wiki/Setup-Phase OmniAuth Setup Phase
11
+ class OmniAuthSetup
12
+
13
+ # OmniAuth expects the class passed to setup to respond to the #call
14
+ # method.
15
+ # @param env [Hash] Rack environment
16
+ def self.call(env)
17
+ new(env).setup
18
+ end
19
+
20
+ # Assign variables and create a request object for use later.
21
+ # env - Rack environment
22
+ def initialize(env)
23
+ @env = env
24
+ @request = ActionDispatch::Request.new(env)
25
+ end
26
+
27
+ # The main purpose of this method is to set the consumer key and secret.
28
+ def setup
29
+ @env['omniauth.strategy'].options.merge!(find_credentials)
30
+ end
31
+
32
+ # Use the subdomain in the request to find the account with credentials
33
+ def find_credentials
34
+ strategy = @env['omniauth.strategy'].options.name
35
+ subdomain = ActionDispatch::Http::URL.extract_subdomains(@env['SERVER_NAME'], 0).first
36
+
37
+ certificate = Certificate.find_by(
38
+ strategy: strategy,
39
+ name: subdomain
40
+ )
41
+ # If subdomain-specific certificate is not found, use default
42
+ certificate ||= default_certificate
43
+ return certificate.credentials
44
+ end
45
+
46
+ # As a placeholder, return a blank certificate
47
+ def default_certificate
48
+ Certificate.new
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,7 @@
1
+ module Platforms
2
+ module Core
3
+
4
+ # Version for display. Update as required.
5
+ VERSION = '0.1.1'
6
+ end
7
+ end
@@ -0,0 +1,18 @@
1
+ require "platforms/core/configuration"
2
+ require "platforms/core/engine"
3
+ require "platforms/core/omni_auth_setup"
4
+ require "platforms/core/o_auth_2"
5
+
6
+ # The top level namespace for Platforms, which includes Core and
7
+ # other vendor-specific implementations.
8
+ module Platforms
9
+ # Common functionality across all Platforms should go in the Core module.
10
+ #
11
+ # That includes minimal storage of external data, which should of course
12
+ # be limited to ensure ongoing consistency. For example, Yammer has the
13
+ # concept of a hashtag, even though Teams does not. The representation
14
+ # sits in Platforms::Core (not Platforms::Yammer) as it is replicating
15
+ # an external data object.
16
+ module Core
17
+ end
18
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :platforms_core do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,241 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: platforms-core
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Benjamin Elias
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-04-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 6.0.2
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 6.0.2.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 6.0.2
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 6.0.2.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: twitter-text
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '3.0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '3.0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: omniauth
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '1.0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '1.0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: sqlite3
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rspec-rails
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: factory_bot_rails
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: hashie
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: simplecov
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ - !ruby/object:Gem::Dependency
132
+ name: webmock
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ - !ruby/object:Gem::Dependency
146
+ name: sinatra
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ - !ruby/object:Gem::Dependency
160
+ name: yard
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ - !ruby/object:Gem::Dependency
174
+ name: yard-activerecord
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ type: :development
181
+ prerelease: false
182
+ version_requirements: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ description: Login to Office 365 Teams, Yammer.
188
+ email:
189
+ - ben@collabital.com
190
+ executables: []
191
+ extensions: []
192
+ extra_rdoc_files: []
193
+ files:
194
+ - MIT-LICENSE
195
+ - README.md
196
+ - Rakefile
197
+ - app/models/platforms/application_record.rb
198
+ - app/models/platforms/certificate.rb
199
+ - app/models/platforms/group.rb
200
+ - app/models/platforms/group_member.rb
201
+ - app/models/platforms/network.rb
202
+ - app/models/platforms/tag.rb
203
+ - app/models/platforms/user.rb
204
+ - app/validators/platforms/product_validator.rb
205
+ - db/migrate/20200308091104_create_platforms_networks.rb
206
+ - db/migrate/20200308091113_create_platforms_users.rb
207
+ - db/migrate/20200308091123_create_platforms_tags.rb
208
+ - db/migrate/20200308091132_create_platforms_groups.rb
209
+ - db/migrate/20200308091141_create_platforms_group_members.rb
210
+ - db/migrate/20200313102128_create_platforms_certificates.rb
211
+ - lib/platforms/core.rb
212
+ - lib/platforms/core/configuration.rb
213
+ - lib/platforms/core/engine.rb
214
+ - lib/platforms/core/o_auth_2.rb
215
+ - lib/platforms/core/omni_auth_setup.rb
216
+ - lib/platforms/core/version.rb
217
+ - lib/tasks/platforms/core_tasks.rake
218
+ homepage: https://www.collabital.com
219
+ licenses:
220
+ - MIT
221
+ metadata: {}
222
+ post_install_message:
223
+ rdoc_options: []
224
+ require_paths:
225
+ - lib
226
+ required_ruby_version: !ruby/object:Gem::Requirement
227
+ requirements:
228
+ - - ">="
229
+ - !ruby/object:Gem::Version
230
+ version: '0'
231
+ required_rubygems_version: !ruby/object:Gem::Requirement
232
+ requirements:
233
+ - - ">="
234
+ - !ruby/object:Gem::Version
235
+ version: '0'
236
+ requirements: []
237
+ rubygems_version: 3.0.6
238
+ signing_key:
239
+ specification_version: 4
240
+ summary: Login for various collaboration platforms.
241
+ test_files: []