platforms-core 0.1.1

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
+ 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: []