Merge branch 'master' into pr/46
Dieser Commit ist enthalten in:
Commit
58d0fda5af
38 geänderte Dateien mit 240 neuen und 132 gelöschten Zeilen
|
@ -5,6 +5,8 @@ import { computed } from "@ember/object";
|
|||
import wizardSchema from '../lib/wizard-schema';
|
||||
import UndoChanges from '../mixins/undo-changes';
|
||||
import Component from "@ember/component";
|
||||
import { notificationLevels } from '../lib/wizard';
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Component.extend(UndoChanges, {
|
||||
componentType: 'action',
|
||||
|
@ -12,6 +14,7 @@ export default Component.extend(UndoChanges, {
|
|||
visible: computed('currentActionId', function() { return this.action.id === this.currentActionId }),
|
||||
createTopic: equal('action.type', 'create_topic'),
|
||||
updateProfile: equal('action.type', 'update_profile'),
|
||||
watchCategories: equal('action.type', 'watch_categories'),
|
||||
sendMessage: equal('action.type', 'send_message'),
|
||||
openComposer: equal('action.type', 'open_composer'),
|
||||
sendToApi: equal('action.type', 'send_to_api'),
|
||||
|
@ -31,6 +34,12 @@ export default Component.extend(UndoChanges, {
|
|||
name: I18n.t(`admin.wizard.action.${type}.label`)
|
||||
};
|
||||
}),
|
||||
availableNotificationLevels: notificationLevels.map((type, index) => {
|
||||
return {
|
||||
id: type,
|
||||
name: I18n.t(`admin.wizard.action.watch_categories.notification_level.${type}`)
|
||||
};
|
||||
}),
|
||||
|
||||
messageUrl: 'https://thepavilion.io/t/2810',
|
||||
|
||||
|
|
|
@ -63,7 +63,8 @@ export default Component.extend(UndoChanges, {
|
|||
if (this.isDropdown) {
|
||||
options.wizardFieldSelection = 'key,value';
|
||||
options.userFieldOptionsSelection = 'output';
|
||||
options.inputTypes = 'association,assignment';
|
||||
options.textSelection = 'key,value,output';
|
||||
options.inputTypes = 'conditional,association,assignment';
|
||||
options.pairConnector = 'association';
|
||||
options.keyPlaceholder = 'admin.wizard.key';
|
||||
options.valuePlaceholder = 'admin.wizard.value';
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Component from "@ember/component";
|
||||
import { A } from "@ember/array";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ['container', 'export'],
|
||||
|
|
|
@ -2,6 +2,7 @@ import { ajax } from 'discourse/lib/ajax';
|
|||
import { default as discourseComputed } from 'discourse-common/utils/decorators';
|
||||
import { notEmpty } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ['container', 'import'],
|
||||
|
|
|
@ -4,6 +4,7 @@ import { computed } from "@ember/object";
|
|||
import { defaultConnector } from '../lib/wizard-mapper';
|
||||
import { later } from "@ember/runloop";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: [':mapper-connector', ':mapper-block', 'hasMultiple::single'],
|
||||
|
|
|
@ -6,6 +6,7 @@ import { defaultSelectionType, selectionTypes } from '../lib/wizard-mapper';
|
|||
import { snakeCase, generateName, userProperties } from '../lib/wizard';
|
||||
import Component from "@ember/component";
|
||||
import { bind, later } from "@ember/runloop";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: [':mapper-selector', 'activeType'],
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { default as discourseComputed } from 'discourse-common/utils/decorators';
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: 'wizard-message',
|
||||
|
|
|
@ -3,6 +3,7 @@ import { notEmpty } from "@ember/object/computed";
|
|||
import { userProperties } from '../lib/wizard';
|
||||
import { scheduleOnce } from "@ember/runloop";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: 'wizard-text-editor',
|
||||
|
|
|
@ -5,6 +5,7 @@ import { default as discourseComputed } from 'discourse-common/utils/decorators'
|
|||
import { not, and, equal } from "@ember/object/computed";
|
||||
import { selectKitContent } from '../lib/wizard';
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Controller.extend({
|
||||
queryParams: ['refresh_list'],
|
||||
|
|
|
@ -3,8 +3,9 @@ import { popupAjaxError } from 'discourse/lib/ajax-error';
|
|||
import { ajax } from 'discourse/lib/ajax';
|
||||
import { notEmpty } from "@ember/object/computed";
|
||||
import CustomWizardLogs from '../models/custom-wizard-logs';
|
||||
import Controller from "@ember/controller";
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
export default Controller.extend({
|
||||
refreshing: false,
|
||||
hasLogs: notEmpty("logs"),
|
||||
page: 0,
|
||||
|
|
|
@ -9,6 +9,7 @@ import { scheduleOnce, later } from "@ember/runloop";
|
|||
import Controller from "@ember/controller";
|
||||
import copyText from "discourse/lib/copy-text";
|
||||
import CustomWizard from '../models/custom-wizard';
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Controller.extend({
|
||||
hasName: notEmpty('wizard.name'),
|
||||
|
|
|
@ -1,58 +1,27 @@
|
|||
import { default as discourseComputed } from 'discourse-common/utils/decorators';
|
||||
import { scheduleOnce } from "@ember/runloop";
|
||||
import Controller from "@ember/controller";
|
||||
|
||||
export default Controller.extend({
|
||||
title: 'admin.wizard.after_time_modal.title',
|
||||
|
||||
setup() {
|
||||
const dateTime = this.get('model.dateTime');
|
||||
const ROUNDING = 30 * 60 * 1000;
|
||||
const nextInterval = moment(Math.ceil((+moment()) / ROUNDING) * ROUNDING);
|
||||
const mDateTime = dateTime ? moment(dateTime) : nextInterval;
|
||||
const mDateTimeLocal = mDateTime.local();
|
||||
const date = mDateTimeLocal.format('YYYY-MM-DD');
|
||||
const time = mDateTimeLocal.format('HH:mm');
|
||||
|
||||
this.setProperties({ date, time });
|
||||
|
||||
scheduleOnce('afterRender', this, () => {
|
||||
const $timePicker = $("#time-picker");
|
||||
$timePicker.timepicker({ timeFormat: 'H:i' });
|
||||
$timePicker.timepicker('setTime', time);
|
||||
$timePicker.change(() => this.set('time', $timePicker.val()));
|
||||
});
|
||||
this.set('bufferedDateTime', moment(this.model.dateTime));
|
||||
},
|
||||
|
||||
@discourseComputed('date', 'time')
|
||||
dateTime: function(date, time) {
|
||||
return moment(date + 'T' + time).format();
|
||||
},
|
||||
|
||||
@discourseComputed('dateTime')
|
||||
@discourseComputed('bufferedDateTime')
|
||||
submitDisabled(dateTime) {
|
||||
return moment().isAfter(dateTime);
|
||||
},
|
||||
|
||||
resetProperties() {
|
||||
this.setProperties({
|
||||
date: null,
|
||||
time: null
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
clear() {
|
||||
this.resetProperties();
|
||||
this.get('model.update')(null);
|
||||
submit() {
|
||||
const dateTime = this.get('bufferedDateTime');
|
||||
this.get('model.update')(moment(dateTime).utc().toISOString());
|
||||
this.send("closeModal");
|
||||
},
|
||||
|
||||
submit() {
|
||||
const dateTime = this.get('dateTime');
|
||||
const formatted = moment(dateTime).utc().toISOString();
|
||||
this.get('model.update')(formatted);
|
||||
this.resetProperties();
|
||||
this.send("closeModal");
|
||||
dateTimeChanged(dateTime) {
|
||||
this.set('bufferedDateTime', dateTime);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import EmberObject from "@ember/object";
|
||||
import { A } from "@ember/array";
|
||||
import I18n from "I18n";
|
||||
|
||||
// Inputs
|
||||
|
||||
|
|
|
@ -141,6 +141,16 @@ const action = {
|
|||
profile_updates: null,
|
||||
custom_fields: null
|
||||
},
|
||||
watch_categories: {
|
||||
categories: null,
|
||||
notification_level: null,
|
||||
mute_remainder: null
|
||||
},
|
||||
send_to_api: {
|
||||
api: null,
|
||||
api_endpoint: null,
|
||||
api_body: null
|
||||
},
|
||||
add_to_group: {
|
||||
group: null
|
||||
},
|
||||
|
@ -158,7 +168,9 @@ const action = {
|
|||
'recipient',
|
||||
'profile_updates',
|
||||
'group',
|
||||
'url'
|
||||
'url',
|
||||
'categories',
|
||||
'mute_remainder'
|
||||
],
|
||||
advanced: [
|
||||
'code',
|
||||
|
|
|
@ -46,7 +46,16 @@ const userProperties = [
|
|||
'location',
|
||||
'website',
|
||||
'bio_raw',
|
||||
'trust_level'
|
||||
'trust_level',
|
||||
'email_level'
|
||||
];
|
||||
|
||||
const notificationLevels = [
|
||||
'regular',
|
||||
'watching',
|
||||
'tracking',
|
||||
'watching_first_post',
|
||||
'muted'
|
||||
];
|
||||
|
||||
function listProperties(type, opts={}) {
|
||||
|
@ -106,5 +115,6 @@ export {
|
|||
snakeCase,
|
||||
userProperties,
|
||||
listProperties,
|
||||
notificationLevels,
|
||||
wizardFieldList
|
||||
};
|
|
@ -1,6 +1,7 @@
|
|||
import CustomWizardLogs from '../models/custom-wizard-logs';
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default Discourse.Route.extend({
|
||||
export default DiscourseRoute.extend({
|
||||
model() {
|
||||
return CustomWizardLogs.list();
|
||||
},
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import CustomWizard from '../models/custom-wizard';
|
||||
import { ajax } from 'discourse/lib/ajax';
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
model(params) {
|
||||
|
|
|
@ -283,6 +283,63 @@
|
|||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if watchCategories}}
|
||||
<div class="setting full field-mapper-setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.action.watch_categories.categories"}}</label>
|
||||
</div>
|
||||
|
||||
<div class="setting-value">
|
||||
{{wizard-mapper
|
||||
inputs=action.categories
|
||||
property='categories'
|
||||
onUpdate=(action 'mappedFieldUpdated')
|
||||
options=(hash
|
||||
textSelection='key,value'
|
||||
wizardFieldSelection=true
|
||||
userFieldSelection='key,value'
|
||||
categorySelection='output'
|
||||
context='action'
|
||||
)}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting full field-mapper-setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.action.watch_categories.mute_remainder"}}</label>
|
||||
</div>
|
||||
|
||||
<div class="setting-value">
|
||||
{{wizard-mapper
|
||||
inputs=action.mute_remainder
|
||||
property='mute_remainder'
|
||||
onUpdate=(action 'mappedFieldUpdated')
|
||||
options=(hash
|
||||
context='action'
|
||||
wizardFieldSelection=true
|
||||
userFieldSelection='key,value'
|
||||
)}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.action.watch_categories.notification_level.label"}}</label>
|
||||
</div>
|
||||
|
||||
<div class="setting-value">
|
||||
{{combo-box
|
||||
value=action.notification_level
|
||||
content=availableNotificationLevels
|
||||
onChange=(action (mut action.notification_level))
|
||||
options=(hash
|
||||
isDisabled=action.custom_title_enabled
|
||||
none='admin.wizard.action.watch_categories.select_a_notification_level'
|
||||
)}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if showAdvanced}}
|
||||
{{wizard-advanced-toggle showAdvanced=action.showAdvanced}}
|
||||
|
||||
|
|
|
@ -1,24 +1,16 @@
|
|||
{{#d-modal-body class="next-session-time-modal" title=title}}
|
||||
<div class="date-time-card">
|
||||
<div class="modal-date-time-set">
|
||||
<div class="modal-date-area">
|
||||
<label class="input-group-label">
|
||||
{{i18n "admin.wizard.after_time_modal.date"}}
|
||||
</label>
|
||||
{{date-picker value=date containerId="date-container"}}
|
||||
</div>
|
||||
<div class="modal-time-area">
|
||||
<label class="input-group-label">
|
||||
{{i18n "admin.wizard.after_time_modal.time"}}
|
||||
</label>
|
||||
<input type="text" id="time-picker"/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="date-container"/>
|
||||
</div>
|
||||
{{date-time-input
|
||||
date=bufferedDateTime
|
||||
onChange=(action "dateTimeChanged")
|
||||
showTime=true
|
||||
clearable=true
|
||||
}}
|
||||
{{/d-modal-body}}
|
||||
|
||||
<div class="modal-footer">
|
||||
{{d-button action="submit" class="btn-primary" label="admin.wizard.after_time_modal.done" disabled=submitDisabled}}
|
||||
<a class="clear" {{action 'clear'}}>{{i18n 'admin.wizard.after_time_modal.clear'}}</a>
|
||||
{{d-button
|
||||
action="submit"
|
||||
class="btn-primary"
|
||||
label="admin.wizard.after_time_modal.done"
|
||||
disabled=submitDisabled}}
|
||||
</div>
|
||||
|
|
|
@ -91,10 +91,12 @@
|
|||
//= require discourse/app/components/input-tip
|
||||
//= require discourse/app/components/date-picker
|
||||
//= require discourse/app/components/text-field
|
||||
//= require discourse/app/components/d-textarea
|
||||
|
||||
//= require discourse/app/templates/components/conditional-loading-spinner
|
||||
//= require discourse/app/templates/components/d-button
|
||||
//= require discourse/app/templates/components/d-editor
|
||||
//= require discourse/app/templates/components/date-picker
|
||||
//= require discourse/app/templates/components/emoji-picker
|
||||
//= require discourse/app/templates/components/popup-input-tip
|
||||
//= require discourse/app/templates/category-tag-autocomplete
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { default as computed, observes } from 'discourse-common/utils/decorators';
|
||||
import { renderAvatar } from 'discourse/helpers/user-avatar';
|
||||
import userSearch from '../lib/user-search';
|
||||
import I18n from "I18n";
|
||||
|
||||
const template = function(params) {
|
||||
const options = params.options;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import ComposerEditor from 'discourse/components/composer-editor';
|
||||
import { default as computed, on } from 'discourse-common/utils/decorators';
|
||||
import { findRawTemplate } from "discourse/lib/raw-templates";
|
||||
import { findRawTemplate } from "discourse-common/lib/raw-templates";
|
||||
import { throttle } from "@ember/runloop";
|
||||
import { scheduleOnce } from "@ember/runloop";
|
||||
import { safariHacksDisabled } from "discourse/lib/utilities";
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import getUrl from "discourse-common/lib/get-url";
|
||||
import { getToken } from "wizard/lib/ajax";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ["wizard-field-upload"],
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import computed from "discourse-common/utils/decorators";
|
||||
import { siteDir, isRTL, isLTR } from "discourse/lib/text-direction";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default Ember.TextField.extend({
|
||||
attributeBindings: ['autocorrect', 'autocapitalize', 'autofocus', 'maxLength', 'dir'],
|
||||
|
|
|
@ -23,7 +23,7 @@ export default {
|
|||
const Store = requirejs("discourse/models/store").default;
|
||||
const registerRawHelpers = requirejs("discourse-common/lib/raw-handlebars-helpers").registerRawHelpers;
|
||||
const RawHandlebars = requirejs("discourse-common/lib/raw-handlebars").default;
|
||||
const Site = requirejs("discourse/models/site").default;
|
||||
const Site = requirejs("discourse/plugins/discourse-custom-wizard/wizard/models/site").default;
|
||||
const RestAdapter = requirejs("discourse/adapters/rest").default;
|
||||
|
||||
Discourse.Model = EmberObject.extend();
|
||||
|
|
10
assets/javascripts/wizard/models/site.js.es6
Normale Datei
10
assets/javascripts/wizard/models/site.js.es6
Normale Datei
|
@ -0,0 +1,10 @@
|
|||
import Site from "discourse/models/site";
|
||||
|
||||
export default Site.reopenClass({
|
||||
// There is no site data actually loaded by the CW yet. This placeholder is
|
||||
// needed by imported classes
|
||||
createCurrent() {
|
||||
const store = Discourse.__container__.lookup("service:store");
|
||||
return store.createRecord("site", {});
|
||||
},
|
||||
})
|
|
@ -1,3 +1,5 @@
|
|||
import I18n from "I18n";
|
||||
|
||||
export default Ember.Route.extend({
|
||||
model(params) {
|
||||
const appModel = this.modelFor('custom');
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
{{date-picker
|
||||
value=field.value
|
||||
id=field.id
|
||||
}}
|
|
@ -481,54 +481,12 @@
|
|||
min-height: 150px;
|
||||
}
|
||||
|
||||
.next-session-time-modal {
|
||||
text-align: center;
|
||||
.modal .modal-body.next-session-time-modal {
|
||||
overflow: visible;
|
||||
|
||||
.date-time-card {
|
||||
width: 270px;
|
||||
padding: 10px 20px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.modal-date-time-set{
|
||||
padding-top: 3px;
|
||||
padding-bottom: 4px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.modal-date-area{
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.modal-time-area{
|
||||
order: 2;
|
||||
margin-left: 10px;
|
||||
|
||||
.modal-time{
|
||||
width: 127px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-timepicker-input {
|
||||
width: 119px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.date-picker{
|
||||
width: 121px;
|
||||
}
|
||||
|
||||
.pika-single {
|
||||
position: relative !important;
|
||||
|
||||
.pika-lendar {
|
||||
border: 1px solid #eee;
|
||||
padding: 14px;
|
||||
margin: 0;
|
||||
float: none;
|
||||
width: auto;
|
||||
}
|
||||
.picker-container {
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -163,6 +163,7 @@ en:
|
|||
category: Category
|
||||
group: Group
|
||||
user_selector: User Selector
|
||||
date: Date
|
||||
|
||||
connector:
|
||||
and: "and"
|
||||
|
@ -208,6 +209,18 @@ en:
|
|||
label: "Update Profile"
|
||||
setting: "Fields"
|
||||
key: "field"
|
||||
watch_categories:
|
||||
label: "Watch Categories"
|
||||
categories: "Categories"
|
||||
mute_remainder: "Mute Remainder"
|
||||
notification_level:
|
||||
label: "Notification Level"
|
||||
regular: "Normal"
|
||||
watching: "Watching"
|
||||
tracking: "Tracking"
|
||||
watching_first_post: "Watching First Post"
|
||||
muted: "Muted"
|
||||
select_a_notification_level: "Select level"
|
||||
post_builder:
|
||||
checkbox: "Post Builder"
|
||||
label: "Builder"
|
||||
|
|
|
@ -116,12 +116,18 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
|||
:post,
|
||||
:post_builder,
|
||||
:post_template,
|
||||
:notification_level,
|
||||
:api,
|
||||
:api_endpoint,
|
||||
:api_body,
|
||||
title: mapped_params,
|
||||
category: mapped_params,
|
||||
tags: mapped_params,
|
||||
custom_fields: mapped_params,
|
||||
required: mapped_params,
|
||||
recipient: mapped_params,
|
||||
categories: mapped_params,
|
||||
mute_remainder: mapped_params,
|
||||
profile_updates: mapped_params,
|
||||
group: mapped_params,
|
||||
url: mapped_params
|
||||
|
|
|
@ -2,7 +2,7 @@ module Jobs
|
|||
class SetAfterTimeWizard < ::Jobs::Base
|
||||
def execute(args)
|
||||
if SiteSetting.custom_wizard_enabled
|
||||
wizard = CustomWizard::Wizard.find(args[:wizard_id])
|
||||
wizard = CustomWizard::Wizard.create(args[:wizard_id])
|
||||
|
||||
if wizard && wizard.after_time
|
||||
user_ids = []
|
||||
|
|
|
@ -97,9 +97,9 @@ class CustomWizard::Action
|
|||
end
|
||||
|
||||
def update_profile
|
||||
return unless (profile_updates = action['profile_updates']).length
|
||||
params = {}
|
||||
|
||||
if (profile_updates = action['profile_updates'])
|
||||
profile_updates.first[:pairs].each do |pair|
|
||||
if allowed_profile_field?(pair['key'])
|
||||
key = cast_profile_key(pair['key'])
|
||||
|
@ -113,6 +113,7 @@ class CustomWizard::Action
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
params = add_custom_fields(params)
|
||||
|
||||
|
@ -133,6 +134,36 @@ class CustomWizard::Action
|
|||
end
|
||||
end
|
||||
|
||||
def watch_categories
|
||||
|
||||
watched_categories = CustomWizard::Mapper.new(
|
||||
inputs: action['categories'],
|
||||
data: data,
|
||||
user: user
|
||||
).perform
|
||||
|
||||
notification_level = action['notification_level']
|
||||
|
||||
if notification_level.blank?
|
||||
log_error("Notifcation Level was not set! Exiting wizard action")
|
||||
return
|
||||
end
|
||||
|
||||
mute_remainder = CustomWizard::Mapper.new(
|
||||
inputs: action['mute_remainder'],
|
||||
data: data,
|
||||
user: user
|
||||
).perform
|
||||
|
||||
Category.all.each do |category|
|
||||
if watched_categories.present? && watched_categories.include?(category.id.to_s)
|
||||
CategoryUser.set_notification_level_for_category(user, CategoryUser.notification_levels[notification_level.to_sym], category.id)
|
||||
elsif mute_remainder
|
||||
CategoryUser.set_notification_level_for_category(user, CategoryUser.notification_levels[:muted], category.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def send_to_api
|
||||
api_body = nil
|
||||
|
||||
|
|
|
@ -258,7 +258,9 @@ class CustomWizard::Builder
|
|||
}
|
||||
).perform
|
||||
|
||||
if content.present?
|
||||
if content.present? &&
|
||||
content[:result].present?
|
||||
|
||||
if content[:type] == 'association'
|
||||
content[:result] = content[:result].map do |item|
|
||||
{
|
||||
|
@ -325,6 +327,10 @@ class CustomWizard::Builder
|
|||
updater.errors.add(id, I18n.t('wizard.field.invalid_file', label: label, types: file_types))
|
||||
end
|
||||
|
||||
if type === 'date' && value.present? && !validate_date(value)
|
||||
updater.errors.add(id, I18n.t('wizard.field.invalid_date'))
|
||||
end
|
||||
|
||||
CustomWizard::Builder.field_validators.each do |validator|
|
||||
if type === validator[:type]
|
||||
validator[:block].call(field, updater, step_template)
|
||||
|
@ -338,6 +344,15 @@ class CustomWizard::Builder
|
|||
.include?(File.extname(value['original_filename'])[1..-1])
|
||||
end
|
||||
|
||||
def validate_date(value)
|
||||
begin
|
||||
Date.parse(value)
|
||||
true
|
||||
rescue ArgumentError
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def is_text_type(field)
|
||||
['text', 'textarea'].include? field['type']
|
||||
end
|
||||
|
|
|
@ -11,6 +11,7 @@ class CustomWizard::Field
|
|||
min_length: nil
|
||||
},
|
||||
text_only: {},
|
||||
date: {},
|
||||
number: {},
|
||||
checkbox: {},
|
||||
url: {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class CustomWizard::Mapper
|
||||
attr_accessor :inputs, :data, :user
|
||||
|
||||
USER_FIELDS = ['name', 'username', 'email', 'date_of_birth', 'title', 'locale', 'trust_level']
|
||||
USER_FIELDS = ['name', 'username', 'email', 'date_of_birth', 'title', 'locale', 'trust_level', 'email_level']
|
||||
PROFILE_FIELDS = ['location', 'website', 'bio_raw']
|
||||
|
||||
def self.user_fields
|
||||
|
@ -188,7 +188,7 @@ class CustomWizard::Mapper
|
|||
|
||||
def map_user_field_options(value)
|
||||
if value.include?(User::USER_FIELD_PREFIX)
|
||||
if field = UserField.find(value.split('_').last)
|
||||
if field = UserField.find_by(id: value.split('_').last)
|
||||
field.user_field_options.map(&:value)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,6 +18,7 @@ config.assets.paths << "#{plugin_asset_path}/stylesheets/wizard"
|
|||
|
||||
if Rails.env.production?
|
||||
config.assets.precompile += %w{
|
||||
wizard-preload.js
|
||||
wizard-custom-guest.js
|
||||
wizard-custom-lib.js
|
||||
wizard-custom.js
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<%= discourse_stylesheet_link_tag (mobile_view? ? :mobile_theme : :desktop_theme) %>
|
||||
<%- end %>
|
||||
|
||||
<%= preload_script "locales/#{I18n.locale}" %>
|
||||
<%= preload_script "ember_jquery" %>
|
||||
<%= preload_script "wizard-vendor" %>
|
||||
<%= preload_script "wizard-application" %>
|
||||
|
@ -19,7 +20,6 @@
|
|||
<%= preload_script "wizard-custom" %>
|
||||
<%= preload_script "wizard-plugin" %>
|
||||
<%= preload_script "pretty-text-bundle" %>
|
||||
<%= preload_script "locales/#{I18n.locale}" %>
|
||||
<script src="<%= ExtraLocalesController.url("wizard") %>"></script>
|
||||
<%= csrf_meta_tags %>
|
||||
|
||||
|
|
Laden …
In neuem Issue referenzieren