mirror of
https://github.com/ascribe/onion.git
synced 2025-01-03 10:25:08 +01:00
Merge pull request #39 from ascribe/AD-1403-api-webhooks
webhooks in settings page
This commit is contained in:
commit
a21e450a93
19
js/actions/webhook_actions.js
Normal file
19
js/actions/webhook_actions.js
Normal file
@ -0,0 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
import { alt } from '../alt';
|
||||
|
||||
|
||||
class WebhookActions {
|
||||
constructor() {
|
||||
this.generateActions(
|
||||
'fetchWebhooks',
|
||||
'successFetchWebhooks',
|
||||
'fetchWebhookEvents',
|
||||
'successFetchWebhookEvents',
|
||||
'removeWebhook',
|
||||
'successRemoveWebhook'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default alt.createActions(WebhookActions);
|
@ -11,6 +11,7 @@ import WhitelabelActions from '../../actions/whitelabel_actions';
|
||||
import AccountSettings from './account_settings';
|
||||
import BitcoinWalletSettings from './bitcoin_wallet_settings';
|
||||
import APISettings from './api_settings';
|
||||
import WebhookSettings from './webhook_settings';
|
||||
|
||||
import AclProxy from '../acl_proxy';
|
||||
|
||||
@ -70,6 +71,7 @@ let SettingsContainer = React.createClass({
|
||||
aclName="acl_view_settings_api">
|
||||
<APISettings />
|
||||
</AclProxy>
|
||||
<WebhookSettings />
|
||||
<AclProxy
|
||||
aclObject={this.state.whitelabel}
|
||||
aclName="acl_view_settings_bitcoin">
|
||||
|
165
js/components/ascribe_settings/webhook_settings.js
Normal file
165
js/components/ascribe_settings/webhook_settings.js
Normal file
@ -0,0 +1,165 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import WebhookStore from '../../stores/webhook_store';
|
||||
import WebhookActions from '../../actions/webhook_actions';
|
||||
|
||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
|
||||
import Form from '../ascribe_forms/form';
|
||||
import Property from '../ascribe_forms/property';
|
||||
|
||||
import AclProxy from '../acl_proxy';
|
||||
|
||||
import ActionPanel from '../ascribe_panel/action_panel';
|
||||
import CollapsibleParagraph from '../ascribe_collapsible/collapsible_paragraph';
|
||||
|
||||
import ApiUrls from '../../constants/api_urls';
|
||||
import AscribeSpinner from '../ascribe_spinner';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
|
||||
let WebhookSettings = React.createClass({
|
||||
propTypes: {
|
||||
defaultExpanded: React.PropTypes.bool
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return WebhookStore.getState();
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
WebhookStore.listen(this.onChange);
|
||||
WebhookActions.fetchWebhooks();
|
||||
WebhookActions.fetchWebhookEvents();
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
WebhookStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
this.setState(state);
|
||||
},
|
||||
|
||||
onRemoveWebhook(webhookId) {
|
||||
return (event) => {
|
||||
WebhookActions.removeWebhook(webhookId);
|
||||
|
||||
let notification = new GlobalNotificationModel(getLangText('Webhook deleted'), 'success', 2000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
};
|
||||
},
|
||||
|
||||
handleCreateSuccess() {
|
||||
this.refs.webhookCreateForm.reset();
|
||||
WebhookActions.fetchWebhooks(true);
|
||||
let notification = new GlobalNotificationModel(getLangText('Webhook successfully created'), 'success', 5000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
},
|
||||
|
||||
getWebhooks(){
|
||||
let content = <AscribeSpinner color='dark-blue' size='lg'/>;
|
||||
|
||||
if (this.state.webhooks) {
|
||||
content = this.state.webhooks.map(function(webhook, i) {
|
||||
const event = webhook.event.split('.')[0];
|
||||
return (
|
||||
<ActionPanel
|
||||
name={webhook.event}
|
||||
key={i}
|
||||
content={
|
||||
<div>
|
||||
<div className='ascribe-panel-title'>
|
||||
{event.toUpperCase()}
|
||||
</div>
|
||||
<div className="ascribe-panel-subtitle">
|
||||
{webhook.target}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
buttons={
|
||||
<div className="pull-right">
|
||||
<div className="pull-right">
|
||||
<button
|
||||
className="pull-right btn btn-tertiary btn-sm"
|
||||
onClick={this.onRemoveWebhook(webhook.id)}>
|
||||
{getLangText('DELETE')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}/>
|
||||
);
|
||||
}, this);
|
||||
}
|
||||
return content;
|
||||
},
|
||||
|
||||
getEvents() {
|
||||
if (this.state.webhookEvents && this.state.webhookEvents.length) {
|
||||
return (
|
||||
<Property
|
||||
name='event'
|
||||
label={getLangText('Select the event to trigger a webhook', '...')}>
|
||||
<select name="events">
|
||||
{this.state.webhookEvents.map((event, i) => {
|
||||
return (
|
||||
<option
|
||||
name={i}
|
||||
key={i}
|
||||
value={ event + '.webhook' }>
|
||||
{ event.toUpperCase() }
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
</Property>);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
|
||||
render() {
|
||||
return (
|
||||
<CollapsibleParagraph
|
||||
title={getLangText('Webhooks')}
|
||||
defaultExpanded={this.props.defaultExpanded}>
|
||||
<div>
|
||||
<p>
|
||||
Webhooks allow external services to receive notifications from ascribe.
|
||||
Currently we support webhook notifications when someone transfers, consigns, loans or shares
|
||||
(by email) a work to you.
|
||||
</p>
|
||||
<p>
|
||||
To get started, simply choose the prefered action that you want to be notified upon and supply
|
||||
a target url.
|
||||
</p>
|
||||
</div>
|
||||
<AclProxy
|
||||
show={this.state.webhookEvents && this.state.webhookEvents.length}>
|
||||
<Form
|
||||
ref="webhookCreateForm"
|
||||
url={ApiUrls.webhooks}
|
||||
handleSuccess={this.handleCreateSuccess}>
|
||||
{ this.getEvents() }
|
||||
<Property
|
||||
name='target'
|
||||
label={getLangText('Redirect Url')}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={getLangText('Enter the url to be triggered')}
|
||||
required/>
|
||||
</Property>
|
||||
<hr />
|
||||
</Form>
|
||||
</AclProxy>
|
||||
{this.getWebhooks()}
|
||||
</CollapsibleParagraph>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default WebhookSettings;
|
@ -72,6 +72,9 @@ let ApiUrls = {
|
||||
'users_username': AppConstants.apiEndpoint + 'users/username/',
|
||||
'users_profile': AppConstants.apiEndpoint + 'users/profile/',
|
||||
'wallet_settings': AppConstants.apiEndpoint + 'users/wallet_settings/',
|
||||
'webhook': AppConstants.apiEndpoint + 'webhooks/${webhook_id}/',
|
||||
'webhooks': AppConstants.apiEndpoint + 'webhooks/',
|
||||
'webhooks_events': AppConstants.apiEndpoint + 'webhooks/events/',
|
||||
'whitelabel_settings': AppConstants.apiEndpoint + 'whitelabel/settings/${subdomain}/',
|
||||
'delete_s3_file': AppConstants.serverUrl + 's3/delete/',
|
||||
'prize_list': AppConstants.apiEndpoint + 'prize/'
|
||||
|
46
js/sources/webhook_source.js
Normal file
46
js/sources/webhook_source.js
Normal file
@ -0,0 +1,46 @@
|
||||
'use strict';
|
||||
|
||||
import requests from '../utils/requests';
|
||||
|
||||
import WebhookActions from '../actions/webhook_actions';
|
||||
|
||||
|
||||
const WebhookSource = {
|
||||
lookupWebhooks: {
|
||||
remote() {
|
||||
return requests.get('webhooks');
|
||||
},
|
||||
local(state) {
|
||||
return state.webhooks && !Object.keys(state.webhooks).length ? state : {};
|
||||
},
|
||||
success: WebhookActions.successFetchWebhooks,
|
||||
error: WebhookActions.errorWebhooks,
|
||||
shouldFetch(state) {
|
||||
return state.webhookMeta.invalidateCache || state.webhooks && !Object.keys(state.webhooks).length;
|
||||
}
|
||||
},
|
||||
|
||||
lookupWebhookEvents: {
|
||||
remote() {
|
||||
return requests.get('webhooks_events');
|
||||
},
|
||||
local(state) {
|
||||
return state.webhookEvents && !Object.keys(state.webhookEvents).length ? state : {};
|
||||
},
|
||||
success: WebhookActions.successFetchWebhookEvents,
|
||||
error: WebhookActions.errorWebhookEvents,
|
||||
shouldFetch(state) {
|
||||
return state.webhookEventsMeta.invalidateCache || state.webhookEvents && !Object.keys(state.webhookEvents).length;
|
||||
}
|
||||
},
|
||||
|
||||
performRemoveWebhook: {
|
||||
remote(state) {
|
||||
return requests.delete('webhook', {'webhook_id': state.webhookMeta.idToDelete });
|
||||
},
|
||||
success: WebhookActions.successRemoveWebhook,
|
||||
error: WebhookActions.errorWebhooks
|
||||
}
|
||||
};
|
||||
|
||||
export default WebhookSource;
|
88
js/stores/webhook_store.js
Normal file
88
js/stores/webhook_store.js
Normal file
@ -0,0 +1,88 @@
|
||||
'use strict';
|
||||
|
||||
import { alt } from '../alt';
|
||||
import WebhookActions from '../actions/webhook_actions';
|
||||
|
||||
import WebhookSource from '../sources/webhook_source';
|
||||
|
||||
class WebhookStore {
|
||||
constructor() {
|
||||
this.webhooks = [];
|
||||
this.webhookEvents = [];
|
||||
this.webhookMeta = {
|
||||
invalidateCache: false,
|
||||
err: null,
|
||||
idToDelete: null
|
||||
};
|
||||
this.webhookEventsMeta = {
|
||||
invalidateCache: false,
|
||||
err: null
|
||||
};
|
||||
|
||||
this.bindActions(WebhookActions);
|
||||
this.registerAsync(WebhookSource);
|
||||
}
|
||||
|
||||
onFetchWebhooks(invalidateCache) {
|
||||
this.webhookMeta.invalidateCache = invalidateCache;
|
||||
this.getInstance().lookupWebhooks();
|
||||
}
|
||||
|
||||
onSuccessFetchWebhooks({ webhooks }) {
|
||||
this.webhookMeta.invalidateCache = false;
|
||||
this.webhookMeta.err = null;
|
||||
this.webhooks = webhooks;
|
||||
|
||||
this.webhookEventsMeta.invalidateCache = true;
|
||||
this.getInstance().lookupWebhookEvents();
|
||||
}
|
||||
|
||||
onFetchWebhookEvents(invalidateCache) {
|
||||
this.webhookEventsMeta.invalidateCache = invalidateCache;
|
||||
this.getInstance().lookupWebhookEvents();
|
||||
}
|
||||
|
||||
onSuccessFetchWebhookEvents({ events }) {
|
||||
this.webhookEventsMeta.invalidateCache = false;
|
||||
this.webhookEventsMeta.err = null;
|
||||
|
||||
// remove all events that have already been used.
|
||||
const usedEvents = this.webhooks
|
||||
.reduce((tempUsedEvents, webhook) => {
|
||||
tempUsedEvents.push(webhook.event.split('.')[0]);
|
||||
return tempUsedEvents;
|
||||
}, []);
|
||||
|
||||
this.webhookEvents = events.filter((event) => {
|
||||
return usedEvents.indexOf(event) === -1;
|
||||
});
|
||||
}
|
||||
|
||||
onRemoveWebhook(id) {
|
||||
this.webhookMeta.invalidateCache = true;
|
||||
this.webhookMeta.idToDelete = id;
|
||||
|
||||
if(!this.getInstance().isLoading()) {
|
||||
this.getInstance().performRemoveWebhook();
|
||||
}
|
||||
}
|
||||
|
||||
onSuccessRemoveWebhook() {
|
||||
this.webhookMeta.idToDelete = null;
|
||||
if(!this.getInstance().isLoading()) {
|
||||
this.getInstance().lookupWebhooks();
|
||||
}
|
||||
}
|
||||
|
||||
onErrorWebhooks(err) {
|
||||
console.logGlobal(err);
|
||||
this.webhookMeta.err = err;
|
||||
}
|
||||
|
||||
onErrorWebhookEvents(err) {
|
||||
console.logGlobal(err);
|
||||
this.webhookEventsMeta.err = err;
|
||||
}
|
||||
}
|
||||
|
||||
export default alt.createStore(WebhookStore, 'WebhookStore');
|
Loading…
Reference in New Issue
Block a user