0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-11-26 11:00:28 +01:00

Merge pull request #14 from angusmcleod/pr/13

Pr/13
Dieser Commit ist enthalten in:
Angus McLeod 2019-08-07 20:59:56 +10:00 committet von GitHub
Commit 6ad821024a
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 4AEE18F83AFDEB23
14 geänderte Dateien mit 339 neuen und 5 gelöschten Zeilen

Datei anzeigen

@ -0,0 +1,42 @@
export default Ember.Component.extend({
classNames: ['container', 'export'],
selected: Ember.A(),
actions: {
checkChanged(event) {
this.set('exportMessage', '');
let selected = this.get('selected');
if (event.target.checked) {
selected.addObject(event.target.id);
} else if (!event.target.checked) {
selected.removeObject(event.target.id);
}
this.set('selected', selected);
},
export() {
const wizards = this.get('selected');
if (!wizards.length) {
this.set('exportMessage', I18n.t("admin.wizard.transfer.export.none_selected"));
} else {
this.set('exportMessage', '');
let url = Discourse.BaseUrl;
let route = '/admin/wizards/transfer/export';
url += route + '?';
wizards.forEach((wizard) => {
let step = 'wizards[]=' + wizard;
step += '&';
url += step;
});
location.href = url;
}
}
}
});

Datei anzeigen

@ -0,0 +1,81 @@
import { ajax } from 'discourse/lib/ajax';
import { default as computed } from 'ember-addons/ember-computed-decorators';
export default Ember.Component.extend({
classNames: ['container', 'import'],
hasLogs: Ember.computed.notEmpty('logs'),
@computed('successIds', 'failureIds')
logs(successIds, failureIds) {
let logs = [];
if (successIds) {
logs.push(...successIds.map(id => {
return { id, type: 'success' };
}));
}
if (failureIds) {
logs.push(...failureIds.map(id => {
return { id, type: 'failure' };
}));
}
return logs;
},
actions: {
setFilePath(event) {
this.set('importMessage', '');
// 512 kb is the max file size
let maxFileSize = 512 * 1024;
if (event.target.files[0] === undefined) {
this.set('filePath', null);
return;
}
if (maxFileSize < event.target.files[0].size) {
this.setProperties({
importMessage: I18n.t('admin.wizard.transfer.import.file_size_error'),
filePath: null
});
$('#file-url').val('');
} else {
this.set('filePath', event.target.files[0]);
}
},
import() {
const filePath = this.get('filePath');
let $formData = new FormData();
if (filePath) {
$formData.append('file', filePath);
ajax('/admin/wizards/transfer/import', {
type: 'POST',
data: $formData,
processData: false,
contentType: false,
}).then(result => {
if (result.error) {
this.set('importMessage', result.error);
} else {
this.setProperties({
successIds: result.success,
failureIds: result.failed,
fileName: $('#file-url')[0].files[0].name
});
}
this.set('filePath', null);
$('#file-url').val('');
});
} else {
this.set('importMessage', I18n.t("admin.wizard.transfer.import.no_file"));
}
}
}
});

Datei anzeigen

@ -0,0 +1 @@
export default Ember.Controller.extend();

Datei anzeigen

@ -11,6 +11,9 @@ export default {
this.route('adminWizardsApis', { path: '/apis', resetNamespace: true }, function() { this.route('adminWizardsApis', { path: '/apis', resetNamespace: true }, function() {
this.route('adminWizardsApi', { path: '/:name', resetNamespace: true }); this.route('adminWizardsApi', { path: '/:name', resetNamespace: true });
}); });
this.route('adminWizardsTransfer', { path: '/transfer', resetNamespace: true });
}); });
} }
}; };

Datei anzeigen

@ -0,0 +1,7 @@
import CustomWizard from '../models/custom-wizard';
export default Discourse.Route.extend({
model() {
return CustomWizard.all();
}
});

Datei anzeigen

@ -0,0 +1,2 @@
{{wizard-export wizards=model}}
{{wizard-import}}

Datei anzeigen

@ -2,6 +2,7 @@
{{nav-item route='adminWizardsCustom' label='admin.wizard.custom_label'}} {{nav-item route='adminWizardsCustom' label='admin.wizard.custom_label'}}
{{nav-item route='adminWizardsSubmissions' label='admin.wizard.submissions_label'}} {{nav-item route='adminWizardsSubmissions' label='admin.wizard.submissions_label'}}
{{nav-item route='adminWizardsApis' label='admin.wizard.api.nav_label'}} {{nav-item route='adminWizardsApis' label='admin.wizard.api.nav_label'}}
{{nav-item route='adminWizardsTransfer' label='admin.wizard.transfer.nav_label'}}
{{/admin-nav}} {{/admin-nav}}
<div class="admin-container"> <div class="admin-container">

Datei anzeigen

@ -0,0 +1,25 @@
<h2>{{i18n 'admin.wizard.transfer.export.label'}}</h2>
<ul class="wizard-list-select">
{{#each wizards as |w|}}
<li>
{{input type="checkbox"
id=(dasherize w.id)
change=(action 'checkChanged')}}
{{#link-to "adminWizard" (dasherize w.id)}}
{{w.name}}
{{/link-to}}
</li>
{{/each}}
</ul>
{{d-button id="export-button"
class="btn btn-primary side"
label="admin.wizard.transfer.export.label"
action=(action "export")}}
{{#if exportMessage}}
<div class="export-message">
{{exportMessage}}
</div>
{{/if}}

Datei anzeigen

@ -0,0 +1,32 @@
<h2>{{i18n 'admin.wizard.transfer.import.label'}}</h2>
<div class="controls">
{{input id='file-url' type="file" change=(action "setFilePath")}}
{{#if importMessage}}
<div class="import-message">
{{importMessage}}
</div>
{{/if}}
{{d-button id="import-button"
class="btn btn-primary side"
label="admin.wizard.transfer.import.label"
action=(action "import")}}
</div>
{{#if hasLogs}}
<div class="import-logs">
<div class="title">
{{i18n 'admin.wizard.transfer.import.logs' fileName=fileName}}
</div>
<ul>
{{#each logs as |l|}}
<li class="import-log">
{{i18n (concat 'admin.wizard.transfer.import.' l.type) id=l.id}}
</li>
{{/each}}
</ul>
</div>
{{/if}}

Datei anzeigen

@ -480,3 +480,40 @@
.wizard-step-contents{ .wizard-step-contents{
height: unset !important; height: unset !important;
} }
// Tansfer tab
.admin-wizards-transfer .admin-container .container {
padding-top: 20px;
}
#file-url {
display: block;
margin-bottom: 10px;
}
.wizard-list-select {
list-style-type: none;
}
.wizard-action-buttons {
flex-direction: column;
}
.import-message {
margin: 10px 0;
}
.import-logs {
margin-top: 20px;
.title {
font-weight: 800;
margin-bottom: 10px;
}
ul {
list-style: none;
}
}

Datei anzeigen

@ -215,6 +215,19 @@ en:
log: log:
label: "Logs" label: "Logs"
transfer:
nav_label: "Transfer"
export:
label: "Export"
none_selected: "Please select atleast one wizard"
import:
label: "Import"
logs: "Import logs for {{fileName}}"
success: 'Wizard "{{id}}" saved successfully'
failure: 'Wizard "{{id}}" could not be saved'
no_file: "Please choose a file to import"
file_size_error: "The file must be JSON and 512kb or less"
wizard_js: wizard_js:
location: location:
name: name:

Datei anzeigen

@ -10,6 +10,15 @@ en:
too_short: "%{label} must be at least %{min} characters" too_short: "%{label} must be at least %{min} characters"
none: "We couldn't find a wizard at that address." none: "We couldn't find a wizard at that address."
no_skip: "Wizard can't be skipped" no_skip: "Wizard can't be skipped"
export:
error:
select_one: "Please select atleast one wizard"
import:
error:
no_file: "No file selected"
file_large: "File too large"
invalid_json: "File is not a valid json file"
no_valid_wizards: "File doesn't contain any valid wizards"
site_settings: site_settings:
wizard_redirect_exclude_paths: "Routes excluded from wizard redirects." wizard_redirect_exclude_paths: "Routes excluded from wizard redirects."

74
controllers/transfer.rb Normale Datei
Datei anzeigen

@ -0,0 +1,74 @@
class CustomWizard::TransferController < ::ApplicationController
before_action :ensure_logged_in
before_action :ensure_admin
skip_before_action :check_xhr, :only => [:export]
def index
end
def export
wizards = params['wizards']
wizard_objects = []
if wizards.nil?
render json: { error: I18n.t('wizard.export.error.select_one') }
return
end
wizards.each do |w|
wizard_objects.push(PluginStore.get('custom_wizard', w.tr('-', '_')))
end
send_data wizard_objects.to_json,
type: "application/json",
disposition: 'attachment',
filename: 'wizards.json'
end
def import
file = File.read(params['file'].tempfile)
if file.nil?
render json: { error: I18n.t('wizard.import.error.no_file') }
return
end
fileSize = file.size
maxFileSize = 512 * 1024
if maxFileSize < fileSize
render json: { error: I18n.t('wizard.import.error.file_large') }
return
end
begin
jsonObject = JSON.parse file
rescue JSON::ParserError
render json: { error: I18n.t('wizard.import.error.invalid_json') }
return
end
countValid = 0
success_ids = []
failed_ids = []
jsonObject.each do |o|
if !CustomWizard::Template.new(o)
failed_ids.push o['id']
next
end
countValid += 1
pluginStoreEntry = PluginStore.new 'custom_wizard'
saved = pluginStoreEntry.set(o['id'], o) unless pluginStoreEntry.get(o['id'])
success_ids.push o['id'] if !!saved
failed_ids.push o['id'] if !saved
end
if countValid == 0
render json: { error: I18n.t('wizard.import.error.no_valid_wizards') }
else
render json: { success: success_ids, failed: failed_ids }
end
end
end

Datei anzeigen

@ -12,6 +12,7 @@ config = Rails.application.config
config.assets.paths << Rails.root.join('plugins', 'discourse-custom-wizard', 'assets', 'javascripts') config.assets.paths << Rails.root.join('plugins', 'discourse-custom-wizard', 'assets', 'javascripts')
config.assets.paths << Rails.root.join('plugins', 'discourse-custom-wizard', 'assets', 'stylesheets', 'wizard') config.assets.paths << Rails.root.join('plugins', 'discourse-custom-wizard', 'assets', 'stylesheets', 'wizard')
if Rails.env.production? if Rails.env.production?
config.assets.precompile += %w{ config.assets.precompile += %w{
wizard-custom-lib.js wizard-custom-lib.js
@ -75,6 +76,10 @@ after_initialize do
delete 'admin/wizards/apis/logs/:name' => 'api#clearlogs' delete 'admin/wizards/apis/logs/:name' => 'api#clearlogs'
get 'admin/wizards/apis/:name/redirect' => 'api#redirect' get 'admin/wizards/apis/:name/redirect' => 'api#redirect'
get 'admin/wizards/apis/:name/authorize' => 'api#authorize' get 'admin/wizards/apis/:name/authorize' => 'api#authorize'
#transfer code
get 'admin/wizards/transfer' => 'transfer#index'
get 'admin/wizards/transfer/export' => 'transfer#export'
post 'admin/wizards/transfer/import' => 'transfer#import'
end end
end end
@ -89,6 +94,8 @@ after_initialize do
load File.expand_path('../controllers/wizard.rb', __FILE__) load File.expand_path('../controllers/wizard.rb', __FILE__)
load File.expand_path('../controllers/steps.rb', __FILE__) load File.expand_path('../controllers/steps.rb', __FILE__)
load File.expand_path('../controllers/admin.rb', __FILE__) load File.expand_path('../controllers/admin.rb', __FILE__)
#transfer code
load File.expand_path('../controllers/transfer.rb', __FILE__)
load File.expand_path('../jobs/refresh_api_access_token.rb', __FILE__) load File.expand_path('../jobs/refresh_api_access_token.rb', __FILE__)
load File.expand_path('../lib/api/api.rb', __FILE__) load File.expand_path('../lib/api/api.rb', __FILE__)
@ -145,7 +152,7 @@ after_initialize do
@excluded_routes ||= SiteSetting.wizard_redirect_exclude_paths.split('|') + ['/w/'] @excluded_routes ||= SiteSetting.wizard_redirect_exclude_paths.split('|') + ['/w/']
url = request.referer || request.original_url url = request.referer || request.original_url
if request.format === 'text/html' && !@excluded_routes.any? { |str| /#{str}/ =~ url } && wizard_id if request.format === 'text/html' && !@excluded_routes.any? {|str| /#{str}/ =~ url} && wizard_id
if request.referer !~ /\/w\// && request.referer !~ /\/invites\// if request.referer !~ /\/w\// && request.referer !~ /\/invites\//
CustomWizard::Wizard.set_submission_redirect(current_user, wizard_id, request.referer) CustomWizard::Wizard.set_submission_redirect(current_user, wizard_id, request.referer)
end end
@ -157,7 +164,7 @@ after_initialize do
end end
end end
add_to_serializer(:current_user, :redirect_to_wizard) { object.custom_fields['redirect_to_wizard'] } add_to_serializer(:current_user, :redirect_to_wizard) {object.custom_fields['redirect_to_wizard']}
## TODO limit this to the first admin ## TODO limit this to the first admin
SiteSerializer.class_eval do SiteSerializer.class_eval do
@ -169,7 +176,7 @@ after_initialize do
def complete_custom_wizard def complete_custom_wizard
if scope.user && requires_completion = CustomWizard::Wizard.prompt_completion(scope.user) if scope.user && requires_completion = CustomWizard::Wizard.prompt_completion(scope.user)
requires_completion.map { |w| { name: w[:name], url: "/w/#{w[:id]}" } } requires_completion.map {|w| {name: w[:name], url: "/w/#{w[:id]}"}}
end end
end end