diff --git a/client/constants.js b/client/constants.js
index 9cb3daa4..ffe8ba61 100644
--- a/client/constants.js
+++ b/client/constants.js
@@ -19,6 +19,9 @@ export const AUTH_ERROR = 'AUTH_ERROR';
export const SETTINGS_UPDATED = 'SETTINGS_UPDATED';
+export const ADDED_API_KEY = 'ADDED_API_KEY';
+export const REMOVED_API_KEY = 'REMOVED_API_KEY';
+
export const SET_PROJECT_NAME = 'SET_PROJECT_NAME';
export const PROJECT_SAVE_SUCCESS = 'PROJECT_SAVE_SUCCESS';
diff --git a/client/modules/User/actions.js b/client/modules/User/actions.js
index 91e5f72b..53fbb68e 100644
--- a/client/modules/User/actions.js
+++ b/client/modules/User/actions.js
@@ -1,5 +1,6 @@
import { browserHistory } from 'react-router';
import axios from 'axios';
+import crypto from 'crypto';
import * as ActionTypes from '../../constants';
import { showErrorModal, justOpenedProject } from '../IDE/actions/ide';
import { showToast, setToastText } from '../IDE/actions/toast';
@@ -218,3 +219,33 @@ export function updateSettings(formValues) {
})
.catch(response => Promise.reject(new Error(response.data.error)));
}
+
+export function addApiKey(label) {
+ return ((dispatch) => {
+ crypto.randomBytes(20, (err, buf) => {
+ const key = buf.toString('hex');
+ const hashedKey = Buffer.from(key).toString('base64');
+ axios.put(`${ROOT_URL}/account/api-keys`, { label, hashedKey }, { withCredentials: true })
+ .then((response) => {
+ window.alert(`Here is your key :\n${key}\nNote it somewhere, you won't be able to see it later !`);
+ dispatch({
+ type: ActionTypes.ADDED_API_KEY,
+ user: response.data
+ });
+ })
+ .catch(response => Promise.reject(new Error(response.data.error)));
+ });
+ });
+}
+
+export function removeApiKey(keyId) {
+ return dispatch =>
+ axios.delete(`${ROOT_URL}/account/api-keys/${keyId}`, { withCredentials: true })
+ .then((response) => {
+ dispatch({
+ type: ActionTypes.REMOVED_API_KEY,
+ user: response.data
+ });
+ })
+ .catch(response => Promise.reject(new Error(response.data.error)));
+}
diff --git a/client/modules/User/components/APIKeyForm.jsx b/client/modules/User/components/APIKeyForm.jsx
index feb81135..2e85dce1 100644
--- a/client/modules/User/components/APIKeyForm.jsx
+++ b/client/modules/User/components/APIKeyForm.jsx
@@ -10,26 +10,25 @@ class APIKeyForm extends React.Component {
}
addKey(event) {
- // TODO
- console.log('addKey');
- this.props.updateSettings();
event.preventDefault();
+ document.getElementById('addKeyForm').reset();
+ this.props.addApiKey(this.state.keyLabel);
return false;
}
- removeKey(k) {
- // TODO
- console.log(k);
+ removeKey(keyId) {
+ this.props.removeApiKey(keyId);
}
render() {
return (
Key label
-
- {[{
- id: 1,
- label: 'MyFirstAPI',
- createdAt: new Date(),
- lastUsedAt: new Date()
- }, {
- id: 2,
- label: 'MyOtherAPI',
- createdAt: new Date(),
- lastUsedAt: new Date()
- }].map(v => (
+ {this.props.apiKeys && this.props.apiKeys.map(v => (
- {v.label} Created on: {v.createdAt.toLocaleDateString()} {v.createdAt.toLocaleTimeString()} |
- Last used on: {v.lastUsedAt.toLocaleDateString()} {v.lastUsedAt.toLocaleTimeString()} |
- |
+ {v.label} Created on: {v.createdAt} |
+ Last used on: {v.lastUsedAt} |
+ |
))}
@@ -65,7 +54,14 @@ class APIKeyForm extends React.Component {
}
APIKeyForm.propTypes = {
- updateSettings: PropTypes.func.isRequired,
+ addApiKey: PropTypes.func.isRequired,
+ removeApiKey: PropTypes.func.isRequired,
+ apiKeys: PropTypes.arrayOf(PropTypes.shape({
+ id: PropTypes.object.isRequired,
+ label: PropTypes.string.isRequired,
+ createdAt: PropTypes.object.isRequired,
+ lastUsedAt: PropTypes.object.isRequired,
+ })).isRequired
};
export default APIKeyForm;
diff --git a/client/modules/User/pages/AdvancedSettingsView.jsx b/client/modules/User/pages/AdvancedSettingsView.jsx
index e963e5a4..a8866bc1 100644
--- a/client/modules/User/pages/AdvancedSettingsView.jsx
+++ b/client/modules/User/pages/AdvancedSettingsView.jsx
@@ -1,22 +1,17 @@
import PropTypes from 'prop-types';
import React from 'react';
-import { reduxForm } from 'redux-form';
+import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { browserHistory } from 'react-router';
import InlineSVG from 'react-inlinesvg';
-import axios from 'axios';
import { Helmet } from 'react-helmet';
-import { updateSettings, initiateVerification } from '../actions';
-import { validateSettings } from '../../../utils/reduxFormUtils';
+import { addApiKey, removeApiKey } from '../actions';
import APIKeyForm from '../components/APIKeyForm';
const exitUrl = require('../../../images/exit.svg');
const logoUrl = require('../../../images/p5js-logo.svg');
-// TODO tmp
-const ident = () => {};
-
-class AccountView extends React.Component {
+class AdvancedSettingsView extends React.Component {
constructor(props) {
super(props);
this.closeAccountPage = this.closeAccountPage.bind(this);
@@ -51,9 +46,7 @@ class AccountView extends React.Component {
);
@@ -64,41 +57,18 @@ function mapStateToProps(state) {
return {
initialValues: state.user, // <- initialValues for reduxForm
user: state.user,
+ apiKeys: state.user.apiKeys,
previousPath: state.ide.previousPath,
theme: state.preferences.theme
};
}
function mapDispatchToProps(dispatch) {
- return bindActionCreators({ updateSettings, initiateVerification }, dispatch);
+ return bindActionCreators({ addApiKey, removeApiKey }, dispatch);
}
-function asyncValidate(formProps, dispatch, props) {
- const fieldToValidate = props.form._active;
- if (fieldToValidate) {
- const queryParams = {};
- queryParams[fieldToValidate] = formProps[fieldToValidate];
- queryParams.check_type = fieldToValidate;
- return axios.get('/api/signup/duplicate_check', { params: queryParams })
- .then((response) => {
- if (response.data.exists) {
- const error = {};
- error[fieldToValidate] = response.data.message;
- throw error;
- }
- });
- }
- return Promise.resolve(true).then(() => {});
-}
-
-AccountView.propTypes = {
+AdvancedSettingsView.propTypes = {
theme: PropTypes.string.isRequired
};
-export default reduxForm({
- form: 'updateAllSettings',
- fields: ['username', 'email', 'currentPassword', 'newPassword'],
- validate: validateSettings,
- asyncValidate,
- asyncBlurFields: ['username', 'email', 'currentPassword']
-}, mapStateToProps, mapDispatchToProps)(AccountView);
+export default connect(mapStateToProps, mapDispatchToProps)(AdvancedSettingsView);
diff --git a/client/modules/User/reducers.js b/client/modules/User/reducers.js
index 73636f2b..718e967f 100644
--- a/client/modules/User/reducers.js
+++ b/client/modules/User/reducers.js
@@ -31,6 +31,10 @@ const user = (state = { authenticated: false }, action) => {
return Object.assign({}, state, { emailVerificationTokenState: 'invalid' });
case ActionTypes.SETTINGS_UPDATED:
return { ...state, ...action.user };
+ case ActionTypes.REMOVED_API_KEY:
+ return { ...state, ...action.user };
+ case ActionTypes.ADDED_API_KEY:
+ return { ...state, ...action.user };
default:
return state;
}