Compare commits
11
Commits
main
...
pricing-table
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fe7be7ef8 | ||
|
|
d6c4ec21ae | ||
|
|
c48cbc7071 | ||
|
|
66cf05943c | ||
|
|
e46693b94e | ||
|
|
fcc414dbbe | ||
|
|
411ac6ec80 | ||
|
|
ce988c9512 | ||
|
|
bf7079928e | ||
|
|
ff981f76e8 | ||
|
|
13d23dc3fa |
@@ -11,20 +11,7 @@ module DiscourseSubscriptions
|
||||
requires_login except: %i[index contributors show]
|
||||
|
||||
def index
|
||||
begin
|
||||
product_ids = Product.all.pluck(:external_id)
|
||||
products = []
|
||||
|
||||
if product_ids.present? && is_stripe_configured?
|
||||
response = ::Stripe::Product.list({ ids: product_ids, active: true })
|
||||
|
||||
products = response[:data].map { |p| serialize_product(p) }
|
||||
end
|
||||
|
||||
render_json_dump products
|
||||
rescue ::Stripe::InvalidRequestError => e
|
||||
render_json_error e.message
|
||||
end
|
||||
head 200
|
||||
end
|
||||
|
||||
def contributors
|
||||
|
||||
@@ -58,12 +58,14 @@ export default Component.extend({
|
||||
}
|
||||
|
||||
if (this.currentUser && this.showContributors) {
|
||||
return ajax("/s/contributors", { method: "get" }).then((result) => {
|
||||
this.setProperties({
|
||||
contributors: result,
|
||||
loading: false,
|
||||
});
|
||||
});
|
||||
return ajax("/subscriptions/contributors", { method: "get" }).then(
|
||||
(result) => {
|
||||
this.setProperties({
|
||||
contributors: result,
|
||||
loading: false,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import Controller from "@ember/controller";
|
||||
import User from "discourse/models/user";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Controller.extend({
|
||||
@discourseComputed()
|
||||
isLoggedIn() {
|
||||
return User.current();
|
||||
},
|
||||
});
|
||||
@@ -1,195 +0,0 @@
|
||||
/* global Stripe */
|
||||
import Controller from "@ember/controller";
|
||||
import { not } from "@ember/object/computed";
|
||||
import { inject as service } from "@ember/service";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "I18n";
|
||||
import Subscription from "discourse/plugins/discourse-subscriptions/discourse/models/subscription";
|
||||
import Transaction from "discourse/plugins/discourse-subscriptions/discourse/models/transaction";
|
||||
|
||||
export default Controller.extend({
|
||||
dialog: service(),
|
||||
router: service(),
|
||||
selectedPlan: null,
|
||||
promoCode: null,
|
||||
cardholderName: null,
|
||||
cardholderAddress: {
|
||||
line1: null,
|
||||
city: null,
|
||||
state: null,
|
||||
country: null,
|
||||
postalCode: null,
|
||||
},
|
||||
isAnonymous: not("currentUser"),
|
||||
isCountryUS: false,
|
||||
isCountryCA: false,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.set(
|
||||
"stripe",
|
||||
Stripe(this.siteSettings.discourse_subscriptions_public_key)
|
||||
);
|
||||
const elements = this.get("stripe").elements();
|
||||
|
||||
this.set("cardElement", elements.create("card", { hidePostalCode: true }));
|
||||
|
||||
this.set("isCountryUS", this.cardholderAddress.country === "US");
|
||||
this.set("isCountryCA", this.cardholderAddress.country === "CA");
|
||||
},
|
||||
|
||||
alert(path) {
|
||||
this.dialog.alert(I18n.t(`discourse_subscriptions.${path}`));
|
||||
},
|
||||
|
||||
@discourseComputed("model.product.repurchaseable", "model.product.subscribed")
|
||||
canPurchase(repurchaseable, subscribed) {
|
||||
if (!repurchaseable && subscribed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
createSubscription(plan) {
|
||||
return this.stripe
|
||||
.createToken(this.get("cardElement"), {
|
||||
name: this.cardholderName, // Recommended by Stripe
|
||||
address_line1: this.cardholderAddress.line1 ?? "",
|
||||
address_city: this.cardholderAddress.city ?? "",
|
||||
address_state: this.cardholderAddress.state ?? "",
|
||||
address_zip: this.cardholderAddress.postalCode ?? "",
|
||||
address_country: this.cardholderAddress.country, // Recommended by Stripe
|
||||
})
|
||||
.then((result) => {
|
||||
if (result.error) {
|
||||
this.set("loading", false);
|
||||
return result;
|
||||
} else {
|
||||
const subscription = Subscription.create({
|
||||
source: result.token.id,
|
||||
plan: plan.get("id"),
|
||||
promo: this.promoCode,
|
||||
cardholderName: this.cardholderName,
|
||||
cardholderAddress: this.cardholderAddress,
|
||||
});
|
||||
|
||||
return subscription.save();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
handleAuthentication(plan, transaction) {
|
||||
return this.stripe
|
||||
.confirmCardPayment(transaction.payment_intent.client_secret)
|
||||
.then((result) => {
|
||||
if (
|
||||
result.paymentIntent &&
|
||||
result.paymentIntent.status === "succeeded"
|
||||
) {
|
||||
return result;
|
||||
} else {
|
||||
this.set("loading", false);
|
||||
this.dialog.alert(result.error.message || result.error);
|
||||
return result;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_advanceSuccessfulTransaction(plan) {
|
||||
this.alert("plans.success");
|
||||
this.set("loading", false);
|
||||
|
||||
this.router.transitionTo(
|
||||
plan.type === "recurring"
|
||||
? "user.billing.subscriptions"
|
||||
: "user.billing.payments",
|
||||
this.currentUser.username.toLowerCase()
|
||||
);
|
||||
},
|
||||
|
||||
actions: {
|
||||
changeCountry(country) {
|
||||
this.set("cardholderAddress.country", country);
|
||||
this.set("isCountryUS", country === "US");
|
||||
this.set("isCountryCA", country === "CA");
|
||||
},
|
||||
|
||||
changeState(stateOrProvince) {
|
||||
this.set("cardholderAddress.state", stateOrProvince);
|
||||
},
|
||||
|
||||
stripePaymentHandler() {
|
||||
this.set("loading", true);
|
||||
const plan = this.get("model.plans")
|
||||
.filterBy("id", this.selectedPlan)
|
||||
.get("firstObject");
|
||||
const cardholderAddress = this.cardholderAddress;
|
||||
const cardholderName = this.cardholderName;
|
||||
|
||||
if (!plan) {
|
||||
this.alert("plans.validate.payment_options.required");
|
||||
this.set("loading", false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cardholderName) {
|
||||
this.alert("subscribe.invalid_cardholder_name");
|
||||
this.set("loading", false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cardholderAddress.country) {
|
||||
this.alert("subscribe.invalid_cardholder_country");
|
||||
this.set("loading", false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cardholderAddress.country === "US" && !cardholderAddress.state) {
|
||||
this.alert("subscribe.invalid_cardholder_state");
|
||||
this.set("loading", false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cardholderAddress.country === "CA" && !cardholderAddress.state) {
|
||||
this.alert("subscribe.invalid_cardholder_province");
|
||||
this.set("loading", false);
|
||||
return;
|
||||
}
|
||||
|
||||
let transaction = this.createSubscription(plan);
|
||||
|
||||
transaction
|
||||
.then((result) => {
|
||||
if (result.error) {
|
||||
this.dialog.alert(result.error.message || result.error);
|
||||
} else if (
|
||||
result.status === "incomplete" ||
|
||||
result.status === "open"
|
||||
) {
|
||||
const transactionId = result.id;
|
||||
const planId = this.selectedPlan;
|
||||
this.handleAuthentication(plan, result).then(
|
||||
(authenticationResult) => {
|
||||
if (authenticationResult && !authenticationResult.error) {
|
||||
return Transaction.finalize(transactionId, planId).then(
|
||||
() => {
|
||||
this._advanceSuccessfulTransaction(plan);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this._advanceSuccessfulTransaction(plan);
|
||||
}
|
||||
})
|
||||
.catch((result) => {
|
||||
this.dialog.alert(
|
||||
result.jqXHR.responseJSON.errors[0] || result.errorThrown
|
||||
);
|
||||
this.set("loading", false);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,3 +0,0 @@
|
||||
import Controller from "@ember/controller";
|
||||
|
||||
export default Controller.extend({});
|
||||
@@ -0,0 +1,37 @@
|
||||
import Controller from "@ember/controller";
|
||||
import { computed } from "@ember/object";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Controller.extend({
|
||||
init() {
|
||||
// Perform any initialization logic here
|
||||
this._super(...arguments);
|
||||
// Additional custom initialization code
|
||||
if (this.currentUser) {
|
||||
this.currentUser
|
||||
.checkEmail()
|
||||
.then(() => this.set("email", this.currentUser.email));
|
||||
}
|
||||
},
|
||||
pricingTable: computed("email", function () {
|
||||
try {
|
||||
const pricing_table_info = JSON.parse(
|
||||
this.siteSettings.discourse_subscriptions_pricing_table
|
||||
);
|
||||
if (this.currentUser) {
|
||||
return htmlSafe(`<stripe-pricing-table
|
||||
pricing-table-id="${pricing_table_info.pricingTableId}"
|
||||
publishable-key="${pricing_table_info.publishableKey}"
|
||||
customer-email="${this.email}"></stripe-pricing-table>`);
|
||||
} else {
|
||||
return htmlSafe(`<stripe-pricing-table
|
||||
pricing-table-id="${pricing_table_info.pricingTableId}"
|
||||
publishable-key="${pricing_table_info.publishableKey}"
|
||||
></stripe-pricing-table>`);
|
||||
}
|
||||
} catch (error) {
|
||||
return I18n.t("discourse_subscriptions.subscribe.no_products");
|
||||
}
|
||||
}),
|
||||
});
|
||||
@@ -12,7 +12,7 @@ export default {
|
||||
api.addNavigationBarItem({
|
||||
name: "subscribe",
|
||||
displayName: I18n.t("discourse_subscriptions.navigation.subscribe"),
|
||||
href: "/s",
|
||||
href: "/subscriptions",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -23,6 +23,36 @@ export default {
|
||||
href: `/u/${user.username}/billing/subscriptions`,
|
||||
content: "Billing",
|
||||
});
|
||||
|
||||
if (user.admin) {
|
||||
api.modifyClassStatic("model:site-setting", {
|
||||
pluginId: "discourse-subscriptions",
|
||||
update(key, value, opts = {}) {
|
||||
if (key === "discourse_subscriptions_pricing_table") {
|
||||
const inputString = value;
|
||||
// Extract pricing-table-id
|
||||
const pricingTableIdRegex = /pricing-table-id="([^"]+)"/;
|
||||
const pricingTableIdMatch =
|
||||
inputString.match(pricingTableIdRegex);
|
||||
const pricingTableId = pricingTableIdMatch
|
||||
? pricingTableIdMatch[1]
|
||||
: null;
|
||||
|
||||
// Extract publishable-key
|
||||
const publishableKeyRegex = /publishable-key="([^"]+)"/;
|
||||
const publishableKeyMatch =
|
||||
inputString.match(publishableKeyRegex);
|
||||
const publishableKey = publishableKeyMatch
|
||||
? publishableKeyMatch[1]
|
||||
: null;
|
||||
if (pricingTableId && publishableKey) {
|
||||
value = JSON.stringify({ pricingTableId, publishableKey });
|
||||
}
|
||||
}
|
||||
this._super(key, value, opts);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -40,12 +40,14 @@ const AdminProduct = EmberObject.extend({
|
||||
|
||||
AdminProduct.reopenClass({
|
||||
findAll() {
|
||||
return ajax("/s/admin/products", { method: "get" }).then((result) => {
|
||||
if (result === null) {
|
||||
return { unconfigured: true };
|
||||
return ajax("/subscriptions/admin/products", { method: "get" }).then(
|
||||
(result) => {
|
||||
if (result === null) {
|
||||
return { unconfigured: true };
|
||||
}
|
||||
return result.map((product) => AdminProduct.create(product));
|
||||
}
|
||||
return result.map((product) => AdminProduct.create(product));
|
||||
});
|
||||
);
|
||||
},
|
||||
|
||||
find(id) {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
export default function () {
|
||||
this.route("subscribe", { path: "/s" }, function () {
|
||||
this.route("show", { path: "/:subscription-id" });
|
||||
});
|
||||
this.route("subscriptions");
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
<div class="container">
|
||||
<div class="title-wrapper">
|
||||
<h1>
|
||||
{{i18n "discourse_subscriptions.subscribe.title"}}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
{{outlet}}
|
||||
</div>
|
||||
@@ -1,5 +0,0 @@
|
||||
{{#unless isLoggedIn}}
|
||||
<LoginRequired />
|
||||
{{/unless}}
|
||||
|
||||
<ProductList @products={{model}} @isLoggedIn={{isLoggedIn}} />
|
||||
@@ -1,126 +0,0 @@
|
||||
<div class="discourse-subscriptions-section-columns">
|
||||
<div class="section-column discourse-subscriptions-confirmation-billing">
|
||||
<h2>
|
||||
{{model.product.name}}
|
||||
</h2>
|
||||
|
||||
<hr />
|
||||
|
||||
<p>
|
||||
{{html-safe model.product.description}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section-column">
|
||||
{{#if canPurchase}}
|
||||
<h2>
|
||||
{{i18n "discourse_subscriptions.subscribe.card.title"}}
|
||||
</h2>
|
||||
|
||||
<hr />
|
||||
|
||||
<PaymentOptions @plans={{model.plans}} @selectedPlan={{selectedPlan}} />
|
||||
|
||||
<hr />
|
||||
|
||||
<SubscribeCard @cardElement={{cardElement}} />
|
||||
|
||||
{{#if loading}}
|
||||
{{loading-spinner}}
|
||||
{{else if isAnonymous}}
|
||||
<LoginRequired />
|
||||
{{else}}
|
||||
<Input
|
||||
@type="text"
|
||||
name="cardholder_name"
|
||||
placeholder={{i18n
|
||||
"discourse_subscriptions.subscribe.cardholder_name"
|
||||
}}
|
||||
@value={{cardholderName}}
|
||||
class="subscribe-name"
|
||||
/>
|
||||
<div class="address-fields">
|
||||
<SubscribeCountrySelect
|
||||
@value={{cardholderAddress.country}}
|
||||
@onChange={{action "changeCountry"}}
|
||||
/>
|
||||
<Input
|
||||
@type="text"
|
||||
name="cardholder_postal_code"
|
||||
placeholder={{i18n
|
||||
"discourse_subscriptions.subscribe.cardholder_address.postal_code"
|
||||
}}
|
||||
@value={{cardholderAddress.postalCode}}
|
||||
class="subscribe-address-postal-code"
|
||||
/>
|
||||
</div>
|
||||
<Input
|
||||
@type="text"
|
||||
name="cardholder_line1"
|
||||
placeholder={{i18n
|
||||
"discourse_subscriptions.subscribe.cardholder_address.line1"
|
||||
}}
|
||||
@value={{cardholderAddress.line1}}
|
||||
class="subscribe-address-line1"
|
||||
/>
|
||||
<div class="address-fields">
|
||||
<Input
|
||||
@type="text"
|
||||
name="cardholder_city"
|
||||
placeholder={{i18n
|
||||
"discourse_subscriptions.subscribe.cardholder_address.city"
|
||||
}}
|
||||
@value={{cardholderAddress.city}}
|
||||
class="subscribe-address-city"
|
||||
/>
|
||||
{{#if isCountryUS}}
|
||||
<SubscribeUsStateSelect
|
||||
@value={{cardholderAddress.state}}
|
||||
@onChange={{action "changeState"}}
|
||||
/>
|
||||
{{else if isCountryCA}}
|
||||
<SubscribeCaProvinceSelect
|
||||
@value={{cardholderAddress.state}}
|
||||
@onChange={{action "changeState"}}
|
||||
/>
|
||||
{{else}}
|
||||
<Input
|
||||
@type="text"
|
||||
name="cardholder_state"
|
||||
placeholder={{i18n
|
||||
"discourse_subscriptions.subscribe.cardholder_address.state"
|
||||
}}
|
||||
@value={{cardholderAddress.state}}
|
||||
class="subscribe-address-state"
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<Input
|
||||
@type="text"
|
||||
name="promo_code"
|
||||
placeholder={{i18n "discourse_subscriptions.subscribe.promo_code"}}
|
||||
@value={{promoCode}}
|
||||
class="subscribe-promo-code"
|
||||
/>
|
||||
|
||||
<DButton
|
||||
@disabled={{loading}}
|
||||
@action={{action "stripePaymentHandler"}}
|
||||
class="btn btn-primary btn-payment"
|
||||
@label="discourse_subscriptions.plans.payment_button"
|
||||
/>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<h2>{{i18n "discourse_subscriptions.subscribe.already_purchased"}}</h2>
|
||||
|
||||
<LinkTo
|
||||
@route="user.billing.subscriptions"
|
||||
@model={{currentUser.username}}
|
||||
class="btn btn-primary"
|
||||
>
|
||||
{{i18n "discourse_subscriptions.subscribe.go_to_billing"}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="container">
|
||||
{{pricingTable}}
|
||||
</div>
|
||||
@@ -7,6 +7,7 @@ en:
|
||||
site_settings:
|
||||
discourse_subscriptions_enabled: Enable the Discourse Subscriptions plugin.
|
||||
discourse_subscriptions_extra_nav_subscribe: Show the subscribe button in the primary navigation
|
||||
discourse_subscriptions_pricing_table: Copy and paste the stripe pricing table embed code here
|
||||
discourse_subscriptions_public_key: Stripe Publishable Key
|
||||
discourse_subscriptions_secret_key: Stripe Secret Key
|
||||
discourse_subscriptions_webhook_secret: Stripe Webhook Secret
|
||||
|
||||
@@ -4,6 +4,10 @@ discourse_subscriptions:
|
||||
discourse_subscriptions_extra_nav_subscribe:
|
||||
default: false
|
||||
client: true
|
||||
discourse_subscriptions_pricing_table:
|
||||
default: ''
|
||||
client: true
|
||||
refresh: true
|
||||
discourse_subscriptions_public_key:
|
||||
default: ''
|
||||
client: true
|
||||
|
||||
@@ -21,10 +21,19 @@ register_svg_icon "far-credit-card" if respond_to?(:register_svg_icon)
|
||||
register_html_builder("server:before-head-close") do |controller|
|
||||
"<script src='https://js.stripe.com/v3/' nonce='#{controller.helpers.csp_nonce_placeholder}'></script>"
|
||||
end
|
||||
register_html_builder("server:before-head-close") do |controller|
|
||||
"<script async src='https://js.stripe.com/v3/pricing-table.js' nonce='#{controller.helpers.csp_nonce_placeholder}'></script>"
|
||||
end
|
||||
|
||||
extend_content_security_policy(script_src: %w[https://js.stripe.com/v3/ https://hooks.stripe.com])
|
||||
extend_content_security_policy(
|
||||
script_src: %w[
|
||||
https://js.stripe.com/v3/
|
||||
https://hooks.stripe.com
|
||||
https://js.stripe.com/v3/pricing-table.js
|
||||
],
|
||||
)
|
||||
|
||||
add_admin_route "discourse_subscriptions.admin_navigation", "discourse-subscriptions.products"
|
||||
add_admin_route "discourse_subscriptions.admin_navigation", "discourse-subscriptions.plans"
|
||||
|
||||
Discourse::Application.routes.append do
|
||||
get "/admin/plugins/discourse-subscriptions" => "admin/plugins#index",
|
||||
@@ -65,14 +74,16 @@ require_relative "app/controllers/concerns/group"
|
||||
after_initialize do
|
||||
::Stripe.api_version = "2024-04-10"
|
||||
|
||||
Discourse::Application.routes.append do
|
||||
mount ::DiscourseSubscriptions::Engine, at: "subscriptions"
|
||||
end
|
||||
|
||||
::Stripe.set_app_info(
|
||||
"Discourse Subscriptions",
|
||||
version: "2.8.2",
|
||||
url: "https://github.com/discourse/discourse-subscriptions",
|
||||
)
|
||||
|
||||
Discourse::Application.routes.append { mount ::DiscourseSubscriptions::Engine, at: "s" }
|
||||
|
||||
add_to_serializer(:site, :show_campaign_banner) do
|
||||
begin
|
||||
enabled = SiteSetting.discourse_subscriptions_enabled
|
||||
|
||||
@@ -12,7 +12,7 @@ RSpec.describe DiscourseSubscriptions::Admin::CouponsController do
|
||||
context "when unauthenticated" do
|
||||
it "does nothing" do
|
||||
::Stripe::PromotionCode.expects(:list).never
|
||||
get "/s/admin/coupons.json"
|
||||
get "/subscriptions/admin/coupons.json"
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
end
|
||||
@@ -29,7 +29,7 @@ RSpec.describe DiscourseSubscriptions::Admin::CouponsController do
|
||||
.with({ limit: 100 })
|
||||
.returns({ data: [{ id: "promo_123", coupon: { valid: true } }] })
|
||||
|
||||
get "/s/admin/coupons.json"
|
||||
get "/subscriptions/admin/coupons.json"
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body[0]["id"]).to eq("promo_123")
|
||||
end
|
||||
@@ -40,7 +40,7 @@ RSpec.describe DiscourseSubscriptions::Admin::CouponsController do
|
||||
.with({ limit: 100 })
|
||||
.returns({ data: [{ id: "promo_123", coupon: { valid: false } }] })
|
||||
|
||||
get "/s/admin/coupons.json"
|
||||
get "/subscriptions/admin/coupons.json"
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body).to be_blank
|
||||
end
|
||||
@@ -53,7 +53,7 @@ RSpec.describe DiscourseSubscriptions::Admin::CouponsController do
|
||||
{ code: "p123", coupon: { amount_off: 2000 } },
|
||||
)
|
||||
|
||||
post "/s/admin/coupons.json",
|
||||
post "/subscriptions/admin/coupons.json",
|
||||
params: {
|
||||
promo: "p123",
|
||||
discount_type: "amount",
|
||||
@@ -71,7 +71,7 @@ RSpec.describe DiscourseSubscriptions::Admin::CouponsController do
|
||||
{ code: "p123", coupon: { percent_off: 20 } },
|
||||
)
|
||||
|
||||
post "/s/admin/coupons.json",
|
||||
post "/subscriptions/admin/coupons.json",
|
||||
params: {
|
||||
promo: "p123",
|
||||
discount_type: "percent",
|
||||
|
||||
@@ -13,11 +13,11 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
||||
describe "index" do
|
||||
it "does not get the plans" do
|
||||
::Stripe::Price.expects(:list).never
|
||||
get "/s/admin/plans.json"
|
||||
get "/subscriptions/admin/plans.json"
|
||||
end
|
||||
|
||||
it "not ok" do
|
||||
get "/s/admin/plans.json"
|
||||
get "/subscriptions/admin/plans.json"
|
||||
expect(response.status).to eq 404
|
||||
end
|
||||
end
|
||||
@@ -25,11 +25,21 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
||||
describe "create" do
|
||||
it "does not create a plan" do
|
||||
::Stripe::Price.expects(:create).never
|
||||
post "/s/admin/plans.json", params: { name: "Rick Astley", amount: 1, interval: "week" }
|
||||
post "/subscriptions/admin/plans.json",
|
||||
params: {
|
||||
name: "Rick Astley",
|
||||
amount: 1,
|
||||
interval: "week",
|
||||
}
|
||||
end
|
||||
|
||||
it "is not ok" do
|
||||
post "/s/admin/plans.json", params: { name: "Rick Astley", amount: 1, interval: "week" }
|
||||
post "/subscriptions/admin/plans.json",
|
||||
params: {
|
||||
name: "Rick Astley",
|
||||
amount: 1,
|
||||
interval: "week",
|
||||
}
|
||||
expect(response.status).to eq 404
|
||||
end
|
||||
end
|
||||
@@ -37,11 +47,11 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
||||
describe "show" do
|
||||
it "does not show the plan" do
|
||||
::Stripe::Price.expects(:retrieve).never
|
||||
get "/s/admin/plans/plan_12345.json"
|
||||
get "/subscriptions/admin/plans/plan_12345.json"
|
||||
end
|
||||
|
||||
it "is not ok" do
|
||||
get "/s/admin/plans/plan_12345.json"
|
||||
get "/subscriptions/admin/plans/plan_12345.json"
|
||||
expect(response.status).to eq 404
|
||||
end
|
||||
end
|
||||
@@ -49,7 +59,7 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
||||
describe "update" do
|
||||
it "does not update a plan" do
|
||||
::Stripe::Price.expects(:update).never
|
||||
delete "/s/admin/plans/plan_12345.json"
|
||||
delete "/subscriptions/admin/plans/plan_12345.json"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -62,19 +72,19 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
||||
describe "index" do
|
||||
it "lists the plans" do
|
||||
::Stripe::Price.expects(:list).with(nil)
|
||||
get "/s/admin/plans.json"
|
||||
get "/subscriptions/admin/plans.json"
|
||||
end
|
||||
|
||||
it "lists the plans for the product" do
|
||||
::Stripe::Price.expects(:list).with({ product: "prod_id123" })
|
||||
get "/s/admin/plans.json", params: { product_id: "prod_id123" }
|
||||
get "/subscriptions/admin/plans.json", params: { product_id: "prod_id123" }
|
||||
end
|
||||
end
|
||||
|
||||
describe "show" do
|
||||
it "shows a plan" do
|
||||
::Stripe::Price.expects(:retrieve).with("plan_12345").returns(currency: "aud")
|
||||
get "/s/admin/plans/plan_12345.json"
|
||||
get "/subscriptions/admin/plans/plan_12345.json"
|
||||
expect(response.status).to eq 200
|
||||
end
|
||||
|
||||
@@ -83,7 +93,7 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
||||
.expects(:retrieve)
|
||||
.with("plan_12345")
|
||||
.returns(currency: "aud", recurring: { interval: "year" })
|
||||
get "/s/admin/plans/plan_12345.json"
|
||||
get "/subscriptions/admin/plans/plan_12345.json"
|
||||
|
||||
plan = response.parsed_body
|
||||
expect(plan["currency"]).to eq "AUD"
|
||||
@@ -94,17 +104,29 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
||||
describe "create" do
|
||||
it "creates a plan with a nickname" do
|
||||
::Stripe::Price.expects(:create).with(has_entry(:nickname, "Veg"))
|
||||
post "/s/admin/plans.json", params: { nickname: "Veg", metadata: { group_name: "" } }
|
||||
post "/subscriptions/admin/plans.json",
|
||||
params: {
|
||||
nickname: "Veg",
|
||||
metadata: {
|
||||
group_name: "",
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
it "creates a plan with a currency" do
|
||||
::Stripe::Price.expects(:create).with(has_entry(:currency, "AUD"))
|
||||
post "/s/admin/plans.json", params: { currency: "AUD", metadata: { group_name: "" } }
|
||||
post "/subscriptions/admin/plans.json",
|
||||
params: {
|
||||
currency: "AUD",
|
||||
metadata: {
|
||||
group_name: "",
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
it "creates a plan with an interval" do
|
||||
::Stripe::Price.expects(:create).with(has_entry(recurring: { interval: "week" }))
|
||||
post "/s/admin/plans.json",
|
||||
post "/subscriptions/admin/plans.json",
|
||||
params: {
|
||||
type: "recurring",
|
||||
interval: "week",
|
||||
@@ -116,17 +138,23 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
||||
|
||||
it "creates a plan as a one-time purchase" do
|
||||
::Stripe::Price.expects(:create).with(Not(has_key(:recurring)))
|
||||
post "/s/admin/plans.json", params: { metadata: { group_name: "" } }
|
||||
post "/subscriptions/admin/plans.json", params: { metadata: { group_name: "" } }
|
||||
end
|
||||
|
||||
it "creates a plan with an amount" do
|
||||
::Stripe::Price.expects(:create).with(has_entry(:unit_amount, "102"))
|
||||
post "/s/admin/plans.json", params: { amount: "102", metadata: { group_name: "" } }
|
||||
post "/subscriptions/admin/plans.json",
|
||||
params: {
|
||||
amount: "102",
|
||||
metadata: {
|
||||
group_name: "",
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
it "creates a plan with a product" do
|
||||
::Stripe::Price.expects(:create).with(has_entry(product: "prod_walterwhite"))
|
||||
post "/s/admin/plans.json",
|
||||
post "/subscriptions/admin/plans.json",
|
||||
params: {
|
||||
product: "prod_walterwhite",
|
||||
metadata: {
|
||||
@@ -137,7 +165,13 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
||||
|
||||
it "creates a plan with an active status" do
|
||||
::Stripe::Price.expects(:create).with(has_entry(:active, "false"))
|
||||
post "/s/admin/plans.json", params: { active: "false", metadata: { group_name: "" } }
|
||||
post "/subscriptions/admin/plans.json",
|
||||
params: {
|
||||
active: "false",
|
||||
metadata: {
|
||||
group_name: "",
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
# TODO: Need to fix the metadata tests
|
||||
@@ -145,19 +179,19 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
||||
|
||||
#it 'has metadata' do
|
||||
# ::Stripe::Price.expects(:create).with(has_entry(:group_name, "discourse-user-group-name"))
|
||||
# post "/s/admin/plans.json", params: { amount: "100", metadata: { group_name: 'discourse-user-group-name' } }
|
||||
# post "/subscriptions/admin/plans.json", params: { amount: "100", metadata: { group_name: 'discourse-user-group-name' } }
|
||||
#end
|
||||
|
||||
#it "creates a plan with a trial period" do
|
||||
# ::Stripe::Price.expects(:create).with(has_entry(trial_period_days: '14'))
|
||||
# post "/s/admin/plans.json", params: { trial_period_days: '14' }
|
||||
# post "/subscriptions/admin/plans.json", params: { trial_period_days: '14' }
|
||||
#end
|
||||
end
|
||||
|
||||
describe "update" do
|
||||
it "updates a plan" do
|
||||
::Stripe::Price.expects(:update)
|
||||
patch "/s/admin/plans/plan_12345.json",
|
||||
patch "/subscriptions/admin/plans/plan_12345.json",
|
||||
params: {
|
||||
trial_period_days: "14",
|
||||
metadata: {
|
||||
|
||||
@@ -12,31 +12,31 @@ RSpec.describe DiscourseSubscriptions::Admin::ProductsController do
|
||||
context "when unauthenticated" do
|
||||
it "does not list the products" do
|
||||
::Stripe::Product.expects(:list).never
|
||||
get "/s/admin/products.json"
|
||||
get "/subscriptions/admin/products.json"
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
|
||||
it "does not create the product" do
|
||||
::Stripe::Product.expects(:create).never
|
||||
post "/s/admin/products.json"
|
||||
post "/subscriptions/admin/products.json"
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
|
||||
it "does not show the product" do
|
||||
::Stripe::Product.expects(:retrieve).never
|
||||
get "/s/admin/products/prod_qwerty123.json"
|
||||
get "/subscriptions/admin/products/prod_qwerty123.json"
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
|
||||
it "does not update the product" do
|
||||
::Stripe::Product.expects(:update).never
|
||||
put "/s/admin/products/prod_qwerty123.json"
|
||||
put "/subscriptions/admin/products/prod_qwerty123.json"
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
|
||||
it "does not delete the product" do
|
||||
::Stripe::Product.expects(:delete).never
|
||||
delete "/s/admin/products/u2.json"
|
||||
delete "/subscriptions/admin/products/u2.json"
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
end
|
||||
@@ -50,7 +50,7 @@ RSpec.describe DiscourseSubscriptions::Admin::ProductsController do
|
||||
it "gets the empty products" do
|
||||
SiteSetting.discourse_subscriptions_public_key = "public-key"
|
||||
SiteSetting.discourse_subscriptions_secret_key = "secret-key"
|
||||
get "/s/admin/products.json"
|
||||
get "/subscriptions/admin/products.json"
|
||||
expect(response.parsed_body).to be_empty
|
||||
end
|
||||
end
|
||||
@@ -58,24 +58,24 @@ RSpec.describe DiscourseSubscriptions::Admin::ProductsController do
|
||||
describe "create" do
|
||||
it "is of product type service" do
|
||||
::Stripe::Product.expects(:create).with(has_entry(:type, "service"))
|
||||
post "/s/admin/products.json", params: {}
|
||||
post "/subscriptions/admin/products.json", params: {}
|
||||
end
|
||||
|
||||
it "has a name" do
|
||||
::Stripe::Product.expects(:create).with(has_entry(:name, "Jesse Pinkman"))
|
||||
post "/s/admin/products.json", params: { name: "Jesse Pinkman" }
|
||||
post "/subscriptions/admin/products.json", params: { name: "Jesse Pinkman" }
|
||||
end
|
||||
|
||||
it "has an active attribute" do
|
||||
::Stripe::Product.expects(:create).with(has_entry(active: "false"))
|
||||
post "/s/admin/products.json", params: { active: "false" }
|
||||
post "/subscriptions/admin/products.json", params: { active: "false" }
|
||||
end
|
||||
|
||||
it "has a statement descriptor" do
|
||||
::Stripe::Product.expects(:create).with(
|
||||
has_entry(statement_descriptor: "Blessed are the cheesemakers"),
|
||||
)
|
||||
post "/s/admin/products.json",
|
||||
post "/subscriptions/admin/products.json",
|
||||
params: {
|
||||
statement_descriptor: "Blessed are the cheesemakers",
|
||||
}
|
||||
@@ -83,7 +83,7 @@ RSpec.describe DiscourseSubscriptions::Admin::ProductsController do
|
||||
|
||||
it "has no statement descriptor if empty" do
|
||||
::Stripe::Product.expects(:create).with(has_key(:statement_descriptor)).never
|
||||
post "/s/admin/products.json", params: { statement_descriptor: "" }
|
||||
post "/subscriptions/admin/products.json", params: { statement_descriptor: "" }
|
||||
end
|
||||
|
||||
it "has metadata" do
|
||||
@@ -96,7 +96,7 @@ RSpec.describe DiscourseSubscriptions::Admin::ProductsController do
|
||||
),
|
||||
)
|
||||
|
||||
post "/s/admin/products.json",
|
||||
post "/subscriptions/admin/products.json",
|
||||
params: {
|
||||
metadata: {
|
||||
description: "Oi, I think he just said bless be all the bignoses!",
|
||||
@@ -109,21 +109,21 @@ RSpec.describe DiscourseSubscriptions::Admin::ProductsController do
|
||||
describe "show" do
|
||||
it "retrieves the product" do
|
||||
::Stripe::Product.expects(:retrieve).with("prod_walterwhite")
|
||||
get "/s/admin/products/prod_walterwhite.json"
|
||||
get "/subscriptions/admin/products/prod_walterwhite.json"
|
||||
end
|
||||
end
|
||||
|
||||
describe "update" do
|
||||
it "updates the product" do
|
||||
::Stripe::Product.expects(:update)
|
||||
patch "/s/admin/products/prod_walterwhite.json", params: {}
|
||||
patch "/subscriptions/admin/products/prod_walterwhite.json", params: {}
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete" do
|
||||
it "deletes the product" do
|
||||
::Stripe::Product.expects(:delete).with("prod_walterwhite")
|
||||
delete "/s/admin/products/prod_walterwhite.json"
|
||||
delete "/subscriptions/admin/products/prod_walterwhite.json"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -24,13 +24,13 @@ RSpec.describe DiscourseSubscriptions::Admin::SubscriptionsController do
|
||||
context "when unauthenticated" do
|
||||
it "does nothing" do
|
||||
::Stripe::Subscription.expects(:list).never
|
||||
get "/s/admin/subscriptions.json"
|
||||
get "/subscriptions/admin/subscriptions.json"
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
|
||||
it "does not destroy a subscription" do
|
||||
::Stripe::Subscription.expects(:delete).never
|
||||
patch "/s/admin/subscriptions/sub_12345.json"
|
||||
patch "/subscriptions/admin/subscriptions/sub_12345.json"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -50,7 +50,7 @@ RSpec.describe DiscourseSubscriptions::Admin::SubscriptionsController do
|
||||
.expects(:list)
|
||||
.with(expand: ["data.plan.product"], limit: 10, starting_after: nil)
|
||||
.returns(has_more: false, data: [{ id: "sub_12345" }, { id: "sub_nope" }])
|
||||
get "/s/admin/subscriptions.json"
|
||||
get "/subscriptions/admin/subscriptions.json"
|
||||
subscriptions = response.parsed_body["data"][0]["id"]
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
@@ -62,7 +62,7 @@ RSpec.describe DiscourseSubscriptions::Admin::SubscriptionsController do
|
||||
.expects(:list)
|
||||
.with(expand: ["data.plan.product"], limit: 10, starting_after: "sub_nope")
|
||||
.returns(has_more: false, data: [{ id: "sub_77777" }, { id: "sub_yepnoep" }])
|
||||
get "/s/admin/subscriptions.json", params: { last_record: "sub_nope" }
|
||||
get "/subscriptions/admin/subscriptions.json", params: { last_record: "sub_nope" }
|
||||
subscriptions = response.parsed_body["data"][0]["id"]
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
@@ -81,7 +81,7 @@ RSpec.describe DiscourseSubscriptions::Admin::SubscriptionsController do
|
||||
.with("sub_12345")
|
||||
.returns(plan: { product: "pr_34578" }, customer: "c_123")
|
||||
|
||||
expect { delete "/s/admin/subscriptions/sub_12345.json" }.to change {
|
||||
expect { delete "/subscriptions/admin/subscriptions/sub_12345.json" }.to change {
|
||||
DiscourseSubscriptions::Customer.count
|
||||
}.by(-1)
|
||||
end
|
||||
@@ -100,7 +100,7 @@ RSpec.describe DiscourseSubscriptions::Admin::SubscriptionsController do
|
||||
customer: "c_123",
|
||||
)
|
||||
|
||||
expect { delete "/s/admin/subscriptions/sub_12345.json" }.to change {
|
||||
expect { delete "/subscriptions/admin/subscriptions/sub_12345.json" }.to change {
|
||||
user.groups.count
|
||||
}.by(-1)
|
||||
end
|
||||
@@ -119,7 +119,7 @@ RSpec.describe DiscourseSubscriptions::Admin::SubscriptionsController do
|
||||
customer: "c_123",
|
||||
)
|
||||
|
||||
expect { delete "/s/admin/subscriptions/sub_12345.json" }.not_to change {
|
||||
expect { delete "/subscriptions/admin/subscriptions/sub_12345.json" }.not_to change {
|
||||
user.groups.count
|
||||
}
|
||||
end
|
||||
@@ -136,7 +136,7 @@ RSpec.describe DiscourseSubscriptions::Admin::SubscriptionsController do
|
||||
::Stripe::Invoice.expects(:retrieve).with("in_123").returns(payment_intent: "pi_123")
|
||||
::Stripe::Refund.expects(:create).with({ payment_intent: "pi_123" })
|
||||
|
||||
delete "/s/admin/subscriptions/sub_12345.json", params: { refund: true }
|
||||
delete "/subscriptions/admin/subscriptions/sub_12345.json", params: { refund: true }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,7 +15,7 @@ RSpec.describe DiscourseSubscriptions::AdminController do
|
||||
end
|
||||
|
||||
it "is ok" do
|
||||
get "/s/admin.json"
|
||||
get "/subscriptions/admin.json"
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,7 +17,7 @@ RSpec.describe DiscourseSubscriptions::HooksController do
|
||||
.with("we-want-a-shrubbery", "stripe-webhook-signature", "zascharoo")
|
||||
.returns(type: "something")
|
||||
|
||||
post "/s/hooks.json", params: payload, headers: headers
|
||||
post "/subscriptions/hooks.json", params: payload, headers: headers
|
||||
|
||||
expect(response.status).to eq 200
|
||||
end
|
||||
@@ -51,7 +51,7 @@ RSpec.describe DiscourseSubscriptions::HooksController do
|
||||
end
|
||||
|
||||
it "is successfull" do
|
||||
post "/s/hooks.json"
|
||||
post "/subscriptions/hooks.json"
|
||||
expect(response.status).to eq 200
|
||||
end
|
||||
|
||||
@@ -60,7 +60,7 @@ RSpec.describe DiscourseSubscriptions::HooksController do
|
||||
event_data[:object][:status] = "incomplete"
|
||||
event_data[:previous_attributes] = { status: "incomplete" }
|
||||
|
||||
expect { post "/s/hooks.json" }.not_to change { user.groups.count }
|
||||
expect { post "/subscriptions/hooks.json" }.not_to change { user.groups.count }
|
||||
|
||||
expect(response.status).to eq 200
|
||||
end
|
||||
@@ -69,7 +69,7 @@ RSpec.describe DiscourseSubscriptions::HooksController do
|
||||
event_data[:object][:status] = "incomplete"
|
||||
event_data[:previous_attributes] = { status: "something-else" }
|
||||
|
||||
expect { post "/s/hooks.json" }.not_to change { user.groups.count }
|
||||
expect { post "/subscriptions/hooks.json" }.not_to change { user.groups.count }
|
||||
|
||||
expect(response.status).to eq 200
|
||||
end
|
||||
@@ -78,7 +78,7 @@ RSpec.describe DiscourseSubscriptions::HooksController do
|
||||
event_data[:object][:status] = "complete"
|
||||
event_data[:previous_attributes] = { status: "incomplete" }
|
||||
|
||||
expect { post "/s/hooks.json" }.to change { user.groups.count }.by(1)
|
||||
expect { post "/subscriptions/hooks.json" }.to change { user.groups.count }.by(1)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
end
|
||||
@@ -95,13 +95,15 @@ RSpec.describe DiscourseSubscriptions::HooksController do
|
||||
end
|
||||
|
||||
it "deletes the customer" do
|
||||
expect { post "/s/hooks.json" }.to change { DiscourseSubscriptions::Customer.count }.by(-1)
|
||||
expect { post "/subscriptions/hooks.json" }.to change {
|
||||
DiscourseSubscriptions::Customer.count
|
||||
}.by(-1)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
end
|
||||
|
||||
it "removes the user from the group" do
|
||||
expect { post "/s/hooks.json" }.to change { user.groups.count }.by(-1)
|
||||
expect { post "/subscriptions/hooks.json" }.to change { user.groups.count }.by(-1)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
end
|
||||
|
||||
@@ -68,56 +68,6 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
SiteSetting.discourse_subscriptions_secret_key = "secret-key"
|
||||
end
|
||||
|
||||
describe "#index" do
|
||||
it "gets products" do
|
||||
::Stripe::Product
|
||||
.expects(:list)
|
||||
.with({ ids: product_ids, active: true })
|
||||
.returns(data: [product])
|
||||
|
||||
get "/s.json"
|
||||
|
||||
expect(response.parsed_body).to eq(
|
||||
[
|
||||
{
|
||||
"id" => "prodct_23456",
|
||||
"name" => "Very Special Product",
|
||||
"description" =>
|
||||
PrettyText.cook(
|
||||
"Many people listened to my phone call with the Ukrainian President while it was being made",
|
||||
),
|
||||
"subscribed" => false,
|
||||
"repurchaseable" => false,
|
||||
},
|
||||
],
|
||||
)
|
||||
end
|
||||
|
||||
it "is subscribed" do
|
||||
Fabricate(:customer, product_id: product[:id], user_id: user.id, customer_id: "x")
|
||||
::Stripe::Product
|
||||
.expects(:list)
|
||||
.with({ ids: product_ids, active: true })
|
||||
.returns(data: [product])
|
||||
|
||||
get "/s.json"
|
||||
data = response.parsed_body
|
||||
expect(data.first["subscribed"]).to eq true
|
||||
end
|
||||
|
||||
it "is not subscribed" do
|
||||
::DiscourseSubscriptions::Customer.delete_all
|
||||
::Stripe::Product
|
||||
.expects(:list)
|
||||
.with({ ids: product_ids, active: true })
|
||||
.returns(data: [product])
|
||||
|
||||
get "/s.json"
|
||||
data = response.parsed_body
|
||||
expect(data.first["subscribed"]).to eq false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#get_contributors" do
|
||||
before do
|
||||
Fabricate(:product, external_id: "prod_campaign")
|
||||
@@ -132,7 +82,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
context "when not showing contributors" do
|
||||
it "returns nothing if not set to show contributors" do
|
||||
SiteSetting.discourse_subscriptions_campaign_show_contributors = false
|
||||
get "/s/contributors.json"
|
||||
get "/subscriptions/contributors.json"
|
||||
|
||||
data = response.parsed_body
|
||||
expect(data).to be_empty
|
||||
@@ -145,7 +95,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
it "filters users by campaign product if set" do
|
||||
SiteSetting.discourse_subscriptions_campaign_product = "prod_campaign"
|
||||
|
||||
get "/s/contributors.json"
|
||||
get "/subscriptions/contributors.json"
|
||||
|
||||
data = response.parsed_body
|
||||
expect(data.first["id"]).to eq campaign_user.id
|
||||
@@ -155,7 +105,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
it "shows all purchases if campaign product not set" do
|
||||
SiteSetting.discourse_subscriptions_campaign_product = nil
|
||||
|
||||
get "/s/contributors.json"
|
||||
get "/subscriptions/contributors.json"
|
||||
|
||||
data = response.parsed_body
|
||||
expect(data.length).to eq 2
|
||||
@@ -170,7 +120,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
.expects(:list)
|
||||
.with(active: true, product: "prod_walterwhite")
|
||||
.returns(prices)
|
||||
get "/s/prod_walterwhite.json"
|
||||
get "/subscriptions/prod_walterwhite.json"
|
||||
|
||||
expect(response.parsed_body).to eq(
|
||||
{
|
||||
@@ -222,7 +172,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
::Stripe::Customer.expects(:create).never
|
||||
::Stripe::Price.expects(:retrieve).never
|
||||
::Stripe::Subscription.expects(:create).never
|
||||
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
post "/subscriptions/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -257,7 +207,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
.returns(status: "active", customer: "cus_1234")
|
||||
|
||||
expect {
|
||||
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
post "/subscriptions/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
}.to change { DiscourseSubscriptions::Customer.count }
|
||||
end
|
||||
|
||||
@@ -291,7 +241,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
::Stripe::Invoice.expects(:pay).returns(status: "paid", customer: "cus_1234")
|
||||
|
||||
expect {
|
||||
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
post "/subscriptions/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
}.to change { DiscourseSubscriptions::Customer.count }
|
||||
end
|
||||
|
||||
@@ -300,13 +250,13 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
::Stripe::Subscription.expects(:create).returns(status: "active", customer: "cus_1234")
|
||||
|
||||
expect {
|
||||
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
post "/subscriptions/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
}.to change { DiscourseSubscriptions::Customer.count }
|
||||
|
||||
::Stripe::Customer.expects(:retrieve).with("cus_1234")
|
||||
|
||||
expect {
|
||||
post "/s/create.json", params: { plan: "plan_5678", source: "tok_5678" }
|
||||
post "/subscriptions/create.json", params: { plan: "plan_5678", source: "tok_5678" }
|
||||
}.not_to change { DiscourseSubscriptions::Customer.count }
|
||||
end
|
||||
|
||||
@@ -315,7 +265,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
::Stripe::Price.expects(:retrieve).returns(type: "recurring", metadata: {})
|
||||
::Stripe::Subscription.expects(:create).returns(status: "active", customer: "cus_1234")
|
||||
expect {
|
||||
post "/s/create.json",
|
||||
post "/subscriptions/create.json",
|
||||
params: {
|
||||
plan: "plan_1234",
|
||||
source: "tok_1234",
|
||||
@@ -346,7 +296,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
|
||||
::Stripe::PromotionCode.expects(:list).with({ code: "invalid" }).returns(data: [])
|
||||
|
||||
post "/s/create.json",
|
||||
post "/subscriptions/create.json",
|
||||
params: {
|
||||
plan: "plan_1234",
|
||||
source: "tok_1234",
|
||||
@@ -391,7 +341,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
.returns(status: "active", customer: "cus_1234")
|
||||
|
||||
expect {
|
||||
post "/s/create.json",
|
||||
post "/subscriptions/create.json",
|
||||
params: {
|
||||
plan: "plan_1234",
|
||||
source: "tok_1234",
|
||||
@@ -434,7 +384,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
::Stripe::Invoice.expects(:pay).returns(status: "paid", customer: "cus_1234")
|
||||
|
||||
expect {
|
||||
post "/s/create.json",
|
||||
post "/subscriptions/create.json",
|
||||
params: {
|
||||
plan: "plan_1234",
|
||||
source: "tok_1234",
|
||||
@@ -462,7 +412,11 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
)
|
||||
|
||||
expect {
|
||||
post "/s/finalize.json", params: { plan: "plan_1234", transaction: "sub_1234" }
|
||||
post "/subscriptions/finalize.json",
|
||||
params: {
|
||||
plan: "plan_1234",
|
||||
transaction: "sub_1234",
|
||||
}
|
||||
}.to change { DiscourseSubscriptions::Customer.count }
|
||||
end
|
||||
end
|
||||
@@ -482,7 +436,11 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
)
|
||||
|
||||
expect {
|
||||
post "/s/finalize.json", params: { plan: "plan_1234", transaction: "in_1234" }
|
||||
post "/subscriptions/finalize.json",
|
||||
params: {
|
||||
plan: "plan_1234",
|
||||
transaction: "in_1234",
|
||||
}
|
||||
}.to change { DiscourseSubscriptions::Customer.count }
|
||||
end
|
||||
end
|
||||
@@ -505,7 +463,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
group_name: "admins",
|
||||
},
|
||||
)
|
||||
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
post "/subscriptions/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
expect(user.admin).to eq false
|
||||
end
|
||||
|
||||
@@ -516,7 +474,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
group_name: "other",
|
||||
},
|
||||
)
|
||||
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
post "/subscriptions/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
expect(user.groups).to be_empty
|
||||
end
|
||||
end
|
||||
@@ -536,7 +494,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
::Stripe::Subscription.expects(:create).returns(status: "failed")
|
||||
|
||||
expect {
|
||||
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
post "/subscriptions/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
}.not_to change { group.users.count }
|
||||
|
||||
expect(user.groups).to be_empty
|
||||
@@ -546,7 +504,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
::Stripe::Subscription.expects(:create).returns(status: "active")
|
||||
|
||||
expect {
|
||||
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
post "/subscriptions/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
}.to change { group.users.count }
|
||||
|
||||
expect(user.groups).not_to be_empty
|
||||
@@ -556,7 +514,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
||||
::Stripe::Subscription.expects(:create).returns(status: "trialing")
|
||||
|
||||
expect {
|
||||
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
post "/subscriptions/create.json", params: { plan: "plan_1234", source: "tok_1234" }
|
||||
}.to change { group.users.count }
|
||||
|
||||
expect(user.groups).not_to be_empty
|
||||
|
||||
@@ -12,7 +12,7 @@ RSpec.describe DiscourseSubscriptions::User::PaymentsController do
|
||||
context "when not authenticated" do
|
||||
it "does not get the payment intents" do
|
||||
::Stripe::PaymentIntent.expects(:list).never
|
||||
get "/s/user/payments.json"
|
||||
get "/subscriptions/user/payments.json"
|
||||
expect(response.status).to eq(403)
|
||||
end
|
||||
end
|
||||
@@ -52,7 +52,7 @@ RSpec.describe DiscourseSubscriptions::User::PaymentsController do
|
||||
],
|
||||
)
|
||||
|
||||
get "/s/user/payments.json"
|
||||
get "/subscriptions/user/payments.json"
|
||||
|
||||
parsed_body = response.parsed_body
|
||||
invoice = parsed_body[0]["invoice"]
|
||||
|
||||
@@ -14,18 +14,21 @@ RSpec.describe DiscourseSubscriptions::User::SubscriptionsController do
|
||||
context "when not authenticated" do
|
||||
it "does not get the subscriptions" do
|
||||
::Stripe::Customer.expects(:list).never
|
||||
get "/s/user/subscriptions.json"
|
||||
get "/subscriptions/user/subscriptions.json"
|
||||
end
|
||||
|
||||
it "does not destroy a subscription" do
|
||||
::Stripe::Subscription.expects(:delete).never
|
||||
patch "/s/user/subscriptions/sub_12345.json"
|
||||
patch "/subscriptions/user/subscriptions/sub_12345.json"
|
||||
end
|
||||
|
||||
it "doesn't update payment method for subscription" do
|
||||
::Stripe::Subscription.expects(:update).never
|
||||
::Stripe::PaymentMethod.expects(:attach).never
|
||||
put "/s/user/subscriptions/sub_12345.json", params: { payment_method: "pm_abc123abc" }
|
||||
put "/subscriptions/user/subscriptions/sub_12345.json",
|
||||
params: {
|
||||
payment_method: "pm_abc123abc",
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -74,7 +77,7 @@ RSpec.describe DiscourseSubscriptions::User::SubscriptionsController do
|
||||
.with(email: user.email, expand: ["data.subscriptions"])
|
||||
.returns(customers)
|
||||
|
||||
get "/s/user/subscriptions.json"
|
||||
get "/subscriptions/user/subscriptions.json"
|
||||
|
||||
subscription = response.parsed_body.first
|
||||
|
||||
@@ -100,7 +103,10 @@ RSpec.describe DiscourseSubscriptions::User::SubscriptionsController do
|
||||
it "updates the payment method for subscription" do
|
||||
::Stripe::Subscription.expects(:update).once
|
||||
::Stripe::PaymentMethod.expects(:attach).once
|
||||
put "/s/user/subscriptions/sub_1234.json", params: { payment_method: "pm_abc123abc" }
|
||||
put "/subscriptions/user/subscriptions/sub_1234.json",
|
||||
params: {
|
||||
payment_method: "pm_abc123abc",
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -29,7 +29,7 @@ describe "Subscription products", type: :system do
|
||||
end
|
||||
|
||||
it "shows the login modal" do
|
||||
visit("/s")
|
||||
visit("/subscriptions")
|
||||
|
||||
find("button.login-required.subscriptions").click
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import { acceptance, count } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { stubStripe } from "discourse/plugins/discourse-subscriptions/helpers/stripe";
|
||||
|
||||
acceptance("Discourse Subscriptions", function (needs) {
|
||||
needs.user();
|
||||
needs.hooks.beforeEach(function () {
|
||||
stubStripe();
|
||||
});
|
||||
|
||||
test("viewing product page", async function (assert) {
|
||||
await visit("/s");
|
||||
|
||||
assert.ok(count(".product-list") > 0, "has product page");
|
||||
assert.ok(count(".product:first-child a") > 0, "has a link");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
import { visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("Discourse Subscriptions", function (needs) {
|
||||
needs.user();
|
||||
needs.settings({
|
||||
discourse_subscriptions_pricing_table: JSON.stringify({
|
||||
pricingTableId: "pricingTableId",
|
||||
publishableKey: "publishableKey",
|
||||
}),
|
||||
});
|
||||
|
||||
test("pricing table element includes email", async function (assert) {
|
||||
await visit("/subscriptions");
|
||||
|
||||
assert.equal(
|
||||
document.querySelector("stripe-pricing-table").outerHTML,
|
||||
`<stripe-pricing-table pricing-table-id="pricingTableId" publishable-key="publishableKey" customer-email="[email protected]"></stripe-pricing-table>`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
acceptance("Discourse Subscriptions", function (needs) {
|
||||
needs.settings({
|
||||
discourse_subscriptions_pricing_table: JSON.stringify({
|
||||
pricingTableId: "pricingTableId",
|
||||
publishableKey: "publishableKey",
|
||||
}),
|
||||
});
|
||||
|
||||
test("pricing table works for people without account", async function (assert) {
|
||||
await visit("/subscriptions");
|
||||
|
||||
assert.equal(
|
||||
document.querySelector("stripe-pricing-table").outerHTML,
|
||||
`<stripe-pricing-table pricing-table-id="pricingTableId" publishable-key="publishableKey"></stripe-pricing-table>`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
acceptance("Discourse Subscriptions", function (needs) {
|
||||
needs.user();
|
||||
|
||||
test("pricing table element does not show up if not configured", async function (assert) {
|
||||
await visit("/subscriptions");
|
||||
|
||||
assert.equal(document.querySelector("stripe-pricing-table"), null);
|
||||
});
|
||||
});
|
||||
@@ -1,66 +0,0 @@
|
||||
import { click, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import pretender, { response } from "discourse/tests/helpers/create-pretender";
|
||||
import { acceptance, count } from "discourse/tests/helpers/qunit-helpers";
|
||||
import I18n from "discourse-i18n";
|
||||
import { stubStripe } from "discourse/plugins/discourse-subscriptions/helpers/stripe";
|
||||
|
||||
function singleProductPretender() {
|
||||
pretender.get("/s", () => {
|
||||
const products = [
|
||||
{
|
||||
id: "prod_23o8I7tU4g56",
|
||||
name: "Awesome Product",
|
||||
description:
|
||||
"Subscribe to our awesome product. For only $230.10 per month, you can get access. This is a test site. No real credit card transactions.",
|
||||
},
|
||||
];
|
||||
|
||||
return response(products);
|
||||
});
|
||||
}
|
||||
|
||||
acceptance("Discourse Subscriptions", function (needs) {
|
||||
needs.user();
|
||||
needs.hooks.beforeEach(function () {
|
||||
stubStripe();
|
||||
});
|
||||
|
||||
test("subscribing", async function (assert) {
|
||||
await visit("/s");
|
||||
await click(".product:first-child a");
|
||||
|
||||
assert.ok(
|
||||
count(".discourse-subscriptions-section-columns") > 0,
|
||||
"has the sections for billing"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
count(".subscribe-buttons button") > 0,
|
||||
"has buttons for subscribe"
|
||||
);
|
||||
});
|
||||
|
||||
test("skips products list on sites with one product", async function (assert) {
|
||||
singleProductPretender();
|
||||
|
||||
await visit("/s");
|
||||
|
||||
assert.dom(".subscribe-buttons button").exists({ count: 1 });
|
||||
assert.dom("input.subscribe-promo-code").exists();
|
||||
assert.dom("button.btn-payment").exists();
|
||||
});
|
||||
|
||||
// In YAML `NO:` is a boolean, so we need quotes around `"NO":`.
|
||||
test("Norway is translated correctly", async function (assert) {
|
||||
assert.equal(
|
||||
I18n.t("discourse_subscriptions.subscribe.countries.NO"),
|
||||
"Norway"
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
I18n.t("discourse_subscriptions.subscribe.countries.NG"),
|
||||
"Nigeria"
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
export default function (helpers) {
|
||||
const { response } = helpers;
|
||||
|
||||
this.get("/s", () => {
|
||||
this.get("/subscriptions", () => {
|
||||
const products = [
|
||||
{
|
||||
id: "prod_23o8I7tU4g56",
|
||||
@@ -20,7 +20,7 @@ export default function (helpers) {
|
||||
return response(products);
|
||||
});
|
||||
|
||||
this.get("/s/:id", () => {
|
||||
this.get("/subscriptions/:id", () => {
|
||||
const product = {
|
||||
id: "prod_23o8I7tU4g56",
|
||||
name: "Awesome Product",
|
||||
|
||||
Reference in New Issue
Block a user