+
+ `
+ );
+ });
-Object.keys(requirejs.entries).forEach(function (entry) {
- if (/\-test/.test(entry)) {
- requirejs(entry);
- }
-});
+ Object.keys(requirejs.entries).forEach(function (entry) {
+ if (/\-test/.test(entry)) {
+ requirejs(entry);
+ }
+ });
+}
diff --git a/assets/stylesheets/admin/admin.scss b/assets/stylesheets/admin/admin.scss
index c026263a..f1911f2c 100644
--- a/assets/stylesheets/admin/admin.scss
+++ b/assets/stylesheets/admin/admin.scss
@@ -25,6 +25,14 @@ $error: #ef1700;
}
}
+.admin-wizards .admin-actions {
+ display: flex;
+
+ .btn-pavilion-support {
+ margin-left: 10px;
+ }
+}
+
.wizard-message {
background-color: var(--primary-low);
width: 100%;
@@ -156,6 +164,16 @@ $error: #ef1700;
@extend .wizard-settings-group;
}
+.admin-wizard-container.settings {
+ .wizard-settings {
+ .wizard-subscription-container {
+ [class~="setting"] {
+ margin-bottom: 0;
+ }
+ }
+ }
+}
+
.wizard-custom-field {
background: transparent;
background-color: var(--primary-very-low);
@@ -802,84 +820,6 @@ $error: #ef1700;
vertical-align: middle;
}
-.admin-wizards-subscription {
- .admin-wizard-controls {
- h3,
- label {
- margin: 0;
- }
-
- label {
- padding: 0.4em 0.5em;
- margin-left: 0.75em;
- background-color: var(--success);
- color: var(--secondary);
- }
-
- .buttons {
- display: flex;
- align-items: center;
-
- .loading-container {
- margin-right: 1em;
- }
- }
- }
-
- .custom-wizard-subscription {
- .title-container {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 0.5em;
-
- h3 {
- margin: 0;
- }
-
- .buttons > span {
- margin-right: 0.5em;
- }
- }
-
- .detail-container {
- display: flex;
- align-items: center;
- padding: 1em;
- background-color: var(--primary-very-low);
-
- .subscription-state {
- padding: 0.25em 0.5em;
- margin-right: 0.75em;
-
- &.active {
- background-color: var(--success);
- color: var(--secondary);
- }
- }
- }
- }
-}
-
-.wizard-subscription-selector.select-kit.single-select {
- .select-kit-row {
- .texts {
- display: flex;
- align-items: center;
- }
- &.disabled {
- background: var(--primary-low);
- }
- }
-
- .subscription-label {
- margin-left: 0.75em;
- padding-top: 0.25em;
- color: var(--tertiary);
- font-size: 0.75em;
- }
-}
-
.btn.btn-pavilion-support {
background: var(--pavilion-primary);
color: var(--pavilion-secondary);
@@ -899,7 +839,7 @@ $error: #ef1700;
}
}
-.subscription-container {
+.wizard-subscription-container {
width: 100%;
padding: 1em;
background-color: rgba($pavilion_primary, 0.1);
@@ -907,158 +847,79 @@ $error: #ef1700;
.subscription-header {
display: flex;
justify-content: space-between;
- margin-bottom: 1em;
+ margin-bottom: 0.25em;
h3 {
margin: 0;
}
a {
- color: var(--pavilion-primary);
+ color: var(--primary);
}
}
&:not(.subscribed) .subscription-settings {
filter: blur(1px);
+ pointer-events: none;
}
}
-.admin-wizards-notices {
- .wizard-table {
- overflow: unset;
- }
-}
-
-.wizard-notice {
- padding: 0.75em;
- margin-bottom: 1em;
- border: 1px solid var(--primary-low);
-
- &.dismissed {
- display: none;
- }
-
- &.expired .notice-badge:not(.notice-expired-at),
- &.expired a,
- &.expired p {
- color: var(--primary-medium) !important;
- }
-
- .notice-badge {
- padding: 0 0.5em;
- }
-
- .notice-header {
- display: flex;
-
- .notice-title {
- padding: 0;
- }
-
- .notice-header-right {
- margin-left: auto;
- display: flex;
- align-items: center;
-
- .notice-badge {
- margin-left: 0.5em;
- }
- }
- }
-
- .dismiss-notice-container,
- .hide-notice-container {
- width: 40px;
- display: flex;
- justify-content: center;
- align-items: center;
- }
-
- .dismiss-notice,
- .hide-notice {
- display: flex;
- align-items: center;
-
- .d-icon {
- margin-right: 0;
- color: var(--primary);
- }
- }
-}
-
-.notice-badge {
+.wizard-subscription-badge {
display: inline-flex;
align-items: center;
- min-height: 25px;
+ max-height: 34px;
box-sizing: border-box;
- color: var(--primary) !important;
-}
-
-.admin-actions {
- display: flex;
- align-items: center;
-}
-
-.wizard-notices-link {
position: relative;
- margin-right: 10px;
+ cursor: pointer;
+ padding: 0.5em 0.65em;
+ background-color: rgba($primary-medium, 0.05);
+ border: 1.5px solid rgba($primary-medium, 0.5);
+ color: $primary-medium;
- div > a {
- @include btn;
- color: var(--secondary) !important;
- background-color: var(--primary-medium);
+ &:hover {
+ color: $primary-medium;
+ }
- &.active {
- background-color: var(--tertiary) !important;
- color: var(--secondary) !important;
+ svg {
+ width: 15px;
+ height: 15px;
+ margin-right: 0.45em;
+ margin-bottom: 0.15em;
+ }
+
+ &.standard {
+ background-color: rgba($subscription_standard, 0.05);
+ border: 1.5px solid rgba($subscription_standard, 0.5);
+ color: $subscription_standard;
+ }
+
+ &.business {
+ background-color: $subscription_business;
+ border: 1.5px solid $subscription_business;
+ color: $secondary;
+ }
+
+ .d-icon {
+ margin-right: 0.75em;
+ }
+}
+
+.wizard-subscription-selector.select-kit.single-select {
+ .select-kit-row {
+ .texts {
+ display: flex;
+ align-items: center;
+ }
+ &.disabled {
+ background: var(--primary-low);
+ cursor: unset;
}
}
-}
-.active-notice-count {
- background-color: $danger;
- color: $secondary;
- border-radius: 50%;
- width: 18px;
- height: 18px;
- line-height: 18px;
- text-align: center;
- position: absolute;
- top: -8px;
- right: -8px;
- font-size: 0.7em;
-}
-
-a.show-notice-message {
- padding: 0.25em 0.5em;
- color: var(--primary);
-}
-
-.wizard-notice,
-.wizard-notice-row:not(.expired):not(.dismissed) {
- &.info {
- background-color: rgba($info, 0.1);
- border: 1px solid rgba($info, 0.5);
- }
- &.warning,
- &.connection-error {
- background-color: rgba($warning, 0.1);
- border: 1px solid rgba($warning, 0.5);
- }
-}
-
-.notice-message {
- position: relative;
-
- .cooked-notice-message {
- background-color: var(--secondary);
- padding: 1em;
- z-index: 1;
- box-shadow: shadow("dropdown");
- border-top: 1px solid var(--primary-low);
-
- p {
- margin: 0;
- }
+ .subscription-label {
+ margin-left: 0.75em;
+ padding-top: 0.25em;
+ color: var(--pavilion-primary);
+ font-size: 0.75em;
}
}
diff --git a/assets/stylesheets/admin/wizard/variables.scss b/assets/stylesheets/admin/wizard/variables.scss
index 5912f961..9bb93798 100644
--- a/assets/stylesheets/admin/wizard/variables.scss
+++ b/assets/stylesheets/admin/wizard/variables.scss
@@ -2,8 +2,13 @@ $pavilion_primary: #3c1c8c;
$pavilion_secondary: #ffffff;
$pavilion_warning: rgb(243, 163, 61);
+$subscription_standard: $pavilion_primary;
+$subscription_business: #333;
+
:root {
--pavilion-primary: #{$pavilion_primary};
--pavilion-secondary: #{$pavilion_secondary};
--pavilion-warning: #{$pavilion_warning};
+ --subscription-standard: #{$subscription_standard};
+ --subscription-business: #{$subscription_business};
}
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 34c7003b..45efabb8 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -47,7 +47,7 @@ en:
value: "Value"
profile: "profile"
type: "Type"
- none: "Make a selection"
+ none: "Make a selection"
submission_key: 'submission key'
param_key: 'param'
group: "Group"
@@ -126,9 +126,9 @@ en:
hide: "Hide"
preview: "{{action}} Preview"
popover: "{{action}} Fields"
-
+
input:
- conditional:
+ conditional:
name: 'if'
output: 'then'
assignment:
@@ -137,7 +137,7 @@ en:
name: 'map'
validation:
name: 'ensure'
-
+
selector:
label:
text: "text"
@@ -175,7 +175,7 @@ en:
dependent: "{{property}} is dependent on {{dependent}}"
conflict: "{{type}} with {{property}} '{{value}}' already exists"
after_time: "After time invalid"
-
+
step:
header: "Steps"
title: "Title"
@@ -189,7 +189,7 @@ en:
force_final:
label: "Conditional Final Step"
description: "Display this step as the final step if conditions on later steps have not passed when the user reaches this step."
-
+
field:
header: "Fields"
label: "Label"
@@ -212,7 +212,7 @@ en:
prefill: "Prefill"
content: "Content"
tag_groups: "Tag Groups"
- date_time_format:
+ date_time_format:
label: "Format"
instructions: "Moment.js format"
validations:
@@ -229,7 +229,7 @@ en:
weeks: "Weeks"
months: "Months"
years: "Years"
-
+
type:
text: "Text"
textarea: Textarea
@@ -248,7 +248,7 @@ en:
date: Date
time: Time
date_time: Date & Time
-
+
connector:
and: "and"
or: "or"
@@ -262,7 +262,7 @@ en:
regex: '=~'
association: '→'
is: 'is'
-
+
action:
header: "Actions"
include: "Include Fields"
@@ -270,8 +270,8 @@ en:
post: "Post"
topic_attr: "Topic Attribute"
interpolate_fields: "Insert wizard fields using the field_id in w{}. Insert user fields using field key in u{}."
-
- run_after:
+
+ run_after:
label: "Run After"
wizard_completion: "Wizard Completion"
custom_fields:
@@ -353,11 +353,11 @@ en:
messageable_level: Messageable Level
visibility_level: Visibility Level
members_visibility_level: Members Visibility Level
-
+
custom_field:
nav_label: "Custom Fields"
add: "Add"
- external:
+ external:
label: "from another plugin"
title: "This custom field has been added by another plugin. You can use it in your wizards but you can't edit the field here."
name:
@@ -386,7 +386,7 @@ en:
basic_category: "Category"
basic_group: "Group"
post: "Post"
-
+
submissions:
nav_label: "Submissions"
title: "{{name}} Submissions"
@@ -468,59 +468,22 @@ en:
subscription_container:
title: Subscriber Features
- subscribed:
+ subscribed:
label: Subscribed
title: You're subscribed and can use these features
not_subscribed:
label: Not Subscribed
title: Subscribe to use these features
-
- subscription:
- nav_label: Subscription
- label: In subscription
- additional_label: "Add subscription"
- title: Custom Wizard Subscription
- authorize: Authorize
- authorized: Authorized
- unauthorize: cancel
- not_subscribed: You're not currently subscribed
- subscription:
- title:
- standard: Standard Subscription
- business: Business Subscription
- status:
- active: Active
- inactive: Inactive
- update: Update
- last_updated: Last updated
-
- notice:
- plugin: Custom Wizard Plugin
- message: Message
- time: Time
- status: Status
- title: Title
- dismiss:
- label: Dismiss
- title: Dismiss notice
- dismiss_all:
- label: Dismiss All
- title: Dismiss all informational Custom Wizard notices
- confirm: Are you sure you want to dismiss all informational Custom Wizard notices?
- active: active
- created_at: issued
- updated_at: updated
- expired_at: expired
- dismissed_at: dismissed
type:
- label: Type
- info: Information
- warning: Warning
- connection_error: Connection Error
-
- notices:
- nav_label: Notices
- title: Plugin Notices
+ none:
+ label: Not Subscribed
+ title: There is no Custom Wizard subscription active on this forum.
+ business:
+ label: Business
+ title: There is a Custom Wizard Business subscription active on this forum.
+ standard:
+ label: Standard
+ title: There is a Custom Wizard Standard subscription active on this forum.
wizard_js:
group:
@@ -636,7 +599,7 @@ en:
yourself_confirm:
title: "Did you forget to add recipients?"
body: "Right now this message is only being sent to yourself!"
-
+
realtime_validations:
similar_topics:
insufficient_characters: "Type a minimum 5 characters to start looking for similar topics"
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index d0ca29a6..08cf5336 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -53,20 +53,7 @@ en:
after_signup_after_time: "You can't use 'after time' and 'after signup' on the same wizard."
after_time: "After time setting is invalid."
liquid_syntax_error: "Liquid syntax error in %{attribute}: %{message}"
-
- notice:
- connection_error: "Failed to connect to http://%{domain}"
- compatibility_issue:
- title: The Custom Wizard Plugin is incompatibile with the latest version of Discourse.
- message: Please check the Custom Wizard Plugin status on [%{domain}](http://%{domain}) before updating Discourse.
- plugin_status:
- connection_error:
- title: Unable to connect to the Custom Wizard Plugin status server
- message: Please check the Custom Wizard Plugin status on [%{domain}](http://%{domain}) before updating Discourse. If this issue persists contact support@thepavilion.io for further assistance.
- subscription_message:
- connection_error:
- title: Unable to connect to the Custom Wizard Plugin subscription server
- message: If this issue persists contact support@thepavilion.io for further assistance.
+ subscription: "%{type} %{property} is subscription only"
site_settings:
custom_wizard_enabled: "Enable custom wizards."
diff --git a/config/routes.rb b/config/routes.rb
index 514605de..2d9f52c6 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -45,17 +45,5 @@ Discourse::Application.routes.append do
get 'admin/wizards/manager/export' => 'admin_manager#export'
post 'admin/wizards/manager/import' => 'admin_manager#import'
delete 'admin/wizards/manager/destroy' => 'admin_manager#destroy'
-
- get 'admin/wizards/subscription' => 'admin_subscription#index'
- post 'admin/wizards/subscription' => 'admin_subscription#update_subscription'
- get 'admin/wizards/subscription/authorize' => 'admin_subscription#authorize'
- get 'admin/wizards/subscription/authorize/callback' => 'admin_subscription#authorize_callback'
- delete 'admin/wizards/subscription/authorize' => 'admin_subscription#destroy_authentication'
-
- get 'admin/wizards/notice' => 'admin_notice#index'
- put 'admin/wizards/notice/:notice_id/dismiss' => 'admin_notice#dismiss'
- put 'admin/wizards/notice/:notice_id/hide' => 'admin_notice#hide'
- put 'admin/wizards/notice/dismiss' => 'admin_notice#dismiss_all'
- get 'admin/wizards/notices' => 'admin_notice#index'
end
end
diff --git a/config/settings.yml b/config/settings.yml
index c4337d92..514462d5 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -1,5 +1,5 @@
plugins:
- custom_wizard_enabled:
+ custom_wizard_enabled:
default: true
client: true
wizard_redirect_exclude_paths:
diff --git a/lib/custom_wizard/custom_field.rb b/lib/custom_wizard/custom_field.rb
index ed0c9594..29423ec6 100644
--- a/lib/custom_wizard/custom_field.rb
+++ b/lib/custom_wizard/custom_field.rb
@@ -84,7 +84,7 @@ class ::CustomWizard::CustomField
next
end
- if attr == 'klass' && @subscription.requires_additional_subscription("custom_fields", "klass").include?(value)
+ if attr == 'klass' && !@subscription.includes?(:custom_field, :klass, value)
add_error(I18n.t("wizard.custom_field.error.subscription_type", type: value))
end
@@ -99,7 +99,7 @@ class ::CustomWizard::CustomField
add_error(I18n.t("#{i18n_key}.unsupported_type", type: value))
end
- if attr == 'type' && @subscription.requires_additional_subscription("custom_fields", "type").include?(value)
+ if attr == 'type' && !@subscription.includes?(:custom_field, :type, value)
add_error(I18n.t("wizard.custom_field.error.subscription_type", type: value))
end
diff --git a/lib/custom_wizard/mapper.rb b/lib/custom_wizard/mapper.rb
index c513307b..aa444de1 100644
--- a/lib/custom_wizard/mapper.rb
+++ b/lib/custom_wizard/mapper.rb
@@ -47,7 +47,6 @@ class CustomWizard::Mapper
@data = params[:data] || {}
@user = params[:user]
@opts = params[:opts] || {}
- @subscription = CustomWizard::Subscription.new
end
def perform
@@ -252,7 +251,7 @@ class CustomWizard::Mapper
end
end
- if opts[:template] && @subscription.subscribed?
+ if opts[:template] && CustomWizard::Subscription.subscribed?
template = Liquid::Template.parse(string)
string = template.render(data)
end
diff --git a/lib/custom_wizard/notice.rb b/lib/custom_wizard/notice.rb
deleted file mode 100644
index 9d5c1edf..00000000
--- a/lib/custom_wizard/notice.rb
+++ /dev/null
@@ -1,358 +0,0 @@
-# frozen_string_literal: true
-
-class CustomWizard::Notice
- include ActiveModel::Serialization
-
- PLUGIN_STATUS_DOMAINS = {
- "main" => "plugins.discourse.pavilion.tech",
- "master" => "plugins.discourse.pavilion.tech",
- "tests-passed" => "plugins.discourse.pavilion.tech",
- "stable" => "stable.plugins.discourse.pavilion.tech"
- }
- SUBSCRIPTION_MESSAGE_DOMAIN = "test.thepavilion.io"
- LOCALHOST_DOMAIN = "localhost:3000"
- PLUGIN_STATUSES_TO_WARN = %w(incompatible tests_failing)
- CHECK_PLUGIN_STATUS_ON_BRANCH = %w(tests-passed main stable)
- PAGE_LIMIT = 30
-
- attr_reader :id,
- :title,
- :message,
- :type,
- :archetype,
- :created_at
-
- attr_accessor :retrieved_at,
- :updated_at,
- :dismissed_at,
- :expired_at,
- :hidden_at
-
- def initialize(attrs)
- @id = self.class.generate_notice_id(attrs[:title], attrs[:created_at])
- @title = attrs[:title]
- @message = attrs[:message]
- @type = attrs[:type].to_i
- @archetype = attrs[:archetype].to_i
- @created_at = attrs[:created_at]
- @updated_at = attrs[:updated_at]
- @retrieved_at = attrs[:retrieved_at]
- @dismissed_at = attrs[:dismissed_at]
- @expired_at = attrs[:expired_at]
- @hidden_at = attrs[:hidden_at]
- end
-
- def dismiss!
- if dismissable?
- self.dismissed_at = DateTime.now.iso8601(3)
- self.save_and_publish
- end
- end
-
- def hide!
- if can_hide?
- self.hidden_at = DateTime.now.iso8601(3)
- self.save_and_publish
- end
- end
-
- def expire!
- if !expired?
- self.expired_at = DateTime.now.iso8601(3)
- self.save_and_publish
- end
- end
-
- def save_and_publish
- if self.save
- self.class.publish_notice_count
- true
- else
- false
- end
- end
-
- def expired?
- expired_at.present?
- end
-
- def dismissed?
- dismissed_at.present?
- end
-
- def dismissable?
- !expired? && !dismissed? && type === self.class.types[:info]
- end
-
- def hidden?
- hidden_at.present?
- end
-
- def can_hide?
- !hidden? && (
- type === self.class.types[:connection_error] ||
- type === self.class.types[:warning]
- ) && (
- archetype === self.class.archetypes[:plugin_status]
- )
- end
-
- def save
- attrs = {
- expired_at: expired_at,
- updated_at: updated_at,
- retrieved_at: retrieved_at,
- created_at: created_at,
- title: title,
- message: message,
- type: type,
- archetype: archetype
- }
-
- if current = self.class.find(self.id)
- attrs[:dismissed_at] = current.dismissed_at || self.dismissed_at
- attrs[:hidden_at] = current.hidden_at || self.hidden_at
- end
-
- self.class.store(id, attrs)
- end
-
- def self.types
- @types ||= Enum.new(
- info: 0,
- warning: 1,
- connection_error: 2
- )
- end
-
- def self.archetypes
- @archetypes ||= Enum.new(
- subscription_message: 0,
- plugin_status: 1
- )
- end
-
- def self.update(skip_subscription: false, skip_plugin: false)
- notices = []
-
- if !skip_subscription
- subscription_messages = request(:subscription_message)
-
- if subscription_messages.present?
- subscription_notices = convert_subscription_messages_to_notices(subscription_messages[:messages])
- notices.push(*subscription_notices)
- end
- end
-
- if !skip_plugin && request_plugin_status?
- plugin_status = request(:plugin_status)
-
- if plugin_status.present? && plugin_status[:status].present?
- plugin_notice = convert_plugin_status_to_notice(plugin_status)
- notices.push(plugin_notice) if plugin_notice
- end
- end
-
- if notices.any?
- notices.each do |notice_data|
- notice = new(notice_data)
- notice.retrieved_at = DateTime.now.iso8601(3)
- notice.save
- end
- end
-
- publish_notice_count
- end
-
- def self.publish_notice_count
- payload = {
- active_notice_count: CustomWizard::Notice.active_count
- }
- MessageBus.publish("/custom-wizard/notices", payload, group_ids: [Group::AUTO_GROUPS[:admins]])
- end
-
- def self.convert_subscription_messages_to_notices(messages)
- messages.reduce([]) do |result, message|
- id = generate_notice_id(message[:title], message[:created_at])
- result.push(
- id: id,
- title: message[:title],
- message: message[:message],
- type: types[message[:type].to_sym],
- archetype: archetypes[:subscription_message],
- created_at: message[:created_at],
- expired_at: message[:expired_at]
- )
- result
- end
- end
-
- def self.convert_plugin_status_to_notice(plugin_status)
- notice = nil
-
- if PLUGIN_STATUSES_TO_WARN.include?(plugin_status[:status])
- title = I18n.t('wizard.notice.compatibility_issue.title')
- created_at = plugin_status[:status_changed_at]
- id = generate_notice_id(title, created_at)
-
- unless exists?(id)
- message = I18n.t('wizard.notice.compatibility_issue.message', domain: plugin_status_domain)
- notice = {
- id: id,
- title: title,
- message: message,
- type: types[:warning],
- archetype: archetypes[:plugin_status],
- created_at: created_at
- }
- end
- else
- expire_all(types[:warning], archetypes[:plugin_status])
- end
-
- notice
- end
-
- def self.notify_connection_errors(archetype)
- domain = self.send("#{archetype.to_s}_domain")
- title = I18n.t("wizard.notice.#{archetype.to_s}.connection_error.title")
- notices = list(type: types[:connection_error], archetype: archetypes[archetype.to_sym], title: title)
-
- if notices.any?
- notice = notices.first
- notice.updated_at = DateTime.now.iso8601(3)
- notice.save
- else
- notice = new(
- title: title,
- message: I18n.t("wizard.notice.#{archetype.to_s}.connection_error.message", domain: domain),
- archetype: archetypes[archetype.to_sym],
- type: types[:connection_error],
- created_at: DateTime.now.iso8601(3),
- updated_at: DateTime.now.iso8601(3)
- )
- notice.save
- end
- end
-
- def self.request_plugin_status?
- CHECK_PLUGIN_STATUS_ON_BRANCH.include?(Discourse.git_branch) || Rails.env.test? || Rails.env.development?
- end
-
- def self.subscription_message_domain
- return LOCALHOST_DOMAIN if (Rails.env.test? || Rails.env.development?)
- SUBSCRIPTION_MESSAGE_DOMAIN
- end
-
- def self.subscription_message_url
- "https://#{subscription_message_domain}/subscription-server/messages.json"
- end
-
- def self.plugin_status_domain
- return LOCALHOST_DOMAIN if (Rails.env.test? || Rails.env.development?)
- PLUGIN_STATUS_DOMAINS[Discourse.git_branch]
- end
-
- def self.plugin_status_url
- "https://#{plugin_status_domain}/plugin-manager/status/discourse-custom-wizard"
- end
-
- def self.request(archetype)
- url = self.send("#{archetype.to_s}_url")
-
- begin
- response = Excon.get(url)
- rescue Excon::Error::Socket, Excon::Error::Timeout => e
- response = nil
- end
- connection_error = CustomWizard::Notice::ConnectionError.new(archetype)
-
- if response && response.status == 200
- connection_error.expire!
- expire_all(types[:connection_error], archetypes[archetype.to_sym])
-
- begin
- data = JSON.parse(response.body).deep_symbolize_keys
- rescue JSON::ParserError
- return nil
- end
-
- data
- else
- connection_error.create!
- notify_connection_errors(archetype) if connection_error.reached_limit?
- nil
- end
- end
-
- def self.namespace
- "#{CustomWizard::PLUGIN_NAME}_notice"
- end
-
- def self.find(id)
- raw = PluginStore.get(namespace, id)
- new(raw.symbolize_keys) if raw.present?
- end
-
- def self.exists?(id)
- PluginStoreRow.where(plugin_name: namespace, key: id).exists?
- end
-
- def self.store(id, raw_notice)
- PluginStore.set(namespace, id, raw_notice)
- end
-
- def self.list_query(type: nil, archetype: nil, title: nil, include_all: false, page: nil, visible: false)
- query = PluginStoreRow.where(plugin_name: namespace)
- query = query.where("(value::json->>'hidden_at') IS NULL") if visible
- query = query.where("(value::json->>'dismissed_at') IS NULL") unless include_all
- query = query.where("(value::json->>'expired_at') IS NULL") unless include_all
- query = query.where("(value::json->>'archetype')::integer = ?", archetype) if archetype
- if type
- type_query_str = type.is_a?(Array) ? "(value::json->>'type')::integer IN (?)" : "(value::json->>'type')::integer = ?"
- query = query.where(type_query_str, type)
- end
- query = query.where("(value::json->>'title')::text = ?", title) if title
- query = query.limit(PAGE_LIMIT).offset(page.to_i * PAGE_LIMIT) if !page.nil?
- query.order("value::json->>'expired_at' DESC, value::json->>'updated_at' DESC,value::json->>'dismissed_at' DESC, value::json->>'created_at' DESC")
- end
-
- def self.list(type: nil, archetype: nil, title: nil, include_all: false, page: 0, visible: false)
- list_query(type: type, archetype: archetype, title: title, include_all: include_all, page: page, visible: visible)
- .map { |r| self.new(JSON.parse(r.value).symbolize_keys) }
- end
-
- def self.active_count
- list_query.count
- end
-
- def self.dismiss_all
- dismissed_count = PluginStoreRow.where("
- plugin_name = '#{namespace}' AND
- (value::json->>'type')::integer = #{types[:info]} AND
- (value::json->>'expired_at') IS NULL AND
- (value::json->>'dismissed_at') IS NULL
- ").update_all("
- value = jsonb_set(value::jsonb, '{dismissed_at}', (to_json(now())::text)::jsonb, true)
- ")
- publish_notice_count if dismissed_count.to_i > 0
- dismissed_count
- end
-
- def self.expire_all(type, archetype)
- expired_count = PluginStoreRow.where("
- plugin_name = '#{namespace}' AND
- (value::json->>'type')::integer = #{type} AND
- (value::json->>'archetype')::integer = #{archetype} AND
- (value::json->>'expired_at') IS NULL
- ").update_all("
- value = jsonb_set(value::jsonb, '{expired_at}', (to_json(now())::text)::jsonb, true)
- ")
- publish_notice_count if expired_count.to_i > 0
- expired_count
- end
-
- def self.generate_notice_id(title, created_at)
- Digest::SHA1.hexdigest("#{title}-#{created_at}")
- end
-end
diff --git a/lib/custom_wizard/notice/connection_error.rb b/lib/custom_wizard/notice/connection_error.rb
deleted file mode 100644
index a1d834c6..00000000
--- a/lib/custom_wizard/notice/connection_error.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-# frozen_string_literal: true
-
-class CustomWizard::Notice::ConnectionError
-
- attr_reader :archetype
-
- def initialize(archetype)
- @archetype = archetype
- end
-
- def create!
- if attrs = current_error
- key = "#{archetype.to_s}_error_#{attrs[:id]}"
- attrs[:updated_at] = Time.now
- attrs[:count] = attrs[:count].to_i + 1
- else
- domain = CustomWizard::Notice.send("#{archetype.to_s}_domain")
- id = SecureRandom.hex(8)
- attrs = {
- id: id,
- message: I18n.t("wizard.notice.connection_error", domain: domain),
- archetype: CustomWizard::Notice.archetypes[archetype.to_sym],
- created_at: Time.now,
- count: 1
- }
- key = "#{archetype.to_s}_error_#{id}"
- end
-
- PluginStore.set(namespace, key, attrs)
-
- @current_error = nil
- end
-
- def expire!
- if query = current_error(query_only: true)
- record = query.first
- error = JSON.parse(record.value)
- error['expired_at'] = Time.now
- record.value = error.to_json
- record.save
- end
- end
-
- def plugin_status_limit
- 5
- end
-
- def subscription_message_limit
- 10
- end
-
- def limit
- self.send("#{archetype.to_s}_limit")
- end
-
- def reached_limit?
- return false unless current_error.present?
- current_error[:count].to_i >= limit
- end
-
- def namespace
- "#{CustomWizard::PLUGIN_NAME}_notice_connection"
- end
-
- def current_error(query_only: false)
- @current_error ||= begin
- query = PluginStoreRow.where(plugin_name: namespace)
- query = query.where("(value::json->>'archetype')::integer = ?", CustomWizard::Notice.archetypes[archetype.to_sym])
- query = query.where("(value::json->>'expired_at') IS NULL")
-
- return nil if !query.exists?
- return query if query_only
-
- JSON.parse(query.first.value).deep_symbolize_keys
- end
- end
-end
diff --git a/lib/custom_wizard/subscription.rb b/lib/custom_wizard/subscription.rb
index 7bac7f59..114f6743 100644
--- a/lib/custom_wizard/subscription.rb
+++ b/lib/custom_wizard/subscription.rb
@@ -1,240 +1,170 @@
# frozen_string_literal: true
-
class CustomWizard::Subscription
- include ActiveModel::Serialization
+ STANDARD_PRODUCT_ID = 'prod_LNAGVAaIqDsHmB'
+ BUSINESS_PRODUCT_ID = 'prod_LNABQ50maBQ1pY'
- attr_accessor :authentication,
- :subscription
-
- SUBSCRIPTION_LEVELS = {
- standard: {
- actions: ["send_message", "add_to_group", "watch_categories"],
- custom_fields: {
- klass: [],
- type: ["json"],
+ def self.attributes
+ {
+ wizard: {
+ required: {
+ none: [],
+ standard: ['*'],
+ business: ['*']
+ },
+ permitted: {
+ none: [],
+ standard: ['*'],
+ business: ['*']
+ }
},
- },
- business: {
- actions: ["create_category", "create_group", "send_to_api"],
- custom_fields: {
- klass: ["group", "category"],
- type: [],
+ step: {
+ condition: {
+ none: [],
+ standard: ['*'],
+ business: ['*']
+ },
+ index: {
+ none: [],
+ standard: ['*'],
+ business: ['*']
+ },
+ required_data: {
+ none: [],
+ standard: ['*'],
+ business: ['*']
+ },
+ permitted_params: {
+ none: [],
+ standard: ['*'],
+ business: ['*']
+ }
},
- },
- }
+ field: {
+ condition: {
+ none: [],
+ standard: ['*'],
+ business: ['*']
+ },
+ index: {
+ none: [],
+ standard: ['*'],
+ business: ['*']
+ },
+ type: {
+ none: ['text', 'textarea', 'text_only', 'date', 'time', 'date_time', 'number', 'checkbox', 'dropdown', 'upload'],
+ standard: ['*'],
+ business: ['*']
+ },
+ realtime_validations: {
+ none: [],
+ standard: ['*'],
+ business: ['*']
+ }
+ },
+ action: {
+ type: {
+ none: ['create_topic', 'update_profile', 'open_composer', 'route_to'],
+ standard: ['create_topic', 'update_profile', 'open_composer', 'route_to', 'send_message', 'watch_categories', 'add_to_group'],
+ business: ['*']
+ }
+ },
+ custom_field: {
+ klass: {
+ none: ['topic', 'post'],
+ standard: ['topic', 'post'],
+ business: ['*']
+ },
+ type: {
+ none: ['string', 'boolean', 'integer'],
+ standard: ['string', 'boolean', 'integer'],
+ business: ['*']
+ }
+ }
+ }
+ end
def initialize
- @authentication = CustomWizard::Subscription::Authentication.new(get_authentication)
- @subscription = CustomWizard::Subscription::Subscription.new(get_subscription)
+ @subscription = find_subscription
end
- def authorized?
- @authentication.active?
- end
+ def includes?(feature, attribute, value)
+ attributes = self.class.attributes[feature]
- def subscribed?
- @subscription.active?
- end
+ ## Attribute is not part of a subscription
+ return true unless attributes.present? && attributes.key?(attribute)
- def server
- "test.thepavilion.io"
- end
+ values = attributes[attribute][type]
- def subscription_type
- "stripe"
+ ## Subscription type does not support the attribute.
+ return false if values.blank?
+
+ ## Subscription type supports all values of the attribute.
+ return true if values.first === "*"
+
+ ## Subscription type supports some values of the attributes.
+ values.include?(value)
end
def type
- @subscription.type
+ return :none unless subscribed?
+ return :standard if standard?
+ return :business if business?
end
- def client_name
- "custom-wizard"
+ def subscribed?
+ standard? || business?
end
- def scope
- "discourse-subscription-server:user_subscription"
+ def standard?
+ @subscription.product_id === STANDARD_PRODUCT_ID
end
- def requires_additional_subscription(kategory, sub_kategory)
- case kategory
- when "actions"
- case self.type
- when "business"
- []
- when "standard"
- SUBSCRIPTION_LEVELS[:business][kategory.to_sym]
- else
- SUBSCRIPTION_LEVELS[:standard][kategory.to_sym] + SUBSCRIPTION_LEVELS[:business][kategory.to_sym]
- end
- when "custom_fields"
- case self.type
- when "business"
- []
- when "standard"
- SUBSCRIPTION_LEVELS[:business][kategory.to_sym][sub_kategory.to_sym]
- else
- SUBSCRIPTION_LEVELS[:standard][kategory.to_sym][sub_kategory.to_sym] + SUBSCRIPTION_LEVELS[:business][kategory.to_sym][sub_kategory.to_sym]
- end
- else
- []
- end
+ def business?
+ @subscription.product_id === BUSINESS_PRODUCT_ID
end
- def update
- if @authentication.active?
- response = Excon.get(
- "https://#{server}/subscription-server/user-subscriptions/#{subscription_type}/#{client_name}",
- headers: {
- "User-Api-Key" => @authentication.api_key
- }
- )
+ def client_installed?
+ defined?(SubscriptionClient) == 'constant' && SubscriptionClient.class == Module
+ end
- if response.status == 200
- begin
- data = JSON.parse(response.body).deep_symbolize_keys
- rescue JSON::ParserError
- return false
- end
+ def find_subscription
+ subscription = nil
- return false unless data && data.is_a?(Hash)
- subscriptions = data[:subscriptions]
-
- if subscriptions.present? && type = subscriptions.first[:price_nickname]
- @subscription = set_subscription(type)
- return true
- end
- end
+ if client_installed?
+ subscription = SubscriptionClientSubscription.active
+ .where(product_id: [STANDARD_PRODUCT_ID, BUSINESS_PRODUCT_ID])
+ .order("product_id = '#{BUSINESS_PRODUCT_ID}' DESC")
+ .first
end
- destroy_subscription
- false
- end
-
- def destroy_subscription
- if remove_subscription
- @subscription = CustomWizard::Subscription::Subscription.new(get_subscription)
- !@subscription.active?
- else
- false
+ unless subscription
+ subscription = OpenStruct.new(product_id: nil)
end
- end
- def authentication_url(user_id, request_id)
- keys = @authentication.generate_keys(user_id, request_id)
- params = {
- public_key: keys.public_key,
- nonce: keys.nonce,
- client_id: @authentication.client_id,
- auth_redirect: "#{Discourse.base_url}/admin/wizards/subscription/authorize/callback",
- application_name: SiteSetting.title,
- scopes: scope
- }
-
- uri = URI.parse("https://#{server}/user-api-key/new")
- uri.query = URI.encode_www_form(params)
- uri.to_s
- end
-
- def authentication_response(request_id, payload)
- data = @authentication.decrypt_payload(request_id, payload)
- return false unless data.is_a?(Hash) && data[:key] && data[:user_id]
-
- api_key = data[:key]
- user_id = data[:user_id]
- user = User.find(user_id)
-
- if user&.admin
- @authentication = set_authentication(api_key, user.id)
- true
- else
- false
- end
- end
-
- def destroy_authentication
- if remove_authentication
- @authentication = CustomWizard::Subscription::Authentication.new(get_authentication)
- !@authentication.active?
- else
- false
- end
+ subscription
end
def self.subscribed?
- self.new.subscribed?
+ new.subscribed?
+ end
+
+ def self.business?
+ new.business?
+ end
+
+ def self.standard?
+ new.standard?
end
def self.type
- self.new.type
+ new.type
end
- def self.requires_additional_subscription(kategory, sub_kategory)
- self.new.requires_additional_subscription(kategory, sub_kategory)
+ def self.client_installed?
+ new.client_installed?
end
- def self.authorized?
- self.new.authorized?
- end
-
- def self.update
- self.new.update
- end
-
- def self.namespace
- "custom_wizard_subscription"
- end
-
- private
-
- def subscription_db_key
- "subscription"
- end
-
- def authentication_db_key
- "authentication"
- end
-
- def get_subscription
- raw = PluginStore.get(self.class.namespace, subscription_db_key)
-
- if raw.present?
- OpenStruct.new(
- type: raw['type'],
- updated_at: raw['updated_at']
- )
- end
- end
-
- def remove_subscription
- PluginStore.remove(self.class.namespace, subscription_db_key)
- end
-
- def set_subscription(type)
- PluginStore.set(CustomWizard::Subscription.namespace, subscription_db_key, type: type, updated_at: Time.now)
- CustomWizard::Subscription::Subscription.new(get_subscription)
- end
-
- def get_authentication
- raw = PluginStore.get(self.class.namespace, authentication_db_key)
- OpenStruct.new(
- key: raw && raw['key'],
- auth_by: raw && raw['auth_by'],
- auth_at: raw && raw['auth_at']
- )
- end
-
- def set_authentication(key, user_id)
- PluginStore.set(self.class.namespace, authentication_db_key,
- key: key,
- auth_by: user_id,
- auth_at: Time.now
- )
- CustomWizard::Subscription::Authentication.new(get_authentication)
- end
-
- def remove_authentication
- PluginStore.remove(self.class.namespace, authentication_db_key)
- get_authentication
+ def self.includes?(feature, attribute, value)
+ new.includes?(feature, attribute, value)
end
end
diff --git a/lib/custom_wizard/subscription/authentication.rb b/lib/custom_wizard/subscription/authentication.rb
deleted file mode 100644
index 7ad02d2c..00000000
--- a/lib/custom_wizard/subscription/authentication.rb
+++ /dev/null
@@ -1,95 +0,0 @@
-# frozen_string_literal: true
-class CustomWizard::Subscription::Authentication
- include ActiveModel::Serialization
-
- attr_reader :client_id,
- :auth_by,
- :auth_at,
- :api_key
-
- def initialize(auth)
- if auth
- @api_key = auth.key
- @auth_at = auth.auth_at
- @auth_by = auth.auth_by
- end
-
- @client_id = get_client_id || set_client_id
- end
-
- def active?
- @api_key.present?
- end
-
- def generate_keys(user_id, request_id)
- rsa = OpenSSL::PKey::RSA.generate(2048)
- nonce = SecureRandom.hex(32)
- set_keys(request_id, user_id, rsa, nonce)
-
- OpenStruct.new(nonce: nonce, public_key: rsa.public_key)
- end
-
- def decrypt_payload(request_id, payload)
- keys = get_keys(request_id)
-
- return false unless keys.present? && keys.pem
- delete_keys(request_id)
-
- rsa = OpenSSL::PKey::RSA.new(keys.pem)
- decrypted_payload = rsa.private_decrypt(Base64.decode64(payload))
-
- return false unless decrypted_payload.present?
-
- begin
- data = JSON.parse(decrypted_payload).symbolize_keys
- rescue JSON::ParserError
- return false
- end
-
- return false unless data[:nonce] == keys.nonce
- data[:user_id] = keys.user_id
-
- data
- end
-
- def get_keys(request_id)
- raw = PluginStore.get(CustomWizard::Subscription.namespace, "#{keys_db_key}_#{request_id}")
- OpenStruct.new(
- user_id: raw && raw['user_id'],
- pem: raw && raw['pem'],
- nonce: raw && raw['nonce']
- )
- end
-
- private
-
- def keys_db_key
- "keys"
- end
-
- def client_id_db_key
- "client_id"
- end
-
- def set_keys(request_id, user_id, rsa, nonce)
- PluginStore.set(CustomWizard::Subscription.namespace, "#{keys_db_key}_#{request_id}",
- user_id: user_id,
- pem: rsa.export,
- nonce: nonce
- )
- end
-
- def delete_keys(request_id)
- PluginStore.remove(CustomWizard::Subscription.namespace, "#{keys_db_key}_#{request_id}")
- end
-
- def get_client_id
- PluginStore.get(CustomWizard::Subscription.namespace, client_id_db_key)
- end
-
- def set_client_id
- client_id = SecureRandom.hex(32)
- PluginStore.set(CustomWizard::Subscription.namespace, client_id_db_key, client_id)
- client_id
- end
-end
diff --git a/lib/custom_wizard/subscription/subscription.rb b/lib/custom_wizard/subscription/subscription.rb
deleted file mode 100644
index 0b3bb84d..00000000
--- a/lib/custom_wizard/subscription/subscription.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: true
-class CustomWizard::Subscription::Subscription
- include ActiveModel::Serialization
-
- attr_reader :type,
- :updated_at
-
- def initialize(subscription)
- if subscription
- @type = subscription.type
- @updated_at = subscription.updated_at
- end
- end
-
- def types
- %w(none standard business)
- end
-
- def active?
- types.include?(type) && updated_at.to_datetime > (Time.zone.now - 2.hours).to_datetime
- end
-end
diff --git a/lib/custom_wizard/validators/template.rb b/lib/custom_wizard/validators/template.rb
index 9ae37170..079f9884 100644
--- a/lib/custom_wizard/validators/template.rb
+++ b/lib/custom_wizard/validators/template.rb
@@ -54,34 +54,6 @@ class CustomWizard::TemplateValidator
}
end
- def self.subscription
- {
- wizard: {
- save_submissions: 'false',
- restart_on_revisit: 'true',
- },
- step: {
- condition: 'present',
- index: 'conditional',
- required_data: 'present',
- permitted_params: 'present'
- },
- field: {
- condition: 'present',
- index: 'conditional'
- },
- action: {
- type: %w[
- send_message
- add_to_group
- create_category
- create_group
- send_to_api
- ]
- }
- }
- end
-
private
def check_required(object, type)
@@ -93,16 +65,10 @@ class CustomWizard::TemplateValidator
end
def validate_subscription(object, type)
- self.class.subscription[type].each do |property, subscription_type|
- val = object[property.to_s]
- is_subscription = (val != nil) && (
- subscription_type === 'present' && val.present? ||
- (['true', 'false'].include?(subscription_type) && cast_bool(val) == cast_bool(subscription_type)) ||
- (subscription_type === 'conditional' && val.is_a?(Hash)) ||
- (subscription_type.is_a?(Array) && subscription_type.include?(val))
- )
+ object.keys.each do |property|
+ value = object[property]
- if is_subscription && !@subscription.subscribed?
+ if !@subscription.includes?(type, property.to_sym, value)
errors.add :base, I18n.t("wizard.validation.subscription", type: type.to_s, property: property)
end
end
@@ -148,10 +114,6 @@ class CustomWizard::TemplateValidator
end
end
- def cast_bool(val)
- ActiveRecord::Type::Boolean.new.cast(val)
- end
-
def validate_liquid_template(object, type)
%w[
description
diff --git a/plugin.rb b/plugin.rb
index e745c3a8..ebd5c6d5 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -5,17 +5,13 @@
# authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George
# contact_emails: support@thepavilion.io
# url: https://github.com/paviliondev/discourse-custom-wizard
+# subscription_url: https://coop.pavilion.tech
gem 'liquid', '5.0.1', require: true
register_asset 'stylesheets/admin/admin.scss', :desktop
enabled_site_setting :custom_wizard_enabled
-config = Rails.application.config
-plugin_asset_path = "#{Rails.root}/plugins/discourse-custom-wizard/assets"
-config.assets.paths << "#{plugin_asset_path}/javascripts"
-config.assets.paths << "#{plugin_asset_path}/stylesheets/wizard"
-
if Rails.env.production?
config.assets.precompile += %w{
wizard-custom-guest.js
@@ -59,6 +55,24 @@ class ::Sprockets::DirectiveProcessor
end
end
+## Override necessary due to 'assets/javascripts/wizard', particularly its tests.
+def each_globbed_asset
+ if @path
+ root_path = "#{File.dirname(@path)}/assets/javascripts/discourse"
+
+ Dir.glob(["#{root_path}/**/*"]).sort.each do |f|
+ f_str = f.to_s
+ if File.directory?(f)
+ yield [f, true]
+ elsif f_str.end_with?(".js.es6") || f_str.end_with?(".hbs") || f_str.end_with?(".hbr")
+ yield [f, false]
+ elsif transpile_js && f_str.end_with?(".js")
+ yield [f, false]
+ end
+ end
+ end
+end
+
after_initialize do
%w[
../lib/custom_wizard/engine.rb
@@ -70,15 +84,11 @@ after_initialize do
../app/controllers/custom_wizard/admin/logs.rb
../app/controllers/custom_wizard/admin/manager.rb
../app/controllers/custom_wizard/admin/custom_fields.rb
- ../app/controllers/custom_wizard/admin/subscription.rb
- ../app/controllers/custom_wizard/admin/notice.rb
../app/controllers/custom_wizard/wizard.rb
../app/controllers/custom_wizard/steps.rb
../app/controllers/custom_wizard/realtime_validations.rb
../app/jobs/regular/refresh_api_access_token.rb
../app/jobs/regular/set_after_time_wizard.rb
- ../app/jobs/scheduled/custom_wizard/update_subscription.rb
- ../app/jobs/scheduled/custom_wizard/update_notices.rb
../lib/custom_wizard/validators/template.rb
../lib/custom_wizard/validators/update.rb
../lib/custom_wizard/action_result.rb
@@ -95,13 +105,9 @@ after_initialize do
../lib/custom_wizard/step_updater.rb
../lib/custom_wizard/step.rb
../lib/custom_wizard/submission.rb
+ ../lib/custom_wizard/subscription.rb
../lib/custom_wizard/template.rb
../lib/custom_wizard/wizard.rb
- ../lib/custom_wizard/notice.rb
- ../lib/custom_wizard/notice/connection_error.rb
- ../lib/custom_wizard/subscription.rb
- ../lib/custom_wizard/subscription/subscription.rb
- ../lib/custom_wizard/subscription/authentication.rb
../lib/custom_wizard/api/api.rb
../lib/custom_wizard/api/authorization.rb
../lib/custom_wizard/api/endpoint.rb
@@ -122,10 +128,6 @@ after_initialize do
../app/serializers/custom_wizard/log_serializer.rb
../app/serializers/custom_wizard/submission_serializer.rb
../app/serializers/custom_wizard/realtime_validation/similar_topics_serializer.rb
- ../app/serializers/custom_wizard/subscription/authentication_serializer.rb
- ../app/serializers/custom_wizard/subscription/subscription_serializer.rb
- ../app/serializers/custom_wizard/subscription_serializer.rb
- ../app/serializers/custom_wizard/notice_serializer.rb
../lib/custom_wizard/extensions/extra_locales_controller.rb
../lib/custom_wizard/extensions/invites_controller.rb
../lib/custom_wizard/extensions/users_controller.rb
@@ -271,14 +273,6 @@ after_initialize do
"#{serializer_klass}_serializer".classify.constantize.prepend CustomWizardCustomFieldSerializer
end
- AdminDashboardData.add_problem_check do
- warning_notices = CustomWizard::Notice.list(
- type: CustomWizard::Notice.types[:warning],
- archetype: CustomWizard::Notice.archetypes[:plugin_status]
- )
- warning_notices.any? ? ActionView::Base.full_sanitizer.sanitize(warning_notices.first.message, tags: %w(a)) : nil
- end
-
reloadable_patch do |plugin|
::TagsController.prepend CustomWizardTagsController
::DiscourseTagging.singleton_class.prepend CustomWizardDiscourseTagging
diff --git a/spec/components/custom_wizard/action_spec.rb b/spec/components/custom_wizard/action_spec.rb
index 6149272e..5155a7f4 100644
--- a/spec/components/custom_wizard/action_spec.rb
+++ b/spec/components/custom_wizard/action_spec.rb
@@ -8,6 +8,7 @@ describe CustomWizard::Action do
let(:wizard_template) { get_wizard_fixture("wizard") }
let(:open_composer) { get_wizard_fixture("actions/open_composer") }
let(:create_category) { get_wizard_fixture("actions/create_category") }
+ let(:watch_categories) { get_wizard_fixture("actions/watch_categories") }
let(:create_group) { get_wizard_fixture("actions/create_group") }
let(:add_to_group) { get_wizard_fixture("actions/add_to_group") }
let(:send_message) { get_wizard_fixture("actions/send_message") }
@@ -158,17 +159,6 @@ describe CustomWizard::Action do
end
end
- it 'watches categories' do
- wizard = CustomWizard::Builder.new(@template[:id], user).build
- wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update
- wizard.create_updater(wizard.steps[1].id, {}).update
-
- expect(CategoryUser.where(
- category_id: category.id,
- user_id: user.id
- ).first.notification_level).to eq(0)
- end
-
it 're-routes a user' do
wizard = CustomWizard::Builder.new(@template[:id], user).build
updater = wizard.create_updater(wizard.steps.last.id, {})
@@ -176,11 +166,25 @@ describe CustomWizard::Action do
expect(updater.result[:redirect_on_next]).to eq("https://google.com")
end
- context "subscription actions" do
+ context "standard subscription actions" do
before do
enable_subscription("standard")
end
+ it 'watches categories' do
+ watch_categories[:categories][0][:output] = category.id
+ wizard_template[:actions] << watch_categories
+ update_template(wizard_template)
+
+ wizard = CustomWizard::Builder.new(@template[:id], user).build
+ wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update
+
+ expect(CategoryUser.where(
+ category_id: category.id,
+ user_id: user.id
+ ).first.notification_level).to eq(2)
+ end
+
it '#send_message' do
wizard_template['actions'] << send_message
update_template(wizard_template)
@@ -233,9 +237,16 @@ describe CustomWizard::Action do
expect(topic.first.allowed_groups.map(&:name)).to include('cool_group', 'cool_group_1')
expect(post.exists?).to eq(true)
end
+ end
+
+ context "business subscription actions" do
+ before do
+ enable_subscription("business")
+ end
it '#create_category' do
wizard_template['actions'] << create_category
+ wizard_template['actions'] << create_group
update_template(wizard_template)
wizard = CustomWizard::Builder.new(@template[:id], user).build
diff --git a/spec/components/custom_wizard/builder_spec.rb b/spec/components/custom_wizard/builder_spec.rb
index 1d7b1213..ebcc355b 100644
--- a/spec/components/custom_wizard/builder_spec.rb
+++ b/spec/components/custom_wizard/builder_spec.rb
@@ -100,6 +100,7 @@ describe CustomWizard::Builder do
context "with restricted permissions" do
before do
+ enable_subscription("standard")
@template[:permitted] = permitted_json["permitted"]
CustomWizard::Template.save(@template.as_json)
end
@@ -304,7 +305,7 @@ describe CustomWizard::Builder do
before do
enable_subscription("standard")
@template[:steps][0][:fields][0][:condition] = user_condition_json['condition']
- @template[:steps][2][:fields][5][:condition] = boolean_field_condition_json['condition']
+ @template[:steps][2][:fields][0][:condition] = boolean_field_condition_json['condition']
CustomWizard::Template.save(@template.as_json)
end
@@ -325,7 +326,7 @@ describe CustomWizard::Builder do
builder = CustomWizard::Builder.new(@template[:id], user)
wizard = builder.build
- expect(wizard.steps.last.fields.last.id).to eq(@template[:steps][2][:fields][5]['id'])
+ expect(wizard.steps.last.fields.last.id).to eq(@template[:steps][2][:fields][0]['id'])
end
end
end
diff --git a/spec/components/custom_wizard/notice_spec.rb b/spec/components/custom_wizard/notice_spec.rb
deleted file mode 100644
index 0b34664d..00000000
--- a/spec/components/custom_wizard/notice_spec.rb
+++ /dev/null
@@ -1,159 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../../plugin_helper'
-
-describe CustomWizard::Notice do
- fab!(:user) { Fabricate(:user) }
- let(:subscription_message) {
- {
- title: "Title of message about subscription",
- message: "Message about subscription",
- type: "info",
- created_at: Time.now - 3.day,
- expired_at: nil
- }
- }
- let(:plugin_status) {
- {
- name: 'discourse-custom-wizard',
- status: 'incompatible',
- status_changed_at: Time.now - 3.day
- }
- }
-
- context "subscription message" do
- before do
- freeze_time
- stub_request(:get, described_class.subscription_message_url).to_return(status: 200, body: { messages: [subscription_message] }.to_json)
- described_class.update(skip_plugin: true)
- end
-
- it "converts subscription messages into notices" do
- notice = described_class.list.first
- expect(notice.type).to eq(described_class.types[:info])
- expect(notice.message).to eq(subscription_message[:message])
- expect(notice.created_at.to_datetime).to be_within(1.second).of (subscription_message[:created_at].to_datetime)
- end
-
- it "expires notice if subscription message is expired" do
- subscription_message[:expired_at] = Time.now
- stub_request(:get, described_class.subscription_message_url).to_return(status: 200, body: { messages: [subscription_message] }.to_json)
- described_class.update(skip_plugin: true)
-
- notice = described_class.list(include_all: true).first
- expect(notice.expired?).to eq(true)
- end
-
- it "dismisses informational subscription notices" do
- notice = described_class.list(include_all: true).first
- expect(notice.dismissed?).to eq(false)
-
- notice.dismiss!
- expect(notice.dismissed?).to eq(true)
- end
-
- it "dismisses all informational subscription notices" do
- 4.times do |index|
- subscription_message[:title] += " #{index}"
- stub_request(:get, described_class.subscription_message_url).to_return(status: 200, body: { messages: [subscription_message] }.to_json)
- described_class.update(skip_plugin: true)
- end
- expect(described_class.list.count).to eq(5)
- described_class.dismiss_all
- expect(described_class.list.count).to eq(0)
- end
- end
-
- context "plugin status" do
- before do
- freeze_time
- stub_request(:get, described_class.plugin_status_url).to_return(status: 200, body: plugin_status.to_json)
- described_class.update(skip_subscription: true)
- end
-
- it "converts warning into notice" do
- notice = described_class.list.first
- expect(notice.type).to eq(described_class.types[:warning])
- expect(notice.message).to eq(I18n.t("wizard.notice.compatibility_issue.message", domain: described_class.plugin_status_domain))
- expect(notice.created_at.to_datetime).to be_within(1.second).of (plugin_status[:status_changed_at].to_datetime)
- end
-
- it "expires warning notices if status is recommended or compatible" do
- plugin_status[:status] = 'compatible'
- plugin_status[:status_changed_at] = Time.now
- stub_request(:get, described_class.plugin_status_url).to_return(status: 200, body: plugin_status.to_json)
- described_class.update(skip_subscription: true)
-
- notice = described_class.list(type: described_class.types[:warning], include_all: true).first
- expect(notice.expired?).to eq(true)
- end
-
- it "hides plugin status warnings" do
- notice = described_class.list.first
- expect(notice.hidden?).to eq(false)
-
- notice.hide!
- expect(notice.hidden?).to eq(true)
- end
- end
-
- it "lists notices not expired more than a day ago" do
- subscription_message[:expired_at] = Time.now - 8.hours
- stub_request(:get, described_class.subscription_message_url).to_return(status: 200, body: { messages: [subscription_message] }.to_json)
- stub_request(:get, described_class.plugin_status_url).to_return(status: 200, body: plugin_status.to_json)
-
- described_class.update
- expect(described_class.list(include_all: true).length).to eq(2)
- end
-
- context "connection errors" do
- before do
- freeze_time
- end
-
- it "creates an error if connection to notice server fails" do
- stub_request(:get, described_class.plugin_status_url).to_return(status: 400, body: plugin_status.to_json)
- described_class.update(skip_subscription: true)
-
- error = CustomWizard::Notice::ConnectionError.new(:plugin_status)
- expect(error.current_error.present?).to eq(true)
- end
-
- it "only creates one connection error per type at a time" do
- stub_request(:get, described_class.subscription_message_url).to_return(status: 400, body: { messages: [subscription_message] }.to_json)
- stub_request(:get, described_class.plugin_status_url).to_return(status: 400, body: plugin_status.to_json)
-
- 5.times { described_class.update }
-
- plugin_status_errors = CustomWizard::Notice::ConnectionError.new(:plugin_status)
- subscription_message_errors = CustomWizard::Notice::ConnectionError.new(:subscription_message)
-
- expect(plugin_status_errors.current_error[:count]).to eq(5)
- expect(subscription_message_errors.current_error[:count]).to eq(5)
- end
-
- it "creates a connection error notice if connection errors reach limit" do
- stub_request(:get, described_class.plugin_status_url).to_return(status: 400, body: plugin_status.to_json)
-
- error = CustomWizard::Notice::ConnectionError.new(:plugin_status)
- error.limit.times { described_class.update(skip_subscription: true) }
- notice = described_class.list(type: described_class.types[:connection_error]).first
-
- expect(error.current_error[:count]).to eq(error.limit)
- expect(notice.type).to eq(described_class.types[:connection_error])
- end
-
- it "expires a connection error notice if connection succeeds" do
- stub_request(:get, described_class.plugin_status_url).to_return(status: 400, body: plugin_status.to_json)
- error = CustomWizard::Notice::ConnectionError.new(:plugin_status)
- error.limit.times { described_class.update(skip_subscription: true) }
-
- stub_request(:get, described_class.plugin_status_url).to_return(status: 200, body: plugin_status.to_json)
- described_class.update(skip_subscription: true)
- notice = described_class.list(type: described_class.types[:connection_error], include_all: true).first
-
- expect(notice.type).to eq(described_class.types[:connection_error])
- expect(notice.expired_at.present?).to eq(true)
- end
- end
-end
diff --git a/spec/components/custom_wizard/subscription_spec.rb b/spec/components/custom_wizard/subscription_spec.rb
index 47fb2d3f..984eff9f 100644
--- a/spec/components/custom_wizard/subscription_spec.rb
+++ b/spec/components/custom_wizard/subscription_spec.rb
@@ -1,125 +1,104 @@
# frozen_string_literal: true
-require_relative '../../plugin_helper'
-
describe CustomWizard::Subscription do
- fab!(:user) { Fabricate(:user) }
-
- it "initializes subscription authentication and subscription" do
- subscription = described_class.new
- expect(subscription.authentication.class).to eq(CustomWizard::Subscription::Authentication)
- expect(subscription.subscription.class).to eq(CustomWizard::Subscription::Subscription)
+ def undefine_client_classes
+ Object.send(:remove_const, :SubscriptionClient) if Object.constants.include?(:SubscriptionClient)
+ Object.send(:remove_const, :SubscriptionClientSubscription) if Object.constants.include?(:SubscriptionClientSubscription)
end
- it "returns authorized and subscribed states" do
- subscription = described_class.new
- expect(subscription.authorized?).to eq(false)
- expect(subscription.subscribed?).to eq(false)
+ def define_client_classes
+ load File.expand_path("#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/subscription_client.rb", __FILE__)
end
- context "subscription" do
+ def stub_client_methods
+ [:active, :where, :order, :first].each do |method|
+ SubscriptionClientSubscription.stubs(method)
+ .returns(SubscriptionClientSubscription)
+ end
+ SubscriptionClientSubscription.stubs(:product_id).returns(SecureRandom.hex(8))
+ end
+
+ after do
+ undefine_client_classes
+ end
+
+ it "detects the subscription client" do
+ expect(described_class.client_installed?).to eq(false)
+ end
+
+ context "without a subscription client" do
+ it "is not subscribed" do
+ expect(described_class.subscribed?).to eq(false)
+ end
+
+ it "has none type" do
+ subscription = described_class.new
+ expect(subscription.type).to eq(:none)
+ end
+
+ it "non subscriber features are included" do
+ expect(described_class.includes?(:wizard, :after_signup, true)).to eq(true)
+ end
+
+ it "ubscriber features are not included" do
+ expect(described_class.includes?(:wizard, :permitted, {})).to eq(false)
+ end
+ end
+
+ context "with subscription client" do
before do
- @subscription = described_class.new
+ define_client_classes
+ stub_client_methods
end
- it "updates valid subscriptions" do
- stub_subscription_request(200, valid_subscription)
- expect(@subscription.update).to eq(true)
- expect(@subscription.subscribed?).to eq(true)
+ it "detects the subscription client" do
+ expect(described_class.client_installed?).to eq(true)
end
- it "handles invalid subscriptions" do
- stub_subscription_request(200, invalid_subscription)
- expect(@subscription.update).to eq(false)
- expect(@subscription.subscribed?).to eq(false)
+ context "without a subscription" do
+ it "has none type" do
+ expect(described_class.type).to eq(:none)
+ end
+
+ it "non subscriber features are included" do
+ expect(described_class.includes?(:wizard, :after_signup, true)).to eq(true)
+ end
+
+ it "subscriber features are not included" do
+ expect(described_class.includes?(:wizard, :permitted, {})).to eq(false)
+ end
end
- it "handles subscription http errors" do
- stub_subscription_request(404, {})
- expect(@subscription.update).to eq(false)
- expect(@subscription.subscribed?).to eq(false)
+ context "with standard subscription" do
+ before do
+ SubscriptionClientSubscription.stubs(:product_id).returns(CustomWizard::Subscription::STANDARD_PRODUCT_ID)
+ end
+
+ it "detects standard type" do
+ expect(described_class.type).to eq(:standard)
+ end
+
+ it "standard features are included" do
+ expect(described_class.includes?(:wizard, :type, 'send_message')).to eq(true)
+ end
+
+ it "business features are not included" do
+ expect(described_class.includes?(:action, :type, 'create_category')).to eq(false)
+ end
end
- it "destroys subscriptions" do
- stub_subscription_request(200, valid_subscription)
- expect(@subscription.update).to eq(true)
- expect(@subscription.destroy_subscription).to eq(true)
- expect(@subscription.subscribed?).to eq(false)
- end
+ context "with business subscription" do
+ before do
+ SubscriptionClientSubscription.stubs(:product_id).returns(CustomWizard::Subscription::BUSINESS_PRODUCT_ID)
+ end
- it "has class aliases" do
- authenticate_subscription
- stub_subscription_request(200, valid_subscription)
- expect(described_class.update).to eq(true)
- expect(described_class.subscribed?).to eq(true)
- end
- end
+ it "detects business type" do
+ expect(described_class.type).to eq(:business)
+ end
- context "authentication" do
- before do
- @subscription = described_class.new
- user.update!(admin: true)
- end
-
- it "generates a valid authentication request url" do
- request_id = SecureRandom.hex(32)
- uri = URI(@subscription.authentication_url(user.id, request_id))
- expect(uri.host).to eq(@subscription.server)
-
- parsed_query = Rack::Utils.parse_query uri.query
- expect(parsed_query['public_key'].present?).to eq(true)
- expect(parsed_query['nonce'].present?).to eq(true)
- expect(parsed_query['client_id'].present?).to eq(true)
- expect(parsed_query['auth_redirect'].present?).to eq(true)
- expect(parsed_query['application_name']).to eq(SiteSetting.title)
- expect(parsed_query['scopes']).to eq(@subscription.scope)
- end
-
- def generate_payload(request_id, user_id)
- uri = URI(@subscription.authentication_url(user_id, request_id))
- keys = @subscription.authentication.get_keys(request_id)
- raw_payload = {
- key: "12345",
- nonce: keys.nonce,
- push: false,
- api: UserApiKeysController::AUTH_API_VERSION
- }.to_json
- public_key = OpenSSL::PKey::RSA.new(keys.pem)
- Base64.encode64(public_key.public_encrypt(raw_payload))
- end
-
- it "handles authentication response if request and response is valid" do
- request_id = SecureRandom.hex(32)
- payload = generate_payload(request_id, user.id)
-
- expect(@subscription.authentication_response(request_id, payload)).to eq(true)
- expect(@subscription.authorized?).to eq(true)
- end
-
- it "discards authentication response if user who made request as not an admin" do
- user.update!(admin: false)
-
- request_id = SecureRandom.hex(32)
- payload = generate_payload(request_id, user.id)
-
- expect(@subscription.authentication_response(request_id, payload)).to eq(false)
- expect(@subscription.authorized?).to eq(false)
- end
-
- it "discards authentication response if request_id is invalid" do
- payload = generate_payload(SecureRandom.hex(32), user.id)
-
- expect(@subscription.authentication_response(SecureRandom.hex(32), payload)).to eq(false)
- expect(@subscription.authorized?).to eq(false)
- end
-
- it "destroys authentication" do
- request_id = SecureRandom.hex(32)
- payload = generate_payload(request_id, user.id)
- @subscription.authentication_response(request_id, payload)
-
- expect(@subscription.destroy_authentication).to eq(true)
- expect(@subscription.authorized?).to eq(false)
+ it "business are included" do
+ expect(described_class.includes?(:action, :type, 'create_category')).to eq(true)
+ end
end
end
end
diff --git a/spec/components/custom_wizard/template_spec.rb b/spec/components/custom_wizard/template_spec.rb
index 14e1659b..63ea25c6 100644
--- a/spec/components/custom_wizard/template_spec.rb
+++ b/spec/components/custom_wizard/template_spec.rb
@@ -47,6 +47,8 @@ describe CustomWizard::Template do
context "wizard template list" do
before do
+ enable_subscription('standard')
+
template_json_2 = template_json.dup
template_json_2["id"] = 'super_mega_fun_wizard_2'
template_json_2["permitted"] = permitted_json['permitted']
diff --git a/spec/components/custom_wizard/template_validator_spec.rb b/spec/components/custom_wizard/template_validator_spec.rb
index 3561e272..b149706f 100644
--- a/spec/components/custom_wizard/template_validator_spec.rb
+++ b/spec/components/custom_wizard/template_validator_spec.rb
@@ -5,6 +5,8 @@ describe CustomWizard::TemplateValidator do
let(:template) { get_wizard_fixture("wizard") }
let(:create_category) { get_wizard_fixture("actions/create_category") }
let(:user_condition) { get_wizard_fixture("condition/user_condition") }
+ let(:permitted_json) { get_wizard_fixture("wizard/permitted") }
+ let(:composer_preview) { get_wizard_fixture("field/composer_preview") }
let(:valid_liquid_template) {
<<-LIQUID.strip
@@ -104,7 +106,7 @@ describe CustomWizard::TemplateValidator do
context "without subscription" do
it "invalidates subscription wizard attributes" do
- template[:save_submissions] = false
+ template[:permitted] = permitted_json['permitted']
expect(
CustomWizard::TemplateValidator.new(template).perform
).to eq(false)
@@ -134,11 +136,11 @@ describe CustomWizard::TemplateValidator do
context "with subscription" do
before do
- enable_subscription("standard")
+ enable_subscription("business")
end
it "validates wizard attributes" do
- template[:save_submissions] = false
+ template[:permitted] = permitted_json['permitted']
expect(
CustomWizard::TemplateValidator.new(template).perform
).to eq(true)
@@ -227,7 +229,9 @@ describe CustomWizard::TemplateValidator do
end
it "validates preview templates" do
- template[:steps][0][:fields][4][:preview_template] = invalid_liquid_template
+ enable_subscription("standard")
+ template[:steps][0][:fields] << composer_preview
+ template[:steps][0][:fields][3][:preview_template] = invalid_liquid_template
expect_validation_failure("step_1_field_5.preview_template", liquid_syntax_error)
end
end
diff --git a/spec/components/custom_wizard/update_validator_spec.rb b/spec/components/custom_wizard/update_validator_spec.rb
index a01f70d7..7caa1784 100644
--- a/spec/components/custom_wizard/update_validator_spec.rb
+++ b/spec/components/custom_wizard/update_validator_spec.rb
@@ -3,6 +3,7 @@
describe CustomWizard::UpdateValidator do
fab!(:user) { Fabricate(:user) }
let(:template) { get_wizard_fixture("wizard") }
+ let(:url_field) { get_wizard_fixture("field/url") }
before do
CustomWizard::Template.save(template, skip_jobs: true)
@@ -21,7 +22,6 @@ describe CustomWizard::UpdateValidator do
@template[:steps][0][:fields][0][:min_length] = min_length
@template[:steps][0][:fields][1][:min_length] = min_length
- @template[:steps][0][:fields][2][:min_length] = min_length
CustomWizard::Template.save(@template)
@@ -34,11 +34,6 @@ describe CustomWizard::UpdateValidator do
expect(
updater.errors.messages[:step_1_field_2].first
).to eq(I18n.t('wizard.field.too_short', label: 'Textarea', min: min_length))
-
- updater = perform_validation('step_1', step_1_field_3: 'Te')
- expect(
- updater.errors.messages[:step_1_field_3].first
- ).to eq(I18n.t('wizard.field.too_short', label: 'Composer', min: min_length))
end
it 'prevents submission if the length is over the max length' do
@@ -46,7 +41,6 @@ describe CustomWizard::UpdateValidator do
@template[:steps][0][:fields][0][:max_length] = max_length
@template[:steps][0][:fields][1][:max_length] = max_length
- @template[:steps][0][:fields][2][:max_length] = max_length
CustomWizard::Template.save(@template)
long_string = "Our Competitive Capability solution offers platforms a suite of wholesale offerings. In the future, will you be able to effectively revolutionize synergies in your business? In the emerging market space, industry is ethically investing its mission critical executive searches. Key players will take ownership of their capabilities by iteratively right-sizing world-class visibilities. "
@@ -59,11 +53,6 @@ describe CustomWizard::UpdateValidator do
expect(
updater.errors.messages[:step_1_field_2].first
).to eq(I18n.t('wizard.field.too_long', label: 'Textarea', max: max_length))
-
- updater = perform_validation('step_1', step_1_field_3: long_string)
- expect(
- updater.errors.messages[:step_1_field_3].first
- ).to eq(I18n.t('wizard.field.too_long', label: 'Composer', max: max_length))
end
it "allows submission if the length is under or equal to the max length" do
@@ -71,7 +60,6 @@ describe CustomWizard::UpdateValidator do
@template[:steps][0][:fields][0][:max_length] = max_length
@template[:steps][0][:fields][1][:max_length] = max_length
- @template[:steps][0][:fields][2][:max_length] = max_length
CustomWizard::Template.save(@template)
hundred_chars_string = "This is a line, exactly hundred characters long and not more even a single character more than that."
@@ -84,11 +72,6 @@ describe CustomWizard::UpdateValidator do
expect(
updater.errors.messages[:step_1_field_2].first
).to eq(nil)
-
- updater = perform_validation('step_1', step_1_field_3: hundred_chars_string)
- expect(
- updater.errors.messages[:step_1_field_3].first
- ).to eq(nil)
end
it "applies min length only if the input is non-empty" do
@@ -131,25 +114,33 @@ describe CustomWizard::UpdateValidator do
).to eq(I18n.t('wizard.field.required', label: 'Textarea'))
end
- it 'validates url fields' do
- updater = perform_validation('step_2', step_2_field_6: 'https://discourse.com')
- expect(
- updater.errors.messages[:step_2_field_6].first
- ).to eq(nil)
- end
+ context "subscription fields" do
+ before do
+ enable_subscription("standard")
+ end
- it 'does not validate url fields with non-url inputs' do
- updater = perform_validation('step_2', step_2_field_6: 'discourse')
- expect(
- updater.errors.messages[:step_2_field_6].first
- ).to eq(I18n.t('wizard.field.not_url', label: 'Url'))
- end
+ it 'validates url fields' do
+ updater = perform_validation('step_2', step_2_field_6: 'https://discourse.com')
+ expect(
+ updater.errors.messages[:step_2_field_6].first
+ ).to eq(nil)
+ end
- it 'validates empty url fields' do
- updater = perform_validation('step_2', step_2_field_6: '')
- expect(
- updater.errors.messages[:step_2_field_6].first
- ).to eq(nil)
+ it 'does not validate url fields with non-url inputs' do
+ template[:steps][0][:fields] << url_field
+ CustomWizard::Template.save(template)
+ updater = perform_validation('step_1', step_2_field_6: 'discourse')
+ expect(
+ updater.errors.messages[:step_2_field_6].first
+ ).to eq(I18n.t('wizard.field.not_url', label: 'Url'))
+ end
+
+ it 'validates empty url fields' do
+ updater = perform_validation('step_2', step_2_field_6: '')
+ expect(
+ updater.errors.messages[:step_2_field_6].first
+ ).to eq(nil)
+ end
end
it 'validates date fields' do
diff --git a/spec/components/custom_wizard/wizard_spec.rb b/spec/components/custom_wizard/wizard_spec.rb
index 00354bf1..5dc1cb95 100644
--- a/spec/components/custom_wizard/wizard_spec.rb
+++ b/spec/components/custom_wizard/wizard_spec.rb
@@ -113,69 +113,91 @@ describe CustomWizard::Wizard do
expect(wizard.completed?).to eq(false)
end
- it "permits admins" do
- expect(
- CustomWizard::Wizard.new(@permitted_template, admin_user).permitted?
- ).to eq(true)
- end
+ context "with subscription" do
+ before do
+ enable_subscription("standard")
+ end
- it "permits permitted users" do
- expect(
- CustomWizard::Wizard.new(@permitted_template, trusted_user).permitted?
- ).to eq(true)
- end
+ it "permits admins" do
+ expect(
+ CustomWizard::Wizard.new(@permitted_template, admin_user).permitted?
+ ).to eq(true)
+ end
- it "permits everyone if everyone is permitted" do
- @permitted_template['permitted'][0]['output'] = Group::AUTO_GROUPS[:everyone]
- expect(
- CustomWizard::Wizard.new(@permitted_template, user).permitted?
- ).to eq(true)
- end
+ it "permits permitted users" do
+ expect(
+ CustomWizard::Wizard.new(@permitted_template, trusted_user).permitted?
+ ).to eq(true)
+ end
- it "does not permit unpermitted users" do
- expect(
- CustomWizard::Wizard.new(@permitted_template, user).permitted?
- ).to eq(false)
- end
+ it "permits everyone if everyone is permitted" do
+ @permitted_template['permitted'][0]['output'] = Group::AUTO_GROUPS[:everyone]
+ expect(
+ CustomWizard::Wizard.new(@permitted_template, user).permitted?
+ ).to eq(true)
+ end
- it "does not let an unpermitted user access a wizard" do
- expect(
- CustomWizard::Wizard.new(@permitted_template, user).can_access?
- ).to eq(false)
- end
+ it "does not permit unpermitted users" do
+ expect(
+ CustomWizard::Wizard.new(@permitted_template, user).permitted?
+ ).to eq(false)
+ end
- it "lets a permitted user access an incomplete wizard" do
- expect(
- CustomWizard::Wizard.new(@permitted_template, trusted_user).can_access?
- ).to eq(true)
- end
+ it "does not let an unpermitted user access a wizard" do
+ expect(
+ CustomWizard::Wizard.new(@permitted_template, user).can_access?
+ ).to eq(false)
+ end
- it "lets a permitted user access a complete wizard with multiple submissions" do
- append_steps
+ it "lets a permitted user access an incomplete wizard" do
+ expect(
+ CustomWizard::Wizard.new(@permitted_template, trusted_user).can_access?
+ ).to eq(true)
+ end
- progress_step("step_1", acting_user: trusted_user)
- progress_step("step_2", acting_user: trusted_user)
- progress_step("step_3", acting_user: trusted_user)
+ it "lets a permitted user access a complete wizard with multiple submissions" do
+ append_steps
- @permitted_template["multiple_submissions"] = true
+ progress_step("step_1", acting_user: trusted_user)
+ progress_step("step_2", acting_user: trusted_user)
+ progress_step("step_3", acting_user: trusted_user)
- expect(
- CustomWizard::Wizard.new(@permitted_template, trusted_user).can_access?
- ).to eq(true)
- end
+ @permitted_template["multiple_submissions"] = true
- it "does not let an unpermitted user access a complete wizard without multiple submissions" do
- append_steps
+ expect(
+ CustomWizard::Wizard.new(@permitted_template, trusted_user).can_access?
+ ).to eq(true)
+ end
- progress_step("step_1", acting_user: trusted_user)
- progress_step("step_2", acting_user: trusted_user)
- progress_step("step_3", acting_user: trusted_user)
+ it "does not let an unpermitted user access a complete wizard without multiple submissions" do
+ append_steps
- @permitted_template['multiple_submissions'] = false
+ progress_step("step_1", acting_user: trusted_user)
+ progress_step("step_2", acting_user: trusted_user)
+ progress_step("step_3", acting_user: trusted_user)
- expect(
- CustomWizard::Wizard.new(@permitted_template, trusted_user).can_access?
- ).to eq(false)
+ @permitted_template['multiple_submissions'] = false
+
+ expect(
+ CustomWizard::Wizard.new(@permitted_template, trusted_user).can_access?
+ ).to eq(false)
+ end
+
+ it "sets wizard redirects if user is permitted" do
+ CustomWizard::Template.save(@permitted_template, skip_jobs: true)
+ CustomWizard::Wizard.set_user_redirect('super_mega_fun_wizard', trusted_user)
+ expect(
+ trusted_user.custom_fields['redirect_to_wizard']
+ ).to eq("super_mega_fun_wizard")
+ end
+
+ it "does not set a wizard redirect if user is not permitted" do
+ CustomWizard::Template.save(@permitted_template, skip_jobs: true)
+ CustomWizard::Wizard.set_user_redirect('super_mega_fun_wizard', user)
+ expect(
+ trusted_user.custom_fields['redirect_to_wizard']
+ ).to eq(nil)
+ end
end
it "lists the site groups" do
@@ -203,6 +225,7 @@ describe CustomWizard::Wizard do
context "class methods" do
before do
+ enable_subscription("standard")
CustomWizard::Template.save(@permitted_template, skip_jobs: true)
template_json_2 = template_json.dup
@@ -238,20 +261,4 @@ describe CustomWizard::Wizard do
expect(CustomWizard::Wizard.prompt_completion(user).length).to eq(1)
end
end
-
- it "sets wizard redirects if user is permitted" do
- CustomWizard::Template.save(@permitted_template, skip_jobs: true)
- CustomWizard::Wizard.set_user_redirect('super_mega_fun_wizard', trusted_user)
- expect(
- trusted_user.custom_fields['redirect_to_wizard']
- ).to eq("super_mega_fun_wizard")
- end
-
- it "does not set a wizard redirect if user is not permitted" do
- CustomWizard::Template.save(@permitted_template, skip_jobs: true)
- CustomWizard::Wizard.set_user_redirect('super_mega_fun_wizard', user)
- expect(
- trusted_user.custom_fields['redirect_to_wizard']
- ).to eq(nil)
- end
end
diff --git a/spec/fixtures/actions/watch_categories.json b/spec/fixtures/actions/watch_categories.json
new file mode 100644
index 00000000..20644f44
--- /dev/null
+++ b/spec/fixtures/actions/watch_categories.json
@@ -0,0 +1,23 @@
+{
+ "id": "action_5",
+ "run_after": "step_1",
+ "type": "watch_categories",
+ "notification_level": "tracking",
+ "wizard_user": true,
+ "categories": [
+ {
+ "type": "assignment",
+ "output": "",
+ "output_type": "text",
+ "output_connector": "set"
+ }
+ ],
+ "mute_remainder": [
+ {
+ "type": "assignment",
+ "output": "true",
+ "output_type": "text",
+ "output_connector": "set"
+ }
+ ]
+}
diff --git a/spec/fixtures/field/advanced_types.json b/spec/fixtures/field/advanced_types.json
new file mode 100644
index 00000000..63357cdb
--- /dev/null
+++ b/spec/fixtures/field/advanced_types.json
@@ -0,0 +1,27 @@
+{
+ "fields": [
+ {
+ "id": "step_3_field_2",
+ "label": "Tag",
+ "type": "tag"
+ },
+ {
+ "id": "step_3_field_3",
+ "label": "Category",
+ "type": "category",
+ "limit": 1,
+ "property": "id"
+ },
+ {
+ "id": "step_3_field_4",
+ "label": "Group",
+ "type": "group"
+ },
+ {
+ "id": "step_3_field_5",
+ "label": "User Selector",
+ "description": "",
+ "type": "user_selector"
+ }
+ ]
+}
diff --git a/spec/fixtures/field/composer_preview.json b/spec/fixtures/field/composer_preview.json
new file mode 100644
index 00000000..f4bec04a
--- /dev/null
+++ b/spec/fixtures/field/composer_preview.json
@@ -0,0 +1,7 @@
+{
+ "id": "step_1_field_5",
+ "label": "I'm a preview",
+ "description": "",
+ "type": "composer_preview",
+ "preview_template": "w{step_1_field_1}"
+}
diff --git a/spec/fixtures/field/url.json b/spec/fixtures/field/url.json
new file mode 100644
index 00000000..e3153fe9
--- /dev/null
+++ b/spec/fixtures/field/url.json
@@ -0,0 +1,5 @@
+{
+ "id": "step_2_field_6",
+ "label": "Url",
+ "type": "url"
+}
diff --git a/spec/fixtures/subscription_client.rb b/spec/fixtures/subscription_client.rb
new file mode 100644
index 00000000..a041b507
--- /dev/null
+++ b/spec/fixtures/subscription_client.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+
+module SubscriptionClient; end
+class SubscriptionClientSubscription; end
diff --git a/spec/fixtures/wizard.json b/spec/fixtures/wizard.json
index a05c1782..de5e636e 100644
--- a/spec/fixtures/wizard.json
+++ b/spec/fixtures/wizard.json
@@ -33,23 +33,11 @@
"type": "textarea",
"min_length": ""
},
- {
- "id": "step_1_field_3",
- "label": "Composer",
- "type": "composer"
- },
{
"id": "step_1_field_4",
"label": "I'm only text",
"description": "",
"type": "text_only"
- },
- {
- "id": "step_1_field_5",
- "label": "I'm a preview",
- "description": "",
- "type": "composer_preview",
- "preview_template": "w{step_1_field_1}"
}
],
"description": "Text inputs!"
@@ -87,11 +75,6 @@
"label": "Checkbox",
"type": "checkbox"
},
- {
- "id": "step_2_field_6",
- "label": "Url",
- "type": "url"
- },
{
"id": "step_2_field_7",
"label": "Upload",
@@ -141,35 +124,6 @@
]
}
]
- },
- {
- "id": "step_3_field_2",
- "label": "Tag",
- "type": "tag"
- },
- {
- "id": "step_3_field_3",
- "label": "Category",
- "type": "category",
- "limit": 1,
- "property": "id"
- },
- {
- "id": "step_3_field_4",
- "label": "Group",
- "type": "group"
- },
- {
- "id": "step_3_field_5",
- "label": "User Selector",
- "description": "",
- "type": "user_selector"
- },
- {
- "id": "step_3_field_6",
- "label": "Conditional User Selector",
- "description": "Shown when checkbox in step_2_field_5 is true",
- "type": "user_selector"
}
],
"description": "Unfortunately not the edible type :sushi: "
@@ -264,29 +218,6 @@
}
]
},
- {
- "id": "action_5",
- "run_after": "step_1",
- "type": "watch_categories",
- "notification_level": "tracking",
- "wizard_user": true,
- "categories": [
- {
- "type": "assignment",
- "output": "action_8",
- "output_type": "wizard_action",
- "output_connector": "set"
- }
- ],
- "mute_remainder": [
- {
- "type": "assignment",
- "output": "true",
- "output_type": "text",
- "output_connector": "set"
- }
- ]
- },
{
"id": "action_4",
"run_after": "step_2",
diff --git a/spec/jobs/update_notices_spec.rb b/spec/jobs/update_notices_spec.rb
deleted file mode 100644
index df0697b8..00000000
--- a/spec/jobs/update_notices_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../plugin_helper'
-
-describe Jobs::CustomWizardUpdateNotices do
- let(:subscription_message) {
- {
- message: "Message about subscription",
- type: "info",
- created_at: Time.now - 3.day,
- expired_at: nil
- }
- }
- let(:plugin_status) {
- {
- name: 'discourse-custom-wizard',
- status: 'incompatible',
- status_changed_at: Time.now - 3.day
- }
- }
-
- it "updates the notices" do
- stub_request(:get, CustomWizard::Notice.subscription_message_url).to_return(status: 200, body: { messages: [subscription_message] }.to_json)
- stub_request(:get, CustomWizard::Notice.plugin_status_url).to_return(status: 200, body: plugin_status.to_json)
-
- described_class.new.execute
- expect(CustomWizard::Notice.list.length).to eq(2)
- end
-end
diff --git a/spec/jobs/update_subscription_spec.rb b/spec/jobs/update_subscription_spec.rb
deleted file mode 100644
index c5adaf38..00000000
--- a/spec/jobs/update_subscription_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../plugin_helper'
-
-describe Jobs::CustomWizardUpdateSubscription do
- it "updates the subscription" do
- stub_subscription_request(200, valid_subscription)
- described_class.new.execute
- expect(CustomWizard::Subscription.subscribed?).to eq(true)
- end
-end
diff --git a/spec/plugin_helper.rb b/spec/plugin_helper.rb
index 6e340ccf..a0189de1 100644
--- a/spec/plugin_helper.rb
+++ b/spec/plugin_helper.rb
@@ -8,37 +8,8 @@ def get_wizard_fixture(path)
).with_indifferent_access
end
-def authenticate_subscription
- CustomWizard::Subscription::Authentication.any_instance.stubs(:active?).returns(true)
-end
-
def enable_subscription(type)
- # CustomWizard::Subscription.new
- CustomWizard::Subscription.any_instance.stubs(:subscribed?).returns(true)
- CustomWizard::Subscription.any_instance.stubs(:type).returns(type)
-end
-
-def disable_subscription
- CustomWizard::Subscription.any_instance.stubs(:subscribed?).returns(false)
-end
-
-def valid_subscription
- {
- product_id: "prod_CBTNpi3fqWWkq0",
- price_id: "price_id",
- price_nickname: "business"
- }
-end
-
-def invalid_subscription
- {
- product_id: "prod_CBTNpi3fqWWkq0",
- price_id: "price_id"
- }
-end
-
-def stub_subscription_request(status, subscription)
- authenticate_subscription
- sub = CustomWizard::Subscription.new
- stub_request(:get, "https://#{sub.server}/subscription-server/user-subscriptions/#{sub.subscription_type}/#{sub.client_name}").to_return(status: status, body: { subscriptions: [subscription] }.to_json)
+ CustomWizard::Subscription.stubs(:client_installed?).returns(true)
+ CustomWizard::Subscription.stubs("#{type}?".to_sym).returns(true)
+ CustomWizard::Subscription.any_instance.stubs("#{type}?".to_sym).returns(true)
end
diff --git a/spec/requests/custom_wizard/admin/notice_controller_spec.rb b/spec/requests/custom_wizard/admin/notice_controller_spec.rb
deleted file mode 100644
index 33d03432..00000000
--- a/spec/requests/custom_wizard/admin/notice_controller_spec.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-# frozen_string_literal: true
-require_relative '../../../plugin_helper'
-
-describe CustomWizard::AdminNoticeController do
- fab!(:admin_user) { Fabricate(:user, admin: true) }
- let(:subscription_message_notice) {
- {
- title: "Title of message about subscription",
- message: "Message about subscription",
- type: 0,
- created_at: Time.now.iso8601(3),
- expired_at: nil
- }
- }
- let(:plugin_status_notice) {
- {
- title: "The Custom Wizard Plugin is incompatibile with the latest version of Discourse.",
- message: "Please check the Custom Wizard Plugin status on [localhost:3000](http://localhost:3000) before updating Discourse.",
- type: 1,
- archetype: 1,
- created_at: Time.now.iso8601(3),
- expired_at: nil
- }
- }
-
- before do
- sign_in(admin_user)
- end
-
- it "lists notices" do
- @notice = CustomWizard::Notice.new(subscription_message_notice)
- @notice.save
-
- get "/admin/wizards/notice.json"
- expect(response.status).to eq(200)
- expect(response.parsed_body.length).to eq(1)
- end
-
- it "dismisses notices" do
- @notice = CustomWizard::Notice.new(subscription_message_notice)
- @notice.save
-
- put "/admin/wizards/notice/#{@notice.id}/dismiss.json"
- expect(response.status).to eq(200)
-
- updated = CustomWizard::Notice.find(@notice.id)
- expect(updated.dismissed?).to eq(true)
- end
-
- it "dismisses all notices" do
- 5.times do |index|
- subscription_message_notice[:title] += " #{index}"
- @notice = CustomWizard::Notice.new(subscription_message_notice)
- @notice.save
- end
-
- put "/admin/wizards/notice/dismiss.json"
- expect(response.status).to eq(200)
- expect(CustomWizard::Notice.list.size).to eq(0)
- end
-
- it "hides notices" do
- @notice = CustomWizard::Notice.new(plugin_status_notice)
- @notice.save
-
- put "/admin/wizards/notice/#{@notice.id}/hide.json"
- expect(response.status).to eq(200)
-
- updated = CustomWizard::Notice.find(@notice.id)
- expect(updated.hidden?).to eq(true)
- end
-end
diff --git a/spec/requests/custom_wizard/admin/subscription_controller_spec.rb b/spec/requests/custom_wizard/admin/subscription_controller_spec.rb
deleted file mode 100644
index 2f8aad20..00000000
--- a/spec/requests/custom_wizard/admin/subscription_controller_spec.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-# frozen_string_literal: true
-require_relative '../../../plugin_helper'
-
-describe CustomWizard::AdminSubscriptionController do
- fab!(:admin_user) { Fabricate(:user, admin: true) }
-
- def generate_payload(request_id, user_id)
- uri = URI(@subscription.authentication_url(user_id, request_id))
- keys = @subscription.authentication.get_keys(request_id)
- raw_payload = {
- key: "12345",
- nonce: keys.nonce,
- push: false,
- api: UserApiKeysController::AUTH_API_VERSION
- }.to_json
- public_key = OpenSSL::PKey::RSA.new(keys.pem)
- Base64.encode64(public_key.public_encrypt(raw_payload))
- end
-
- before do
- @subscription = CustomWizard::Subscription.new
- sign_in(admin_user)
- end
-
- it "#index" do
- get "/admin/wizards/subscription.json"
- expect(response.parsed_body['server']).to eq(@subscription.server)
- expect(response.parsed_body['authentication'].deep_symbolize_keys).to eq(CustomWizard::Subscription::AuthenticationSerializer.new(@subscription.authentication, root: false).as_json)
- expect(response.parsed_body['subscription'].deep_symbolize_keys).to eq(CustomWizard::Subscription::SubscriptionSerializer.new(@subscription.subscription, root: false).as_json)
- end
-
- it "#authorize" do
- get "/admin/wizards/subscription/authorize"
- expect(response.status).to eq(302)
- expect(cookies[:user_api_request_id].present?).to eq(true)
- end
-
- it "#destroy_authentication" do
- request_id = SecureRandom.hex(32)
- payload = generate_payload(request_id, admin_user.id)
- @subscription.authentication_response(request_id, payload)
-
- delete "/admin/wizards/subscription/authorize.json"
-
- expect(response.status).to eq(200)
- expect(CustomWizard::Subscription.authorized?).to eq(false)
- end
-
- context "subscription" do
- before do
- stub_subscription_request(200, valid_subscription)
- end
-
- it "handles authentication response and the updates subscription" do
- request_id = cookies[:user_api_request_id] = SecureRandom.hex(32)
- payload = generate_payload(request_id, admin_user.id)
- get "/admin/wizards/subscription/authorize/callback", params: { payload: payload }
-
- expect(response).to redirect_to("/admin/wizards/subscription")
- expect(CustomWizard::Subscription.subscribed?).to eq(true)
- end
-
- it "updates the subscription" do
- authenticate_subscription
- post "/admin/wizards/subscription.json"
-
- expect(response.status).to eq(200)
- expect(CustomWizard::Subscription.subscribed?).to eq(true)
- end
- end
-end
diff --git a/spec/requests/custom_wizard/admin/wizard_controller_spec.rb b/spec/requests/custom_wizard/admin/wizard_controller_spec.rb
index fd2fa006..9f63cb6b 100644
--- a/spec/requests/custom_wizard/admin/wizard_controller_spec.rb
+++ b/spec/requests/custom_wizard/admin/wizard_controller_spec.rb
@@ -8,6 +8,7 @@ describe CustomWizard::AdminWizardController do
before do
CustomWizard::Template.save(template, skip_jobs: true)
+ enable_subscription("standard")
template_2 = template.dup
template_2["id"] = 'super_mega_fun_wizard_2'
diff --git a/spec/requests/custom_wizard/steps_controller_spec.rb b/spec/requests/custom_wizard/steps_controller_spec.rb
index 26ba817a..e05ba917 100644
--- a/spec/requests/custom_wizard/steps_controller_spec.rb
+++ b/spec/requests/custom_wizard/steps_controller_spec.rb
@@ -34,6 +34,7 @@ describe CustomWizard::StepsController do
end
it "when the user cant access the wizard" do
+ enable_subscription("standard")
new_template = wizard_template.dup
new_template["permitted"] = permitted_json["permitted"]
CustomWizard::Template.save(new_template, skip_jobs: true)
diff --git a/spec/requests/custom_wizard/wizard_controller_spec.rb b/spec/requests/custom_wizard/wizard_controller_spec.rb
index 3d081b8a..aa1f479b 100644
--- a/spec/requests/custom_wizard/wizard_controller_spec.rb
+++ b/spec/requests/custom_wizard/wizard_controller_spec.rb
@@ -40,14 +40,15 @@ describe CustomWizard::WizardController do
end
it 'lets user skip if user cant access wizard' do
+ enable_subscription("standard")
@template["permitted"] = permitted_json["permitted"]
CustomWizard::Template.save(@template, skip_jobs: true)
-
put '/w/super-mega-fun-wizard/skip.json'
expect(response.status).to eq(200)
end
it 'returns a no skip message if user is not allowed to skip' do
+ enable_subscription("standard")
@template['required'] = 'true'
CustomWizard::Template.save(@template)
put '/w/super-mega-fun-wizard/skip.json'
diff --git a/spec/serializers/custom_wizard/notice_serializer_spec.rb b/spec/serializers/custom_wizard/notice_serializer_spec.rb
deleted file mode 100644
index 5184d890..00000000
--- a/spec/serializers/custom_wizard/notice_serializer_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../../plugin_helper'
-
-describe CustomWizard::NoticeSerializer do
- before do
- @notice = CustomWizard::Notice.new(
- message: "Message about subscription",
- type: "info",
- created_at: Time.now - 3.day,
- expired_at: nil
- )
- @notice.save
- end
-
- it 'should return notice attributes' do
- serialized_notice = described_class.new(@notice)
- expect(serialized_notice.message).to eq(@notice.message)
- expect(serialized_notice.type).to eq(CustomWizard::Notice.types.key(@notice.type))
- expect(serialized_notice.dismissable).to eq(true)
- end
-end
diff --git a/spec/serializers/custom_wizard/subscription/authentication_serializer_spec.rb b/spec/serializers/custom_wizard/subscription/authentication_serializer_spec.rb
deleted file mode 100644
index ac29f95a..00000000
--- a/spec/serializers/custom_wizard/subscription/authentication_serializer_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../../../plugin_helper'
-
-describe CustomWizard::Subscription::AuthenticationSerializer do
- fab!(:user) { Fabricate(:user) }
-
- it 'should return subscription authentication attributes' do
- auth = CustomWizard::Subscription::Authentication.new(OpenStruct.new(key: '1234', auth_at: Time.now, auth_by: user.id))
- serialized = described_class.new(auth, root: false).as_json
-
- expect(serialized[:active]).to eq(true)
- expect(serialized[:client_id]).to eq(auth.client_id)
- expect(serialized[:auth_by]).to eq(auth.auth_by)
- expect(serialized[:auth_at]).to eq(auth.auth_at)
- end
-end
diff --git a/spec/serializers/custom_wizard/subscription/subscription_serializer_spec.rb b/spec/serializers/custom_wizard/subscription/subscription_serializer_spec.rb
deleted file mode 100644
index 91dc59b1..00000000
--- a/spec/serializers/custom_wizard/subscription/subscription_serializer_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../../../plugin_helper'
-
-describe CustomWizard::Subscription::SubscriptionSerializer do
- it 'should return subscription attributes' do
- sub = CustomWizard::Subscription::Subscription.new(OpenStruct.new(type: 'standard', updated_at: Time.now))
- serialized = described_class.new(sub, root: false).as_json
-
- expect(serialized[:active]).to eq(true)
- expect(serialized[:type]).to eq('standard')
- expect(serialized[:updated_at]).to eq(sub.updated_at)
- end
-end
diff --git a/spec/serializers/custom_wizard/subscription_serializer_spec.rb b/spec/serializers/custom_wizard/subscription_serializer_spec.rb
deleted file mode 100644
index c6ea0ef2..00000000
--- a/spec/serializers/custom_wizard/subscription_serializer_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../../plugin_helper'
-
-describe CustomWizard::SubscriptionSerializer do
- it 'should return subscription attributes' do
- subscription = CustomWizard::Subscription.new
- serialized = described_class.new(subscription, root: false)
-
- expect(serialized.server).to eq(subscription.server)
- expect(serialized.authentication.class).to eq(CustomWizard::Subscription::Authentication)
- expect(serialized.subscription.class).to eq(CustomWizard::Subscription::Subscription)
- end
-end
diff --git a/spec/serializers/custom_wizard/wizard_field_serializer_spec.rb b/spec/serializers/custom_wizard/wizard_field_serializer_spec.rb
index c30279b7..1ac2579e 100644
--- a/spec/serializers/custom_wizard/wizard_field_serializer_spec.rb
+++ b/spec/serializers/custom_wizard/wizard_field_serializer_spec.rb
@@ -19,7 +19,7 @@ describe CustomWizard::FieldSerializer do
expect(json_array.size).to eq(@wizard.steps.first.fields.size)
expect(json_array[0][:label]).to eq("
Text
")
expect(json_array[0][:description]).to eq("Text field description.")
- expect(json_array[3][:index]).to eq(3)
+ expect(json_array[2][:index]).to eq(2)
end
it "should return optional field attributes" do
@@ -29,6 +29,6 @@ describe CustomWizard::FieldSerializer do
scope: Guardian.new(user)
).as_json
expect(json_array[0][:format]).to eq("YYYY-MM-DD")
- expect(json_array[6][:file_types]).to eq(".jpg,.jpeg,.png")
+ expect(json_array[5][:file_types]).to eq(".jpg,.jpeg,.png")
end
end
diff --git a/spec/serializers/custom_wizard/wizard_serializer_spec.rb b/spec/serializers/custom_wizard/wizard_serializer_spec.rb
index 030f109e..526f5259 100644
--- a/spec/serializers/custom_wizard/wizard_serializer_spec.rb
+++ b/spec/serializers/custom_wizard/wizard_serializer_spec.rb
@@ -5,6 +5,7 @@ describe CustomWizard::WizardSerializer do
fab!(:category) { Fabricate(:category) }
let(:template) { get_wizard_fixture("wizard") }
let(:similar_topics_validation) { get_wizard_fixture("field/validation/similar_topics") }
+ let(:advanced_fields) { get_wizard_fixture("field/advanced_types") }
before do
CustomWizard::Template.save(template, skip_jobs: true)
@@ -52,43 +53,51 @@ describe CustomWizard::WizardSerializer do
expect(json[:wizard][:uncategorized_category_id].present?).to eq(false)
end
- it "should return categories if there is a category selector field" do
- json = CustomWizard::WizardSerializer.new(
- CustomWizard::Builder.new(@template[:id], user).build,
- scope: Guardian.new(user)
- ).as_json
- expect(json[:wizard][:categories].present?).to eq(true)
- expect(json[:wizard][:uncategorized_category_id].present?).to eq(true)
- end
+ context "advanced fields" do
+ before do
+ enable_subscription("standard")
+ @template[:steps][0][:fields].push(*advanced_fields['fields'])
+ CustomWizard::Template.save(@template, skip_jobs: true)
+ end
- it "should return categories if there is a similar topics validation scoped to category(s)" do
- @template[:steps][0][:fields][0][:validations] = similar_topics_validation[:validations]
- CustomWizard::Template.save(@template)
+ it "should return categories if there is a category selector field" do
+ json = CustomWizard::WizardSerializer.new(
+ CustomWizard::Builder.new(@template[:id], user).build,
+ scope: Guardian.new(user)
+ ).as_json
+ expect(json[:wizard][:categories].present?).to eq(true)
+ expect(json[:wizard][:uncategorized_category_id].present?).to eq(true)
+ end
- json = CustomWizard::WizardSerializer.new(
- CustomWizard::Builder.new(@template[:id], user).build,
- scope: Guardian.new(user)
- ).as_json
- expect(json[:wizard][:categories].present?).to eq(true)
- expect(json[:wizard][:uncategorized_category_id].present?).to eq(true)
- end
+ it "should return categories if there is a similar topics validation scoped to category(s)" do
+ @template[:steps][0][:fields][0][:validations] = similar_topics_validation[:validations]
+ CustomWizard::Template.save(@template)
- it 'should return groups if there is a group selector field' do
- json = CustomWizard::WizardSerializer.new(
- CustomWizard::Builder.new(@template[:id], user).build,
- scope: Guardian.new(user)
- ).as_json
- expect(json[:wizard][:groups].length).to eq(8)
- end
+ json = CustomWizard::WizardSerializer.new(
+ CustomWizard::Builder.new(@template[:id], user).build,
+ scope: Guardian.new(user)
+ ).as_json
+ expect(json[:wizard][:categories].present?).to eq(true)
+ expect(json[:wizard][:uncategorized_category_id].present?).to eq(true)
+ end
- it 'should not return groups if there is not a group selector field' do
- @template[:steps][2][:fields].delete_at(3)
- CustomWizard::Template.save(@template)
+ it 'should return groups if there is a group selector field' do
+ json = CustomWizard::WizardSerializer.new(
+ CustomWizard::Builder.new(@template[:id], user).build,
+ scope: Guardian.new(user)
+ ).as_json
+ expect(json[:wizard][:groups].length).to eq(8)
+ end
- json = CustomWizard::WizardSerializer.new(
- CustomWizard::Builder.new(@template[:id], user).build,
- scope: Guardian.new(user)
- ).as_json
- expect(json[:wizard][:groups].present?).to eq(false)
+ it 'should not return groups if there is not a group selector field' do
+ @template[:steps][0][:fields].reject! { |f| f["type"] === "group" }
+ CustomWizard::Template.save(@template)
+
+ json = CustomWizard::WizardSerializer.new(
+ CustomWizard::Builder.new(@template[:id], user).build,
+ scope: Guardian.new(user)
+ ).as_json
+ expect(json[:wizard][:groups].present?).to eq(false)
+ end
end
end