bullet_train 1.0.6 → 1.0.10

Sign up to get free protection for your applications and to get access to all the features.
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