teamable 0.0.1.alpha

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: 92e14701652541974d41ad1b2f37bb99ae1ba17e2932da58ff40a60164e40be7
4
+ data.tar.gz: cac90b085b07a4b5b616168a6d4a33a60cf904f357a563c96fe8fbd699dfda1f
5
+ SHA512:
6
+ metadata.gz: a640b4d0df029a0cba8044a7ff47fea7bc56ab9538ae19ffd93a853b56a6b7bdd2001ccca4ca0c0028bd21199c71484ad3b7623b8105f1a3dcd92b2d85cee84e
7
+ data.tar.gz: 6ab50670c95b7451d6c35394302c812307f52f0678638eeced97527c6f8ae175c4e407a53fae297dee8135b7f0091c78cf5c3d55004811504b3f01399c8a3bf5
data/LICENSE.md ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2021 The Teamable developers.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ Teamable
2
+ ========
3
+ [![RuboCop Github Action](https://github.com/kiqr/teamable/actions/workflows/rubocop.yml/badge.svg)](https://github.com/kiqr/teamable/actions/workflows/rubocop.yml)
4
+ [![RSpec](https://github.com/kiqr/teamable/actions/workflows/rspec.yml/badge.svg)](https://github.com/kiqr/teamable/actions/workflows/rspec.yml)
5
+ [![codecov](https://codecov.io/gh/kiqr/teamable/branch/main/graph/badge.svg?token=UZMGXQKJRL)](https://codecov.io/gh/kiqr/teamable)
6
+ [![MIT License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE.md)
7
+
8
+ Teamable enables role based multi-user accounts (teams/organizations). Teams are represented by the `Account` model. An account can have multiple users associated with it and a user can have multiple accounts. You can think of accounts as a common name for **teams** or **organizations**.
9
+
10
+ Every user can have one personal account they're admin of, which allows our code to work the same way whether we're adding resources privately for a user or for a team/organization. When a user signs in for the first time, they will be redirected to `new_account_path` and prompted to create their first personal or team account.
11
+
12
+ ### Team resources
13
+
14
+ **We recommend** you to scope all user resources under accounts instead of users. For example, in an application containing projects, the `Project` model could be declared like this:
15
+
16
+ ```ruby
17
+ class Project < ApplicationRecord
18
+ # belongs_to :user <- don't do this.
19
+ belongs_to :account # personal or team account.
20
+ end
21
+ ```
22
+
23
+ or if you're combining teamable with [acts_as_tenant](https://github.com/ErwinM/acts_as_tenant):
24
+
25
+ ```ruby
26
+ class Project < ApplicationRecord
27
+ acts_as_tenant(:account)
28
+ end
29
+ ```
30
+
31
+ ### Switching between accounts
32
+
33
+ When building your customized account switcher, redirect your user to `switch_account_path`.
34
+
35
+ ```ruby
36
+ current_user.accounts.each do |account|
37
+ button_to account.name, switch_account_path(account), method: :patch
38
+ end
39
+ ```
40
+
41
+ Installation
42
+ ------------
43
+
44
+ Add the following line to Gemfile:
45
+
46
+ ```ruby
47
+ gem "teamable", "~> 1.0"
48
+ ```
49
+
50
+ and run `bundle install` from your terminal to install it.
51
+
52
+ Getting started
53
+ ---------------
54
+
55
+ **Teamable** expects a `User` model to be present and authenticatable before being installed. It also expects your application to respond properly to `current_user` and `user_signed_in?`. An authentication gem like [Authenticatable](https://github.com/kiqr/authenticatable) is recommended, but this gem should also work great with [Devise](https://github.com/heartcombo/devise), other gems or a custom solution.
56
+
57
+ #### Run the install generator
58
+
59
+ Our next step is to run the install generator. To run the installer run the following command:
60
+
61
+ ```console
62
+ $ rails g teamable:install
63
+ ```
64
+
65
+ This will generate two models, `Member` & `Account` with configuration for teamable, migration files and `teamable` routes. It will also inject the `Teamable::Models::User` concern into your `User`-model. The output should be something similar to:
66
+
67
+ ```console
68
+ foo@bar:~$ rails g teamable:install
69
+ insert app/models/user.rb
70
+ create app/models/account.rb
71
+ create app/models/member.rb
72
+ create db/migrate/20211010111722_teamable_create_accounts.rb
73
+ create db/migrate/20211010111723_teamable_create_members.rb
74
+ route teamable "organizations"
75
+ ```
76
+
77
+ Contributing
78
+ ------------
79
+ If you are interested in reporting/fixing issues and contributing directly to the code base, please see [CONTRIBUTING.md](CONTRIBUTING.md) for more information on what we're looking for and how to get started.
80
+
81
+ Versioning
82
+ ----------
83
+ This library aims to adhere to [Semantic Versioning 2.0.0](http://semver.org/). Violations
84
+ of this scheme should be reported as bugs. Specifically, if a minor or patch
85
+ version is released that breaks backward compatibility, that version should be
86
+ immediately yanked and/or a new version should be immediately released that
87
+ restores compatibility. Breaking changes to the public API will only be
88
+ introduced with new major versions. As a result of this policy, you can (and
89
+ should) specify a dependency on this gem using the [Pessimistic Version
90
+ Constraint](http://guides.rubygems.org/patterns/#pessimistic-version-constraint) with two digits of precision. For example:
91
+
92
+ ```ruby
93
+ gem "teamable", "~> 1.0"
94
+ ```
95
+
96
+ License
97
+ -------
98
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Teamable
4
+ class AccountsController < TeamableController
5
+ skip_before_action :authenticate_account!, only: %i[new create switch]
6
+
7
+ # GET /account/new
8
+ def new
9
+ @account = current_user.accounts.new
10
+ end
11
+
12
+ # POST /account
13
+ def create
14
+ @account = current_user.accounts.build(account_params)
15
+ @account.members.build(user: current_user)
16
+
17
+ if @account.save
18
+ update_teamable_session_id!(@account.id)
19
+ redirect_to root_path, notice: "success"
20
+ else
21
+ render :new, status: :unprocessable_entity
22
+ end
23
+ end
24
+
25
+ def switch
26
+ account = current_user.accounts.find(params[:id])
27
+ update_teamable_session_id!(account.id)
28
+ redirect_to after_account_switched_path
29
+ end
30
+
31
+ private
32
+
33
+ # Only allow a list of trusted parameters through.
34
+ def account_params
35
+ params.require(:account).permit(:name, :billing_email)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Teamable
4
+ class SetupController < TeamableController
5
+ # GET /account/setup
6
+ def new
7
+ @account = current_user.accounts.new
8
+ end
9
+
10
+ # POST /account/setup
11
+ def create
12
+ @account = current_user.accounts.build(account_params)
13
+ @account.members.build(user: current_user)
14
+
15
+ if @account.save
16
+ update_teamable_session_id!(@account.id)
17
+ redirect_to root_path, notice: "success"
18
+ else
19
+ render :new, status: :unprocessable_entity
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ # Only allow a list of trusted parameters through.
26
+ def account_params
27
+ params.require(:account).permit(:name, :billing_email)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TeamableController < Teamable.config.parent_controller.constantize
4
+ before_action :authenticate_user!
5
+ before_action :authenticate_account!
6
+ end
@@ -0,0 +1,7 @@
1
+ <%= form_for @account, url: account_path, method: :post do |f| %>
2
+ <%= render 'teamable/shared/errors', resource: @account %>
3
+
4
+ <%= f.text_field :name, placeholder: "Account name" %><br>
5
+ <%= f.text_field :billing_email, placeholder: "Billing email" %><br>
6
+ <%= f.submit "Create account" %>
7
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <h2>New account</h2>
2
+ <p>Create a new personal or team account</p>
3
+
4
+ <%= render "teamable/shared/flash_messages" %>
5
+
6
+ <%= render "form" %>
@@ -0,0 +1,7 @@
1
+ <%= form_for @account, url: setup_account_path, method: :post do |f| %>
2
+ <%= render 'teamable/shared/errors', resource: @account %>
3
+
4
+ <%= f.text_field :name, placeholder: "Account name" %><br>
5
+ <%= f.text_field :billing_email, placeholder: "Billing email" %><br>
6
+ <%= f.submit "Create account" %>
7
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <h2>Setup your account</h2>
2
+ <p>Finish the registration by setting up your account</p>
3
+
4
+ <%= render "teamable/shared/flash_messages" %>
5
+
6
+ <%= render "form" %>
@@ -0,0 +1,7 @@
1
+ <% if resource.errors.any? %>
2
+ <ul>
3
+ <% resource.errors.full_messages.each do |message| %>
4
+ <li><%= message %></li>
5
+ <% end %>
6
+ </ul>
7
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <% flash.each do |key, value| %>
2
+ <%= content_tag :div, value, class: "flash #{key}" %>
3
+ <% end %>
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/base"
4
+ require "rails/generators/active_model"
5
+ require "rails/generators/active_record/migration"
6
+
7
+ module Teamable
8
+ class InvalidUserModel < StandardError; end
9
+
10
+ class InstallGenerator < Rails::Generators::Base
11
+ include ActiveRecord::Generators::Migration
12
+ source_root File.expand_path("templates", __dir__)
13
+
14
+ def check_install_requirements
15
+ return if user_model_exists?
16
+
17
+ say "Teamable requires a User model to be present before you continue with the install", :red
18
+ say "Learn more at: https://github.com/kiqr/teamable#getting-started", :red
19
+ raise Teamable::InvalidUserModel, "Missing file: #{user_model_path}"
20
+ end
21
+
22
+ def inject_into_user_model
23
+ inject_into_class user_model_path, "User" do
24
+ " include Teamable::Models::User\n"
25
+ end
26
+ end
27
+
28
+ def generate_models
29
+ template "models/account.tt", "app/models/account.rb"
30
+ template "models/member.tt", "app/models/member.rb"
31
+ end
32
+
33
+ def generate_migrations
34
+ migration_template "migrations/account.tt", "#{db_migrate_path}/teamable_create_accounts.rb"
35
+ migration_template "migrations/member.tt", "#{db_migrate_path}/teamable_create_members.rb"
36
+ end
37
+
38
+ def add_route
39
+ route 'teamable "account"'
40
+ end
41
+
42
+ private
43
+
44
+ def user_model_exists?
45
+ File.exist?(user_model_path)
46
+ end
47
+
48
+ def user_model_path
49
+ File.join(destination_root, "app/models/user.rb")
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TeamableCreateAccounts < ActiveRecord::Migration[5.2]
4
+ def change
5
+ create_table :accounts do |t|
6
+ t.string :name, null: false
7
+ t.string :billing_email, null: false
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TeamableCreateMembers < ActiveRecord::Migration[5.2]
4
+ def change
5
+ create_table :members do |t|
6
+ t.references :user, foreign_key: { to_table: :users }
7
+ t.references :account, foreign_key: { to_table: :accounts }
8
+ t.string :invitee_email
9
+ t.string :role, nullable: false
10
+ t.timestamps
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Account < ApplicationRecord
4
+ include Teamable::Models::Account
5
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Member < ApplicationRecord
4
+ include Teamable::Models::Member
5
+
6
+ AVAILABLE_ROLES = %w[member admin].freeze
7
+ FIRST_USER_ROLE = "admin" # Default role for the user who created the account.
8
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Teamable
6
+ module Controllers
7
+ module CurrentAccountHelper
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ before_action :load_current_account
12
+
13
+ if respond_to?(:helper_method)
14
+ helpers = %w[current_account account_selected?]
15
+ helper_method(*helpers)
16
+ end
17
+
18
+ rescue_from Teamable::MissingAccountError do
19
+ redirect_to setup_account_path
20
+ end
21
+ end
22
+
23
+ # Raise Teamable::MissingAccountError unless account_selected? is true.
24
+ def authenticate_account!
25
+ return unless user_signed_in?
26
+ return if teamable_controller?
27
+
28
+ raise Teamable::MissingAccountError unless account_selected?
29
+ end
30
+
31
+ # Access current team.
32
+ def current_account
33
+ @current_account ||= Teamable::Current.account
34
+ end
35
+
36
+ # Check if a team has been selected
37
+ def account_selected?
38
+ !!current_account
39
+ end
40
+
41
+ # Store an account id in a session variable.
42
+ # Warning: this does not validate that the current_user
43
+ # actually is a member of the specified account.
44
+ def update_teamable_session_id!(account_id)
45
+ session[:teamable_account_id] = account_id
46
+ end
47
+
48
+ private
49
+
50
+ # Load current account from Account model and store it
51
+ # in the Teamable::Current singleton.
52
+ def load_current_account
53
+ return unless user_signed_in?
54
+
55
+ Teamable::Current.account ||= account_from_session || fallback_account || nil
56
+ end
57
+
58
+ # Try to load current account using session[:teamable_account_id]
59
+ def account_from_session
60
+ return if session[:teamable_account_id].blank?
61
+
62
+ current_user.accounts.find_by(id: session[:teamable_account_id])
63
+ end
64
+
65
+ # Finds last joined account if the user have any associated accounts.
66
+ def fallback_account
67
+ memberships = current_user.members
68
+ return nil if memberships.length.zero?
69
+
70
+ memberships.last.account # Return last joined account.
71
+ end
72
+
73
+ # Check if the current controller is a TeamableController
74
+ def teamable_controller?
75
+ is_a?(::TeamableController)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Teamable
6
+ module Controllers
7
+ module UrlHelpers
8
+ extend ActiveSupport::Concern
9
+
10
+ # Method references in Teamable::AccountsController#switch to redirect a user
11
+ # after they've switched to another account. You can override it in your
12
+ # ApplicationController to provide a custom url.
13
+ def after_account_switched_path
14
+ root_path
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Teamable
4
+ # Global class that holds the current user's selected team.
5
+ class Current < ActiveSupport::CurrentAttributes
6
+ attribute :account
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Teamable
4
+ # Makes Teamable available to Rails as an Engine.
5
+ class Engine < ::Rails::Engine
6
+ initializer "teamable.setup" do
7
+ # Make teamable helpers available in controllers.
8
+ ActionController::Base.include Teamable::Controllers::CurrentAccountHelper
9
+ ActionController::Base.include Teamable::Controllers::UrlHelpers
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Teamable
4
+ class MissingAccountError < StandardError
5
+ end
6
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Teamable
4
+ module Models
5
+ module Account
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ has_many :members
10
+ has_many :users, through: :members
11
+
12
+ validates :name, presence: true
13
+ validates :billing_email, presence: true, uniqueness: true
14
+ validates_format_of :billing_email, with: Teamable.config.email_regexp
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Teamable
4
+ module Models
5
+ module Member
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ belongs_to :user
10
+ belongs_to :account
11
+
12
+ before_validation :set_owner_default_role, on: :create
13
+ validates :role, presence: true
14
+ validates_format_of :invitee_email, with: Teamable.config.email_regexp, allow_blank: true
15
+ validates_inclusion_of :role, in: proc { ::Member::AVAILABLE_ROLES }
16
+ end
17
+
18
+ # Temporary store an invitee's email for validation.
19
+ attr_accessor :invitee_email
20
+
21
+ def role_name
22
+ role.capitalize
23
+ end
24
+
25
+ def role?(input)
26
+ role.include? input.to_s
27
+ end
28
+
29
+ private
30
+
31
+ def set_owner_default_role
32
+ self.role = ::Member::FIRST_USER_ROLE if role.nil?
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Teamable
4
+ module Models
5
+ module User
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ has_many :members
10
+ has_many :accounts, through: :members
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ module Routing
5
+ class Mapper
6
+ def teamable(team_label, options = {}, &block)
7
+ options[:path] ||= team_label.to_s
8
+
9
+ teamable_scope options do
10
+ teamable_accounts(options)
11
+ yield block if block_given?
12
+ end
13
+ end
14
+
15
+ protected
16
+
17
+ def teamable_scope(options, &block)
18
+ scope options[:path], module: "teamable", &block
19
+ end
20
+
21
+ def teamable_accounts(_options)
22
+ resource :account, only: %i[new create], path: "" do
23
+ get :setup, to: "setup#new"
24
+ post :setup, to: "setup#create"
25
+ patch ":id/switch", to: "accounts#switch", as: :switch
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Teamable
4
+ VERSION = "0.0.1.alpha"
5
+ end
data/lib/teamable.rb ADDED
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "teamable/current"
4
+ require "teamable/routes"
5
+ require "teamable/version"
6
+
7
+ require "teamable/engine"
8
+
9
+ require "dry-configurable"
10
+
11
+ # Enable role based multi-user accounts (teams/organizations) in Rails.
12
+ module Teamable
13
+ extend Dry::Configurable
14
+
15
+ module Controllers
16
+ autoload :CurrentAccountHelper, "teamable/controllers/current_account_helper"
17
+ autoload :UrlHelpers, "teamable/controllers/url_helpers"
18
+ end
19
+
20
+ module Models
21
+ autoload :Account, "teamable/models/account"
22
+ autoload :Member, "teamable/models/member"
23
+ autoload :User, "teamable/models/user"
24
+ end
25
+
26
+ autoload :MissingAccountError, "teamable/errors/missing_account_error"
27
+
28
+ # The controller class that all Teamable controllers will inherit from.
29
+ # Defaults to `ApplicationController`.
30
+ setting :parent_controller, "ApplicationController"
31
+
32
+ # Email regex used to validate email formats. It simply asserts that
33
+ # one (and only one) @ exists in the given string. This is mainly
34
+ # to give user feedback and not to assert the e-mail validity.
35
+ setting :email_regexp, /\A[^@\s]+@[^@\s]+\z/
36
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: teamable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.alpha
5
+ platform: ruby
6
+ authors:
7
+ - Rasmus Kjellberg
8
+ - KIQR
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2021-10-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: dry-configurable
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: 0.11.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: 0.11.0
28
+ description:
29
+ email: hello@kiqr.dev
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - LICENSE.md
35
+ - README.md
36
+ - app/controllers/teamable/accounts_controller.rb
37
+ - app/controllers/teamable/setup_controller.rb
38
+ - app/controllers/teamable_controller.rb
39
+ - app/views/teamable/accounts/_form.html.erb
40
+ - app/views/teamable/accounts/new.html.erb
41
+ - app/views/teamable/setup/_form.html.erb
42
+ - app/views/teamable/setup/new.html.erb
43
+ - app/views/teamable/shared/_errors.html.erb
44
+ - app/views/teamable/shared/_flash_messages.html.erb
45
+ - lib/generators/teamable/install_generator.rb
46
+ - lib/generators/teamable/templates/migrations/account.tt
47
+ - lib/generators/teamable/templates/migrations/member.tt
48
+ - lib/generators/teamable/templates/models/account.tt
49
+ - lib/generators/teamable/templates/models/member.tt
50
+ - lib/teamable.rb
51
+ - lib/teamable/controllers/current_account_helper.rb
52
+ - lib/teamable/controllers/url_helpers.rb
53
+ - lib/teamable/current.rb
54
+ - lib/teamable/engine.rb
55
+ - lib/teamable/errors/missing_account_error.rb
56
+ - lib/teamable/models/account.rb
57
+ - lib/teamable/models/member.rb
58
+ - lib/teamable/models/user.rb
59
+ - lib/teamable/routes.rb
60
+ - lib/teamable/version.rb
61
+ homepage: https://github.com/kiqr/teamable
62
+ licenses:
63
+ - MIT
64
+ metadata:
65
+ bug_tracker_uri: https://github.com/kiqr/teamable/issues
66
+ documentation_uri: https://github.com/kiqr/teamable/issues
67
+ source_code_uri: https://github.com/kiqr/teamable
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '2.6'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">"
80
+ - !ruby/object:Gem::Version
81
+ version: 1.3.1
82
+ requirements: []
83
+ rubygems_version: 3.2.26
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: Extension to enable teams for Authenticatable
87
+ test_files: []