Implemented api key deletion

This commit is contained in:
Jori Lallo
2016-08-26 22:04:28 -07:00
parent 4a1535d6c8
commit 6e39cebb08
9 changed files with 112 additions and 14 deletions

View File

@ -6,6 +6,7 @@ import { Input, ButtonOutline, InlineForm } from 'rebass';
import Layout, { Title } from 'components/Layout'; import Layout, { Title } from 'components/Layout';
import CenteredContent from 'components/CenteredContent'; import CenteredContent from 'components/CenteredContent';
import SlackAuthLink from 'components/SlackAuthLink'; import SlackAuthLink from 'components/SlackAuthLink';
import ApiKeyRow from './components/ApiKeyRow';
import styles from './Settings.scss'; import styles from './Settings.scss';
@ -65,13 +66,12 @@ class Settings extends React.Component {
{ this.store.apiKeys && ( { this.store.apiKeys && (
<table className={ styles.apiKeyTable }> <table className={ styles.apiKeyTable }>
{ this.store.apiKeys.map(key => ( { this.store.apiKeys.map(key => (
<tr> <ApiKeyRow
<td>{ key.name }</td> id={ key.id }
<td><code>{ key.secret }</code></td> name={ key.name }
{/* <td> secret={ key.secret }
<span className={ styles.deleteAction }>Delete</span> onDelete={ this.store.deleteApiKey }
</td> */} />
</tr>
)) } )) }
</table> </table>
) } ) }

View File

@ -17,9 +17,3 @@
color: #969696; color: #969696;
} }
} }
.deleteAction {
font-size: 14px;
cursor: pointer;
color: $textColor;
}

View File

@ -40,6 +40,22 @@ class SearchStore {
this.isFetching = false; this.isFetching = false;
} }
@action deleteApiKey = async (id) => {
this.isFetching = true;
try {
await client.post('/apiKeys.delete', {
id,
});
runInAction('deleteApiKey', () => {
this.fetchApiKeys();
});
} catch (e) {
console.error("Something went wrong");
}
this.isFetching = false;
}
@action setKeyName = (value) => { @action setKeyName = (value) => {
this.keyName = value.target.value; this.keyName = value.target.value;
} }

View File

@ -0,0 +1,50 @@
import React, { PropTypes } from 'react';
import styles from './ApiKeyRow.scss';
import classNames from 'classnames/bind';
const cx = classNames.bind(styles);
class ApiKeyRow extends React.Component {
static propTypes = {
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
secret: PropTypes.string.isRequired,
onDelete: PropTypes.func.isRequired,
}
state = {
disabled: false,
}
onClick = () => {
this.props.onDelete(this.props.id);
this.setState({ disabled: true });
}
render() {
const {
name,
secret,
} = this.props;
const {
disabled,
} = this.state;
return (
<tr>
<td>{ name }</td>
<td><code>{ secret }</code></td>
<td>
<span
role="button"
onClick={ this.onClick }
className={ cx(styles.deleteAction, { disabled }) }
>Delete</span>
</td>
</tr>
);
}
}
export default ApiKeyRow;

View File

@ -0,0 +1,10 @@
@import '~styles/constants.scss';
.deleteAction {
font-size: 14px;
color: $textColor;
}
.disabled {
opacity: 0.5;
}

View File

@ -0,0 +1,2 @@
import ApiKeyRow from './ApiKeyRow';
export default ApiKeyRow;

View File

@ -93,6 +93,9 @@ hr {
border-bottom-style: solid; border-bottom-style: solid;
border-bottom-color: #ccc; border-bottom-color: #ccc;
} }
*[role=button] {
cursor: pointer;
}
:global { :global {
.hljs { .hljs {

View File

@ -50,4 +50,27 @@ router.post('apiKeys.list', auth(), pagination(), async (ctx) => {
}; };
}); });
router.post('apiKeys.delete', auth(), async (ctx) => {
const {
id,
} = ctx.body;
ctx.assertPresent(id, 'id is required');
const user = ctx.state.user;
const key = await ApiKey.findById(id);
if (!key || key.userId !== user.id) throw httpErrors.BadRequest();
// Delete the actual document
try {
await key.destroy();
} catch (e) {
throw httpErrors.BadRequest('Error while deleting key');
}
ctx.body = {
success: true,
};
});
export default router; export default router;

View File

@ -232,7 +232,7 @@ router.post('documents.delete', auth(), async (ctx) => {
} }
ctx.body = { ctx.body = {
ok: true, success: true,
}; };
}); });