Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-11-22 17:30:29 +01:00
Merge branch 'main' into admin-acceptance-tests
Dieser Commit ist enthalten in:
Commit
23fafeaf05
16 geänderte Dateien mit 95 neuen und 19 gelöschten Zeilen
7
SECURITY.md
Normale Datei
7
SECURITY.md
Normale Datei
|
@ -0,0 +1,7 @@
|
||||||
|
# Security Policy
|
||||||
|
|
||||||
|
The security of Discourse plugins are premised on the security of [Discourse](https://github.com/discourse/discourse). Please first consider whether a security issue is best reported and handled by the Discourse team. You can view the Discourse security policy [here](https://github.com/discourse/discourse/security/policy).
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
If you find a security vulnerability that is specific to this plugin, please report it to development@pavilion.tech. Security issues always take precedence over all other work. All commits specific to security are prefixed with SECURITY.
|
|
@ -114,6 +114,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
||||||
:property,
|
:property,
|
||||||
:preview_template,
|
:preview_template,
|
||||||
:placeholder,
|
:placeholder,
|
||||||
|
:can_create_tag,
|
||||||
prefill: mapped_params,
|
prefill: mapped_params,
|
||||||
content: mapped_params,
|
content: mapped_params,
|
||||||
condition: mapped_params,
|
condition: mapped_params,
|
||||||
|
|
|
@ -17,6 +17,7 @@ class CustomWizard::FieldSerializer < ::ApplicationSerializer
|
||||||
:property,
|
:property,
|
||||||
:content,
|
:content,
|
||||||
:tag_groups,
|
:tag_groups,
|
||||||
|
:can_create_tag,
|
||||||
:validations,
|
:validations,
|
||||||
:max_length,
|
:max_length,
|
||||||
:char_counter,
|
:char_counter,
|
||||||
|
@ -98,6 +99,10 @@ class CustomWizard::FieldSerializer < ::ApplicationSerializer
|
||||||
object.tag_groups
|
object.tag_groups
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def can_create_tag
|
||||||
|
object.can_create_tag
|
||||||
|
end
|
||||||
|
|
||||||
def validations
|
def validations
|
||||||
validations = {}
|
validations = {}
|
||||||
object.validations&.each do |type, props|
|
object.validations&.each do |type, props|
|
||||||
|
|
|
@ -149,7 +149,7 @@ export default ComposerEditor.extend({
|
||||||
extraButtons(toolbar) {
|
extraButtons(toolbar) {
|
||||||
const component = this;
|
const component = this;
|
||||||
|
|
||||||
if (this.allowUpload && this.uploadIcon && !this.site.mobileView) {
|
if (this.allowUpload && this.uploadIcon) {
|
||||||
toolbar.addButton({
|
toolbar.addButton({
|
||||||
id: "upload",
|
id: "upload",
|
||||||
group: "insertions",
|
group: "insertions",
|
||||||
|
|
|
@ -5,11 +5,7 @@ import { scheduleOnce } from "@ember/runloop";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
|
||||||
const excludedUserProperties = [
|
const excludedUserProperties = ["profile_background", "card_background"];
|
||||||
"avatar",
|
|
||||||
"profile_background",
|
|
||||||
"card_background",
|
|
||||||
];
|
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNames: "wizard-text-editor",
|
classNames: "wizard-text-editor",
|
||||||
|
@ -52,12 +48,12 @@ export default Component.extend({
|
||||||
|
|
||||||
@discourseComputed("wizardFields")
|
@discourseComputed("wizardFields")
|
||||||
wizardFieldList(wizardFields) {
|
wizardFieldList(wizardFields) {
|
||||||
return wizardFields.map((f) => ` w{${f.id}}`);
|
return (wizardFields || []).map((f) => ` w{${f.id}}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed("wizardActions")
|
@discourseComputed("wizardActions")
|
||||||
wizardActionList(wizardActions) {
|
wizardActionList(wizardActions) {
|
||||||
return wizardActions.map((a) => ` w{${a.id}}`);
|
return (wizardActions || []).map((a) => ` w{${a.id}}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
|
|
@ -36,7 +36,8 @@ export default Controller.extend({
|
||||||
|
|
||||||
@discourseComputed("wizard.id")
|
@discourseComputed("wizard.id")
|
||||||
wizardUrl(wizardId) {
|
wizardUrl(wizardId) {
|
||||||
return window.location.origin + "/w/" + dasherize(wizardId);
|
let baseUrl = window.location.href.split("/admin");
|
||||||
|
return baseUrl[0] + "/w/" + dasherize(wizardId);
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed("wizard.after_time_scheduled")
|
@discourseComputed("wizard.after_time_scheduled")
|
||||||
|
|
|
@ -5,4 +5,5 @@
|
||||||
everyTag=true
|
everyTag=true
|
||||||
options=(hash
|
options=(hash
|
||||||
maximum=field.limit
|
maximum=field.limit
|
||||||
|
allowAny=field.can_create_tag
|
||||||
)}}
|
)}}
|
||||||
|
|
|
@ -222,6 +222,18 @@
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n "admin.wizard.field.can_create_tag"}}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input
|
||||||
|
type="checkbox"
|
||||||
|
checked=field.can_create_tag}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#wizard-subscription-container}}
|
{{#wizard-subscription-container}}
|
||||||
|
|
|
@ -16,7 +16,7 @@ en:
|
||||||
x_characters:
|
x_characters:
|
||||||
one: "%{count} Character"
|
one: "%{count} Character"
|
||||||
other: "%{count} Characters"
|
other: "%{count} Characters"
|
||||||
quit: "Maybe Later"
|
quit: "Exit"
|
||||||
done_custom: "Done"
|
done_custom: "Done"
|
||||||
back: "Back"
|
back: "Back"
|
||||||
next: "Next"
|
next: "Next"
|
||||||
|
@ -277,6 +277,7 @@ en:
|
||||||
prefill: "Prefill"
|
prefill: "Prefill"
|
||||||
content: "Content"
|
content: "Content"
|
||||||
tag_groups: "Tag Groups"
|
tag_groups: "Tag Groups"
|
||||||
|
can_create_tag: "Can Create Tag"
|
||||||
date_time_format:
|
date_time_format:
|
||||||
label: "Format"
|
label: "Format"
|
||||||
instructions: "<a href='https://momentjs.com/docs/#/displaying/format/' target='_blank'>Moment.js format</a>"
|
instructions: "<a href='https://momentjs.com/docs/#/displaying/format/' target='_blank'>Moment.js format</a>"
|
||||||
|
|
|
@ -20,9 +20,6 @@ pre-commit:
|
||||||
glob: "*.js"
|
glob: "*.js"
|
||||||
include: "app/assets/javascripts|plugins/.+?/assets/javascripts"
|
include: "app/assets/javascripts|plugins/.+?/assets/javascripts"
|
||||||
run: yarn eslint -f compact --quiet {staged_files}
|
run: yarn eslint -f compact --quiet {staged_files}
|
||||||
i18n-lint:
|
|
||||||
glob: "**/{client,server}.en.yml"
|
|
||||||
run: bundle exec ruby script/i18n_lint.rb {staged_files}
|
|
||||||
|
|
||||||
lints:
|
lints:
|
||||||
parallel: true
|
parallel: true
|
||||||
|
@ -36,6 +33,3 @@ lints:
|
||||||
run: yarn prettier --list-different **/*.scss
|
run: yarn prettier --list-different **/*.scss
|
||||||
eslint:
|
eslint:
|
||||||
run: yarn eslint -f compact --quiet --ext .js .
|
run: yarn eslint -f compact --quiet --ext .js .
|
||||||
i18n-lint:
|
|
||||||
glob: "**/{client,server}.en.yml"
|
|
||||||
run: bundle exec ruby script/i18n_lint.rb {all_files}
|
|
||||||
|
|
|
@ -135,6 +135,10 @@ class CustomWizard::Builder
|
||||||
params[:limit] = field_template['limit']
|
params[:limit] = field_template['limit']
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if field_template['type'] === 'tag'
|
||||||
|
params[:can_create_tag] = standardise_boolean(field_template['can_create_tag'])
|
||||||
|
end
|
||||||
|
|
||||||
if field_template['type'] === 'category'
|
if field_template['type'] === 'category'
|
||||||
params[:property] = field_template['property']
|
params[:property] = field_template['property']
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,6 +22,7 @@ class CustomWizard::Field
|
||||||
:property,
|
:property,
|
||||||
:content,
|
:content,
|
||||||
:tag_groups,
|
:tag_groups,
|
||||||
|
:can_create_tag,
|
||||||
:preview_template,
|
:preview_template,
|
||||||
:placeholder
|
:placeholder
|
||||||
|
|
||||||
|
@ -47,6 +48,7 @@ class CustomWizard::Field
|
||||||
@property = attrs[:property]
|
@property = attrs[:property]
|
||||||
@content = attrs[:content]
|
@content = attrs[:content]
|
||||||
@tag_groups = attrs[:tag_groups]
|
@tag_groups = attrs[:tag_groups]
|
||||||
|
@can_create_tag = attrs[:can_create_tag]
|
||||||
@preview_template = attrs[:preview_template]
|
@preview_template = attrs[:preview_template]
|
||||||
@placeholder = attrs[:placeholder]
|
@placeholder = attrs[:placeholder]
|
||||||
end
|
end
|
||||||
|
@ -113,7 +115,8 @@ class CustomWizard::Field
|
||||||
limit: nil,
|
limit: nil,
|
||||||
prefill: nil,
|
prefill: nil,
|
||||||
content: nil,
|
content: nil,
|
||||||
tag_groups: nil
|
tag_groups: nil,
|
||||||
|
can_create_tag: false
|
||||||
},
|
},
|
||||||
category: {
|
category: {
|
||||||
limit: 1,
|
limit: 1,
|
||||||
|
|
|
@ -211,6 +211,8 @@ class CustomWizard::Mapper
|
||||||
user.send(value)
|
user.send(value)
|
||||||
elsif USER_OPTION_FIELDS.include?(value)
|
elsif USER_OPTION_FIELDS.include?(value)
|
||||||
user.user_option.send(value)
|
user.user_option.send(value)
|
||||||
|
elsif value.include?('avatar')
|
||||||
|
get_avatar_url(value)
|
||||||
else
|
else
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
@ -269,4 +271,15 @@ class CustomWizard::Mapper
|
||||||
def bool(value)
|
def bool(value)
|
||||||
ActiveRecord::Type::Boolean.new.cast(value)
|
ActiveRecord::Type::Boolean.new.cast(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_avatar_url(value)
|
||||||
|
parts = value.split('.')
|
||||||
|
valid_sizes = Discourse.avatar_sizes.to_a
|
||||||
|
|
||||||
|
if value === 'avatar' || parts.size === 1 || valid_sizes.exclude?(parts.last.to_i)
|
||||||
|
user.small_avatar_url
|
||||||
|
else
|
||||||
|
user.avatar_template_url.gsub("{size}", parts.last)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
# name: discourse-custom-wizard
|
# name: discourse-custom-wizard
|
||||||
# about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more.
|
# about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more.
|
||||||
# version: 2.0.7
|
# version: 2.1.3
|
||||||
# authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever
|
# authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever
|
||||||
# url: https://github.com/paviliondev/discourse-custom-wizard
|
# url: https://github.com/paviliondev/discourse-custom-wizard
|
||||||
# contact_emails: development@pavilion.tech
|
# contact_emails: development@pavilion.tech
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# frozen_string_literal: true
|
# rubocop:disable Style/FrozenStringLiteralComment
|
||||||
|
|
||||||
describe CustomWizard::Mapper do
|
describe CustomWizard::Mapper do
|
||||||
fab!(:user1) {
|
fab!(:user1) {
|
||||||
|
@ -254,6 +254,36 @@ describe CustomWizard::Mapper do
|
||||||
user: user1
|
user: user1
|
||||||
).perform).to eq("Time: #{Time.now.strftime("%B %-d, %Y")}")
|
).perform).to eq("Time: #{Time.now.strftime("%B %-d, %Y")}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "avatar" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['interpolate_avatar'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq("Avatar: ![avatar](#{user1.small_avatar_url})")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "avatar with invalid size" do
|
||||||
|
avatar_inputs = inputs['interpolate_avatar'].dup
|
||||||
|
avatar_inputs[0]["output"] = "Avatar: ![avatar](u{avatar.345})"
|
||||||
|
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: avatar_inputs,
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq("Avatar: ![avatar](#{user1.small_avatar_url})")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "avatar with valid size" do
|
||||||
|
avatar_inputs = inputs['interpolate_avatar'].dup
|
||||||
|
avatar_inputs[0]["output"] = "Avatar: ![avatar](u{avatar.120})"
|
||||||
|
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: avatar_inputs,
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq("Avatar: ![avatar](#{user1.avatar_template_url.gsub("{size}", "120")})")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "handles greater than pairs" do
|
it "handles greater than pairs" do
|
||||||
|
|
8
spec/fixtures/mapper/inputs.json
gevendort
8
spec/fixtures/mapper/inputs.json
gevendort
|
@ -89,6 +89,14 @@
|
||||||
"output": "Time: v{time}"
|
"output": "Time: v{time}"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"interpolate_avatar": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": "Avatar: ![avatar](u{avatar})"
|
||||||
|
}
|
||||||
|
],
|
||||||
"validation": [
|
"validation": [
|
||||||
{
|
{
|
||||||
"type": "validation",
|
"type": "validation",
|
||||||
|
|
Laden …
In neuem Issue referenzieren