Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-11-25 18:50:27 +01:00
complete OAuth authorization && Start API Admin UI
Dieser Commit ist enthalten in:
Ursprung
3da8833410
Commit
01a9e7f148
17 geänderte Dateien mit 472 neuen und 122 gelöschten Zeilen
78
assets/javascripts/discourse/controllers/admin-wizards-api.js.es6
Normale Datei
78
assets/javascripts/discourse/controllers/admin-wizards-api.js.es6
Normale Datei
|
@ -0,0 +1,78 @@
|
||||||
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
|
import CustomWizardApi from '../models/custom-wizard-api';
|
||||||
|
|
||||||
|
export default Ember.Controller.extend({
|
||||||
|
loadingSubscriptions: false,
|
||||||
|
notAuthorized: Ember.computed.not('api.authorized'),
|
||||||
|
authorizationTypes: ['oauth', 'basic'],
|
||||||
|
isOauth: Ember.computed.equal('api.authType', 'oauth'),
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
addParam() {
|
||||||
|
this.get('api.authParams').pushObject({});
|
||||||
|
},
|
||||||
|
|
||||||
|
removeParam(param) {
|
||||||
|
this.get('api.authParams').removeObject(param);
|
||||||
|
},
|
||||||
|
|
||||||
|
authorize() {
|
||||||
|
const api = this.get('api');
|
||||||
|
const { authType, authUrl, authParams } = api;
|
||||||
|
let query = '?';
|
||||||
|
|
||||||
|
if (authType === 'oauth') {
|
||||||
|
query += `client_id=${api.get('clientId')}&redirect_uri=${encodeURIComponent(api.get('redirectUri'))}&response_type=code`;
|
||||||
|
|
||||||
|
if (authParams) {
|
||||||
|
authParams.forEach(p => {
|
||||||
|
query += `&${p.key}=${encodeURIComponent(p.value)}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// basic auth
|
||||||
|
}
|
||||||
|
|
||||||
|
window.location.href = authUrl + query;
|
||||||
|
},
|
||||||
|
|
||||||
|
save() {
|
||||||
|
const api = this.get('api');
|
||||||
|
const service = api.get('service');
|
||||||
|
|
||||||
|
let data = {};
|
||||||
|
|
||||||
|
data['auth_type'] = api.get('authType');
|
||||||
|
data['auth_url'] = api.get('authUrl');
|
||||||
|
|
||||||
|
if (data.auth_type === 'oauth') {
|
||||||
|
data['client_id'] = api.get('clientId');
|
||||||
|
data['client_secret'] = api.get('clientSecret');
|
||||||
|
|
||||||
|
let params = api.get('authParams');
|
||||||
|
|
||||||
|
if (params) {
|
||||||
|
data['auth_params'] = JSON.stringify(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
data['token_url'] = api.get('tokenUrl');
|
||||||
|
} else {
|
||||||
|
data['username'] = api.get('username');
|
||||||
|
data['password'] = api.get('password');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.set('savingApi', true);
|
||||||
|
|
||||||
|
ajax(`/admin/wizards/apis/${service}/save`, {
|
||||||
|
type: 'PUT',
|
||||||
|
data
|
||||||
|
}).catch(popupAjaxError)
|
||||||
|
.then(result => {
|
||||||
|
if (result.success) {
|
||||||
|
this.set('api', CustomWizardApi.create(result.api));
|
||||||
|
}
|
||||||
|
}).finally(() => this.set('savingApi', false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -8,6 +8,9 @@ export default {
|
||||||
this.route('adminWizardsSubmissions', { path: '/submissions', resetNamespace: true }, function() {
|
this.route('adminWizardsSubmissions', { path: '/submissions', resetNamespace: true }, function() {
|
||||||
this.route('adminWizardSubmissions', { path: '/:wizard_id', resetNamespace: true });
|
this.route('adminWizardSubmissions', { path: '/:wizard_id', resetNamespace: true });
|
||||||
});
|
});
|
||||||
|
this.route('adminWizardsApis', { path: '/apis', resetNamespace: true }, function() {
|
||||||
|
this.route('adminWizardsApi', { path: '/:service', resetNamespace: true });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
50
assets/javascripts/discourse/models/custom-wizard-api.js.es6
Normale Datei
50
assets/javascripts/discourse/models/custom-wizard-api.js.es6
Normale Datei
|
@ -0,0 +1,50 @@
|
||||||
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
|
import { default as computed } from 'ember-addons/ember-computed-decorators';
|
||||||
|
|
||||||
|
const CustomWizardApi = Discourse.Model.extend({
|
||||||
|
@computed('service')
|
||||||
|
redirectUri(service) {
|
||||||
|
const baseUrl = location.protocol+'//'+location.hostname+(location.port ? ':'+location.port: '');
|
||||||
|
return baseUrl + `/admin/wizards/apis/${service}/redirect`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
CustomWizardApi.reopenClass({
|
||||||
|
create(params) {
|
||||||
|
const api = this._super.apply(this);
|
||||||
|
api.setProperties({
|
||||||
|
service: params.service,
|
||||||
|
authType: params.auth_type,
|
||||||
|
authUrl: params.auth_url,
|
||||||
|
tokenUrl: params.token_url,
|
||||||
|
clientId: params.client_id,
|
||||||
|
clientSecret: params.client_secret,
|
||||||
|
authParams: Ember.A(params.auth_params),
|
||||||
|
authorized: params.authorized,
|
||||||
|
accessToken: params.access_token,
|
||||||
|
refreshToken: params.refresh_token,
|
||||||
|
code: params.code,
|
||||||
|
tokenExpiresAt: params.token_expires_at,
|
||||||
|
tokenRefreshAt: params.token_refresh_at
|
||||||
|
});
|
||||||
|
return api;
|
||||||
|
},
|
||||||
|
|
||||||
|
find(service) {
|
||||||
|
return ajax(`/admin/wizards/apis/${service}`, {
|
||||||
|
type: 'GET'
|
||||||
|
}).then(result => {
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
list() {
|
||||||
|
return ajax("/admin/wizards/apis", {
|
||||||
|
type: 'GET'
|
||||||
|
}).then(result => {
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default CustomWizardApi;
|
15
assets/javascripts/discourse/routes/admin-wizards-api.js.es6
Normale Datei
15
assets/javascripts/discourse/routes/admin-wizards-api.js.es6
Normale Datei
|
@ -0,0 +1,15 @@
|
||||||
|
import CustomWizardApi from '../models/custom-wizard-api';
|
||||||
|
|
||||||
|
export default Discourse.Route.extend({
|
||||||
|
model(params) {
|
||||||
|
if (params.service === 'new') {
|
||||||
|
return {};
|
||||||
|
} else {
|
||||||
|
return CustomWizardApi.find(params.service);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController(controller, model){
|
||||||
|
controller.set("api", CustomWizardApi.create(model));
|
||||||
|
}
|
||||||
|
});
|
11
assets/javascripts/discourse/routes/admin-wizards-apis.js.es6
Normale Datei
11
assets/javascripts/discourse/routes/admin-wizards-apis.js.es6
Normale Datei
|
@ -0,0 +1,11 @@
|
||||||
|
import CustomWizardApi from '../models/custom-wizard-api';
|
||||||
|
|
||||||
|
export default Discourse.Route.extend({
|
||||||
|
model() {
|
||||||
|
return CustomWizardApi.list();
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController(controller, model){
|
||||||
|
controller.set("model", model);
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,16 +0,0 @@
|
||||||
<div class="wizard-submissions">
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
{{#each fields as |f|}}
|
|
||||||
<th>{{f}}</th>
|
|
||||||
{{/each}}
|
|
||||||
</tr>
|
|
||||||
{{#each submissions as |s|}}
|
|
||||||
<tr>
|
|
||||||
{{#each-in s as |k v|}}
|
|
||||||
<td>{{v}}</td>
|
|
||||||
{{/each-in}}
|
|
||||||
</tr>
|
|
||||||
{{/each}}
|
|
||||||
</table>
|
|
||||||
</div>
|
|
124
assets/javascripts/discourse/templates/admin-wizards-api.hbs
Normale Datei
124
assets/javascripts/discourse/templates/admin-wizards-api.hbs
Normale Datei
|
@ -0,0 +1,124 @@
|
||||||
|
<div class="wizard-api-authorization">
|
||||||
|
|
||||||
|
<div class="details">
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.service'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{input value=api.service}}
|
||||||
|
</div>
|
||||||
|
<div class="control-label">
|
||||||
|
<span>{{i18n 'admin.wizard.api.redirect_uri'}}</span>
|
||||||
|
<span>{{api.redirectUri}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.auth_type'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{combo-box value=api.authType content=authorizationTypes none='admin.wizard.api.auth_type_none'}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.auth_url'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{input value=api.authUrl}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.token_url'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{input value=api.tokenUrl}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if isOauth}}
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.client_id'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{input value=api.clientId}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.client_secret'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{input value=api.clientSecret}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.params'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{#each api.authParams as |param|}}
|
||||||
|
<div class="param">
|
||||||
|
{{input value=param.key placeholder=(i18n 'admin.wizard.api.param_key')}}
|
||||||
|
{{input value=param.value placeholder=(i18n 'admin.wizard.api.param_value')}}
|
||||||
|
{{d-button action='removeParam' actionParam=param icon='times'}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
{{d-button label='admin.wizard.api.param_new' icon='plus' action='addParam'}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='buttons'>
|
||||||
|
{{d-button label="admin.wizard.api.save" action="save"}}
|
||||||
|
{{#if savingApi}}
|
||||||
|
{{loading-spinner size="small"}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='buttons'>
|
||||||
|
{{d-button label="admin.wizard.api.authorize" action="authorize"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="authorization">
|
||||||
|
{{#if api.authorized}}
|
||||||
|
<span class="authorization-indicator authorized"></span>
|
||||||
|
<span>{{i18n "admin.wizard.api.authorized"}}</span>
|
||||||
|
{{else}}
|
||||||
|
<span class="authorization-indicator not-authorized"></span>
|
||||||
|
<span>{{i18n "admin.wizard.api.not_authorized"}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="keys">
|
||||||
|
<div class="control-group">
|
||||||
|
<label>Access Token:</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{api.accessToken}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>Expires At:</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{api.tokenExpiresAt}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>Refresh At:</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{api.tokenRefreshAt}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>Refresh Token:</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{api.refreshToken}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>Code:</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{api.code}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
20
assets/javascripts/discourse/templates/admin-wizards-apis.hbs
Normale Datei
20
assets/javascripts/discourse/templates/admin-wizards-apis.hbs
Normale Datei
|
@ -0,0 +1,20 @@
|
||||||
|
<div class='row'>
|
||||||
|
<div class='content-list wizard-list'>
|
||||||
|
<ul>
|
||||||
|
{{#each model as |api|}}
|
||||||
|
<li>
|
||||||
|
{{#link-to "adminWizardsApi" api.service}}{{api.service}}{{/link-to}}
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
<div class="new-api">
|
||||||
|
{{#link-to 'adminWizardsApi' 'new' class="btn"}}
|
||||||
|
{{d-icon "plus"}} {{i18n 'admin.wizard.api.new'}}
|
||||||
|
{{/link-to}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
{{outlet}}
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,6 +1,7 @@
|
||||||
{{#admin-nav}}
|
{{#admin-nav}}
|
||||||
{{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'}}
|
||||||
{{/admin-nav}}
|
{{/admin-nav}}
|
||||||
|
|
||||||
<div class="admin-container">
|
<div class="admin-container">
|
||||||
|
|
|
@ -126,6 +126,25 @@ en:
|
||||||
label: "Custom Category"
|
label: "Custom Category"
|
||||||
wizard_field: "Wizard Field"
|
wizard_field: "Wizard Field"
|
||||||
user_field: "User Field"
|
user_field: "User Field"
|
||||||
|
api:
|
||||||
|
nav_label: 'APIs'
|
||||||
|
new: 'New Api'
|
||||||
|
service: 'Api Service'
|
||||||
|
redirect_uri: "Redirect Uri"
|
||||||
|
auth_type: 'Authorization Type'
|
||||||
|
auth_type_none: 'Select a type'
|
||||||
|
token_url: "Token Url"
|
||||||
|
auth_url: 'Authorization Url'
|
||||||
|
client_id: 'Client Id'
|
||||||
|
client_secret: 'Client Secret'
|
||||||
|
save: "Save"
|
||||||
|
authorize: 'Authorize'
|
||||||
|
authorized: 'Authorized'
|
||||||
|
not_authorized: "Not Authorized"
|
||||||
|
params: 'Params'
|
||||||
|
param_new: 'New Param'
|
||||||
|
param_key: 'Param Key'
|
||||||
|
param_value: 'Param Value'
|
||||||
|
|
||||||
wizard_js:
|
wizard_js:
|
||||||
location:
|
location:
|
||||||
|
|
55
controllers/admin_api.rb
Normale Datei
55
controllers/admin_api.rb
Normale Datei
|
@ -0,0 +1,55 @@
|
||||||
|
class CustomWizard::AdminApiController < ::ApplicationController
|
||||||
|
before_action :ensure_logged_in
|
||||||
|
before_action :ensure_admin
|
||||||
|
skip_before_action :check_xhr, only: [:redirect]
|
||||||
|
|
||||||
|
def index
|
||||||
|
end
|
||||||
|
|
||||||
|
def list
|
||||||
|
serializer = ActiveModel::ArraySerializer.new(
|
||||||
|
CustomWizard::Authorization.list,
|
||||||
|
each_serializer: CustomWizard::ApiListItemSerializer
|
||||||
|
)
|
||||||
|
|
||||||
|
render json: MultiJson.dump(serializer)
|
||||||
|
end
|
||||||
|
|
||||||
|
def find
|
||||||
|
params.require(:service)
|
||||||
|
render_serialized(CustomWizard::Authorization.get(params[:service]), CustomWizard::ApiSerializer, root: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def save
|
||||||
|
params.require(:service)
|
||||||
|
|
||||||
|
data = params.permit(
|
||||||
|
:service,
|
||||||
|
:auth_type,
|
||||||
|
:auth_url,
|
||||||
|
:token_url,
|
||||||
|
:client_id,
|
||||||
|
:client_secret,
|
||||||
|
:username,
|
||||||
|
:password,
|
||||||
|
:auth_params
|
||||||
|
).to_h
|
||||||
|
|
||||||
|
data[:auth_params] = JSON.parse(data[:auth_params]) if data[:auth_params]
|
||||||
|
|
||||||
|
result = CustomWizard::Authorization.set(data[:service], data.except!(:service))
|
||||||
|
|
||||||
|
render json: success_json.merge(api: CustomWizard::ApiSerializer.new(result, root: false))
|
||||||
|
end
|
||||||
|
|
||||||
|
def redirect
|
||||||
|
params.require(:service)
|
||||||
|
params.require(:code)
|
||||||
|
|
||||||
|
CustomWizard::Authorization.set(params[:service], code: params[:code])
|
||||||
|
|
||||||
|
CustomWizard::Authorization.get_token(params[:service])
|
||||||
|
|
||||||
|
return redirect_to path('/admin/wizards/apis/' + params[:service])
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,15 +0,0 @@
|
||||||
class CustomWizard::AuthorizationController < ::ApplicationController
|
|
||||||
skip_before_action :check_xhr,
|
|
||||||
:preload_json,
|
|
||||||
:redirect_to_login_if_required,
|
|
||||||
:verify_authenticity_token
|
|
||||||
|
|
||||||
def callback
|
|
||||||
|
|
||||||
params.require(:service)
|
|
||||||
params.require(:code)
|
|
||||||
|
|
||||||
CustomWizard::Authorization.set_code(service, params[:code])
|
|
||||||
CustomWizard::Authorization.get_access_token(service)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,7 +1,7 @@
|
||||||
module Jobs
|
module Jobs
|
||||||
class RefreshApiAccessToken < Jobs::Base
|
class RefreshApiAccessToken < Jobs::Base
|
||||||
def execute(args)
|
def execute(args)
|
||||||
CustomWizard::Authorization.refresh_access_token(args[:service])
|
CustomWizard::Authorization.refresh_token(args[:service])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,81 +1,59 @@
|
||||||
require 'excon'
|
require 'excon'
|
||||||
|
|
||||||
class CustomWizard::Authorization
|
class CustomWizard::Authorization
|
||||||
|
include ActiveModel::SerializerSupport
|
||||||
|
|
||||||
BASIC_AUTH = 'basic_authentication'
|
NGROK_URL = ''
|
||||||
OAUTH2_AUTH = 'OAuth2_authentication'
|
|
||||||
|
|
||||||
def self.authentication_protocol(service)
|
attr_accessor :authorized,
|
||||||
PluginStore.get(service, 'authentication_protocol') || {}
|
:service,
|
||||||
|
:auth_type,
|
||||||
|
:auth_url,
|
||||||
|
:token_url,
|
||||||
|
:client_id,
|
||||||
|
:client_secret,
|
||||||
|
:auth_params,
|
||||||
|
:access_token,
|
||||||
|
:refresh_token,
|
||||||
|
:token_expires_at,
|
||||||
|
:token_refresh_at,
|
||||||
|
:code,
|
||||||
|
:username,
|
||||||
|
:password
|
||||||
|
|
||||||
|
def initialize(service, params)
|
||||||
|
@service = service
|
||||||
|
data = params.is_a?(String) ? ::JSON.parse(params) : params
|
||||||
|
|
||||||
|
data.each do |k, v|
|
||||||
|
self.send "#{k}=", v if self.respond_to?(k)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.set_authentication_protocol(service, protocol)
|
def authorized
|
||||||
raise Discourse::InvalidParameters.new(:protocol) unless [BASIC_AUTH, OAUTH2_AUTH].include? protocol
|
@authorized ||= @access_token && @token_expires_at.to_datetime > Time.now
|
||||||
PluginStore.set(service, 'authentication_protocol', protocol)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.access_token(service)
|
def self.set(service, data)
|
||||||
PluginStore.get(service, 'access_token') || {}
|
model = self.get(service) || {}
|
||||||
|
|
||||||
|
data.each do |k, v|
|
||||||
|
model.send "#{k}=", v if model.respond_to?(k)
|
||||||
|
end
|
||||||
|
|
||||||
|
PluginStore.set("custom_wizard_#{service}", 'authorization', model.as_json)
|
||||||
|
|
||||||
|
self.get(service)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.set_access_token(service, data)
|
def self.get(service)
|
||||||
PluginStore.set(service, 'access_token', data)
|
data = PluginStore.get("custom_wizard_#{service}", 'authorization')
|
||||||
|
self.new(service, data)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.refresh_token (service)
|
def self.list
|
||||||
PluginStore.get(service, 'refresh_token')
|
PluginStoreRow.where("plugin_name LIKE 'custom_wizard_%' AND key = 'authorization'")
|
||||||
end
|
.map { |record| self.new(record['plugin_name'].split('_').last, record['value']) }
|
||||||
|
|
||||||
def self.set_refresh_token(service, token)
|
|
||||||
PluginStore.set(service, 'refresh_token', token)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.code(service)
|
|
||||||
PluginStore.get(service,'code')
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.set_code(service, code)
|
|
||||||
PluginStore.set(service, 'code', code)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.username(service)
|
|
||||||
PluginStore.get(service,'username')
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.set_username(service, username)
|
|
||||||
PluginStore.set(service, 'username', username)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.password(service)
|
|
||||||
PluginStore.get(service,'password')
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.set_password(service, password)
|
|
||||||
PluginStore.set(service, 'password', password)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.client_id(service)
|
|
||||||
PluginStore.get(service,'client_id')
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.set_client_id(service, client_id)
|
|
||||||
PluginStore.set(service, 'client_id', client_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.client_secret(service)
|
|
||||||
PluginStore.get(service,'client_secret')
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.set_client_secret(service, client_secret)
|
|
||||||
PluginStore.set(service, 'client_secret', client_secret)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.url(service)
|
|
||||||
PluginStore.get(service,'url')
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.set_url(service, url)
|
|
||||||
PluginStore.set(service, 'url', url)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.get_header_authorization_string(service)
|
def self.get_header_authorization_string(service)
|
||||||
|
@ -98,17 +76,19 @@ class CustomWizard::Authorization
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.get_access_token(service)
|
def self.get_token(service)
|
||||||
|
authorization = CustomWizard::Authorization.get(service)
|
||||||
|
|
||||||
body = {
|
body = {
|
||||||
client_id: CustomWizard::Authorization.client_id(service),
|
client_id: authorization.client_id,
|
||||||
client_secret: CustomWizard::Authorization.client_secret(service),
|
client_secret: authorization.client_secret,
|
||||||
code: CustomWizard::Authorization.code(service),
|
code: authorization.code,
|
||||||
grant_type: 'authorization_code',
|
grant_type: 'authorization_code',
|
||||||
redirect_uri: (Rails.env.development? ? CustomWizard::NGROK_URL : Discourse.base_url) + '/custom_wizard/authorization/callback'
|
redirect_uri: Discourse.base_url + "/admin/wizards/apis/#{service}/redirect"
|
||||||
}
|
}
|
||||||
|
|
||||||
result = Excon.post(
|
result = Excon.post(
|
||||||
CustomWizard::Authorization.url(service),
|
authorization.token_url,
|
||||||
:headers => {
|
:headers => {
|
||||||
"Content-Type" => "application/x-www-form-urlencoded"
|
"Content-Type" => "application/x-www-form-urlencoded"
|
||||||
},
|
},
|
||||||
|
@ -118,16 +98,18 @@ class CustomWizard::Authorization
|
||||||
self.handle_token_result(service, result)
|
self.handle_token_result(service, result)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.refresh_access_token(service)
|
def self.refresh_token(service)
|
||||||
|
authorization = CustomWizard::Authorization.get(service)
|
||||||
|
|
||||||
body = {
|
body = {
|
||||||
grant_type: 'refresh_token',
|
grant_type: 'refresh_token',
|
||||||
refresh_token: CustomWizard::Authorization.refresh_token(service)
|
refresh_token: authorization.refresh_token
|
||||||
}
|
}
|
||||||
|
|
||||||
authorization_string = CustomWizard::Authorization.client_id(service) + ':' + CustomWizard::Authorization.client_secret(service)
|
authorization_string = authorization.client_id + ':' + authorization.client_secret
|
||||||
|
|
||||||
result = Excon.post(
|
result = Excon.post(
|
||||||
CustomWizard::Authorization.url(service),
|
authorization.token_url,
|
||||||
:headers => {
|
:headers => {
|
||||||
"Content-Type" => "application/x-www-form-urlencoded",
|
"Content-Type" => "application/x-www-form-urlencoded",
|
||||||
"Authorization" => "Basic #{Base64.strict_encode64(authorization_string)}"
|
"Authorization" => "Basic #{Base64.strict_encode64(authorization_string)}"
|
||||||
|
@ -140,9 +122,11 @@ class CustomWizard::Authorization
|
||||||
|
|
||||||
def self.handle_token_result(service, result)
|
def self.handle_token_result(service, result)
|
||||||
data = JSON.parse(result.body)
|
data = JSON.parse(result.body)
|
||||||
|
|
||||||
return false if (data['error'])
|
return false if (data['error'])
|
||||||
|
|
||||||
token = data['access_token']
|
access_token = data['access_token']
|
||||||
|
refresh_token = data['refresh_token']
|
||||||
expires_at = Time.now + data['expires_in'].seconds
|
expires_at = Time.now + data['expires_in'].seconds
|
||||||
refresh_at = expires_at.to_time - 2.hours
|
refresh_at = expires_at.to_time - 2.hours
|
||||||
|
|
||||||
|
@ -152,18 +136,11 @@ class CustomWizard::Authorization
|
||||||
|
|
||||||
Jobs.enqueue_at(refresh_at, :refresh_api_access_token, opts)
|
Jobs.enqueue_at(refresh_at, :refresh_api_access_token, opts)
|
||||||
|
|
||||||
CustomWizard::Authorization.set_access_token(
|
CustomWizard::Authorization.set(service,
|
||||||
service: service,
|
access_token: access_token,
|
||||||
token: token,
|
refresh_token: refresh_token,
|
||||||
expires_at: expires_at,
|
token_expires_at: expires_at,
|
||||||
refresh_at: refresh_at
|
token_refresh_at: refresh_at
|
||||||
)
|
)
|
||||||
|
|
||||||
CustomWizard::Authorization.set_refresh_token(service, data['refresh_token'])
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.authorized(service)
|
|
||||||
CustomWizard::Authorization.access_token[service, :token] &&
|
|
||||||
CustomWizard::Authorization.access_token[service, :expires_at].to_datetime > Time.now
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
12
plugin.rb
12
plugin.rb
|
@ -49,12 +49,12 @@ after_initialize do
|
||||||
get ':wizard_id/steps' => 'wizard#index'
|
get ':wizard_id/steps' => 'wizard#index'
|
||||||
get ':wizard_id/steps/:step_id' => 'wizard#index'
|
get ':wizard_id/steps/:step_id' => 'wizard#index'
|
||||||
put ':wizard_id/steps/:step_id' => 'steps#update'
|
put ':wizard_id/steps/:step_id' => 'steps#update'
|
||||||
get 'authorization/callback' => "authorization#callback"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
require_dependency 'admin_constraint'
|
require_dependency 'admin_constraint'
|
||||||
Discourse::Application.routes.append do
|
Discourse::Application.routes.append do
|
||||||
mount ::CustomWizard::Engine, at: 'w'
|
mount ::CustomWizard::Engine, at: 'w'
|
||||||
|
post 'wizard/authorization/callback' => "custom_wizard/authorization#callback"
|
||||||
|
|
||||||
scope module: 'custom_wizard', constraints: AdminConstraint.new do
|
scope module: 'custom_wizard', constraints: AdminConstraint.new do
|
||||||
get 'admin/wizards' => 'admin#index'
|
get 'admin/wizards' => 'admin#index'
|
||||||
|
@ -67,11 +67,17 @@ after_initialize do
|
||||||
delete 'admin/wizards/custom/remove' => 'admin#remove'
|
delete 'admin/wizards/custom/remove' => 'admin#remove'
|
||||||
get 'admin/wizards/submissions' => 'admin#index'
|
get 'admin/wizards/submissions' => 'admin#index'
|
||||||
get 'admin/wizards/submissions/:wizard_id' => 'admin#submissions'
|
get 'admin/wizards/submissions/:wizard_id' => 'admin#submissions'
|
||||||
|
get 'admin/wizards/apis' => 'admin_api#list'
|
||||||
|
get 'admin/wizards/apis/new' => 'admin_api#index'
|
||||||
|
get 'admin/wizards/apis/:service' => 'admin_api#find'
|
||||||
|
put 'admin/wizards/apis/:service/save' => 'admin_api#save'
|
||||||
|
get 'admin/wizards/apis/:service/redirect' => 'admin_api#redirect'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
load File.expand_path('../jobs/clear_after_time_wizard.rb', __FILE__)
|
load File.expand_path('../jobs/clear_after_time_wizard.rb', __FILE__)
|
||||||
load File.expand_path('../jobs/set_after_time_wizard.rb', __FILE__)
|
load File.expand_path('../jobs/set_after_time_wizard.rb', __FILE__)
|
||||||
|
load File.expand_path('../jobs/refresh_api_access_token.rb', __FILE__)
|
||||||
load File.expand_path('../lib/builder.rb', __FILE__)
|
load File.expand_path('../lib/builder.rb', __FILE__)
|
||||||
load File.expand_path('../lib/field.rb', __FILE__)
|
load File.expand_path('../lib/field.rb', __FILE__)
|
||||||
load File.expand_path('../lib/step_updater.rb', __FILE__)
|
load File.expand_path('../lib/step_updater.rb', __FILE__)
|
||||||
|
@ -82,7 +88,9 @@ 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__)
|
||||||
load File.expand_path('../controllers/authorization.rb', __FILE__)
|
load File.expand_path('../controllers/admin_api.rb', __FILE__)
|
||||||
|
load File.expand_path('../serializers/api_serializer.rb', __FILE__)
|
||||||
|
load File.expand_path('../serializers/api_list_item_serializer.rb', __FILE__)
|
||||||
|
|
||||||
::UsersController.class_eval do
|
::UsersController.class_eval do
|
||||||
def wizard_path
|
def wizard_path
|
||||||
|
|
3
serializers/api_list_item_serializer.rb
Normale Datei
3
serializers/api_list_item_serializer.rb
Normale Datei
|
@ -0,0 +1,3 @@
|
||||||
|
class CustomWizard::ApiListItemSerializer < ApplicationSerializer
|
||||||
|
attributes :service
|
||||||
|
end
|
17
serializers/api_serializer.rb
Normale Datei
17
serializers/api_serializer.rb
Normale Datei
|
@ -0,0 +1,17 @@
|
||||||
|
class CustomWizard::ApiSerializer < ApplicationSerializer
|
||||||
|
attributes :service,
|
||||||
|
:auth_type,
|
||||||
|
:auth_url,
|
||||||
|
:token_url,
|
||||||
|
:client_id,
|
||||||
|
:client_secret,
|
||||||
|
:authorized,
|
||||||
|
:auth_params,
|
||||||
|
:access_token,
|
||||||
|
:refresh_token,
|
||||||
|
:token_expires_at,
|
||||||
|
:token_refresh_at,
|
||||||
|
:code,
|
||||||
|
:username,
|
||||||
|
:password
|
||||||
|
end
|
Laden …
In neuem Issue referenzieren