user upgrades: add UserUpgrade model.
Add a model to store the status of user upgrades. * Store the upgrade purchaser and the upgrade receiver (these are different for a gifted upgrade, the same for a self upgrade). * Store the upgrade type: gold, platinum, or gold-to-platinum upgrades. * Store the upgrade status: ** pending: User is still on the Stripe checkout page, no payment received yet. ** processing: User has completed checkout, but the checkout status in Stripe is still 'unpaid'. ** complete: We've received notification from Stripe that the payment has gone through and the user has been upgraded. * Store the Stripe checkout ID, to cross-reference the upgrade record on Danbooru with the checkout record on Stripe. This is the upgrade flow: * When the user clicks the upgrade button on the upgrade page, we call POST /user_upgrades and create a pending UserUpgrade. * We redirect the user to the checkout page on Stripe. * When the user completes checkout on Stripe, Stripe sends us a webhook notification at POST /webhooks/receive. * When we receive the webhook, we check the payment status, and if it's paid we mark the UserUpgrade as complete and upgrade the user. * After Stripe sees that we have successfully processed the webhook, they redirect the user to the /user_upgrades/:id page, where we show the user their upgrade receipt.
This commit is contained in:
@@ -3,8 +3,8 @@ class UserUpgradesController < ApplicationController
|
|||||||
respond_to :js, :html
|
respond_to :js, :html
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@user_upgrade = UserUpgrade.new(recipient: user, purchaser: CurrentUser.user, level: params[:level].to_i)
|
@user_upgrade = authorize UserUpgrade.create(recipient: user, purchaser: CurrentUser.user, status: "pending", upgrade_type: params[:upgrade_type])
|
||||||
@checkout = @user_upgrade.create_checkout
|
@checkout = @user_upgrade.create_checkout!
|
||||||
|
|
||||||
respond_with(@user_upgrade)
|
respond_with(@user_upgrade)
|
||||||
end
|
end
|
||||||
@@ -13,7 +13,8 @@ class UserUpgradesController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
authorize User, :upgrade?
|
@user_upgrade = authorize UserUpgrade.find(params[:id])
|
||||||
|
respond_with(@user_upgrade)
|
||||||
end
|
end
|
||||||
|
|
||||||
def user
|
def user
|
||||||
|
|||||||
@@ -99,6 +99,8 @@ class User < ApplicationRecord
|
|||||||
has_many :post_votes
|
has_many :post_votes
|
||||||
has_many :post_versions, foreign_key: :updater_id
|
has_many :post_versions, foreign_key: :updater_id
|
||||||
has_many :bans, -> {order("bans.id desc")}
|
has_many :bans, -> {order("bans.id desc")}
|
||||||
|
has_many :received_upgrades, class_name: "UserUpgrade", foreign_key: :recipient_id, dependent: :destroy
|
||||||
|
has_many :purchased_upgrades, class_name: "UserUpgrade", foreign_key: :purchaser_id, dependent: :destroy
|
||||||
has_one :recent_ban, -> {order("bans.id desc")}, :class_name => "Ban"
|
has_one :recent_ban, -> {order("bans.id desc")}, :class_name => "Ban"
|
||||||
|
|
||||||
has_one :api_key
|
has_one :api_key
|
||||||
|
|||||||
@@ -1,5 +1,18 @@
|
|||||||
class UserUpgrade
|
class UserUpgrade < ApplicationRecord
|
||||||
attr_reader :recipient, :purchaser, :level
|
belongs_to :recipient, class_name: "User"
|
||||||
|
belongs_to :purchaser, class_name: "User"
|
||||||
|
|
||||||
|
enum upgrade_type: {
|
||||||
|
gold: 0,
|
||||||
|
platinum: 10,
|
||||||
|
gold_to_platinum: 20
|
||||||
|
}, _suffix: "upgrade"
|
||||||
|
|
||||||
|
enum status: {
|
||||||
|
pending: 0,
|
||||||
|
processing: 10,
|
||||||
|
complete: 20
|
||||||
|
}
|
||||||
|
|
||||||
def self.stripe_publishable_key
|
def self.stripe_publishable_key
|
||||||
Danbooru.config.stripe_publishable_key
|
Danbooru.config.stripe_publishable_key
|
||||||
@@ -21,51 +34,63 @@ class UserUpgrade
|
|||||||
platinum_price - gold_price
|
platinum_price - gold_price
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(recipient:, purchaser:, level:)
|
def level
|
||||||
@recipient, @purchaser, @level = recipient, purchaser, level.to_i
|
case upgrade_type
|
||||||
end
|
when "gold"
|
||||||
|
User::Levels::GOLD
|
||||||
def upgrade_type
|
when "platinum"
|
||||||
if level == User::Levels::GOLD && recipient.level == User::Levels::MEMBER
|
User::Levels::PLATINUM
|
||||||
:gold_upgrade
|
when "gold_to_platinum"
|
||||||
elsif level == User::Levels::PLATINUM && recipient.level == User::Levels::MEMBER
|
User::Levels::PLATINUM
|
||||||
:platinum_upgrade
|
|
||||||
elsif level == User::Levels::PLATINUM && recipient.level == User::Levels::GOLD
|
|
||||||
:gold_to_platinum_upgrade
|
|
||||||
else
|
else
|
||||||
raise ArgumentError, "Invalid upgrade"
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def upgrade_price
|
def upgrade_price
|
||||||
case upgrade_type
|
case upgrade_type
|
||||||
when :gold_upgrade
|
when "gold"
|
||||||
UserUpgrade.gold_price
|
UserUpgrade.gold_price
|
||||||
when :platinum_upgrade
|
when "platinum"
|
||||||
UserUpgrade.platinum_price
|
UserUpgrade.platinum_price
|
||||||
when :gold_to_platinum_upgrade
|
when "gold_to_platinum"
|
||||||
UserUpgrade.gold_to_platinum_price
|
UserUpgrade.gold_to_platinum_price
|
||||||
|
else
|
||||||
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def upgrade_description
|
def upgrade_description
|
||||||
case upgrade_type
|
case upgrade_type
|
||||||
when :gold_upgrade
|
when "gold"
|
||||||
"Upgrade to Gold"
|
"Upgrade to Gold"
|
||||||
when :platinum_upgrade
|
when "platinum"
|
||||||
"Upgrade to Platinum"
|
"Upgrade to Platinum"
|
||||||
when :gold_to_platinum_upgrade
|
when "gold_to_platinum"
|
||||||
"Upgrade Gold to Platinum"
|
"Upgrade Gold to Platinum"
|
||||||
|
else
|
||||||
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def level_string
|
||||||
|
User.level_string(level)
|
||||||
|
end
|
||||||
|
|
||||||
def is_gift?
|
def is_gift?
|
||||||
recipient != purchaser
|
recipient != purchaser
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_upgrade!
|
def process_upgrade!(payment_status)
|
||||||
recipient.with_lock do
|
recipient.with_lock do
|
||||||
upgrade_recipient!
|
return if status == "complete"
|
||||||
|
|
||||||
|
if payment_status == "paid"
|
||||||
|
upgrade_recipient!
|
||||||
|
update!(status: :complete)
|
||||||
|
else
|
||||||
|
update!(status: :processing)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -74,12 +99,12 @@ class UserUpgrade
|
|||||||
end
|
end
|
||||||
|
|
||||||
concerning :StripeMethods do
|
concerning :StripeMethods do
|
||||||
def create_checkout
|
def create_checkout!
|
||||||
Stripe::Checkout::Session.create(
|
checkout = Stripe::Checkout::Session.create(
|
||||||
mode: "payment",
|
mode: "payment",
|
||||||
success_url: Routes.user_upgrade_url(user_id: recipient.id),
|
success_url: Routes.user_upgrade_url(self),
|
||||||
cancel_url: Routes.new_user_upgrade_url(user_id: recipient.id),
|
cancel_url: Routes.new_user_upgrade_url(user_id: recipient.id),
|
||||||
client_reference_id: "user_#{purchaser.id}",
|
client_reference_id: "user_upgrade_#{id}",
|
||||||
customer_email: recipient.email_address&.address,
|
customer_email: recipient.email_address&.address,
|
||||||
payment_method_types: ["card"],
|
payment_method_types: ["card"],
|
||||||
line_items: [{
|
line_items: [{
|
||||||
@@ -93,6 +118,7 @@ class UserUpgrade
|
|||||||
quantity: 1,
|
quantity: 1,
|
||||||
}],
|
}],
|
||||||
metadata: {
|
metadata: {
|
||||||
|
user_upgrade_id: id,
|
||||||
purchaser_id: purchaser.id,
|
purchaser_id: purchaser.id,
|
||||||
recipient_id: recipient.id,
|
recipient_id: recipient.id,
|
||||||
purchaser_name: purchaser.name,
|
purchaser_name: purchaser.name,
|
||||||
@@ -102,6 +128,9 @@ class UserUpgrade
|
|||||||
level: level,
|
level: level,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
update!(stripe_id: checkout.id)
|
||||||
|
checkout
|
||||||
end
|
end
|
||||||
|
|
||||||
class_methods do
|
class_methods do
|
||||||
@@ -122,7 +151,7 @@ class UserUpgrade
|
|||||||
event = build_event(request)
|
event = build_event(request)
|
||||||
|
|
||||||
if event.type == "checkout.session.completed"
|
if event.type == "checkout.session.completed"
|
||||||
checkout_session_completed(event)
|
checkout_session_completed(event.data.object)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -132,13 +161,9 @@ class UserUpgrade
|
|||||||
Stripe::Webhook.construct_event(payload, signature, stripe_webhook_secret)
|
Stripe::Webhook.construct_event(payload, signature, stripe_webhook_secret)
|
||||||
end
|
end
|
||||||
|
|
||||||
def checkout_session_completed(event)
|
def checkout_session_completed(checkout)
|
||||||
recipient = User.find(event.data.object.metadata.recipient_id)
|
user_upgrade = UserUpgrade.find(checkout.metadata.user_upgrade_id)
|
||||||
purchaser = User.find(event.data.object.metadata.purchaser_id)
|
user_upgrade.process_upgrade!(checkout.payment_status)
|
||||||
level = event.data.object.metadata.level
|
|
||||||
|
|
||||||
user_upgrade = UserUpgrade.new(recipient: recipient, purchaser: purchaser, level: level)
|
|
||||||
user_upgrade.process_upgrade!
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
9
app/policies/user_upgrade_policy.rb
Normal file
9
app/policies/user_upgrade_policy.rb
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
class UserUpgradePolicy < ApplicationPolicy
|
||||||
|
def create?
|
||||||
|
user.is_member?
|
||||||
|
end
|
||||||
|
|
||||||
|
def show?
|
||||||
|
record.recipient == user || record.purchaser == user || user.is_owner?
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -101,11 +101,11 @@
|
|||||||
<p>You can pay with a credit or debit card. Safebooru uses <a href="https://www.stripe.com">Stripe</a>
|
<p>You can pay with a credit or debit card. Safebooru uses <a href="https://www.stripe.com">Stripe</a>
|
||||||
as a payment intermediary so none of your personal information will be stored on the site.</p>
|
as a payment intermediary so none of your personal information will be stored on the site.</p>
|
||||||
|
|
||||||
<% if user.level < User::Levels::GOLD %>
|
<% if user.level == User::Levels::MEMBER %>
|
||||||
<p><%= button_to "Upgrade to Gold", user_upgrade_path(user_id: user.id, level: User::Levels::GOLD), remote: true, disable_with: "Redirecting..." %></p>
|
<p><%= button_to "Upgrade to Gold", user_upgrades_path(user_id: user.id, upgrade_type: "gold"), remote: true, disable_with: "Redirecting..." %></p>
|
||||||
<p><%= button_to "Upgrade to Platinum", user_upgrade_path(user_id: user.id, level: User::Levels::PLATINUM), remote: true, disable_with: "Redirecting..." %></p>
|
<p><%= button_to "Upgrade to Platinum", user_upgrades_path(user_id: user.id, upgrade_type: "platinum"), remote: true, disable_with: "Redirecting..." %></p>
|
||||||
<% elsif user.level < User::Levels::PLATINUM %>
|
<% elsif user.level == User::Levels::GOLD %>
|
||||||
<p><%= button_to "Upgrade Gold to Platinum", user_upgrade_path(user_id: user.id, level: User::Levels::PLATINUM), remote: true, disable_with: "Redirecting..." %></p>
|
<p><%= button_to "Upgrade Gold to Platinum", user_upgrades_path(user_id: user.id, upgrade_type: "gold_to_platinum"), remote: true, disable_with: "Redirecting..." %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% else %>
|
<% else %>
|
||||||
|
|||||||
@@ -1,22 +1,47 @@
|
|||||||
<% page_title "Account Upgraded" %>
|
<% page_title "User Upgrade Status" %>
|
||||||
<%= render "users/secondary_links" %>
|
<%= render "users/secondary_links" %>
|
||||||
|
|
||||||
<div id="c-user-upgrades">
|
<div id="c-user-upgrades">
|
||||||
<div id="a-show">
|
<div id="a-show">
|
||||||
<% if flash[:success] %>
|
<h1>User Upgrade</h1>
|
||||||
<h1>Congratulations!</h1>
|
|
||||||
|
|
||||||
<% if user != CurrentUser.user %>
|
<p>
|
||||||
<p><%= user.name %> is now a <%= user.level_string %> user. Thanks for supporting the site!</p>
|
<ul>
|
||||||
|
<li>
|
||||||
|
<strong>Purchased</strong>
|
||||||
|
<%= time_ago_in_words_tagged @user_upgrade.updated_at %>
|
||||||
|
by <%= link_to_user @user_upgrade.purchaser %>
|
||||||
|
<% if @user_upgrade.is_gift? %>
|
||||||
|
for <%= link_to_user @user_upgrade.recipient %>
|
||||||
|
<% end %>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Upgrade Type</strong>
|
||||||
|
<%= @user_upgrade.upgrade_type.humanize %>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Status</strong>
|
||||||
|
<%= @user_upgrade.status.humanize %>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<% if @user_upgrade.status == "complete" %>
|
||||||
|
<% if @user_upgrade.is_gift? && CurrentUser.user == @user_upgrade.recipient %>
|
||||||
|
<p><%= link_to_user @user_upgrade.purchaser %> has upgraded your account to <%= @user_upgrade.level_string %>. Enjoy your new account!</p>
|
||||||
|
<% elsif @user_upgrade.is_gift? && CurrentUser.user == @user_upgrade.purchaser %>
|
||||||
|
<p><%= link_to_user @user_upgrade.recipient %> is now a <%= @user_upgrade.level_string %> user. Thanks for supporting the site!</p>
|
||||||
<% else %>
|
<% else %>
|
||||||
<p>You are now a <%= user.level_string %> user. Thanks for supporting the site!</p>
|
<p>You are now a <%= @user_upgrade.level_string %> user. Thanks for supporting the site!</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<p><%= link_to "Go back to #{Danbooru.config.canonical_app_name}", "https://danbooru.donmai.us" %> to start using your new account.</p>
|
<p><%= link_to "Go back to #{Danbooru.config.canonical_app_name}", "https://danbooru.donmai.us" %> to continue using the site.</p>
|
||||||
<% elsif flash[:error] %>
|
<% else %>
|
||||||
<h1>An error occurred!</h1>
|
<%= content_for :html_header do %>
|
||||||
<p><%= flash[:error] %></p>
|
<meta http-equiv="refresh" content="5">
|
||||||
<p><%= link_to "Try again", new_user_upgrade_path %></p>
|
<% end %>
|
||||||
|
|
||||||
|
<p>This order is still being processed. You will be notified as soon as the order is complete.</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ Rails.application.routes.draw do
|
|||||||
get :custom_style
|
get :custom_style
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
resource :user_upgrade, :only => [:new, :create, :show]
|
resources :user_upgrades, only: [:new, :create, :show]
|
||||||
resources :user_feedbacks, except: [:destroy]
|
resources :user_feedbacks, except: [:destroy]
|
||||||
resources :user_name_change_requests, only: [:new, :create, :show, :index]
|
resources :user_name_change_requests, only: [:new, :create, :show, :index]
|
||||||
resources :webhooks do
|
resources :webhooks do
|
||||||
|
|||||||
20
db/migrate/20201224101208_create_user_upgrades.rb
Normal file
20
db/migrate/20201224101208_create_user_upgrades.rb
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
class CreateUserUpgrades < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
create_table :user_upgrades do |t|
|
||||||
|
t.timestamps
|
||||||
|
|
||||||
|
t.references :recipient, index: true, null: false
|
||||||
|
t.references :purchaser, index: true, null: false
|
||||||
|
t.integer :upgrade_type, index: true, null: false
|
||||||
|
t.integer :status, index: true, null: false
|
||||||
|
t.string :stripe_id, index: true, null: true
|
||||||
|
end
|
||||||
|
|
||||||
|
# Reserve ID space for backfilling old upgrades.
|
||||||
|
reversible do |dir|
|
||||||
|
dir.up do
|
||||||
|
execute "SELECT setval('user_upgrades_id_seq', 25000, false)"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -3104,6 +3104,41 @@ CREATE SEQUENCE public.user_name_change_requests_id_seq
|
|||||||
ALTER SEQUENCE public.user_name_change_requests_id_seq OWNED BY public.user_name_change_requests.id;
|
ALTER SEQUENCE public.user_name_change_requests_id_seq OWNED BY public.user_name_change_requests.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: user_upgrades; Type: TABLE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.user_upgrades (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
created_at timestamp(6) without time zone NOT NULL,
|
||||||
|
updated_at timestamp(6) without time zone NOT NULL,
|
||||||
|
recipient_id bigint NOT NULL,
|
||||||
|
purchaser_id bigint NOT NULL,
|
||||||
|
upgrade_type integer NOT NULL,
|
||||||
|
status integer NOT NULL,
|
||||||
|
stripe_id character varying
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: user_upgrades_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.user_upgrades_id_seq
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: user_upgrades_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.user_upgrades_id_seq OWNED BY public.user_upgrades.id;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: users_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
-- Name: users_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -4172,6 +4207,13 @@ ALTER TABLE ONLY public.user_feedback ALTER COLUMN id SET DEFAULT nextval('publi
|
|||||||
ALTER TABLE ONLY public.user_name_change_requests ALTER COLUMN id SET DEFAULT nextval('public.user_name_change_requests_id_seq'::regclass);
|
ALTER TABLE ONLY public.user_name_change_requests ALTER COLUMN id SET DEFAULT nextval('public.user_name_change_requests_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: user_upgrades id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.user_upgrades ALTER COLUMN id SET DEFAULT nextval('public.user_upgrades_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: users id; Type: DEFAULT; Schema: public; Owner: -
|
-- Name: users id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -4537,6 +4579,14 @@ ALTER TABLE ONLY public.user_name_change_requests
|
|||||||
ADD CONSTRAINT user_name_change_requests_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT user_name_change_requests_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: user_upgrades user_upgrades_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.user_upgrades
|
||||||
|
ADD CONSTRAINT user_upgrades_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -7045,6 +7095,41 @@ CREATE INDEX index_user_name_change_requests_on_original_name ON public.user_nam
|
|||||||
CREATE INDEX index_user_name_change_requests_on_user_id ON public.user_name_change_requests USING btree (user_id);
|
CREATE INDEX index_user_name_change_requests_on_user_id ON public.user_name_change_requests USING btree (user_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: index_user_upgrades_on_purchaser_id; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX index_user_upgrades_on_purchaser_id ON public.user_upgrades USING btree (purchaser_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: index_user_upgrades_on_recipient_id; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX index_user_upgrades_on_recipient_id ON public.user_upgrades USING btree (recipient_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: index_user_upgrades_on_status; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX index_user_upgrades_on_status ON public.user_upgrades USING btree (status);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: index_user_upgrades_on_stripe_id; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX index_user_upgrades_on_stripe_id ON public.user_upgrades USING btree (stripe_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: index_user_upgrades_on_upgrade_type; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX index_user_upgrades_on_upgrade_type ON public.user_upgrades USING btree (upgrade_type);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: index_users_on_created_at; Type: INDEX; Schema: public; Owner: -
|
-- Name: index_users_on_created_at; Type: INDEX; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -7437,6 +7522,7 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|||||||
('20200816175151'),
|
('20200816175151'),
|
||||||
('20201201211748'),
|
('20201201211748'),
|
||||||
('20201213052805'),
|
('20201213052805'),
|
||||||
('20201219201007');
|
('20201219201007'),
|
||||||
|
('20201224101208');
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
38
test/factories/user_upgrade.rb
Normal file
38
test/factories/user_upgrade.rb
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
FactoryBot.define do
|
||||||
|
factory(:user_upgrade) do
|
||||||
|
recipient { create(:member_user) }
|
||||||
|
purchaser { recipient }
|
||||||
|
upgrade_type { "gold" }
|
||||||
|
status { "pending" }
|
||||||
|
stripe_id { nil }
|
||||||
|
|
||||||
|
factory(:self_gold_upgrade) do
|
||||||
|
upgrade_type { "gold" }
|
||||||
|
end
|
||||||
|
|
||||||
|
factory(:self_platinum_upgrade) do
|
||||||
|
upgrade_type { "platinum" }
|
||||||
|
end
|
||||||
|
|
||||||
|
factory(:self_gold_to_platinum_upgrade) do
|
||||||
|
recipient { create(:gold_user) }
|
||||||
|
upgrade_type { "gold_to_platinum" }
|
||||||
|
end
|
||||||
|
|
||||||
|
factory(:gift_gold_upgrade) do
|
||||||
|
purchaser { create(:user) }
|
||||||
|
upgrade_type { "gold" }
|
||||||
|
end
|
||||||
|
|
||||||
|
factory(:gift_platinum_upgrade) do
|
||||||
|
purchaser { create(:user) }
|
||||||
|
upgrade_type { "platinum" }
|
||||||
|
end
|
||||||
|
|
||||||
|
factory(:gift_gold_to_platinum_upgrade) do
|
||||||
|
recipient { create(:gold_user) }
|
||||||
|
purchaser { create(:user) }
|
||||||
|
upgrade_type { "gold_to_platinum" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -3,38 +3,184 @@ require 'test_helper'
|
|||||||
class UserUpgradesControllerTest < ActionDispatch::IntegrationTest
|
class UserUpgradesControllerTest < ActionDispatch::IntegrationTest
|
||||||
context "The user upgrades controller" do
|
context "The user upgrades controller" do
|
||||||
context "new action" do
|
context "new action" do
|
||||||
should "render" do
|
should "render for a self upgrade" do
|
||||||
|
@user = create(:user)
|
||||||
|
get_auth new_user_upgrade_path, @user
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
should "render for a gift upgrade" do
|
||||||
|
@recipient = create(:user)
|
||||||
|
get_auth new_user_upgrade_path(user_id: @recipient.id), create(:user)
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
should "render for an anonymous user" do
|
||||||
get new_user_upgrade_path
|
get new_user_upgrade_path
|
||||||
|
|
||||||
assert_response :success
|
assert_response :success
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "show action" do
|
context "show action" do
|
||||||
should "render" do
|
context "for a completed upgrade" do
|
||||||
get_auth user_upgrade_path, create(:user)
|
should "render for a self upgrade" do
|
||||||
assert_response :success
|
@user_upgrade = create(:self_gold_upgrade, status: "complete")
|
||||||
|
get_auth user_upgrade_path(@user_upgrade), @user_upgrade.purchaser
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
should "render for a gift upgrade for the purchaser" do
|
||||||
|
@user_upgrade = create(:gift_gold_upgrade, status: "complete")
|
||||||
|
get_auth user_upgrade_path(@user_upgrade), @user_upgrade.purchaser
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
should "render for a gift upgrade for the recipient" do
|
||||||
|
@user_upgrade = create(:gift_gold_upgrade, status: "complete")
|
||||||
|
get_auth user_upgrade_path(@user_upgrade), @user_upgrade.recipient
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
should "render for the site owner" do
|
||||||
|
@user_upgrade = create(:self_gold_upgrade, status: "complete")
|
||||||
|
get_auth user_upgrade_path(@user_upgrade), create(:owner_user)
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be inaccessible to other users" do
|
||||||
|
@user_upgrade = create(:self_gold_upgrade, status: "complete")
|
||||||
|
get_auth user_upgrade_path(@user_upgrade), create(:user)
|
||||||
|
|
||||||
|
assert_response 403
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "for a pending upgrade" do
|
||||||
|
should "render" do
|
||||||
|
@user_upgrade = create(:self_gold_upgrade, status: "pending")
|
||||||
|
get_auth user_upgrade_path(@user_upgrade), @user_upgrade.purchaser
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "create action" do
|
context "create action" do
|
||||||
mock_stripe!
|
mock_stripe!
|
||||||
|
|
||||||
context "for a self upgrade to Gold" do
|
context "for a self upgrade" do
|
||||||
should "redirect the user to the Stripe checkout page" do
|
context "to Gold" do
|
||||||
user = create(:member_user)
|
should "create a pending upgrade" do
|
||||||
post_auth user_upgrade_path(user_id: user.id), user, params: { level: User::Levels::GOLD }, xhr: true
|
@user = create(:member_user)
|
||||||
|
|
||||||
assert_response :success
|
post_auth user_upgrades_path(user_id: @user.id), @user, params: { upgrade_type: "gold" }, xhr: true
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
@user_upgrade = @user.purchased_upgrades.last
|
||||||
|
assert_equal(@user, @user_upgrade.purchaser)
|
||||||
|
assert_equal(@user, @user_upgrade.recipient)
|
||||||
|
assert_equal("gold", @user_upgrade.upgrade_type)
|
||||||
|
assert_equal("pending", @user_upgrade.status)
|
||||||
|
assert_not_nil(@user_upgrade.stripe_id)
|
||||||
|
assert_match(/redirectToCheckout/, response.body)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "to Platinum" do
|
||||||
|
should "create a pending upgrade" do
|
||||||
|
@user = create(:member_user)
|
||||||
|
|
||||||
|
post_auth user_upgrades_path(user_id: @user.id), @user, params: { upgrade_type: "platinum" }, xhr: true
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
@user_upgrade = @user.purchased_upgrades.last
|
||||||
|
assert_equal(@user, @user_upgrade.purchaser)
|
||||||
|
assert_equal(@user, @user_upgrade.recipient)
|
||||||
|
assert_equal("platinum", @user_upgrade.upgrade_type)
|
||||||
|
assert_equal("pending", @user_upgrade.status)
|
||||||
|
assert_not_nil(@user_upgrade.stripe_id)
|
||||||
|
assert_match(/redirectToCheckout/, response.body)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "from Gold to Platinum" do
|
||||||
|
should "create a pending upgrade" do
|
||||||
|
@user = create(:member_user)
|
||||||
|
|
||||||
|
post_auth user_upgrades_path(user_id: @user.id), @user, params: { upgrade_type: "gold_to_platinum" }, xhr: true
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
@user_upgrade = @user.purchased_upgrades.last
|
||||||
|
assert_equal(@user, @user_upgrade.purchaser)
|
||||||
|
assert_equal(@user, @user_upgrade.recipient)
|
||||||
|
assert_equal("gold_to_platinum", @user_upgrade.upgrade_type)
|
||||||
|
assert_equal("pending", @user_upgrade.status)
|
||||||
|
assert_not_nil(@user_upgrade.stripe_id)
|
||||||
|
assert_match(/redirectToCheckout/, response.body)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "for a gifted upgrade to Gold" do
|
context "for a gifted upgrade" do
|
||||||
should "redirect the user to the Stripe checkout page" do
|
context "to Gold" do
|
||||||
recipient = create(:member_user)
|
should "create a pending upgrade" do
|
||||||
purchaser = create(:member_user)
|
@recipient = create(:member_user)
|
||||||
post_auth user_upgrade_path(user_id: recipient.id), purchaser, params: { level: User::Levels::GOLD }, xhr: true
|
@purchaser = create(:member_user)
|
||||||
|
|
||||||
assert_response :success
|
post_auth user_upgrades_path(user_id: @recipient.id), @purchaser, params: { upgrade_type: "gold" }, xhr: true
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
@user_upgrade = @purchaser.purchased_upgrades.last
|
||||||
|
assert_equal(@purchaser, @user_upgrade.purchaser)
|
||||||
|
assert_equal(@recipient, @user_upgrade.recipient)
|
||||||
|
assert_equal("gold", @user_upgrade.upgrade_type)
|
||||||
|
assert_equal("pending", @user_upgrade.status)
|
||||||
|
assert_not_nil(@user_upgrade.stripe_id)
|
||||||
|
assert_match(/redirectToCheckout/, response.body)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "to Platinum" do
|
||||||
|
should "create a pending upgrade" do
|
||||||
|
@recipient = create(:member_user)
|
||||||
|
@purchaser = create(:member_user)
|
||||||
|
|
||||||
|
post_auth user_upgrades_path(user_id: @recipient.id), @purchaser, params: { upgrade_type: "platinum" }, xhr: true
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
@user_upgrade = @purchaser.purchased_upgrades.last
|
||||||
|
assert_equal(@purchaser, @user_upgrade.purchaser)
|
||||||
|
assert_equal(@recipient, @user_upgrade.recipient)
|
||||||
|
assert_equal("platinum", @user_upgrade.upgrade_type)
|
||||||
|
assert_equal("pending", @user_upgrade.status)
|
||||||
|
assert_not_nil(@user_upgrade.stripe_id)
|
||||||
|
assert_match(/redirectToCheckout/, response.body)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "from Gold to Platinum" do
|
||||||
|
should "create a pending upgrade" do
|
||||||
|
@recipient = create(:gold_user)
|
||||||
|
@purchaser = create(:member_user)
|
||||||
|
|
||||||
|
post_auth user_upgrades_path(user_id: @recipient.id), @purchaser, params: { upgrade_type: "gold_to_platinum" }, xhr: true
|
||||||
|
assert_response :success
|
||||||
|
|
||||||
|
@user_upgrade = @purchaser.purchased_upgrades.last
|
||||||
|
assert_equal(@purchaser, @user_upgrade.purchaser)
|
||||||
|
assert_equal(@recipient, @user_upgrade.recipient)
|
||||||
|
assert_equal("gold_to_platinum", @user_upgrade.upgrade_type)
|
||||||
|
assert_equal("pending", @user_upgrade.status)
|
||||||
|
assert_not_nil(@user_upgrade.stripe_id)
|
||||||
|
assert_match(/redirectToCheckout/, response.body)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ require 'test_helper'
|
|||||||
class WebhooksControllerTest < ActionDispatch::IntegrationTest
|
class WebhooksControllerTest < ActionDispatch::IntegrationTest
|
||||||
mock_stripe!
|
mock_stripe!
|
||||||
|
|
||||||
def post_webhook(*args, **metadata)
|
def post_webhook(*args, payment_status: "paid", **metadata)
|
||||||
event = StripeMock.mock_webhook_event(*args, metadata: metadata)
|
event = StripeMock.mock_webhook_event(*args, payment_status: payment_status, metadata: metadata)
|
||||||
signature = generate_stripe_signature(event)
|
signature = generate_stripe_signature(event)
|
||||||
headers = { "Stripe-Signature": signature }
|
headers = { "Stripe-Signature": signature }
|
||||||
|
|
||||||
@@ -58,105 +58,83 @@ class WebhooksControllerTest < ActionDispatch::IntegrationTest
|
|||||||
end
|
end
|
||||||
|
|
||||||
context "for a checkout.session.completed event" do
|
context "for a checkout.session.completed event" do
|
||||||
|
context "for completed event with an unpaid payment status" do
|
||||||
|
should "not upgrade the user" do
|
||||||
|
@user_upgrade = create(:self_gold_upgrade)
|
||||||
|
post_webhook("checkout.session.completed", { user_upgrade_id: @user_upgrade.id, payment_status: "unpaid" })
|
||||||
|
|
||||||
|
assert_response 200
|
||||||
|
assert_equal("processing", @user_upgrade.reload.status)
|
||||||
|
assert_equal(User::Levels::MEMBER, @user_upgrade.recipient.reload.level)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "for a self upgrade" do
|
context "for a self upgrade" do
|
||||||
context "of a Member to Gold" do
|
context "to Gold" do
|
||||||
should "upgrade the user" do
|
should "upgrade the user" do
|
||||||
@user = create(:member_user)
|
@user_upgrade = create(:self_gold_upgrade)
|
||||||
|
post_webhook("checkout.session.completed", { user_upgrade_id: @user_upgrade.id })
|
||||||
post_webhook("checkout.session.completed", {
|
|
||||||
recipient_id: @user.id,
|
|
||||||
purchaser_id: @user.id,
|
|
||||||
upgrade_type: "gold_upgrade",
|
|
||||||
level: User::Levels::GOLD,
|
|
||||||
})
|
|
||||||
|
|
||||||
assert_response 200
|
assert_response 200
|
||||||
assert_equal(User::Levels::GOLD, @user.reload.level)
|
assert_equal("complete", @user_upgrade.reload.status)
|
||||||
|
assert_equal(User::Levels::GOLD, @user_upgrade.recipient.reload.level)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "of a Member to Platinum" do
|
context "to Platinum" do
|
||||||
should "upgrade the user" do
|
should "upgrade the user" do
|
||||||
@user = create(:member_user)
|
@user_upgrade = create(:self_platinum_upgrade)
|
||||||
|
post_webhook("checkout.session.completed", { user_upgrade_id: @user_upgrade.id })
|
||||||
post_webhook("checkout.session.completed", {
|
|
||||||
recipient_id: @user.id,
|
|
||||||
purchaser_id: @user.id,
|
|
||||||
upgrade_type: "platinum_upgrade",
|
|
||||||
level: User::Levels::PLATINUM,
|
|
||||||
})
|
|
||||||
|
|
||||||
assert_response 200
|
assert_response 200
|
||||||
assert_equal(User::Levels::PLATINUM, @user.reload.level)
|
assert_equal("complete", @user_upgrade.reload.status)
|
||||||
|
assert_equal(User::Levels::PLATINUM, @user_upgrade.recipient.reload.level)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "of a Gold user to Platinum" do
|
context "from Gold to Platinum" do
|
||||||
should "upgrade the user" do
|
should "upgrade the user" do
|
||||||
@user = create(:gold_user)
|
@user_upgrade = create(:self_gold_to_platinum_upgrade)
|
||||||
|
post_webhook("checkout.session.completed", { user_upgrade_id: @user_upgrade.id })
|
||||||
post_webhook("checkout.session.completed", {
|
|
||||||
recipient_id: @user.id,
|
|
||||||
purchaser_id: @user.id,
|
|
||||||
upgrade_type: "gold_to_platinum_upgrade",
|
|
||||||
level: User::Levels::PLATINUM,
|
|
||||||
})
|
|
||||||
|
|
||||||
assert_response 200
|
assert_response 200
|
||||||
assert_equal(User::Levels::PLATINUM, @user.reload.level)
|
assert_equal("complete", @user_upgrade.reload.status)
|
||||||
|
assert_equal(User::Levels::PLATINUM, @user_upgrade.recipient.reload.level)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "for a gifted upgrade" do
|
context "for a gifted upgrade" do
|
||||||
context "of a Member to Gold" do
|
context "to Gold" do
|
||||||
should "upgrade the user" do
|
should "upgrade the user" do
|
||||||
@recipient = create(:member_user)
|
@user_upgrade = create(:gift_gold_upgrade)
|
||||||
@purchaser = create(:member_user)
|
post_webhook("checkout.session.completed", { user_upgrade_id: @user_upgrade.id })
|
||||||
|
|
||||||
post_webhook("checkout.session.completed", {
|
|
||||||
recipient_id: @recipient.id,
|
|
||||||
purchaser_id: @purchaser.id,
|
|
||||||
upgrade_type: "gold_upgrade",
|
|
||||||
level: User::Levels::GOLD,
|
|
||||||
})
|
|
||||||
|
|
||||||
assert_response 200
|
assert_response 200
|
||||||
assert_equal(User::Levels::GOLD, @recipient.reload.level)
|
assert_equal("complete", @user_upgrade.reload.status)
|
||||||
|
assert_equal(User::Levels::GOLD, @user_upgrade.recipient.reload.level)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "of a Member to Platinum" do
|
context "to Platinum" do
|
||||||
should "upgrade the user" do
|
should "upgrade the user" do
|
||||||
@recipient = create(:member_user)
|
@user_upgrade = create(:gift_platinum_upgrade)
|
||||||
@purchaser = create(:member_user)
|
post_webhook("checkout.session.completed", { user_upgrade_id: @user_upgrade.id })
|
||||||
|
|
||||||
post_webhook("checkout.session.completed", {
|
|
||||||
recipient_id: @recipient.id,
|
|
||||||
purchaser_id: @purchaser.id,
|
|
||||||
upgrade_type: "platinum_upgrade",
|
|
||||||
level: User::Levels::PLATINUM,
|
|
||||||
})
|
|
||||||
|
|
||||||
assert_response 200
|
assert_response 200
|
||||||
assert_equal(User::Levels::PLATINUM, @recipient.reload.level)
|
assert_equal("complete", @user_upgrade.reload.status)
|
||||||
|
assert_equal(User::Levels::PLATINUM, @user_upgrade.recipient.reload.level)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "of a Gold user to Platinum" do
|
context "from Gold to Platinum" do
|
||||||
should "upgrade the user" do
|
should "upgrade the user" do
|
||||||
@recipient = create(:gold_user)
|
@user_upgrade = create(:gift_gold_to_platinum_upgrade)
|
||||||
@purchaser = create(:member_user)
|
post_webhook("checkout.session.completed", { user_upgrade_id: @user_upgrade.id })
|
||||||
|
|
||||||
post_webhook("checkout.session.completed", {
|
|
||||||
recipient_id: @recipient.id,
|
|
||||||
purchaser_id: @purchaser.id,
|
|
||||||
upgrade_type: "gold_to_platinum_upgrade",
|
|
||||||
level: User::Levels::PLATINUM,
|
|
||||||
})
|
|
||||||
|
|
||||||
assert_response 200
|
assert_response 200
|
||||||
assert_equal(User::Levels::PLATINUM, @recipient.reload.level)
|
assert_equal("complete", @user_upgrade.reload.status)
|
||||||
|
assert_equal(User::Levels::PLATINUM, @user_upgrade.recipient.reload.level)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,37 +3,45 @@ require 'test_helper'
|
|||||||
class UserUpgradeTest < ActiveSupport::TestCase
|
class UserUpgradeTest < ActiveSupport::TestCase
|
||||||
context "UserUpgrade:" do
|
context "UserUpgrade:" do
|
||||||
context "the #process_upgrade! method" do
|
context "the #process_upgrade! method" do
|
||||||
setup do
|
context "for a self upgrade" do
|
||||||
@user = create(:user)
|
context "to Gold" do
|
||||||
@user_upgrade = UserUpgrade.new(recipient: @user, purchaser: @user, level: User::Levels::GOLD)
|
setup do
|
||||||
end
|
@user_upgrade = create(:self_gold_upgrade)
|
||||||
|
|
||||||
should "update the user's level" do
|
|
||||||
@user_upgrade.process_upgrade!
|
|
||||||
assert_equal(User::Levels::GOLD, @user.reload.level)
|
|
||||||
end
|
|
||||||
|
|
||||||
should "log an account upgrade modaction" do
|
|
||||||
assert_difference("ModAction.user_account_upgrade.count") do
|
|
||||||
@user_upgrade.process_upgrade!
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "send the user a dmail" do
|
|
||||||
assert_difference("@user.dmails.received.count") do
|
|
||||||
@user_upgrade.process_upgrade!
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "for an upgrade for a user above Platinum level" do
|
|
||||||
should "not demote the user" do
|
|
||||||
@user.update!(level: User::Levels::BUILDER)
|
|
||||||
|
|
||||||
assert_raise(User::PrivilegeError) do
|
|
||||||
@user_upgrade.process_upgrade!
|
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal(true, @user.reload.is_builder?)
|
should "update the user's level if the payment status is paid" do
|
||||||
|
@user_upgrade.process_upgrade!("paid")
|
||||||
|
|
||||||
|
assert_equal(User::Levels::GOLD, @user_upgrade.recipient.level)
|
||||||
|
assert_equal("complete", @user_upgrade.status)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not update the user's level if the payment is unpaid" do
|
||||||
|
@user_upgrade.process_upgrade!("unpaid")
|
||||||
|
|
||||||
|
assert_equal(User::Levels::MEMBER, @user_upgrade.recipient.level)
|
||||||
|
assert_equal("processing", @user_upgrade.status)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not update the user's level if the upgrade status is complete" do
|
||||||
|
@user_upgrade.update!(status: "complete")
|
||||||
|
@user_upgrade.process_upgrade!("paid")
|
||||||
|
|
||||||
|
assert_equal(User::Levels::MEMBER, @user_upgrade.recipient.level)
|
||||||
|
assert_equal("complete", @user_upgrade.status)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "log an account upgrade modaction" do
|
||||||
|
assert_difference("ModAction.user_account_upgrade.count") do
|
||||||
|
@user_upgrade.process_upgrade!("paid")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "send the recipient a dmail" do
|
||||||
|
assert_difference("@user_upgrade.recipient.dmails.received.count") do
|
||||||
|
@user_upgrade.process_upgrade!("paid")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user