bullet_train 1.0.6 → 1.0.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: edaadd5d50965bf9b15be0e2c69ead2e4180ab34a1cba61035546546dd00bb87
4
- data.tar.gz: 0b41c024ef616cd3a33b114da7dca2f0c0161713003269569a210e2937814004
3
+ metadata.gz: a460b28ddcaa9b63e0b3d86ff22bd1f55947bb98e76abe6febde2be804253732
4
+ data.tar.gz: efe38f3559f947a23bbb33a87bf199e692c4595d886b01911c2756945576a750
5
5
  SHA512:
6
- metadata.gz: 0c599a9871fdf7b746ac62452489554e271c62a8384ca6f747bb512f0334bdd22d6ec78e9fb6218d2a78a17f26afe343a78e70aff0fd4c9d7d5992f8a2a322fe
7
- data.tar.gz: ca2f4b81605161e94f3a704d63bdcbcbced15228688f2ee454e1db9876d1d198e56e9ba9f3b5f34f2c7b1841fa5ac655bba5dedd1e5bf6cd7016a6d1c19414cf
6
+ metadata.gz: c46781c9c2a4f4fc3c6e31326610fa87839c73d0f96b802c344a2048683f73c7842720fcd2d059b7adb11630767490d9bbc6fadda839a624fe80a6ff28766db8
7
+ data.tar.gz: cead3f1bc71f9d70ea51fa211252770370f07526dbc9879073f1326fd9fe2fd9b52ebbd6f9a8922b998b848b2da2add9bc9ad991928c088348bd33a1e8fc35e7
@@ -1,3 +1,3 @@
1
1
  class Account::InvitationsController < Account::ApplicationController
2
- include Invitations::ControllerBase
2
+ include Account::Invitations::ControllerBase
3
3
  end
@@ -0,0 +1,18 @@
1
+ class Account::TwoFactorsController < Account::ApplicationController
2
+ before_action :authenticate_user!
3
+
4
+ def create
5
+ @backup_codes = current_user.generate_otp_backup_codes!
6
+ @user = current_user
7
+
8
+ current_user.update(
9
+ otp_secret: User.generate_otp_secret,
10
+ otp_required_for_login: true
11
+ )
12
+ end
13
+
14
+ def destroy
15
+ @user = current_user
16
+ current_user.update(otp_required_for_login: false)
17
+ end
18
+ end
@@ -0,0 +1,118 @@
1
+ module Account::Controllers::Base
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ include LoadsAndAuthorizesResource
6
+ include Fields::ControllerSupport
7
+
8
+ before_action :set_last_seen_at, if: proc {
9
+ user_signed_in? && (current_user.last_seen_at.nil? || current_user.last_seen_at < 1.minute.ago)
10
+ }
11
+
12
+ layout "account"
13
+
14
+ before_action :authenticate_user!
15
+ before_action :set_paper_trail_whodunnit
16
+ before_action :ensure_onboarding_is_complete_and_set_next_step
17
+ end
18
+
19
+ class_methods do
20
+ # this is a template method called by LoadsAndAuthorizesResource.
21
+ # it allows that module to understand what namespaces of a controller
22
+ # are organizing the controllers, and which are organizing the models.
23
+ def regex_to_remove_controller_namespace
24
+ /^Account::/
25
+ end
26
+ end
27
+
28
+ def adding_user_email?
29
+ is_a?(Account::Onboarding::UserEmailController)
30
+ end
31
+
32
+ def adding_user_details?
33
+ is_a?(Account::Onboarding::UserDetailsController)
34
+ end
35
+
36
+ def adding_team?
37
+ return true if request.get? && request.path == new_account_team_path
38
+ return true if request.post? && request.path == account_teams_path
39
+ false
40
+ end
41
+
42
+ def switching_teams?
43
+ return true if request.get? && request.path == account_teams_path
44
+ false
45
+ end
46
+
47
+ def managing_account?
48
+ is_a?(Account::UsersController) || self.class.module_parents.include?(Oauth)
49
+ end
50
+
51
+ def accepting_invitation?
52
+ (params[:controller] == "account/invitations") && (params[:action] == "show" || params[:action] == "accept")
53
+ end
54
+
55
+ def ensure_onboarding_is_complete_and_set_next_step
56
+ unless ensure_onboarding_is_complete
57
+ session[:after_onboarding_url] ||= request.url
58
+ end
59
+ end
60
+
61
+ def ensure_onboarding_is_complete
62
+ # This is temporary, but if we've gotten this far and `@team` is loaded, we need to ensure current_team is
63
+ # updated for the checks below. This entire concept of `current_team` is going away soon.
64
+ current_user.update(current_team: @team) if @team&.persisted?
65
+
66
+ # since the onboarding controllers are child classes of this class,
67
+ # we actually have to check to make sure we're not currently on that
68
+ # step otherwise we'll end up in an endless redirection loop.
69
+ if current_user.email_is_oauth_placeholder?
70
+ if adding_user_email?
71
+ return true
72
+ else
73
+ redirect_to edit_account_onboarding_user_email_path(current_user)
74
+ return false
75
+ end
76
+ end
77
+
78
+ # some team-related onboarding steps need to be skipped if we're in the process
79
+ # of creating a new team.
80
+ unless adding_team? || accepting_invitation?
81
+
82
+ # USER ONBOARDING STUFF
83
+ # first we make sure the user is properly onboarded.
84
+ unless current_team.present?
85
+
86
+ # don't force the user to create a team if they've already got one.
87
+ if current_user.teams.any?
88
+ current_user.update(current_team: current_user.teams.first)
89
+ else
90
+ redirect_to new_account_team_path
91
+ return false
92
+ end
93
+ end
94
+
95
+ # TEAM ONBOARDING STUFF.
96
+ # then make sure the team is properly onboarded.
97
+
98
+ # since the onboarding controllers are child classes of this class,
99
+ # we actually have to check to make sure we're not currently on that
100
+ # step otherwise we'll end up in an endless redirection loop.
101
+ unless current_user.details_provided?
102
+ if adding_user_details?
103
+ return true
104
+ else
105
+ redirect_to edit_account_onboarding_user_detail_path(current_user)
106
+ return false
107
+ end
108
+ end
109
+
110
+ end
111
+
112
+ true
113
+ end
114
+
115
+ def set_last_seen_at
116
+ current_user.update_attribute(:last_seen_at, Time.current)
117
+ end
118
+ end
@@ -1,7 +1,7 @@
1
1
  module Account::Users::ControllerBase
2
2
  extend ActiveSupport::Concern
3
3
 
4
- include do
4
+ included do
5
5
  load_and_authorize_resource
6
6
 
7
7
  before_action do
@@ -0,0 +1,119 @@
1
+ module Controllers::Base
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ # these are common for authentication workflows.
6
+ include InvitationOnlyHelper
7
+ include InvitationsHelper
8
+
9
+ include DeviseCurrentAttributes
10
+
11
+ around_action :set_locale
12
+ layout :layout_by_resource
13
+
14
+ before_action { @updating = request.headers["X-Cable-Ready"] == "update" }
15
+
16
+ # TODO Extract this into an optional `bullet_train-sentry` package.
17
+ before_action :set_sentry_context
18
+
19
+ skip_before_action :verify_authenticity_token, if: -> { controller_name == "sessions" && action_name == "create" }
20
+
21
+ rescue_from CanCan::AccessDenied do |exception|
22
+ if current_user.nil?
23
+ respond_to do |format|
24
+ format.html do
25
+ session["user_return_to"] = request.path
26
+ redirect_to [:new, :user, :session], alert: exception.message
27
+ end
28
+ end
29
+ elsif current_user.teams.none?
30
+ respond_to do |format|
31
+ format.html { redirect_to [:new, :account, :team], alert: exception.message }
32
+ end
33
+ else
34
+ respond_to do |format|
35
+ # TODO we do this for now because it ensures `current_team` doesn't remain set in an invalid state.
36
+ format.html { redirect_to [:account, current_user.teams.first], alert: exception.message }
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ # this is an ugly hack, but it's what is recommended at
43
+ # https://github.com/plataformatec/devise/wiki/How-To:-Create-custom-layouts
44
+ def layout_by_resource
45
+ if devise_controller?
46
+ "devise"
47
+ else
48
+ "public"
49
+ end
50
+ end
51
+
52
+ def after_sign_in_path_for(resource_or_scope)
53
+ resource = resource_or_scope.class.name.downcase
54
+ stored_location_for(resource) || account_dashboard_path
55
+ end
56
+
57
+ def after_sign_up_path_for(resource_or_scope)
58
+ resource = resource_or_scope.class.name.downcase
59
+ stored_location_for(resource) || account_dashboard_path
60
+ end
61
+
62
+ def current_team
63
+ helpers.current_team
64
+ end
65
+
66
+ def current_membership
67
+ helpers.current_membership
68
+ end
69
+
70
+ def current_locale
71
+ helpers.current_locale
72
+ end
73
+
74
+ def enforce_invitation_only
75
+ if invitation_only?
76
+ unless helpers.invited?
77
+ redirect_to [:account, :teams], notice: t("teams.notifications.invitation_only")
78
+ end
79
+ end
80
+ end
81
+
82
+ def set_locale
83
+ I18n.locale = [
84
+ current_user&.locale,
85
+ current_user&.current_team&.locale,
86
+ http_accept_language.compatible_language_from(I18n.available_locales),
87
+ I18n.default_locale.to_s
88
+ ].compact.find { |potential_locale| I18n.available_locales.include?(potential_locale.to_sym) }
89
+ yield
90
+ I18n.locale = I18n.default_locale
91
+ end
92
+
93
+ # Whitelist the account namespace and prevent JavaScript
94
+ # embedding when passing paths as parameters in links.
95
+ def only_allow_path(path)
96
+ return if path.nil?
97
+ account_namespace_regexp = /^\/account\/*+/
98
+ scheme = URI.parse(path).scheme
99
+ return nil unless path.match?(account_namespace_regexp) && scheme != "javascript"
100
+ path
101
+ end
102
+
103
+ # TODO Extract this into an optional `bullet_train-sentry` package.
104
+ def set_sentry_context
105
+ return unless ENV["SENTRY_DSN"]
106
+
107
+ Sentry.configure_scope do |scope|
108
+ scope.set_user(id: current_user.id, email: current_user.email) if current_user
109
+
110
+ scope.set_context(
111
+ "request",
112
+ {
113
+ url: request.url,
114
+ params: params.to_unsafe_h
115
+ }
116
+ )
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,13 @@
1
+ module DeviseCurrentAttributes
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ before_action :set_current_user
6
+ end
7
+
8
+ def set_current_user
9
+ if current_user
10
+ Current.user = current_user
11
+ end
12
+ end
13
+ end
@@ -1,7 +1,7 @@
1
1
  module Registrations::ControllerBase
2
2
  extend ActiveSupport::Concern
3
3
 
4
- include do
4
+ included do
5
5
  def new
6
6
  if invitation_only?
7
7
  unless session[:invitation_uuid] || session[:invitation_key]
@@ -1,7 +1,7 @@
1
1
  module Sessions::ControllerBase
2
2
  extend ActiveSupport::Concern
3
3
 
4
- include do
4
+ included do
5
5
  def pre_otp
6
6
  if (@email = params["user"]["email"].downcase.strip.presence)
7
7
  @user = User.find_by(email: @email)
@@ -0,0 +1,60 @@
1
+ module Records::Base
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ if defined?(Webhooks::Outgoing::IssuingModel)
6
+ include Webhooks::Outgoing::IssuingModel
7
+ end
8
+
9
+ if defined?(ObfuscatesId)
10
+ include ObfuscatesId
11
+ end
12
+
13
+ if defined?(QuestionMethodsFromScopes)
14
+ include QuestionMethodsFromScopes
15
+ end
16
+
17
+ include CableReady::Updatable
18
+ enable_updates
19
+
20
+ extend ActiveHash::Associations::ActiveRecordExtensions
21
+
22
+ # 🏚 i'd like to deprecate these. they're not descriptive enough.
23
+ scope :newest, -> { order("created_at DESC") }
24
+ scope :oldest, -> { order("created_at ASC") }
25
+
26
+ scope :newest_created, -> { order("created_at DESC") }
27
+ scope :oldest_created, -> { order("created_at ASC") }
28
+ scope :newest_updated, -> { order("updated_at DESC") }
29
+ scope :oldest_updated, -> { order("updated_at ASC") }
30
+
31
+ # Microscope adds useful scopes targeting ActiveRecord `boolean`, `date` and `datetime` attributes.
32
+ # https://github.com/mirego/microscope
33
+ acts_as_microscope
34
+ end
35
+
36
+ class_methods do
37
+ # by default we represent methods by their first string attribute.
38
+ def label_attribute
39
+ columns_hash.values.find { |column| column.sql_type_metadata.type == :string }&.name
40
+ end
41
+ end
42
+
43
+ # this is a template method you can override in activerecord models if we shouldn't just use their first string to
44
+ # identify them.
45
+ def label_string
46
+ if (label_attribute = self.class.label_attribute)
47
+ send("#{label_attribute}_was")
48
+ else
49
+ self.class.name.underscore.split("/").last.titleize
50
+ end
51
+ end
52
+
53
+ def parent_collection
54
+ # TODO Try to suggest what the entire method definition should actually be
55
+ # using parent_key below to do so.
56
+ model_name = self.class
57
+ # parent_key = model_name.reflect_on_all_associations(:belongs_to).first.name
58
+ raise "You're trying to use a feature that requires #{model_name} to have a `collection` method defined that returns the Active Record association that this model belongs to within its parent object."
59
+ end
60
+ end
@@ -0,0 +1 @@
1
+ $("#two-factor").html("<%= j render partial: "devise/registrations/two_factor"%>");
@@ -0,0 +1 @@
1
+ $("#two-factor").html("<%= j render partial: "devise/registrations/two_factor"%>");
@@ -0,0 +1 @@
1
+ <%= render "themes/#{current_theme}/layouts/account" %>
@@ -0,0 +1 @@
1
+ <%= render "themes/#{current_theme}/layouts/devise" %>
@@ -1,3 +1,3 @@
1
1
  module BulletTrain
2
- VERSION = "1.0.6"
2
+ VERSION = "1.0.10"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bullet_train
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.6
4
+ version: 1.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Culver
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-30 00:00:00.000000000 Z
11
+ date: 2022-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -40,13 +40,17 @@ files:
40
40
  - app/controllers/account/onboarding/user_details_controller.rb
41
41
  - app/controllers/account/onboarding/user_email_controller.rb
42
42
  - app/controllers/account/teams_controller.rb
43
+ - app/controllers/account/two_factors_controller.rb
43
44
  - app/controllers/account/users_controller.rb
45
+ - app/controllers/concerns/account/controllers/base.rb
44
46
  - app/controllers/concerns/account/invitations/controller_base.rb
45
47
  - app/controllers/concerns/account/memberships/controller_base.rb
46
48
  - app/controllers/concerns/account/onboarding/user_details/controller_base.rb
47
49
  - app/controllers/concerns/account/onboarding/user_email/controller_base.rb
48
50
  - app/controllers/concerns/account/teams/controller_base.rb
49
51
  - app/controllers/concerns/account/users/controller_base.rb
52
+ - app/controllers/concerns/controllers/base.rb
53
+ - app/controllers/concerns/devise_current_attributes.rb
50
54
  - app/controllers/concerns/registrations/controller_base.rb
51
55
  - app/controllers/concerns/sessions/controller_base.rb
52
56
  - app/controllers/registrations_controller.rb
@@ -71,6 +75,7 @@ files:
71
75
  - app/mailers/user_mailer.rb
72
76
  - app/models/concerns/invitations/base.rb
73
77
  - app/models/concerns/memberships/base.rb
78
+ - app/models/concerns/records/base.rb
74
79
  - app/models/concerns/teams/base.rb
75
80
  - app/models/concerns/users/base.rb
76
81
  - app/models/invitation.rb
@@ -109,6 +114,8 @@ files:
109
114
  - app/views/account/teams/new.html.erb
110
115
  - app/views/account/teams/show.html.erb
111
116
  - app/views/account/teams/show.json.jbuilder
117
+ - app/views/account/two_factors/create.js.erb
118
+ - app/views/account/two_factors/destroy.js.erb
112
119
  - app/views/account/users/_breadcrumbs.html.erb
113
120
  - app/views/account/users/_form.html.erb
114
121
  - app/views/account/users/edit.html.erb
@@ -128,6 +135,8 @@ files:
128
135
  - app/views/devise/shared/_links.html.erb
129
136
  - app/views/devise/shared/_oauth.html.erb
130
137
  - app/views/devise/unlocks/new.html.erb
138
+ - app/views/layouts/account.html.erb
139
+ - app/views/layouts/devise.html.erb
131
140
  - config/locales/en/devise.en.yml
132
141
  - config/locales/en/invitations.en.yml
133
142
  - config/locales/en/memberships.en.yml