diff --git a/client/coral-admin/src/components/UserDetail.css b/client/coral-admin/src/components/UserDetail.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/client/coral-admin/src/components/UserDetail.js b/client/coral-admin/src/components/UserDetail.js
new file mode 100644
index 000000000..aa6997dc4
--- /dev/null
+++ b/client/coral-admin/src/components/UserDetail.js
@@ -0,0 +1,39 @@
+import React, {PropTypes} from 'react';
+import {Button, Drawer} from 'coral-ui';
+import styles from './UserDetail.js';
+
+const UserDetail = ({user}) => {
+ const localProfile = user.profiles.find(p => p.provider === 'local');
+ const facebookProfile = user.profiles.find(p => p.provider === 'facebook');
+ let profile;
+ if (localProfile) {
+ profile = profile.id;
+ } else if (facebookProfile) {
+ profile = {facebookProfile.id} ;
+ }
+
+ return (
+
+ {user.username}
+ {profile}
Copy
+ Member since {user.created_at}
+
+ Account summary
+ Data represents the last six months of activity
+
+
+
+ );
+};
+
+UserDetail.propTypes = {
+ user: PropTypes.shape({
+ username: PropTypes.string.isRequired,
+ profiles: PropTypes.arrayOf(PropTypes.shape({
+ id: PropTypes.string,
+ provider: PropTypes.string
+ }))
+ })
+};
+
+export default UserDetail;
diff --git a/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js b/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js
index eb59f369e..fac092a77 100644
--- a/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js
+++ b/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js
@@ -5,7 +5,7 @@ import key from 'keymaster';
import isEqual from 'lodash/isEqual';
import styles from './components/styles.css';
-import {modQueueQuery} from '../../graphql/queries';
+import {modQueueQuery, getUserDetail} from '../../graphql/queries';
import {banUser, setCommentStatus} from '../../graphql/mutations';
import {fetchSettings} from 'actions/settings';
@@ -19,6 +19,7 @@ import ModerationMenu from './components/ModerationMenu';
import ModerationHeader from './components/ModerationHeader';
import NotFoundAsset from './components/NotFoundAsset';
import ModerationKeysModal from '../../components/ModerationKeysModal';
+import UserDetail from '../../components/UserDetail';
class ModerationContainer extends Component {
state = {
@@ -76,6 +77,15 @@ class ModerationContainer extends Component {
}
}
+ viewUserDetail = (id) => {
+ console.log('getting user detail', id, typeof getUserDetail);
+ try {
+ getUserDetail({id});
+ } catch (e) {
+ console.log(e);
+ }
+ }
+
selectSort = (sort) => {
this.setState({sort});
this.props.modQueueResort(sort);
@@ -180,6 +190,7 @@ class ModerationContainer extends Component {
assetId={providedAssetId}
sort={this.state.sort}
commentCount={activeTabCount}
+ viewUserDetail={this.viewUserDetail}
/>
-
+ {data.user && }
);
}
diff --git a/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js b/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js
index f986b947b..093c2f5dd 100644
--- a/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js
+++ b/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js
@@ -9,7 +9,16 @@ import translations from 'coral-admin/src/translations';
import LoadMore from './components/LoadMore';
const lang = new I18n(translations);
-const ModerationQueue = ({comments, selectedIndex, commentCount, singleView, loadMore, activeTab, sort, ...props}) => {
+const ModerationQueue = ({
+ comments,
+ selectedIndex,
+ commentCount,
+ singleView,
+ loadMore,
+ activeTab,
+ sort,
+ viewUserDetail,
+ ...props}) => {
return (
@@ -26,6 +35,7 @@ const ModerationQueue = ({comments, selectedIndex, commentCount, singleView, loa
bannedWords={props.bannedWords}
actions={actionsMap[status]}
showBanUserDialog={props.showBanUserDialog}
+ viewUserDetail={viewUserDetail}
acceptComment={props.acceptComment}
rejectComment={props.rejectComment}
currentAsset={props.currentAsset}
@@ -47,6 +57,7 @@ const ModerationQueue = ({comments, selectedIndex, commentCount, singleView, loa
};
ModerationQueue.propTypes = {
+ viewUserDetail: PropTypes.func.isRequired,
bannedWords: PropTypes.arrayOf(PropTypes.string).isRequired,
suspectWords: PropTypes.arrayOf(PropTypes.string).isRequired,
currentAsset: PropTypes.object,
diff --git a/client/coral-admin/src/containers/ModerationQueue/components/Comment.js b/client/coral-admin/src/containers/ModerationQueue/components/Comment.js
index 0fdf435bd..b35c688cd 100644
--- a/client/coral-admin/src/containers/ModerationQueue/components/Comment.js
+++ b/client/coral-admin/src/containers/ModerationQueue/components/Comment.js
@@ -18,7 +18,7 @@ import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
const lang = new I18n(translations);
-const Comment = ({actions = [], comment, ...props}) => {
+const Comment = ({actions = [], comment, viewUserDetail, ...props}) => {
const links = linkify.getMatches(comment.body);
const linkText = links ? links.map(link => link.raw) : [];
const flagActionSummaries = getActionSummary('FlagActionSummary', comment);
@@ -35,7 +35,10 @@ const Comment = ({actions = [], comment, ...props}) => {
-
+ {
+ console.log('clickt', comment.user.id);
+ viewUserDetail(comment.user.id);
+ }}>
{comment.user.name}
@@ -89,6 +92,7 @@ const Comment = ({actions = [], comment, ...props}) => {
};
Comment.propTypes = {
+ viewUserDetail: PropTypes.func.isRequired,
acceptComment: PropTypes.func.isRequired,
rejectComment: PropTypes.func.isRequired,
suspectWords: PropTypes.arrayOf(PropTypes.string).isRequired,
@@ -100,8 +104,9 @@ Comment.propTypes = {
actions: PropTypes.array,
created_at: PropTypes.string.isRequired,
user: PropTypes.shape({
+ id: PropTypes.string,
status: PropTypes.string
- }),
+ }).isRequired,
asset: PropTypes.shape({
title: PropTypes.string,
id: PropTypes.string
diff --git a/client/coral-admin/src/containers/ModerationQueue/components/styles.css b/client/coral-admin/src/containers/ModerationQueue/components/styles.css
index a22fbbc64..baa098d91 100644
--- a/client/coral-admin/src/containers/ModerationQueue/components/styles.css
+++ b/client/coral-admin/src/containers/ModerationQueue/components/styles.css
@@ -423,3 +423,14 @@ span {
position: relative;
top: 7px;
}
+
+.username {
+ color: blue;
+ text-decoration: underline;
+ padding: 5px;
+ cursor: pointer;
+
+ &:hover {
+ background-color: rgba(255, 0, 0, .1);
+ }
+}
diff --git a/client/coral-admin/src/graphql/queries/index.js b/client/coral-admin/src/graphql/queries/index.js
index 9d2357ce7..aa5ffa505 100644
--- a/client/coral-admin/src/graphql/queries/index.js
+++ b/client/coral-admin/src/graphql/queries/index.js
@@ -4,6 +4,7 @@ import MOD_QUEUE_QUERY from './modQueueQuery.graphql';
import MOD_QUEUE_LOAD_MORE from './loadMore.graphql';
import MOD_USER_FLAGGED_QUERY from './modUserFlaggedQuery.graphql';
import METRICS from './metricsQuery.graphql';
+import USER_DETAIL from './userDetail.graphql';
export const modQueueQuery = graphql(MOD_QUEUE_QUERY, {
options: ({params: {id = null}}) => {
@@ -93,3 +94,17 @@ export const modQueueResort = (id, fetchMore) => (sort) => {
updateQuery: (oldData, {fetchMoreResult:{data}}) => data
});
};
+
+export const getUserDetail = ({id}) => {
+ console.log('close', id);
+ return graphql(USER_DETAIL, {
+ options: () => {
+ console.log('so close!', id);
+ return {
+ variables: {
+ id
+ }
+ };
+ }
+ });
+};
diff --git a/client/coral-admin/src/graphql/queries/userDetail.graphql b/client/coral-admin/src/graphql/queries/userDetail.graphql
new file mode 100644
index 000000000..f489e16d9
--- /dev/null
+++ b/client/coral-admin/src/graphql/queries/userDetail.graphql
@@ -0,0 +1,6 @@
+query UserDetail ($id: ID!) {
+ user(id: $id) {
+ id
+ username
+ }
+}
diff --git a/client/coral-ui/components/Drawer.css b/client/coral-ui/components/Drawer.css
new file mode 100644
index 000000000..57a44075e
--- /dev/null
+++ b/client/coral-ui/components/Drawer.css
@@ -0,0 +1,12 @@
+.wrapper {
+ transition: opacity 250ms;
+ position: fixed;
+ z-index: 10000;
+ background-color: rgba(0, 0, 0, .2);
+ height: 100%;
+ width: 100%;
+}
+
+.drawer {
+ transition: transform 500ms ease-in-out;
+}
diff --git a/client/coral-ui/components/Drawer.js b/client/coral-ui/components/Drawer.js
new file mode 100644
index 000000000..d56677d76
--- /dev/null
+++ b/client/coral-ui/components/Drawer.js
@@ -0,0 +1,17 @@
+import React, {PropTypes} from 'react';
+import styles from './Drawer.css';
+
+const Drawer = (props) => {
+ return (
+
+ );
+};
+
+Drawer.propTypes = {
+ active: PropTypes.bool
+};
+
+export default Drawer;
diff --git a/client/coral-ui/index.js b/client/coral-ui/index.js
index 148da0383..3e9456727 100644
--- a/client/coral-ui/index.js
+++ b/client/coral-ui/index.js
@@ -23,3 +23,4 @@ export {default as Select} from './components/Select';
export {default as Option} from './components/Option';
export {default as SnackBar} from './components/SnackBar';
export {default as TextArea} from './components/TextArea';
+export {default as Drawer} from './components/Drawer';
diff --git a/graph/resolvers/root_query.js b/graph/resolvers/root_query.js
index 4dcb7ea11..622584310 100644
--- a/graph/resolvers/root_query.js
+++ b/graph/resolvers/root_query.js
@@ -96,6 +96,16 @@ const RootQuery = {
return await Users.getByQuery({ids: currentUser.ignoresUsers});
},
+ // this returns an arbitrary user
+ user(_, {id}, {user, loaders: {Users}}) {
+ console.log("user id!", id);
+ if (user == null || !user.hasRoles('ADMIN')) {
+ return null;
+ }
+
+ return Users.getByID.load(id);
+ },
+
// This endpoint is used for loading the user moderation queues (users whose username has been flagged),
// so hide it in the event that we aren't an admin.
users(_, {query: {action_type, limit, cursor, sort}}, {user, loaders: {Users, Actions}}) {
diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql
index 81105ff58..4fa7a1531 100644
--- a/graph/typeDefs.graphql
+++ b/graph/typeDefs.graphql
@@ -585,6 +585,9 @@ type RootQuery {
# Users returned based on a query.
users(query: UsersQuery): [User]
+ # a single User by id
+ user(id: ID!): User
+
# Asset metrics related to user actions are saturated into the assets
# returned. Parameters `from` and `to` are related to the action created_at field.
assetMetrics(from: Date!, to: Date!, sort: ASSET_METRICS_SORT!, limit: Int = 10): [Asset!]