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]
|
requires_login except: %i[index contributors show]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
begin
|
head 200
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def contributors
|
def contributors
|
||||||
|
|||||||
@@ -58,12 +58,14 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.currentUser && this.showContributors) {
|
if (this.currentUser && this.showContributors) {
|
||||||
return ajax("/s/contributors", { method: "get" }).then((result) => {
|
return ajax("/subscriptions/contributors", { method: "get" }).then(
|
||||||
this.setProperties({
|
(result) => {
|
||||||
contributors: result,
|
this.setProperties({
|
||||||
loading: false,
|
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({
|
api.addNavigationBarItem({
|
||||||
name: "subscribe",
|
name: "subscribe",
|
||||||
displayName: I18n.t("discourse_subscriptions.navigation.subscribe"),
|
displayName: I18n.t("discourse_subscriptions.navigation.subscribe"),
|
||||||
href: "/s",
|
href: "/subscriptions",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,6 +23,36 @@ export default {
|
|||||||
href: `/u/${user.username}/billing/subscriptions`,
|
href: `/u/${user.username}/billing/subscriptions`,
|
||||||
content: "Billing",
|
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({
|
AdminProduct.reopenClass({
|
||||||
findAll() {
|
findAll() {
|
||||||
return ajax("/s/admin/products", { method: "get" }).then((result) => {
|
return ajax("/subscriptions/admin/products", { method: "get" }).then(
|
||||||
if (result === null) {
|
(result) => {
|
||||||
return { unconfigured: true };
|
if (result === null) {
|
||||||
|
return { unconfigured: true };
|
||||||
|
}
|
||||||
|
return result.map((product) => AdminProduct.create(product));
|
||||||
}
|
}
|
||||||
return result.map((product) => AdminProduct.create(product));
|
);
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
find(id) {
|
find(id) {
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
export default function () {
|
export default function () {
|
||||||
this.route("subscribe", { path: "/s" }, function () {
|
this.route("subscriptions");
|
||||||
this.route("show", { path: "/:subscription-id" });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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:
|
site_settings:
|
||||||
discourse_subscriptions_enabled: Enable the Discourse Subscriptions plugin.
|
discourse_subscriptions_enabled: Enable the Discourse Subscriptions plugin.
|
||||||
discourse_subscriptions_extra_nav_subscribe: Show the subscribe button in the primary navigation
|
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_public_key: Stripe Publishable Key
|
||||||
discourse_subscriptions_secret_key: Stripe Secret Key
|
discourse_subscriptions_secret_key: Stripe Secret Key
|
||||||
discourse_subscriptions_webhook_secret: Stripe Webhook Secret
|
discourse_subscriptions_webhook_secret: Stripe Webhook Secret
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ discourse_subscriptions:
|
|||||||
discourse_subscriptions_extra_nav_subscribe:
|
discourse_subscriptions_extra_nav_subscribe:
|
||||||
default: false
|
default: false
|
||||||
client: true
|
client: true
|
||||||
|
discourse_subscriptions_pricing_table:
|
||||||
|
default: ''
|
||||||
|
client: true
|
||||||
|
refresh: true
|
||||||
discourse_subscriptions_public_key:
|
discourse_subscriptions_public_key:
|
||||||
default: ''
|
default: ''
|
||||||
client: true
|
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|
|
register_html_builder("server:before-head-close") do |controller|
|
||||||
"<script src='https://js.stripe.com/v3/' nonce='#{controller.helpers.csp_nonce_placeholder}'></script>"
|
"<script src='https://js.stripe.com/v3/' nonce='#{controller.helpers.csp_nonce_placeholder}'></script>"
|
||||||
end
|
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
|
Discourse::Application.routes.append do
|
||||||
get "/admin/plugins/discourse-subscriptions" => "admin/plugins#index",
|
get "/admin/plugins/discourse-subscriptions" => "admin/plugins#index",
|
||||||
@@ -65,14 +74,16 @@ require_relative "app/controllers/concerns/group"
|
|||||||
after_initialize do
|
after_initialize do
|
||||||
::Stripe.api_version = "2024-04-10"
|
::Stripe.api_version = "2024-04-10"
|
||||||
|
|
||||||
|
Discourse::Application.routes.append do
|
||||||
|
mount ::DiscourseSubscriptions::Engine, at: "subscriptions"
|
||||||
|
end
|
||||||
|
|
||||||
::Stripe.set_app_info(
|
::Stripe.set_app_info(
|
||||||
"Discourse Subscriptions",
|
"Discourse Subscriptions",
|
||||||
version: "2.8.2",
|
version: "2.8.2",
|
||||||
url: "https://github.com/discourse/discourse-subscriptions",
|
url: "https://github.com/discourse/discourse-subscriptions",
|
||||||
)
|
)
|
||||||
|
|
||||||
Discourse::Application.routes.append { mount ::DiscourseSubscriptions::Engine, at: "s" }
|
|
||||||
|
|
||||||
add_to_serializer(:site, :show_campaign_banner) do
|
add_to_serializer(:site, :show_campaign_banner) do
|
||||||
begin
|
begin
|
||||||
enabled = SiteSetting.discourse_subscriptions_enabled
|
enabled = SiteSetting.discourse_subscriptions_enabled
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ RSpec.describe DiscourseSubscriptions::Admin::CouponsController do
|
|||||||
context "when unauthenticated" do
|
context "when unauthenticated" do
|
||||||
it "does nothing" do
|
it "does nothing" do
|
||||||
::Stripe::PromotionCode.expects(:list).never
|
::Stripe::PromotionCode.expects(:list).never
|
||||||
get "/s/admin/coupons.json"
|
get "/subscriptions/admin/coupons.json"
|
||||||
expect(response.status).to eq(404)
|
expect(response.status).to eq(404)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -29,7 +29,7 @@ RSpec.describe DiscourseSubscriptions::Admin::CouponsController do
|
|||||||
.with({ limit: 100 })
|
.with({ limit: 100 })
|
||||||
.returns({ data: [{ id: "promo_123", coupon: { valid: true } }] })
|
.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.status).to eq(200)
|
||||||
expect(response.parsed_body[0]["id"]).to eq("promo_123")
|
expect(response.parsed_body[0]["id"]).to eq("promo_123")
|
||||||
end
|
end
|
||||||
@@ -40,7 +40,7 @@ RSpec.describe DiscourseSubscriptions::Admin::CouponsController do
|
|||||||
.with({ limit: 100 })
|
.with({ limit: 100 })
|
||||||
.returns({ data: [{ id: "promo_123", coupon: { valid: false } }] })
|
.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.status).to eq(200)
|
||||||
expect(response.parsed_body).to be_blank
|
expect(response.parsed_body).to be_blank
|
||||||
end
|
end
|
||||||
@@ -53,7 +53,7 @@ RSpec.describe DiscourseSubscriptions::Admin::CouponsController do
|
|||||||
{ code: "p123", coupon: { amount_off: 2000 } },
|
{ code: "p123", coupon: { amount_off: 2000 } },
|
||||||
)
|
)
|
||||||
|
|
||||||
post "/s/admin/coupons.json",
|
post "/subscriptions/admin/coupons.json",
|
||||||
params: {
|
params: {
|
||||||
promo: "p123",
|
promo: "p123",
|
||||||
discount_type: "amount",
|
discount_type: "amount",
|
||||||
@@ -71,7 +71,7 @@ RSpec.describe DiscourseSubscriptions::Admin::CouponsController do
|
|||||||
{ code: "p123", coupon: { percent_off: 20 } },
|
{ code: "p123", coupon: { percent_off: 20 } },
|
||||||
)
|
)
|
||||||
|
|
||||||
post "/s/admin/coupons.json",
|
post "/subscriptions/admin/coupons.json",
|
||||||
params: {
|
params: {
|
||||||
promo: "p123",
|
promo: "p123",
|
||||||
discount_type: "percent",
|
discount_type: "percent",
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
|||||||
describe "index" do
|
describe "index" do
|
||||||
it "does not get the plans" do
|
it "does not get the plans" do
|
||||||
::Stripe::Price.expects(:list).never
|
::Stripe::Price.expects(:list).never
|
||||||
get "/s/admin/plans.json"
|
get "/subscriptions/admin/plans.json"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "not ok" do
|
it "not ok" do
|
||||||
get "/s/admin/plans.json"
|
get "/subscriptions/admin/plans.json"
|
||||||
expect(response.status).to eq 404
|
expect(response.status).to eq 404
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -25,11 +25,21 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
|||||||
describe "create" do
|
describe "create" do
|
||||||
it "does not create a plan" do
|
it "does not create a plan" do
|
||||||
::Stripe::Price.expects(:create).never
|
::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
|
end
|
||||||
|
|
||||||
it "is not ok" do
|
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
|
expect(response.status).to eq 404
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -37,11 +47,11 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
|||||||
describe "show" do
|
describe "show" do
|
||||||
it "does not show the plan" do
|
it "does not show the plan" do
|
||||||
::Stripe::Price.expects(:retrieve).never
|
::Stripe::Price.expects(:retrieve).never
|
||||||
get "/s/admin/plans/plan_12345.json"
|
get "/subscriptions/admin/plans/plan_12345.json"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "is not ok" do
|
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
|
expect(response.status).to eq 404
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -49,7 +59,7 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
|||||||
describe "update" do
|
describe "update" do
|
||||||
it "does not update a plan" do
|
it "does not update a plan" do
|
||||||
::Stripe::Price.expects(:update).never
|
::Stripe::Price.expects(:update).never
|
||||||
delete "/s/admin/plans/plan_12345.json"
|
delete "/subscriptions/admin/plans/plan_12345.json"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -62,19 +72,19 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
|||||||
describe "index" do
|
describe "index" do
|
||||||
it "lists the plans" do
|
it "lists the plans" do
|
||||||
::Stripe::Price.expects(:list).with(nil)
|
::Stripe::Price.expects(:list).with(nil)
|
||||||
get "/s/admin/plans.json"
|
get "/subscriptions/admin/plans.json"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "lists the plans for the product" do
|
it "lists the plans for the product" do
|
||||||
::Stripe::Price.expects(:list).with({ product: "prod_id123" })
|
::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
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "show" do
|
describe "show" do
|
||||||
it "shows a plan" do
|
it "shows a plan" do
|
||||||
::Stripe::Price.expects(:retrieve).with("plan_12345").returns(currency: "aud")
|
::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
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -83,7 +93,7 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
|||||||
.expects(:retrieve)
|
.expects(:retrieve)
|
||||||
.with("plan_12345")
|
.with("plan_12345")
|
||||||
.returns(currency: "aud", recurring: { interval: "year" })
|
.returns(currency: "aud", recurring: { interval: "year" })
|
||||||
get "/s/admin/plans/plan_12345.json"
|
get "/subscriptions/admin/plans/plan_12345.json"
|
||||||
|
|
||||||
plan = response.parsed_body
|
plan = response.parsed_body
|
||||||
expect(plan["currency"]).to eq "AUD"
|
expect(plan["currency"]).to eq "AUD"
|
||||||
@@ -94,17 +104,29 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
|||||||
describe "create" do
|
describe "create" do
|
||||||
it "creates a plan with a nickname" do
|
it "creates a plan with a nickname" do
|
||||||
::Stripe::Price.expects(:create).with(has_entry(:nickname, "Veg"))
|
::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
|
end
|
||||||
|
|
||||||
it "creates a plan with a currency" do
|
it "creates a plan with a currency" do
|
||||||
::Stripe::Price.expects(:create).with(has_entry(:currency, "AUD"))
|
::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
|
end
|
||||||
|
|
||||||
it "creates a plan with an interval" do
|
it "creates a plan with an interval" do
|
||||||
::Stripe::Price.expects(:create).with(has_entry(recurring: { interval: "week" }))
|
::Stripe::Price.expects(:create).with(has_entry(recurring: { interval: "week" }))
|
||||||
post "/s/admin/plans.json",
|
post "/subscriptions/admin/plans.json",
|
||||||
params: {
|
params: {
|
||||||
type: "recurring",
|
type: "recurring",
|
||||||
interval: "week",
|
interval: "week",
|
||||||
@@ -116,17 +138,23 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
|||||||
|
|
||||||
it "creates a plan as a one-time purchase" do
|
it "creates a plan as a one-time purchase" do
|
||||||
::Stripe::Price.expects(:create).with(Not(has_key(:recurring)))
|
::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
|
end
|
||||||
|
|
||||||
it "creates a plan with an amount" do
|
it "creates a plan with an amount" do
|
||||||
::Stripe::Price.expects(:create).with(has_entry(:unit_amount, "102"))
|
::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
|
end
|
||||||
|
|
||||||
it "creates a plan with a product" do
|
it "creates a plan with a product" do
|
||||||
::Stripe::Price.expects(:create).with(has_entry(product: "prod_walterwhite"))
|
::Stripe::Price.expects(:create).with(has_entry(product: "prod_walterwhite"))
|
||||||
post "/s/admin/plans.json",
|
post "/subscriptions/admin/plans.json",
|
||||||
params: {
|
params: {
|
||||||
product: "prod_walterwhite",
|
product: "prod_walterwhite",
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -137,7 +165,13 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
|||||||
|
|
||||||
it "creates a plan with an active status" do
|
it "creates a plan with an active status" do
|
||||||
::Stripe::Price.expects(:create).with(has_entry(:active, "false"))
|
::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
|
end
|
||||||
|
|
||||||
# TODO: Need to fix the metadata tests
|
# TODO: Need to fix the metadata tests
|
||||||
@@ -145,19 +179,19 @@ RSpec.describe DiscourseSubscriptions::Admin::PlansController do
|
|||||||
|
|
||||||
#it 'has metadata' do
|
#it 'has metadata' do
|
||||||
# ::Stripe::Price.expects(:create).with(has_entry(:group_name, "discourse-user-group-name"))
|
# ::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
|
#end
|
||||||
|
|
||||||
#it "creates a plan with a trial period" do
|
#it "creates a plan with a trial period" do
|
||||||
# ::Stripe::Price.expects(:create).with(has_entry(trial_period_days: '14'))
|
# ::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
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "update" do
|
describe "update" do
|
||||||
it "updates a plan" do
|
it "updates a plan" do
|
||||||
::Stripe::Price.expects(:update)
|
::Stripe::Price.expects(:update)
|
||||||
patch "/s/admin/plans/plan_12345.json",
|
patch "/subscriptions/admin/plans/plan_12345.json",
|
||||||
params: {
|
params: {
|
||||||
trial_period_days: "14",
|
trial_period_days: "14",
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -12,31 +12,31 @@ RSpec.describe DiscourseSubscriptions::Admin::ProductsController do
|
|||||||
context "when unauthenticated" do
|
context "when unauthenticated" do
|
||||||
it "does not list the products" do
|
it "does not list the products" do
|
||||||
::Stripe::Product.expects(:list).never
|
::Stripe::Product.expects(:list).never
|
||||||
get "/s/admin/products.json"
|
get "/subscriptions/admin/products.json"
|
||||||
expect(response.status).to eq(404)
|
expect(response.status).to eq(404)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not create the product" do
|
it "does not create the product" do
|
||||||
::Stripe::Product.expects(:create).never
|
::Stripe::Product.expects(:create).never
|
||||||
post "/s/admin/products.json"
|
post "/subscriptions/admin/products.json"
|
||||||
expect(response.status).to eq(404)
|
expect(response.status).to eq(404)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not show the product" do
|
it "does not show the product" do
|
||||||
::Stripe::Product.expects(:retrieve).never
|
::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)
|
expect(response.status).to eq(404)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not update the product" do
|
it "does not update the product" do
|
||||||
::Stripe::Product.expects(:update).never
|
::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)
|
expect(response.status).to eq(404)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not delete the product" do
|
it "does not delete the product" do
|
||||||
::Stripe::Product.expects(:delete).never
|
::Stripe::Product.expects(:delete).never
|
||||||
delete "/s/admin/products/u2.json"
|
delete "/subscriptions/admin/products/u2.json"
|
||||||
expect(response.status).to eq(404)
|
expect(response.status).to eq(404)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -50,7 +50,7 @@ RSpec.describe DiscourseSubscriptions::Admin::ProductsController do
|
|||||||
it "gets the empty products" do
|
it "gets the empty products" do
|
||||||
SiteSetting.discourse_subscriptions_public_key = "public-key"
|
SiteSetting.discourse_subscriptions_public_key = "public-key"
|
||||||
SiteSetting.discourse_subscriptions_secret_key = "secret-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
|
expect(response.parsed_body).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -58,24 +58,24 @@ RSpec.describe DiscourseSubscriptions::Admin::ProductsController do
|
|||||||
describe "create" do
|
describe "create" do
|
||||||
it "is of product type service" do
|
it "is of product type service" do
|
||||||
::Stripe::Product.expects(:create).with(has_entry(:type, "service"))
|
::Stripe::Product.expects(:create).with(has_entry(:type, "service"))
|
||||||
post "/s/admin/products.json", params: {}
|
post "/subscriptions/admin/products.json", params: {}
|
||||||
end
|
end
|
||||||
|
|
||||||
it "has a name" do
|
it "has a name" do
|
||||||
::Stripe::Product.expects(:create).with(has_entry(:name, "Jesse Pinkman"))
|
::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
|
end
|
||||||
|
|
||||||
it "has an active attribute" do
|
it "has an active attribute" do
|
||||||
::Stripe::Product.expects(:create).with(has_entry(active: "false"))
|
::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
|
end
|
||||||
|
|
||||||
it "has a statement descriptor" do
|
it "has a statement descriptor" do
|
||||||
::Stripe::Product.expects(:create).with(
|
::Stripe::Product.expects(:create).with(
|
||||||
has_entry(statement_descriptor: "Blessed are the cheesemakers"),
|
has_entry(statement_descriptor: "Blessed are the cheesemakers"),
|
||||||
)
|
)
|
||||||
post "/s/admin/products.json",
|
post "/subscriptions/admin/products.json",
|
||||||
params: {
|
params: {
|
||||||
statement_descriptor: "Blessed are the cheesemakers",
|
statement_descriptor: "Blessed are the cheesemakers",
|
||||||
}
|
}
|
||||||
@@ -83,7 +83,7 @@ RSpec.describe DiscourseSubscriptions::Admin::ProductsController do
|
|||||||
|
|
||||||
it "has no statement descriptor if empty" do
|
it "has no statement descriptor if empty" do
|
||||||
::Stripe::Product.expects(:create).with(has_key(:statement_descriptor)).never
|
::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
|
end
|
||||||
|
|
||||||
it "has metadata" do
|
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: {
|
params: {
|
||||||
metadata: {
|
metadata: {
|
||||||
description: "Oi, I think he just said bless be all the bignoses!",
|
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
|
describe "show" do
|
||||||
it "retrieves the product" do
|
it "retrieves the product" do
|
||||||
::Stripe::Product.expects(:retrieve).with("prod_walterwhite")
|
::Stripe::Product.expects(:retrieve).with("prod_walterwhite")
|
||||||
get "/s/admin/products/prod_walterwhite.json"
|
get "/subscriptions/admin/products/prod_walterwhite.json"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "update" do
|
describe "update" do
|
||||||
it "updates the product" do
|
it "updates the product" do
|
||||||
::Stripe::Product.expects(:update)
|
::Stripe::Product.expects(:update)
|
||||||
patch "/s/admin/products/prod_walterwhite.json", params: {}
|
patch "/subscriptions/admin/products/prod_walterwhite.json", params: {}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "delete" do
|
describe "delete" do
|
||||||
it "deletes the product" do
|
it "deletes the product" do
|
||||||
::Stripe::Product.expects(:delete).with("prod_walterwhite")
|
::Stripe::Product.expects(:delete).with("prod_walterwhite")
|
||||||
delete "/s/admin/products/prod_walterwhite.json"
|
delete "/subscriptions/admin/products/prod_walterwhite.json"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ RSpec.describe DiscourseSubscriptions::Admin::SubscriptionsController do
|
|||||||
context "when unauthenticated" do
|
context "when unauthenticated" do
|
||||||
it "does nothing" do
|
it "does nothing" do
|
||||||
::Stripe::Subscription.expects(:list).never
|
::Stripe::Subscription.expects(:list).never
|
||||||
get "/s/admin/subscriptions.json"
|
get "/subscriptions/admin/subscriptions.json"
|
||||||
expect(response.status).to eq(404)
|
expect(response.status).to eq(404)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not destroy a subscription" do
|
it "does not destroy a subscription" do
|
||||||
::Stripe::Subscription.expects(:delete).never
|
::Stripe::Subscription.expects(:delete).never
|
||||||
patch "/s/admin/subscriptions/sub_12345.json"
|
patch "/subscriptions/admin/subscriptions/sub_12345.json"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ RSpec.describe DiscourseSubscriptions::Admin::SubscriptionsController do
|
|||||||
.expects(:list)
|
.expects(:list)
|
||||||
.with(expand: ["data.plan.product"], limit: 10, starting_after: nil)
|
.with(expand: ["data.plan.product"], limit: 10, starting_after: nil)
|
||||||
.returns(has_more: false, data: [{ id: "sub_12345" }, { id: "sub_nope" }])
|
.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"]
|
subscriptions = response.parsed_body["data"][0]["id"]
|
||||||
|
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
@@ -62,7 +62,7 @@ RSpec.describe DiscourseSubscriptions::Admin::SubscriptionsController do
|
|||||||
.expects(:list)
|
.expects(:list)
|
||||||
.with(expand: ["data.plan.product"], limit: 10, starting_after: "sub_nope")
|
.with(expand: ["data.plan.product"], limit: 10, starting_after: "sub_nope")
|
||||||
.returns(has_more: false, data: [{ id: "sub_77777" }, { id: "sub_yepnoep" }])
|
.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"]
|
subscriptions = response.parsed_body["data"][0]["id"]
|
||||||
|
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
@@ -81,7 +81,7 @@ RSpec.describe DiscourseSubscriptions::Admin::SubscriptionsController do
|
|||||||
.with("sub_12345")
|
.with("sub_12345")
|
||||||
.returns(plan: { product: "pr_34578" }, customer: "c_123")
|
.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
|
DiscourseSubscriptions::Customer.count
|
||||||
}.by(-1)
|
}.by(-1)
|
||||||
end
|
end
|
||||||
@@ -100,7 +100,7 @@ RSpec.describe DiscourseSubscriptions::Admin::SubscriptionsController do
|
|||||||
customer: "c_123",
|
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
|
user.groups.count
|
||||||
}.by(-1)
|
}.by(-1)
|
||||||
end
|
end
|
||||||
@@ -119,7 +119,7 @@ RSpec.describe DiscourseSubscriptions::Admin::SubscriptionsController do
|
|||||||
customer: "c_123",
|
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
|
user.groups.count
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@@ -136,7 +136,7 @@ RSpec.describe DiscourseSubscriptions::Admin::SubscriptionsController do
|
|||||||
::Stripe::Invoice.expects(:retrieve).with("in_123").returns(payment_intent: "pi_123")
|
::Stripe::Invoice.expects(:retrieve).with("in_123").returns(payment_intent: "pi_123")
|
||||||
::Stripe::Refund.expects(:create).with({ 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
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ RSpec.describe DiscourseSubscriptions::AdminController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "is ok" do
|
it "is ok" do
|
||||||
get "/s/admin.json"
|
get "/subscriptions/admin.json"
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ RSpec.describe DiscourseSubscriptions::HooksController do
|
|||||||
.with("we-want-a-shrubbery", "stripe-webhook-signature", "zascharoo")
|
.with("we-want-a-shrubbery", "stripe-webhook-signature", "zascharoo")
|
||||||
.returns(type: "something")
|
.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
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
@@ -51,7 +51,7 @@ RSpec.describe DiscourseSubscriptions::HooksController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "is successfull" do
|
it "is successfull" do
|
||||||
post "/s/hooks.json"
|
post "/subscriptions/hooks.json"
|
||||||
expect(response.status).to eq 200
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ RSpec.describe DiscourseSubscriptions::HooksController do
|
|||||||
event_data[:object][:status] = "incomplete"
|
event_data[:object][:status] = "incomplete"
|
||||||
event_data[:previous_attributes] = { 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
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
@@ -69,7 +69,7 @@ RSpec.describe DiscourseSubscriptions::HooksController do
|
|||||||
event_data[:object][:status] = "incomplete"
|
event_data[:object][:status] = "incomplete"
|
||||||
event_data[:previous_attributes] = { status: "something-else" }
|
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
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
@@ -78,7 +78,7 @@ RSpec.describe DiscourseSubscriptions::HooksController do
|
|||||||
event_data[:object][:status] = "complete"
|
event_data[:object][:status] = "complete"
|
||||||
event_data[:previous_attributes] = { status: "incomplete" }
|
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
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
@@ -95,13 +95,15 @@ RSpec.describe DiscourseSubscriptions::HooksController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "deletes the customer" do
|
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
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
|
|
||||||
it "removes the user from the group" do
|
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
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -68,56 +68,6 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
SiteSetting.discourse_subscriptions_secret_key = "secret-key"
|
SiteSetting.discourse_subscriptions_secret_key = "secret-key"
|
||||||
end
|
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
|
describe "#get_contributors" do
|
||||||
before do
|
before do
|
||||||
Fabricate(:product, external_id: "prod_campaign")
|
Fabricate(:product, external_id: "prod_campaign")
|
||||||
@@ -132,7 +82,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
context "when not showing contributors" do
|
context "when not showing contributors" do
|
||||||
it "returns nothing if not set to show contributors" do
|
it "returns nothing if not set to show contributors" do
|
||||||
SiteSetting.discourse_subscriptions_campaign_show_contributors = false
|
SiteSetting.discourse_subscriptions_campaign_show_contributors = false
|
||||||
get "/s/contributors.json"
|
get "/subscriptions/contributors.json"
|
||||||
|
|
||||||
data = response.parsed_body
|
data = response.parsed_body
|
||||||
expect(data).to be_empty
|
expect(data).to be_empty
|
||||||
@@ -145,7 +95,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
it "filters users by campaign product if set" do
|
it "filters users by campaign product if set" do
|
||||||
SiteSetting.discourse_subscriptions_campaign_product = "prod_campaign"
|
SiteSetting.discourse_subscriptions_campaign_product = "prod_campaign"
|
||||||
|
|
||||||
get "/s/contributors.json"
|
get "/subscriptions/contributors.json"
|
||||||
|
|
||||||
data = response.parsed_body
|
data = response.parsed_body
|
||||||
expect(data.first["id"]).to eq campaign_user.id
|
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
|
it "shows all purchases if campaign product not set" do
|
||||||
SiteSetting.discourse_subscriptions_campaign_product = nil
|
SiteSetting.discourse_subscriptions_campaign_product = nil
|
||||||
|
|
||||||
get "/s/contributors.json"
|
get "/subscriptions/contributors.json"
|
||||||
|
|
||||||
data = response.parsed_body
|
data = response.parsed_body
|
||||||
expect(data.length).to eq 2
|
expect(data.length).to eq 2
|
||||||
@@ -170,7 +120,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
.expects(:list)
|
.expects(:list)
|
||||||
.with(active: true, product: "prod_walterwhite")
|
.with(active: true, product: "prod_walterwhite")
|
||||||
.returns(prices)
|
.returns(prices)
|
||||||
get "/s/prod_walterwhite.json"
|
get "/subscriptions/prod_walterwhite.json"
|
||||||
|
|
||||||
expect(response.parsed_body).to eq(
|
expect(response.parsed_body).to eq(
|
||||||
{
|
{
|
||||||
@@ -222,7 +172,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
::Stripe::Customer.expects(:create).never
|
::Stripe::Customer.expects(:create).never
|
||||||
::Stripe::Price.expects(:retrieve).never
|
::Stripe::Price.expects(:retrieve).never
|
||||||
::Stripe::Subscription.expects(:create).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
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -257,7 +207,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
.returns(status: "active", customer: "cus_1234")
|
.returns(status: "active", customer: "cus_1234")
|
||||||
|
|
||||||
expect {
|
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 }
|
}.to change { DiscourseSubscriptions::Customer.count }
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -291,7 +241,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
::Stripe::Invoice.expects(:pay).returns(status: "paid", customer: "cus_1234")
|
::Stripe::Invoice.expects(:pay).returns(status: "paid", customer: "cus_1234")
|
||||||
|
|
||||||
expect {
|
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 }
|
}.to change { DiscourseSubscriptions::Customer.count }
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -300,13 +250,13 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
::Stripe::Subscription.expects(:create).returns(status: "active", customer: "cus_1234")
|
::Stripe::Subscription.expects(:create).returns(status: "active", customer: "cus_1234")
|
||||||
|
|
||||||
expect {
|
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 }
|
}.to change { DiscourseSubscriptions::Customer.count }
|
||||||
|
|
||||||
::Stripe::Customer.expects(:retrieve).with("cus_1234")
|
::Stripe::Customer.expects(:retrieve).with("cus_1234")
|
||||||
|
|
||||||
expect {
|
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 }
|
}.not_to change { DiscourseSubscriptions::Customer.count }
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -315,7 +265,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
::Stripe::Price.expects(:retrieve).returns(type: "recurring", metadata: {})
|
::Stripe::Price.expects(:retrieve).returns(type: "recurring", metadata: {})
|
||||||
::Stripe::Subscription.expects(:create).returns(status: "active", customer: "cus_1234")
|
::Stripe::Subscription.expects(:create).returns(status: "active", customer: "cus_1234")
|
||||||
expect {
|
expect {
|
||||||
post "/s/create.json",
|
post "/subscriptions/create.json",
|
||||||
params: {
|
params: {
|
||||||
plan: "plan_1234",
|
plan: "plan_1234",
|
||||||
source: "tok_1234",
|
source: "tok_1234",
|
||||||
@@ -346,7 +296,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
|
|
||||||
::Stripe::PromotionCode.expects(:list).with({ code: "invalid" }).returns(data: [])
|
::Stripe::PromotionCode.expects(:list).with({ code: "invalid" }).returns(data: [])
|
||||||
|
|
||||||
post "/s/create.json",
|
post "/subscriptions/create.json",
|
||||||
params: {
|
params: {
|
||||||
plan: "plan_1234",
|
plan: "plan_1234",
|
||||||
source: "tok_1234",
|
source: "tok_1234",
|
||||||
@@ -391,7 +341,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
.returns(status: "active", customer: "cus_1234")
|
.returns(status: "active", customer: "cus_1234")
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
post "/s/create.json",
|
post "/subscriptions/create.json",
|
||||||
params: {
|
params: {
|
||||||
plan: "plan_1234",
|
plan: "plan_1234",
|
||||||
source: "tok_1234",
|
source: "tok_1234",
|
||||||
@@ -434,7 +384,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
::Stripe::Invoice.expects(:pay).returns(status: "paid", customer: "cus_1234")
|
::Stripe::Invoice.expects(:pay).returns(status: "paid", customer: "cus_1234")
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
post "/s/create.json",
|
post "/subscriptions/create.json",
|
||||||
params: {
|
params: {
|
||||||
plan: "plan_1234",
|
plan: "plan_1234",
|
||||||
source: "tok_1234",
|
source: "tok_1234",
|
||||||
@@ -462,7 +412,11 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
)
|
)
|
||||||
|
|
||||||
expect {
|
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 }
|
}.to change { DiscourseSubscriptions::Customer.count }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -482,7 +436,11 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
)
|
)
|
||||||
|
|
||||||
expect {
|
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 }
|
}.to change { DiscourseSubscriptions::Customer.count }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -505,7 +463,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
group_name: "admins",
|
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
|
expect(user.admin).to eq false
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -516,7 +474,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
group_name: "other",
|
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
|
expect(user.groups).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -536,7 +494,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
::Stripe::Subscription.expects(:create).returns(status: "failed")
|
::Stripe::Subscription.expects(:create).returns(status: "failed")
|
||||||
|
|
||||||
expect {
|
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 }
|
}.not_to change { group.users.count }
|
||||||
|
|
||||||
expect(user.groups).to be_empty
|
expect(user.groups).to be_empty
|
||||||
@@ -546,7 +504,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
::Stripe::Subscription.expects(:create).returns(status: "active")
|
::Stripe::Subscription.expects(:create).returns(status: "active")
|
||||||
|
|
||||||
expect {
|
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 }
|
}.to change { group.users.count }
|
||||||
|
|
||||||
expect(user.groups).not_to be_empty
|
expect(user.groups).not_to be_empty
|
||||||
@@ -556,7 +514,7 @@ RSpec.describe DiscourseSubscriptions::SubscribeController do
|
|||||||
::Stripe::Subscription.expects(:create).returns(status: "trialing")
|
::Stripe::Subscription.expects(:create).returns(status: "trialing")
|
||||||
|
|
||||||
expect {
|
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 }
|
}.to change { group.users.count }
|
||||||
|
|
||||||
expect(user.groups).not_to be_empty
|
expect(user.groups).not_to be_empty
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ RSpec.describe DiscourseSubscriptions::User::PaymentsController do
|
|||||||
context "when not authenticated" do
|
context "when not authenticated" do
|
||||||
it "does not get the payment intents" do
|
it "does not get the payment intents" do
|
||||||
::Stripe::PaymentIntent.expects(:list).never
|
::Stripe::PaymentIntent.expects(:list).never
|
||||||
get "/s/user/payments.json"
|
get "/subscriptions/user/payments.json"
|
||||||
expect(response.status).to eq(403)
|
expect(response.status).to eq(403)
|
||||||
end
|
end
|
||||||
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
|
parsed_body = response.parsed_body
|
||||||
invoice = parsed_body[0]["invoice"]
|
invoice = parsed_body[0]["invoice"]
|
||||||
|
|||||||
@@ -14,18 +14,21 @@ RSpec.describe DiscourseSubscriptions::User::SubscriptionsController do
|
|||||||
context "when not authenticated" do
|
context "when not authenticated" do
|
||||||
it "does not get the subscriptions" do
|
it "does not get the subscriptions" do
|
||||||
::Stripe::Customer.expects(:list).never
|
::Stripe::Customer.expects(:list).never
|
||||||
get "/s/user/subscriptions.json"
|
get "/subscriptions/user/subscriptions.json"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not destroy a subscription" do
|
it "does not destroy a subscription" do
|
||||||
::Stripe::Subscription.expects(:delete).never
|
::Stripe::Subscription.expects(:delete).never
|
||||||
patch "/s/user/subscriptions/sub_12345.json"
|
patch "/subscriptions/user/subscriptions/sub_12345.json"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't update payment method for subscription" do
|
it "doesn't update payment method for subscription" do
|
||||||
::Stripe::Subscription.expects(:update).never
|
::Stripe::Subscription.expects(:update).never
|
||||||
::Stripe::PaymentMethod.expects(:attach).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
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -74,7 +77,7 @@ RSpec.describe DiscourseSubscriptions::User::SubscriptionsController do
|
|||||||
.with(email: user.email, expand: ["data.subscriptions"])
|
.with(email: user.email, expand: ["data.subscriptions"])
|
||||||
.returns(customers)
|
.returns(customers)
|
||||||
|
|
||||||
get "/s/user/subscriptions.json"
|
get "/subscriptions/user/subscriptions.json"
|
||||||
|
|
||||||
subscription = response.parsed_body.first
|
subscription = response.parsed_body.first
|
||||||
|
|
||||||
@@ -100,7 +103,10 @@ RSpec.describe DiscourseSubscriptions::User::SubscriptionsController do
|
|||||||
it "updates the payment method for subscription" do
|
it "updates the payment method for subscription" do
|
||||||
::Stripe::Subscription.expects(:update).once
|
::Stripe::Subscription.expects(:update).once
|
||||||
::Stripe::PaymentMethod.expects(:attach).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
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ describe "Subscription products", type: :system do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "shows the login modal" do
|
it "shows the login modal" do
|
||||||
visit("/s")
|
visit("/subscriptions")
|
||||||
|
|
||||||
find("button.login-required.subscriptions").click
|
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) {
|
export default function (helpers) {
|
||||||
const { response } = helpers;
|
const { response } = helpers;
|
||||||
|
|
||||||
this.get("/s", () => {
|
this.get("/subscriptions", () => {
|
||||||
const products = [
|
const products = [
|
||||||
{
|
{
|
||||||
id: "prod_23o8I7tU4g56",
|
id: "prod_23o8I7tU4g56",
|
||||||
@@ -20,7 +20,7 @@ export default function (helpers) {
|
|||||||
return response(products);
|
return response(products);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.get("/s/:id", () => {
|
this.get("/subscriptions/:id", () => {
|
||||||
const product = {
|
const product = {
|
||||||
id: "prod_23o8I7tU4g56",
|
id: "prod_23o8I7tU4g56",
|
||||||
name: "Awesome Product",
|
name: "Awesome Product",
|
||||||
|
|||||||
Reference in New Issue
Block a user