bullet_train 1.1.3 → 1.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/concerns/account/memberships/controller_base.rb +9 -4
- data/app/helpers/account/teams_helper.rb +10 -0
- data/app/models/billing/mock_limiter.rb +9 -0
- data/app/models/concerns/memberships/base.rb +1 -1
- data/app/models/concerns/records/base.rb +4 -0
- data/app/models/concerns/teams/base.rb +10 -0
- data/app/views/account/invitations/_breadcrumbs.html.erb +1 -1
- data/app/views/account/invitations/_form.html.erb +40 -38
- data/app/views/account/memberships/_form.html.erb +0 -1
- data/app/views/account/memberships/_index.html.erb +56 -53
- data/config/locales/en/teams.en.yml +5 -1
- data/config/locales/en/users.en.yml +10 -2
- data/lib/bullet_train/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a08595be0c53652a5cd5dfeeb920bc080476a31b180bb4832919398bcb0e2bf0
|
4
|
+
data.tar.gz: 8132b225ed537f17fd13c17a8d6edc4c99b63712d56cd208a5fda981074e819d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f6b84f79d914c69c184c1e0e8c9213eb0b8a000fcfbdc017768f5876408f99ec4a00c481e14c7f21ff9bc3de9652847c6ca37378e0446e153dbea918494bb94
|
7
|
+
data.tar.gz: 7d59102fd98d4b0fc7877be50b40285d4ef1597d694242e70b70e4d8807638220bbad1232ada6edafd8ab968767d3012ad78a1f7f2347ef220bf911a7447ce2c
|
@@ -84,11 +84,16 @@ module Account::Memberships::ControllerBase
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def reinvite
|
87
|
-
|
88
|
-
|
89
|
-
|
87
|
+
if helpers.current_limits.can?(:create, Membership)
|
88
|
+
@invitation = Invitation.new(membership: @membership, team: @team, email: @membership.user_email, from_membership: current_membership)
|
89
|
+
if @invitation.save
|
90
|
+
redirect_to [:account, @team, :memberships], notice: I18n.t("account.memberships.notifications.reinvited")
|
91
|
+
else
|
92
|
+
redirect_to [:account, @team, :memberships], notice: "There was an error creating the invitation (#{@invitation.errors.full_messages.to_sentence})"
|
93
|
+
end
|
90
94
|
else
|
91
|
-
|
95
|
+
flash[:error] = :create_limit
|
96
|
+
redirect_to [:account, @team, :memberships]
|
92
97
|
end
|
93
98
|
end
|
94
99
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module Account::TeamsHelper
|
2
2
|
def current_team
|
3
|
+
# TODO We do not want this to be based on the `current_team_id`.
|
4
|
+
# TODO We want this to be based on the current resource being loaded.
|
3
5
|
current_user&.current_team
|
4
6
|
end
|
5
7
|
|
@@ -77,4 +79,12 @@ module Account::TeamsHelper
|
|
77
79
|
def can_invite?
|
78
80
|
can?(:create, Invitation.new(team: current_team))
|
79
81
|
end
|
82
|
+
|
83
|
+
def current_limits
|
84
|
+
@limiter ||= if billing_enabled? && defined?(Billing::Limiter)
|
85
|
+
Billing::Limiter.new(current_team)
|
86
|
+
else
|
87
|
+
Billing::MockLimiter.new(current_team)
|
88
|
+
end
|
89
|
+
end
|
80
90
|
end
|
@@ -4,6 +4,10 @@ module Records::Base
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
+
if billing_enabled? && defined?(Billing::UsageSupport)
|
8
|
+
include Billing::UsageSupport
|
9
|
+
end
|
10
|
+
|
7
11
|
if defined?(Webhooks::Outgoing::IssuingModel)
|
8
12
|
include Webhooks::Outgoing::IssuingModel
|
9
13
|
end
|
@@ -27,6 +27,10 @@ module Teams::Base
|
|
27
27
|
if defined?(Billing::Stripe::Subscription)
|
28
28
|
has_many :billing_stripe_subscriptions, class_name: "Billing::Stripe::Subscription", dependent: :destroy, foreign_key: :team_id
|
29
29
|
end
|
30
|
+
|
31
|
+
if defined?(Billing::Usage::TeamSupport)
|
32
|
+
include Billing::Usage::TeamSupport
|
33
|
+
end
|
30
34
|
end
|
31
35
|
|
32
36
|
# validations
|
@@ -62,6 +66,12 @@ module Teams::Base
|
|
62
66
|
|
63
67
|
# TODO Probably we can provide a way for gem packages to define these kinds of extensions.
|
64
68
|
if billing_enabled?
|
69
|
+
def current_billing_subscription
|
70
|
+
# If by some bug we have two subscriptions, we want to use the one that existed first.
|
71
|
+
# The reasoning here is that it's more likely to be on some legacy plan that benefits the customer.
|
72
|
+
billing_subscriptions.active.order(:created_at).first
|
73
|
+
end
|
74
|
+
|
65
75
|
def needs_billing_subscription?
|
66
76
|
return false if freemium_enabled?
|
67
77
|
billing_subscriptions.active.empty?
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<% invitation ||= @invitation %>
|
2
2
|
<% team ||= @team || invitation&.team %>
|
3
3
|
<%= render 'account/teams/breadcrumbs', team: team %>
|
4
|
-
<%= render 'account/shared/breadcrumb', label: t('.label'), url: [:account, team, :memberships] %>
|
4
|
+
<%= render 'account/shared/breadcrumb', label: t('memberships.label'), url: [:account, team, :memberships] %>
|
5
5
|
<%= render 'account/shared/breadcrumb', label: t('.label'), url: [:account, team, :invitations] %>
|
6
6
|
<% if invitation&.persisted? %>
|
7
7
|
<%= render 'account/shared/breadcrumb', label: invitation.label_string, url: [:account, invitation] %>
|
@@ -1,49 +1,51 @@
|
|
1
1
|
<%= form_with(model: [:account, (@team unless invitation.persisted?), invitation], class: 'form', local: true) do |form| %>
|
2
|
-
<%= render
|
2
|
+
<%= render "shared/limits/form", form: form, model: invitation.membership, cancel_path: @cancel_path || account_invitation_path(invitation) do %>
|
3
|
+
<%= render 'account/shared/forms/errors', form: form %>
|
3
4
|
|
4
|
-
|
5
|
+
<%= render 'shared/fields/email_field', form: form, method: :email, options: {autofocus: true} %>
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
<%= form.fields_for :membership do |membership_form| %>
|
8
|
+
<div class="grid grid-cols-1 gap-y gap-x sm:grid-cols-6">
|
9
|
+
<div class="sm:col-span-3">
|
10
|
+
<%= render 'shared/fields/text_field', form: membership_form, method: :user_first_name %>
|
11
|
+
</div>
|
11
12
|
|
12
|
-
|
13
|
-
|
13
|
+
<div class="sm:col-span-3">
|
14
|
+
<%= render 'shared/fields/text_field', form: membership_form, method: :user_last_name %>
|
15
|
+
</div>
|
14
16
|
</div>
|
15
|
-
|
16
|
-
<% end %>
|
17
|
+
<% end %>
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
19
|
+
<% if can? :manage, @team %>
|
20
|
+
<%= form.fields_for :membership do |fields| %>
|
21
|
+
<%= fields.hidden_field :team_id, value: @team.id %>
|
22
|
+
<div class="space-y-3">
|
23
|
+
<% Membership.assignable_roles.each do |role| %>
|
24
|
+
<% if current_membership.can_manage_role?(role) %>
|
25
|
+
<div class="flex items-top">
|
26
|
+
<%= fields.check_box :role_ids, {multiple: true, class: "h-4 w-4 text-blue focus:ring-blue-dark border-gray-300 rounded mt-0.5"}, role.id, nil %>
|
27
|
+
<label for="invitation_membership_attributes_role_ids_<%= role.id %>" class="ml-2 block select-none">
|
28
|
+
<span><%= t('invitations.form.invite_as', role_key: t("memberships.fields.role_ids.options.#{role.key}.label")) %></span>
|
29
|
+
<div class="mt-0.5 text-gray-400 font-light leading-normal">
|
30
|
+
<%= t("memberships.fields.role_ids.options.#{role.key}.description") %>
|
31
|
+
</div>
|
32
|
+
</label>
|
33
|
+
</div>
|
34
|
+
<% end %>
|
33
35
|
<% end %>
|
34
|
-
|
35
|
-
|
36
|
+
</div>
|
37
|
+
<% end %>
|
36
38
|
<% end %>
|
37
|
-
<% end %>
|
38
39
|
|
39
|
-
|
40
|
+
<%# 🚅 super scaffolding will insert new fields above this line. %>
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
42
|
+
<div class="buttons">
|
43
|
+
<%= form.submit (form.object.persisted? ? t('.buttons.update') : t('.buttons.create')), class: "button" %>
|
44
|
+
<% if form.object.persisted? %>
|
45
|
+
<%= link_to t('global.buttons.cancel'), account_invitation_path(invitation), class: "button-secondary" %>
|
46
|
+
<% else %>
|
47
|
+
<%= link_to t('global.buttons.cancel'), @cancel_path || account_team_invitations_path(@team), class: "button-secondary" %>
|
48
|
+
<% end %>
|
49
|
+
</div>
|
50
|
+
<% end %>
|
49
51
|
<% end %>
|
@@ -2,65 +2,68 @@
|
|
2
2
|
<% hide_actions ||= false %>
|
3
3
|
<% hide_back ||= false %>
|
4
4
|
|
5
|
-
<%=
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
<%= updates_for context, :memberships do %>
|
6
|
+
<%= render 'account/shared/box' do |p| %>
|
7
|
+
<% p.content_for :title, t(".contexts.#{context.class.name.underscore}.header") %>
|
8
|
+
<% p.content_for :description do %>
|
9
|
+
<%= raw t(".contexts.#{context.class.name.underscore}.#{memberships.any? ? 'description' : 'description_empty'}") %>
|
10
|
+
<%= render "shared/limits/index", model: memberships.model %>
|
11
|
+
<% end %>
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
13
|
+
<% p.content_for :table do %>
|
14
|
+
<% if memberships.any? %>
|
15
|
+
<table class="table">
|
16
|
+
<thead>
|
17
|
+
<tr>
|
18
|
+
<th><%= t('memberships.singular') %></th>
|
19
|
+
<th><%= t('memberships.fields.role_ids.heading') %></th>
|
20
|
+
<%# 🚅 super scaffolding will insert new field headers above this line. %>
|
21
|
+
<th></th>
|
22
|
+
</tr>
|
23
|
+
</thead>
|
24
|
+
<tbody data-model="Membership" data-scope="current">
|
25
|
+
<% memberships.each do |membership| %>
|
26
|
+
<tr data-id="<%= membership.id %>">
|
25
27
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
<td class="px-6 py-4 whitespace-nowrap">
|
29
|
+
<%= link_to [:account, membership], class: 'block flex items-center group hover:no-underline no-underline' do %>
|
30
|
+
<div class="flex-shrink-0 h-10 w-10">
|
31
|
+
<%= image_tag membership_profile_photo_url(membership), title: membership.label_string, class: 'h-10 w-10 rounded-full' %>
|
32
|
+
</div>
|
31
33
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
<div class="ml-3">
|
35
|
+
<span class="group-hover:underline"><%= membership.label_string %></span>
|
36
|
+
<% if membership.unclaimed? %>
|
37
|
+
<span class="ml-1.5 px-2 inline-flex text-xs text-green-dark bg-green-light border border-green-dark rounded-md">
|
38
|
+
Invited
|
39
|
+
</span>
|
40
|
+
<% end %>
|
41
|
+
</div>
|
42
|
+
<% end %>
|
43
|
+
</td>
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
45
|
+
<td>
|
46
|
+
<% if membership.roles_without_defaults.any? %>
|
47
|
+
<%= membership.roles_without_defaults.map { |role| t("memberships.fields.role_ids.options.#{role.key}.label") }.to_sentence %>
|
48
|
+
<% else %>
|
49
|
+
<%= t("memberships.fields.role_ids.options.default.label") %>
|
50
|
+
<% end %>
|
51
|
+
</td>
|
52
|
+
<td class="text-right">
|
53
|
+
<%= link_to t('.buttons.show'), [:account, membership], class: 'button-secondary button-smaller' %>
|
54
|
+
</td>
|
55
|
+
</tr>
|
56
|
+
<% end %>
|
57
|
+
</tbody>
|
58
|
+
</table>
|
59
|
+
<% end %>
|
57
60
|
<% end %>
|
58
|
-
<% end %>
|
59
61
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
62
|
+
<% unless hide_actions %>
|
63
|
+
<% p.content_for :actions do %>
|
64
|
+
<%= link_to t('invitations.buttons.new'), new_account_team_invitation_path(@team, cancel_path: account_team_memberships_path(@team)), class: "#{first_button_primary}" %>
|
65
|
+
<%= link_to t('global.buttons.back'), [:account, context], class: "#{first_button_primary} back" unless hide_back %>
|
66
|
+
<% end %>
|
64
67
|
<% end %>
|
65
68
|
<% end %>
|
66
69
|
<% end %>
|
@@ -60,8 +60,11 @@ en:
|
|
60
60
|
heading: *locale
|
61
61
|
# 🚅 super scaffolding will insert new fields above this line.
|
62
62
|
created_at:
|
63
|
-
_: &created_at
|
63
|
+
_: &created_at Signed Up At
|
64
64
|
heading: *created_at
|
65
|
+
updated_at:
|
66
|
+
_: &updated_at Updated At
|
67
|
+
heading: *updated_at
|
65
68
|
_: &self
|
66
69
|
name:
|
67
70
|
label: Your Team Name
|
@@ -84,3 +87,4 @@ en:
|
|
84
87
|
locale: *locale
|
85
88
|
# 🚅 super scaffolding will insert new activerecord attributes above this line.
|
86
89
|
created_at: *created_at
|
90
|
+
updated_at: *updated_at
|
@@ -27,6 +27,10 @@ en:
|
|
27
27
|
notifications:
|
28
28
|
updated: User was successfully updated.
|
29
29
|
fields: &fields
|
30
|
+
id:
|
31
|
+
_: &id Team ID
|
32
|
+
label: *id
|
33
|
+
heading: *id
|
30
34
|
name:
|
31
35
|
heading: Name
|
32
36
|
first_name:
|
@@ -64,8 +68,11 @@ en:
|
|
64
68
|
help: By default the interface language will adjust based on each team's language setting, but you can set a global personal preference for your account here.
|
65
69
|
# 🚅 super scaffolding will insert new fields above this line.
|
66
70
|
created_at:
|
67
|
-
_: &created_at Signed Up
|
71
|
+
_: &created_at Signed Up At
|
68
72
|
heading: *created_at
|
73
|
+
updated_at:
|
74
|
+
_: &updated_at Updated At
|
75
|
+
heading: *updated_at
|
69
76
|
# this is how we define customizations to fields for a specific namespace.
|
70
77
|
_: &self
|
71
78
|
email:
|
@@ -105,6 +112,7 @@ en:
|
|
105
112
|
time_zone: *time_zone
|
106
113
|
locale: *locale
|
107
114
|
# 🚅 super scaffolding will insert new activerecord attributes above this line.
|
108
|
-
created_at: *created_at
|
109
115
|
password: *password
|
110
116
|
password_confirmation: *password_confirmation
|
117
|
+
created_at: *created_at
|
118
|
+
updated_at: *updated_at
|
data/lib/bullet_train/version.rb
CHANGED
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.1.
|
4
|
+
version: 1.1.5
|
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-09-
|
11
|
+
date: 2022-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: standard
|
@@ -483,6 +483,7 @@ files:
|
|
483
483
|
- app/mailers/concerns/mailers/base.rb
|
484
484
|
- app/mailers/devise_mailer.rb
|
485
485
|
- app/mailers/user_mailer.rb
|
486
|
+
- app/models/billing/mock_limiter.rb
|
486
487
|
- app/models/concerns/current_attributes/base.rb
|
487
488
|
- app/models/concerns/invitations/base.rb
|
488
489
|
- app/models/concerns/memberships/base.rb
|