-
chat_bubble person
+
+
+ chat_bubble
+ person
+
{content}
;
diff --git a/client/coral-plugin-replies/ReplyBox.js b/client/coral-plugin-replies/ReplyBox.js
index c50bca124..807ad6699 100644
--- a/client/coral-plugin-replies/ReplyBox.js
+++ b/client/coral-plugin-replies/ReplyBox.js
@@ -1,21 +1,29 @@
-import React, {PropTypes} from 'react';
+import React, {Component, PropTypes} from 'react';
import CommentBox from '../coral-plugin-commentbox/CommentBox';
const name = 'coral-plugin-replies';
-const ReplyBox = ({styles, postItem, assetId, authorId, addNotification, parentId, commentPostedHandler, setActiveReplyBox}) => (
-
-
-
-);
+class ReplyBox extends Component {
+
+ componentDidMount() {
+ document.getElementById('replyText').focus();
+ }
+
+ render() {
+ const {styles, postItem, assetId, authorId, addNotification, parentId, commentPostedHandler, setActiveReplyBox} = this.props;
+ return
+
+
;
+ }
+}
ReplyBox.propTypes = {
setActiveReplyBox: PropTypes.func.isRequired,
diff --git a/client/coral-ui/components/Button.css b/client/coral-ui/components/Button.css
index 9a2611630..14ed64aa2 100644
--- a/client/coral-ui/components/Button.css
+++ b/client/coral-ui/components/Button.css
@@ -9,7 +9,7 @@
min-width: 64px;
padding: 0 8px;
display: inline-block;
- font-family: 'Roboto','Helvetica','Arial',sans-serif;
+ font-family: inherit;
font-size: 14px;
overflow: hidden;
will-change: box-shadow,transform;
diff --git a/client/coral-ui/components/Icon.js b/client/coral-ui/components/Icon.js
index 65bf52f72..11432c753 100644
--- a/client/coral-ui/components/Icon.js
+++ b/client/coral-ui/components/Icon.js
@@ -1,7 +1,7 @@
import React from 'react';
import {Icon as IconMDL} from 'react-mdl';
-const Icon = ({className, name}) => (
+const Icon = ({className = '', name}) => (
);
diff --git a/client/coral-ui/components/TextArea.css b/client/coral-ui/components/TextArea.css
new file mode 100644
index 000000000..794064cf1
--- /dev/null
+++ b/client/coral-ui/components/TextArea.css
@@ -0,0 +1,15 @@
+.textArea {
+ textarea {
+ width: 100%;
+ display: block;
+ outline: none;
+ border: 1px solid rgba(0,0,0,.12);
+ padding: 6px;
+ box-sizing: border-box;
+ border-radius: 2px;
+ margin: 5px auto;
+ min-height: 175px;
+ font-size: 14px;
+ resize: none;
+ }
+}
diff --git a/client/coral-ui/components/TextArea.js b/client/coral-ui/components/TextArea.js
new file mode 100644
index 000000000..fedc7914b
--- /dev/null
+++ b/client/coral-ui/components/TextArea.js
@@ -0,0 +1,14 @@
+import React, {PropTypes} from 'react';
+import styles from './TextArea.css';
+
+const TextArea = ({className, value = '', ...props}) => (
+
+
+
+);
+
+TextArea.propTypes = {
+ onChange: PropTypes.func,
+};
+
+export default TextArea;
diff --git a/client/coral-ui/index.js b/client/coral-ui/index.js
index b3498c3e0..148da0383 100644
--- a/client/coral-ui/index.js
+++ b/client/coral-ui/index.js
@@ -22,3 +22,4 @@ export {default as WizardNav} from './components/WizardNav';
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';
diff --git a/graph/loaders/users.js b/graph/loaders/users.js
index 90c661f71..145b0dfdb 100644
--- a/graph/loaders/users.js
+++ b/graph/loaders/users.js
@@ -3,11 +3,51 @@ const DataLoader = require('dataloader');
const util = require('./util');
const UsersService = require('../../services/users');
+const UserModel = require('../../models/user');
const genUserByIDs = (context, ids) => UsersService
.findByIdArray(ids)
.then(util.singleJoinBy(ids, 'id'));
+/**
+ * Retrieves users based on the passed in query that is filtered by the
+ * current used passed in via the context.
+ * @param {Object} context graph context
+ * @param {Object} query query terms to apply to the users query
+ */
+const getUsersByQuery = ({user}, {ids, limit, cursor, sort}) => {
+
+ let users = UserModel.find();
+
+ if (ids) {
+ users = users.find({
+ id: {
+ $in: ids
+ }
+ });
+ }
+
+ if (cursor) {
+ if (sort === 'REVERSE_CHRONOLOGICAL') {
+ users = users.where({
+ created_at: {
+ $lt: cursor
+ }
+ });
+ } else {
+ users = users.where({
+ created_at: {
+ $gt: cursor
+ }
+ });
+ }
+ }
+
+ return users
+ .sort({created_at: sort === 'REVERSE_CHRONOLOGICAL' ? -1 : 1})
+ .limit(limit);
+};
+
/**
* Creates a set of loaders based on a GraphQL context.
* @param {Object} context the context of the GraphQL request
@@ -15,6 +55,7 @@ const genUserByIDs = (context, ids) => UsersService
*/
module.exports = (context) => ({
Users: {
+ getByQuery: (query) => getUsersByQuery(context, query),
getByID: new DataLoader((ids) => genUserByIDs(context, ids))
}
});
diff --git a/graph/mutators/comment.js b/graph/mutators/comment.js
index 553c3f44c..bcab347d7 100644
--- a/graph/mutators/comment.js
+++ b/graph/mutators/comment.js
@@ -3,6 +3,7 @@ const errors = require('../../errors');
const AssetsService = require('../../services/assets');
const ActionsService = require('../../services/actions');
const CommentsService = require('../../services/comments');
+const linkify = require('linkify-it')();
const Wordlist = require('../../services/wordlist');
@@ -54,13 +55,16 @@ const createComment = ({user, loaders: {Comments}}, {body, asset_id, parent_id =
* @param {String} body body of a comment
* @return {Object} resolves to the wordlist results
*/
-const filterNewComment = (context, {body}) => {
+const filterNewComment = (context, {body, asset_id}) => {
// Create a new instance of the Wordlist.
const wl = new Wordlist();
// Load the wordlist and filter the comment content.
- return wl.load().then(() => wl.scan('body', body));
+ return Promise.all([
+ wl.load().then(() => wl.scan('body', body)),
+ AssetsService.rectifySettings(AssetsService.findById(asset_id))
+ ]);
};
/**
@@ -72,7 +76,7 @@ const filterNewComment = (context, {body}) => {
* @param {Object} [wordlist={}] the results of the wordlist scan
* @return {Promise} resolves to the comment's status
*/
-const resolveNewCommentStatus = (context, {asset_id, body}, wordlist = {}) => {
+const resolveNewCommentStatus = (context, {asset_id, body}, wordlist = {}, settings) => {
// Decide the status based on whether or not the current asset/settings
// has pre-mod enabled or not. If the comment was rejected based on the
@@ -82,6 +86,8 @@ const resolveNewCommentStatus = (context, {asset_id, body}, wordlist = {}) => {
if (wordlist.banned) {
status = Promise.resolve('REJECTED');
+ } else if (settings.premodLinksEnable && linkify.test(body)) {
+ status = Promise.resolve('PREMOD');
} else {
status = AssetsService
.rectifySettings(AssetsService.findById(asset_id).then((asset) => {
@@ -131,13 +137,13 @@ const createPublicComment = (context, commentInput) => {
// We then take the wordlist and the comment into consideration when
// considering what status to assign the new comment, and resolve the new
// status to set the comment to.
- .then((wordlist) => resolveNewCommentStatus(context, commentInput, wordlist)
+ .then(([wordlist, settings]) => resolveNewCommentStatus(context, commentInput, wordlist, settings)
// Then we actually create the comment with the new status.
.then((status) => createComment(context, commentInput, status))
.then((comment) => {
- // If the comment was flagged as being suspect, we need to add a
+ // If the comment has a suspect word or a link, we need to add a
// flag to it to indicate that it needs to be looked at.
// Otherwise just return the new comment.
diff --git a/graph/mutators/user.js b/graph/mutators/user.js
index 3f87c1fb5..6f94ae9b1 100644
--- a/graph/mutators/user.js
+++ b/graph/mutators/user.js
@@ -6,18 +6,26 @@ const setUserStatus = ({user}, {id, status}) => {
.then(res => res);
};
-module.exports = (context) => {
- if (context.user && context.user.can('mutation:setUserStatus')) {
- return {
- User: {
- setUserStatus: (action) => setUserStatus(context, action)
- }
- };
- }
+const suspendUser = ({user}, {id}) => {
+ return UsersService.suspendUser(id)
+ .then(res => res);
+};
- return {
+module.exports = (context) => {
+ let mutators = {
User: {
- setUserStatus: () => Promise.reject(errors.ErrNotAuthorized)
+ setUserStatus: () => Promise.reject(errors.ErrNotAuthorized),
+ suspendUser: () => Promise.reject(errors.ErrNotAuthorized)
}
};
+
+ if (context.user && context.user.can('mutation:setUserStatus')) {
+ mutators.User.setUserStatus = (action) => setUserStatus(context, action);
+ }
+
+ if (context.user && context.user.can('mutation:suspendUser')) {
+ mutators.User.suspendUser = (action) => suspendUser(context, action);
+ }
+
+ return mutators;
};
diff --git a/graph/resolvers/root_mutation.js b/graph/resolvers/root_mutation.js
index dc540b202..f819cc586 100644
--- a/graph/resolvers/root_mutation.js
+++ b/graph/resolvers/root_mutation.js
@@ -47,6 +47,9 @@ const RootMutation = {
setUserStatus(_, {id, status}, {mutators: {User}}) {
return wrapResponse(null)(User.setUserStatus({id, status}));
},
+ suspendUser(_, {id}, {mutators: {User}}) {
+ return wrapResponse(null)(User.suspendUser({id}));
+ },
setCommentStatus(_, {id, status}, {mutators: {Comment}}) {
return wrapResponse(null)(Comment.setCommentStatus({id, status}));
},
diff --git a/graph/resolvers/root_query.js b/graph/resolvers/root_query.js
index bdcdcef78..d577ddddb 100644
--- a/graph/resolvers/root_query.js
+++ b/graph/resolvers/root_query.js
@@ -82,6 +82,28 @@ const RootQuery = {
}
return user;
+ },
+
+ // 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}}) {
+
+ if (user == null || !user.hasRoles('ADMIN')) {
+ return null;
+ }
+
+ const query = {limit, cursor, sort};
+
+ if (action_type) {
+ return Actions.getByTypes({action_type, item_type: 'USERS'})
+ .then((ids) => {
+
+ // Perform the query using the available resolver.
+ return Users.getByQuery({ids, limit, cursor, sort});
+ });
+ }
+
+ return Users.getByQuery(query);
}
};
diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql
index daf9edafa..29000c84d 100644
--- a/graph/typeDefs.graphql
+++ b/graph/typeDefs.graphql
@@ -31,7 +31,7 @@ type User {
username: String!
# Action summaries against the user.
- action_summaries: [ActionSummary]
+ action_summaries: [FlagActionSummary]
# Actions completed on the parent.
actions: [Action]
@@ -45,6 +45,9 @@ type User {
# returns all comments based on a query.
comments(query: CommentsQuery): [Comment]
+ # returns all users based on a query.
+ users(query: UsersQuery): [User]
+
# returns user status
status: USER_STATUS
}
@@ -60,6 +63,20 @@ type Tag {
created_at: Date!
}
+# UsersQuery allows the ability to query users by a specific fields.
+input UsersQuery {
+ action_type: ACTION_TYPE
+
+ # Limit the number of results to be returned.
+ limit: Int = 10
+
+ # Skip results from the last created_at timestamp.
+ cursor: Date
+
+ # Sort the results by created_at.
+ sort: SORT_ORDER = REVERSE_CHRONOLOGICAL
+}
+
################################################################################
## Comments
################################################################################
@@ -370,6 +387,7 @@ type Settings {
infoBoxEnable: Boolean
infoBoxContent: String
+ premodLinksEnable: Boolean
questionBoxEnable: Boolean
questionBoxContent: String
closeTimeout: Int
@@ -500,6 +518,9 @@ type RootQuery {
# role.
me: User
+ # Users returned based on a query.
+ users(query: UsersQuery): [User]
+
# Asset metrics related to user actions are saturated into the assets
# returned.
assetMetrics(from: Date!, to: Date!, sort: ACTION_TYPE!, limit: Int = 10): [Asset!]
@@ -633,6 +654,14 @@ type SetUserStatusResponse implements Response {
errors: [UserError]
}
+# SuspendUserResponse is the response returned with possibly some errors
+# relating to the suspend action attempt.
+type SuspendUserResponse implements Response {
+
+ # An array of errors relating to the mutation that occurred.
+ errors: [UserError]
+}
+
# SetCommentStatusResponse is the response returned with possibly some errors
# relating to the delete action attempt.
type SetCommentStatusResponse implements Response {
@@ -645,14 +674,14 @@ type SetCommentStatusResponse implements Response {
type AddCommentTagResponse implements Response {
# An array of errors relating to the mutation that occured.
comment: Comment
- errors: [UserError]
+ errors: [UserError]
}
# Response to removeCommentTag mutation
type RemoveCommentTagResponse implements Response {
# An array of errors relating to the mutation that occured.
comment: Comment
- errors: [UserError]
+ errors: [UserError]
}
# All mutations for the application are defined on this object.
@@ -676,6 +705,9 @@ type RootMutation {
# Sets User status. Requires the `ADMIN` role.
setUserStatus(id: ID!, status: USER_STATUS!): SetUserStatusResponse
+ # Sets User status to BANNED and canEditName to true. Requires the `ADMIN` role.
+ suspendUser(id: ID!): SuspendUserResponse
+
# Sets Comment status. Requires the `ADMIN` role.
setCommentStatus(id: ID!, status: COMMENT_STATUS!): SetCommentStatusResponse
diff --git a/models/setting.js b/models/setting.js
index 993384ff1..ac54584a4 100644
--- a/models/setting.js
+++ b/models/setting.js
@@ -40,6 +40,10 @@ const SettingSchema = new Schema({
type: String,
default: ''
},
+ premodLinksEnable: {
+ type: Boolean,
+ default: false
+ },
organizationName: {
type: String
},
diff --git a/models/user.js b/models/user.js
index 2b65bd300..ea4195b8a 100644
--- a/models/user.js
+++ b/models/user.js
@@ -156,9 +156,10 @@ const USER_GRAPH_OPERATIONS = [
'mutation:deleteAction',
'mutation:editName',
'mutation:setUserStatus',
+ 'mutation:suspendUser',
'mutation:setCommentStatus',
'mutation:addCommentTag',
- 'mutation:removeCommentTag',
+ 'mutation:removeCommentTag'
];
/**
@@ -174,7 +175,7 @@ UserSchema.method('can', function(...actions) {
return false;
}
- if (actions.some((action) => action === 'mutation:setUserStatus' || action === 'mutation:setCommentStatus') && !this.hasRoles('ADMIN')) {
+ if (actions.some((action) => action === 'mutation:setUserStatus' || action === 'mutation:suspendUser' || action === 'mutation:setCommentStatus') && !this.hasRoles('ADMIN')) {
return false;
}
diff --git a/package.json b/package.json
index f67a36908..92442efd2 100644
--- a/package.json
+++ b/package.json
@@ -70,6 +70,7 @@
"inquirer": "^3.0.1",
"jsonwebtoken": "^7.1.9",
"kue": "^0.11.5",
+ "linkify-it": "^2.0.3",
"lodash": "^4.16.6",
"metascraper": "^1.0.6",
"minimist": "^1.2.0",
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100755
index 000000000..be75408cd
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/public/img/android-icon-144x144.png b/public/img/android-icon-144x144.png
new file mode 100755
index 000000000..c18ebc610
Binary files /dev/null and b/public/img/android-icon-144x144.png differ
diff --git a/public/img/android-icon-192x192.png b/public/img/android-icon-192x192.png
new file mode 100755
index 000000000..613792d40
Binary files /dev/null and b/public/img/android-icon-192x192.png differ
diff --git a/public/img/android-icon-36x36.png b/public/img/android-icon-36x36.png
new file mode 100755
index 000000000..b08960fea
Binary files /dev/null and b/public/img/android-icon-36x36.png differ
diff --git a/public/img/android-icon-48x48.png b/public/img/android-icon-48x48.png
new file mode 100755
index 000000000..3dcfcaeaf
Binary files /dev/null and b/public/img/android-icon-48x48.png differ
diff --git a/public/img/android-icon-72x72.png b/public/img/android-icon-72x72.png
new file mode 100755
index 000000000..9e3c0b654
Binary files /dev/null and b/public/img/android-icon-72x72.png differ
diff --git a/public/img/android-icon-96x96.png b/public/img/android-icon-96x96.png
new file mode 100755
index 000000000..1d7bcc163
Binary files /dev/null and b/public/img/android-icon-96x96.png differ
diff --git a/public/img/apple-icon-114x114.png b/public/img/apple-icon-114x114.png
new file mode 100755
index 000000000..1575be1ce
Binary files /dev/null and b/public/img/apple-icon-114x114.png differ
diff --git a/public/img/apple-icon-120x120.png b/public/img/apple-icon-120x120.png
new file mode 100755
index 000000000..e16fa5495
Binary files /dev/null and b/public/img/apple-icon-120x120.png differ
diff --git a/public/img/apple-icon-144x144.png b/public/img/apple-icon-144x144.png
new file mode 100755
index 000000000..c18ebc610
Binary files /dev/null and b/public/img/apple-icon-144x144.png differ
diff --git a/public/img/apple-icon-152x152.png b/public/img/apple-icon-152x152.png
new file mode 100755
index 000000000..1855b9f44
Binary files /dev/null and b/public/img/apple-icon-152x152.png differ
diff --git a/public/img/apple-icon-180x180.png b/public/img/apple-icon-180x180.png
new file mode 100755
index 000000000..677a61bba
Binary files /dev/null and b/public/img/apple-icon-180x180.png differ
diff --git a/public/img/apple-icon-57x57.png b/public/img/apple-icon-57x57.png
new file mode 100755
index 000000000..f777aa003
Binary files /dev/null and b/public/img/apple-icon-57x57.png differ
diff --git a/public/img/apple-icon-60x60.png b/public/img/apple-icon-60x60.png
new file mode 100755
index 000000000..df7ee450a
Binary files /dev/null and b/public/img/apple-icon-60x60.png differ
diff --git a/public/img/apple-icon-72x72.png b/public/img/apple-icon-72x72.png
new file mode 100755
index 000000000..9e3c0b654
Binary files /dev/null and b/public/img/apple-icon-72x72.png differ
diff --git a/public/img/apple-icon-76x76.png b/public/img/apple-icon-76x76.png
new file mode 100755
index 000000000..3cef6c189
Binary files /dev/null and b/public/img/apple-icon-76x76.png differ
diff --git a/public/img/apple-icon-precomposed.png b/public/img/apple-icon-precomposed.png
new file mode 100755
index 000000000..805d88945
Binary files /dev/null and b/public/img/apple-icon-precomposed.png differ
diff --git a/public/img/apple-icon.png b/public/img/apple-icon.png
new file mode 100755
index 000000000..805d88945
Binary files /dev/null and b/public/img/apple-icon.png differ
diff --git a/public/img/coralWordMark-color.png b/public/img/coralWordMark-color.png
new file mode 100755
index 000000000..9c9044148
Binary files /dev/null and b/public/img/coralWordMark-color.png differ
diff --git a/public/img/favicon-16x16.png b/public/img/favicon-16x16.png
new file mode 100755
index 000000000..20b075359
Binary files /dev/null and b/public/img/favicon-16x16.png differ
diff --git a/public/img/favicon-32x32.png b/public/img/favicon-32x32.png
new file mode 100755
index 000000000..ee1d75621
Binary files /dev/null and b/public/img/favicon-32x32.png differ
diff --git a/public/img/favicon-96x96.png b/public/img/favicon-96x96.png
new file mode 100755
index 000000000..1d7bcc163
Binary files /dev/null and b/public/img/favicon-96x96.png differ
diff --git a/public/img/logo_white.png b/public/img/logo_white.png
new file mode 100755
index 000000000..02b3f53f3
Binary files /dev/null and b/public/img/logo_white.png differ
diff --git a/public/img/logomark_512x512.svg b/public/img/logomark_512x512.svg
new file mode 100755
index 000000000..3c6a62250
--- /dev/null
+++ b/public/img/logomark_512x512.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/public/img/ms-icon-144x144.png b/public/img/ms-icon-144x144.png
new file mode 100755
index 000000000..c18ebc610
Binary files /dev/null and b/public/img/ms-icon-144x144.png differ
diff --git a/public/img/ms-icon-150x150.png b/public/img/ms-icon-150x150.png
new file mode 100755
index 000000000..f522f9aa7
Binary files /dev/null and b/public/img/ms-icon-150x150.png differ
diff --git a/public/img/ms-icon-310x310.png b/public/img/ms-icon-310x310.png
new file mode 100755
index 000000000..166949a37
Binary files /dev/null and b/public/img/ms-icon-310x310.png differ
diff --git a/public/img/ms-icon-70x70.png b/public/img/ms-icon-70x70.png
new file mode 100755
index 000000000..83b246409
Binary files /dev/null and b/public/img/ms-icon-70x70.png differ
diff --git a/public/img/user_portrait_placeholder.png b/public/img/user_portrait_placeholder.png
new file mode 100755
index 000000000..562891c12
Binary files /dev/null and b/public/img/user_portrait_placeholder.png differ
diff --git a/public/manifest.json b/public/manifest.json
new file mode 100755
index 000000000..97d1632d6
--- /dev/null
+++ b/public/manifest.json
@@ -0,0 +1,41 @@
+{
+ "name": "App",
+ "icons": [
+ {
+ "src": "\/img\/android-icon-36x36.png",
+ "sizes": "36x36",
+ "type": "image\/png",
+ "density": "0.75"
+ },
+ {
+ "src": "\/img\/android-icon-48x48.png",
+ "sizes": "48x48",
+ "type": "image\/png",
+ "density": "1.0"
+ },
+ {
+ "src": "\/img\/android-icon-72x72.png",
+ "sizes": "72x72",
+ "type": "image\/png",
+ "density": "1.5"
+ },
+ {
+ "src": "\/img\/android-icon-96x96.png",
+ "sizes": "96x96",
+ "type": "image\/png",
+ "density": "2.0"
+ },
+ {
+ "src": "\/img\/android-icon-144x144.png",
+ "sizes": "144x144",
+ "type": "image\/png",
+ "density": "3.0"
+ },
+ {
+ "src": "\/img\/android-icon-192x192.png",
+ "sizes": "192x192",
+ "type": "image\/png",
+ "density": "4.0"
+ }
+ ]
+}
diff --git a/routes/admin/index.js b/routes/admin/index.js
index e2473bca9..cb256327a 100644
--- a/routes/admin/index.js
+++ b/routes/admin/index.js
@@ -12,7 +12,7 @@ router.get('/password-reset', (req, res) => {
// TODO: store the redirect uri in the token or something fancy.
// admins and regular users should probably be redirected to different places.
- res.render('password-reset', {redirectUri: process.env.TALK_ROOT_URL});
+ res.render('admin/password-reset', {redirectUri: process.env.TALK_ROOT_URL});
});
router.get('*', (req, res) => {
diff --git a/services/users.js b/services/users.js
index b58776a75..90ca2fae2 100644
--- a/services/users.js
+++ b/services/users.js
@@ -378,6 +378,22 @@ module.exports = class UsersService {
});
}
+ /**
+ * Suspend a user. It changes the status to BANNED and canEditName to True.
+ * @param {String} id id of a user
+ * @param {Function} done callback after the operation is complete
+ */
+ static suspendUser(id) {
+ return UserModel.update({
+ id
+ }, {
+ $set: {
+ status: 'BANNED',
+ canEditName: true
+ }
+ });
+ }
+
/**
* Finds a user with the id.
* @param {String} id user id (uuid)
diff --git a/test/client/coral-framework/reducers/notificationReducer.spec.js b/test/client/coral-framework/reducers/notificationReducer.spec.js
deleted file mode 100644
index 40c50d11a..000000000
--- a/test/client/coral-framework/reducers/notificationReducer.spec.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import {Map} from 'immutable';
-import {expect} from 'chai';
-import notificationReducer from '../../../../client/coral-framework/reducers/notification';
-import * as actions from '../../../../client/coral-framework/actions/notification';
-
-describe ('notificationsReducer', () => {
- describe('ADD_NOTIFICATION', () => {
- it('should add a notification', () => {
- const action = {
- type: actions.ADD_NOTIFICATION,
- text: 'Test notification',
- notifType: 'test'
- };
- const store = new Map({});
- const result = notificationReducer(store, action);
- expect(result.get('text')).to.equal(action.text);
- expect(result.get('type')).to.equal(action.notifType);
- });
- });
-
- describe('CLEAR_NOTIFICATION', () => {
- it('should clear a notification', () => {
- const action = {
- type: actions.CLEAR_NOTIFICATION
- };
- const store = new Map({
- text: 'Test notification',
- type: 'test'
- });
- const result = notificationReducer(store, action);
- expect(result.get('text')).to.equal('');
- expect(result.get('type')).to.equal('');
- });
- });
-});
diff --git a/test/client/coral-framework/store/notificationReducer.spec.js b/test/client/coral-framework/store/notificationReducer.spec.js
deleted file mode 100644
index 40c50d11a..000000000
--- a/test/client/coral-framework/store/notificationReducer.spec.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import {Map} from 'immutable';
-import {expect} from 'chai';
-import notificationReducer from '../../../../client/coral-framework/reducers/notification';
-import * as actions from '../../../../client/coral-framework/actions/notification';
-
-describe ('notificationsReducer', () => {
- describe('ADD_NOTIFICATION', () => {
- it('should add a notification', () => {
- const action = {
- type: actions.ADD_NOTIFICATION,
- text: 'Test notification',
- notifType: 'test'
- };
- const store = new Map({});
- const result = notificationReducer(store, action);
- expect(result.get('text')).to.equal(action.text);
- expect(result.get('type')).to.equal(action.notifType);
- });
- });
-
- describe('CLEAR_NOTIFICATION', () => {
- it('should clear a notification', () => {
- const action = {
- type: actions.CLEAR_NOTIFICATION
- };
- const store = new Map({
- text: 'Test notification',
- type: 'test'
- });
- const result = notificationReducer(store, action);
- expect(result.get('text')).to.equal('');
- expect(result.get('type')).to.equal('');
- });
- });
-});
diff --git a/test/graph/mutations/addCommentTag.js b/test/graph/mutations/addCommentTag.js
index 14a746705..0835e81bc 100644
--- a/test/graph/mutations/addCommentTag.js
+++ b/test/graph/mutations/addCommentTag.js
@@ -54,7 +54,7 @@ describe('graph.mutations.addCommentTag', () => {
}
expect(response.errors).to.be.empty;
expect(response.data.addCommentTag.errors).to.deep.equal([{'translation_key':'NOT_AUTHORIZED'}]);
- expect(response.data.addCommentTag.comment).to.be.null;
+ expect(response.data.addCommentTag.comment).to.be.null;
});
});
});
diff --git a/views/admin.ejs b/views/admin.ejs
index 32d38734a..dafd5e3cc 100644
--- a/views/admin.ejs
+++ b/views/admin.ejs
@@ -5,6 +5,20 @@
Talk - Coral Admin
+
+
+
+
+
+
+
+
+
+
+
+
+
+