Compare commits

...
926 Commits
Author SHA1 Message Date
Kim Gardner 9d25a4c14a Merge pull request #661 from coralproject/comment-stream-cleanup
Refinement of design for banned and suspend user messaging on comment stream.
2017-06-07 17:12:25 -04:00
Kim Gardner 801d0a92af Merge branch 'master' into comment-stream-cleanup 2017-06-07 17:07:39 -04:00
David Erwin 8bf86f34ee Merge pull request #654 from coralproject/off-topic-features
Off Topic Features
2017-06-07 15:43:03 -04:00
Kim Gardner 14a35033da Merge branch 'master' into comment-stream-cleanup 2017-06-07 14:33:29 -04:00
Chi Vinh Le 05da69d097 Remove falsely commited css styles 2017-06-08 01:23:22 +07:00
Chi Vinh Le ffce78ef60 Move Icon and translation service to plugin-api 2017-06-08 01:18:02 +07:00
Chi Vinh Le 6561f733b7 Use correct prefix 2017-06-08 01:17:36 +07:00
Chi Vinh Le b9758ba942 Fix overlap not clickable 2017-06-08 00:59:44 +07:00
Chi Vinh Le 4e56406c37 Fix tabsize in css 2017-06-08 00:49:18 +07:00
Chi Vinh Le 06858bf071 Move Slot and withReaction to beta 2017-06-08 00:42:21 +07:00
Chi Vinh Le 66e4f02a1a Selectors, resolving merge errors, better class names, removing comment reducer 2017-06-08 00:29:05 +07:00
IAmSamHankins c3d76c6a4f messaging style updates, and update to translation files. 2017-06-07 12:55:40 -04:00
Belen Curcio c8534a91a6 Merge branch 'off-topic-features' of github.com:coralproject/talk into off-topic-features 2017-06-07 13:53:54 -03:00
Belen Curcio 87ddfea689 indexes css 2017-06-07 13:53:33 -03:00
Belén Curcio 830441c531 Merge branch 'master' into off-topic-features 2017-06-07 13:24:58 -03:00
Riley Davis 7417d51973 Merge pull request #660 from coralproject/math-is-hard
percents have to be multiplied by 100
2017-06-07 10:22:45 -06:00
Belen Curcio 847a30ff92 Adding correct classNames 2017-06-07 13:19:36 -03:00
Riley Davis 9f4df35c3a percents have to be multiplied by 100 2017-06-07 10:15:50 -06:00
Belen Curcio f6ad9c9373 Adding camelcase for plugin reducers 🎉 <3 2017-06-07 13:14:52 -03:00
Belen Curcio 8872248d63 Addiing Stable API Architecture 2017-06-07 13:10:17 -03:00
Belen Curcio d780eea357 Merge branch 'off-topic-features' of github.com:coralproject/talk into off-topic-features 2017-06-07 12:38:31 -03:00
Belen Curcio 20aba92ad2 Linting 2017-06-07 12:37:59 -03:00
Chi Vinh Le 7a2fd95eca Merge branch 'master' into off-topic-features
Conflicts:
	client/coral-embed-stream/src/components/Comment.css
	client/coral-embed-stream/src/components/Comment.js
	client/coral-embed-stream/src/components/Stream.js
	client/coral-embed-stream/src/reducers/index.js
	client/coral-framework/helpers/plugins.js
2017-06-07 22:37:06 +07:00
Belen Curcio d7dfae89a3 Global classNames, and more 2017-06-07 12:05:53 -03:00
David Erwin fa33fe2ed2 Merge pull request #657 from coralproject/better-refetch-detection
Better refetch detection
2017-06-07 09:29:19 -04:00
Belen Curcio 456eedfd31 Clearing tags and naming convention 2017-06-07 10:04:52 -03:00
Belen Curcio 4725f07757 Viewing Options state and name conventions 2017-06-07 09:53:53 -03:00
Belen Curcio e24f6ca9f1 Renaming to commentClassNames 2017-06-07 09:28:12 -03:00
Chi Vinh Le ceb99cf205 Better refetch detection 2017-06-07 17:45:33 +07:00
Kiwi e47d3b085e Merge pull request #656 from coralproject/service-fix
Resolve facebook login issue
2017-06-07 16:57:19 +07:00
Belén Curcio 5e1fcc48e1 Merge branch 'master' into service-fix 2017-06-06 20:45:06 -03:00
Belen Curcio b5c9e92cc6 Adding streamBox slot and coral-plugin-viewing-options 🎉 2017-06-06 20:42:42 -03:00
Wyatt Johnson 71ff1c31f8 moved plugin to lazy load 2017-06-06 16:49:51 -06:00
IAmSamHankins cc76517ba8 minor copy changes in Configure tab on stream, and style updates to banned user message on stream 2017-06-06 17:37:14 -04:00
Belen Curcio 6f909c3451 Containers and Components structure 2017-06-06 18:21:03 -03:00
Belen Curcio 2202c8ae5b Fully working filter 2017-06-06 18:08:13 -03:00
Kim Gardner 6d8133b1b5 Merge pull request #655 from coralproject/move-config
move edit comment config
2017-06-06 16:57:48 -04:00
Riley Davis 2384ae4baa move edit comment config 2017-06-06 14:49:07 -06:00
Belen Curcio 1c7ad9a8ac Plugin reducers working again with reducer name 2017-06-06 17:29:56 -03:00
Belen Curcio c3360aa020 Plugin reducers working again 2017-06-06 17:23:35 -03:00
Belen Curcio 4aa7900769 Not connecting comment Component to the Store 2017-06-06 17:09:13 -03:00
Riley Davis 0dc61f33f5 Merge pull request #646 from coralproject/bulk-actions
bulk operations on User Detail comments
2017-06-06 13:26:28 -06:00
Riley Davis 8af0d929c2 Merge branch 'master' into bulk-actions 2017-06-06 13:15:04 -06:00
Riley Davis 4e19d5eecf don't have functions re-created every render 2017-06-06 13:11:31 -06:00
Riley Davis 5465563856 reload and clear selections 2017-06-06 12:52:26 -06:00
Belen Curcio b5a64bd2f9 Filter State 2017-06-06 15:45:56 -03:00
Kim Gardner b02782d532 Merge pull request #653 from coralproject/support-wss
Use wss when connection is secure
2017-06-06 14:39:35 -04:00
Chi Vinh Le 7cb05cebef Use wss when connection is secure 2017-06-07 01:32:37 +07:00
Kim Gardner 80d4ffa5bf Merge branch 'master' into bulk-actions 2017-06-06 14:13:47 -04:00
Riley Davis 9963f6d337 Merge pull request #651 from ebirving/active-tab-classnames
add semantic classname to active tab
2017-06-06 12:11:44 -06:00
Kim Gardner eff923424c Merge branch 'master' into bulk-actions 2017-06-06 14:11:16 -04:00
Erica Irving c3e32f37dc add coral- prefix as requested 2017-06-06 13:43:45 -04:00
Riley Davis 18f11a84cf Merge branch 'master' into active-tab-classnames 2017-06-06 11:14:47 -06:00
Riley Davis b0bdfff785 Merge pull request #649 from ebirving/respect-plugin-styles
add classnames to RespectButton component
2017-06-06 11:14:32 -06:00
Riley Davis dc55febac8 Merge branch 'master' into respect-plugin-styles 2017-06-06 11:09:36 -06:00
David Erwin 4d6e02228c Merge pull request #643 from coralproject/subscribe-to-comments
Subscribe to comment updates
2017-06-06 13:00:58 -04:00
Chi Vinh Le c50fe9f91d Merge branch 'master' into subscribe-to-comments
Conflicts:
	client/coral-embed-stream/src/components/Comment.js
2017-06-06 23:44:27 +07:00
Riley Davis 7d5a73bc95 Merge branch 'master' into respect-plugin-styles 2017-06-06 10:40:33 -06:00
Riley Davis 5f3220dba9 Merge pull request #652 from coralproject/css-override-classes
Css override classes + tab bugfix
2017-06-06 10:40:21 -06:00
Kim Gardner 700ab38cb0 Merge branch 'master' into css-override-classes 2017-06-06 12:34:13 -04:00
Riley Davis 6fcd003e76 remove console.log 2017-06-06 10:32:14 -06:00
Kiwi 0069d17672 Merge branch 'master' into subscribe-to-comments 2017-06-06 23:19:22 +07:00
Chi Vinh Le afdcdff51e Handle ignored user case 2017-06-06 23:18:37 +07:00
Erica Irving 3d8478dfb2 add semantic classname to active tab 2017-06-06 12:17:32 -04:00
Kim Gardner 71d2f44d38 Merge pull request #650 from coralproject/copy-updates
Copy changes
2017-06-06 12:07:40 -04:00
Kim Gardner 124ea19b52 Update en.yml 2017-06-06 12:03:12 -04:00
Erica Irving 512a463589 add classnames to RespectButton component 2017-06-06 11:28:28 -04:00
Belen Curcio e9cb61a534 Arrow for filtering 2017-06-06 12:13:26 -03:00
Belen Curcio a6db60096c Fully working, needs docs 2017-06-06 11:58:51 -03:00
Belen Curcio 9364272ffc Ádd classnames based on tags 2017-06-06 11:53:19 -03:00
Chi Vinh Le 1ceb72ca5c Fix error with tombstones 2017-06-06 21:26:43 +07:00
Belen Curcio 9e001f5ce9 addClassNames, removeClassNames, reducers and actions for Comment Component 2017-06-06 11:15:35 -03:00
Chi Vinh Le 0fcdd09f9f Lazily create apollo client 2017-06-06 20:50:07 +07:00
Belen Curcio 3ad3b3af1c Adding filters 2017-06-06 09:43:34 -03:00
Chi Vinh Le d3f7e6210c Simplify transition code 2017-06-06 19:06:42 +07:00
Chi Vinh Le 447ec7e524 Deeply pass commentIsIgnored 2017-06-06 19:05:18 +07:00
Chi Vinh Le f8ca14d3d3 Reset stream after refetching 2017-06-06 18:45:45 +07:00
Belen Curcio 5faa92e8b3 Label style, top level comments, no offtopic replies 2017-06-06 08:09:34 -03:00
Kim Gardner 17783c91c4 Merge branch 'master' into bulk-actions 2017-06-05 23:06:03 -04:00
Riley Davis ad4c4a0a5b fix for active tab not showing. user box classNames 2017-06-05 16:46:58 -06:00
Wyatt Johnson 7956c193c5 Merge branch 'master' into subscribe-to-comments 2017-06-05 16:38:28 -06:00
Wyatt Johnson 2aa3b7a5a0 Merge pull request #641 from coralproject/safari-cookie-time
Use same lifespan for cookies as for tokens
2017-06-05 16:38:13 -06:00
Wyatt Johnson 2f77842072 Merge branch 'master' into safari-cookie-time 2017-06-05 16:32:29 -06:00
Wyatt Johnson a595e94394 Removed parse-duration in favour of ms 2017-06-05 16:31:06 -06:00
riley d03647067d Merge branch 'master' into css-override-classes 2017-06-05 16:19:46 -06:00
Riley Davis fb537c9990 Merge pull request #648 from coralproject/StephanieDClark-master
Stephanie's changes to add classNames to Tab and TabBar
2017-06-05 16:18:19 -06:00
Riley Davis 8ea7ba9b69 Merge branch 'master' into css-override-classes 2017-06-05 16:13:45 -06:00
David Erwin 15297cd674 Update css naming convention 2017-06-05 18:12:38 -04:00
Riley Davis e46802910c Merge branch 'master' into StephanieDClark-master 2017-06-05 16:09:12 -06:00
riley 19b90910ba better tab classNames 2017-06-05 16:08:53 -06:00
David Erwin 291cee3af4 Merge pull request #647 from coralproject/auth-token-hooks
Added new tokenUserNotFound plugin hook
2017-06-05 18:05:56 -04:00
Wyatt Johnson 069c4c5e50 Merge branch 'master' into auth-token-hooks 2017-06-05 16:00:23 -06:00
Riley Davis 7d54fb60a8 use existing className attr instead of custom property 2017-06-05 15:57:34 -06:00
Wyatt Johnson e8143aea14 Added new tokenUserNotFound plugin hook 2017-06-05 15:52:32 -06:00
StephanieDClark 9e1d010db3 Adjusting tab classes 2017-06-05 14:48:50 -07:00
David Erwin 728d523b9e Begin adding css override classes 2017-06-05 17:25:27 -04:00
StephanieDClark 5838f5d486 fix lint errors 2017-06-05 14:00:21 -07:00
Riley Davis 1c8e1cc46c Merge branch 'master' into bulk-actions 2017-06-05 14:42:07 -06:00
Riley Davis c4a41af33b clear selected ids when panel is closed 2017-06-05 14:40:03 -06:00
StephanieDClark 5e463c00fd Merge branch 'master' into master 2017-06-05 13:35:36 -07:00
Kim Gardner 933a9371f3 Merge branch 'master' into safari-cookie-time 2017-06-05 16:35:23 -04:00
Kim Gardner 0be77fa5fd Merge pull request #645 from coralproject/fix-typos
Fix typos
2017-06-05 16:28:08 -04:00
Kim Gardner 49eecaa65b Fix typos 2017-06-05 16:22:17 -04:00
Riley Davis 39d8a5d01b bulk operations on User Detail comments 2017-06-05 14:20:34 -06:00
StephanieDClark 414e5d78bd Fix yarn lint error 2017-06-05 12:58:04 -07:00
Kiwi e9a6c3dfe3 Merge branch 'master' into subscribe-to-comments 2017-06-06 02:42:35 +07:00
StephanieDClark 3b7603ee31 add supplied classes to tabbar 2017-06-05 12:39:35 -07:00
StephanieDClark 8c89296007 add supplied classes to tab 2017-06-05 12:38:36 -07:00
StephanieDClark 32fe291847 Add classes to tabbar, tab 2017-06-05 12:37:13 -07:00
Chi Vinh Le 056ddc7010 Meaningful comment 2017-06-06 02:25:42 +07:00
Chi Vinh Le 2d0eec15c1 Readd falsely deleted part 2017-06-06 02:25:32 +07:00
Chi Vinh Le 2be73d1df2 Unsubscribe on unmount 2017-06-06 02:10:56 +07:00
Chi Vinh Le 3ad17f008f Refactor fetchMore updaters 2017-06-06 01:44:17 +07:00
David Erwin 547547d04c Merge pull request #638 from coralproject/auth-token-via-config
Use config auth_token if present on http headers
2017-06-05 14:22:48 -04:00
David Erwin 90d7e3706c Improve auth token logic. 2017-06-05 13:58:13 -04:00
Chi Vinh Le 9993350b7e Animate flash for new comments 2017-06-06 00:54:12 +07:00
David Erwin 7c66d846c2 Add auth token comment 2017-06-05 13:38:06 -04:00
Chi Vinh Le 6b0cdae183 Subscribe to comments 2017-06-05 20:51:08 +07:00
Chi Vinh Le c20df65ebc Use same lifespan for cookies as for tokens 2017-06-05 18:21:40 +07:00
Kiwi 7efdccb683 Merge branch 'master' into auth-token-via-config 2017-06-05 17:57:13 +07:00
Chi Vinh Le a9796d47cd Check login after loading config 2017-06-05 17:51:06 +07:00
Chi Vinh Le 7c145bbb3c Refactor import order and framework initialization 2017-06-05 17:49:43 +07:00
Chi Vinh Le ac9e70bc67 Add same getAuthToken logic to apollo transport 2017-06-05 17:48:09 +07:00
Chi Vinh Le defd28b20f Remove double login checks 2017-06-05 17:46:57 +07:00
Chi Vinh Le b05b54a991 Add auth_token default config 2017-06-05 17:46:30 +07:00
Kim Gardner 3c96b7eb1e Merge pull request #640 from coralproject/user-comment-history
user detail design pass
2017-06-02 17:27:13 -04:00
Kim Gardner 6e483842f1 Merge branch 'master' into user-comment-history 2017-06-02 17:22:48 -04:00
Kim Gardner 0276c00828 Merge pull request #639 from coralproject/key-trans-missing
Key translation missing
2017-06-02 17:08:48 -04:00
gaba c6efc586ae Merge branch 'master' into key-trans-missing 2017-06-02 14:03:33 -07:00
gaba 6de9c69668 Missing key translation. 2017-06-02 14:02:45 -07:00
Kim Gardner 396abaae22 Merge pull request #637 from coralproject/i18n-emails
I18n emails
2017-06-02 16:59:32 -04:00
gaba e98b9ff9bc Some translations missing and a folder that should not be there. 2017-06-02 13:50:48 -07:00
Gabriela Rodríguez Berón cbf83206b8 Merge branch 'master' into i18n-emails 2017-06-02 13:35:09 -07:00
Kim Gardner 664ace170b Merge pull request #618 from coralproject/user-comment-history
show comments on the UserDetail drawer
2017-06-02 16:10:22 -04:00
Kim Gardner bd60eca6f9 Merge branch 'master' into user-comment-history 2017-06-02 15:58:54 -04:00
Riley Davis e097b8eb21 design pass 2017-06-02 13:50:00 -06:00
Kim Gardner 058cab970b Merge pull request #636 from coralproject/story-146187883
UX Updates
2017-06-02 15:25:40 -04:00
Riley Davis 22c2843ae5 remove moderate link per designs 2017-06-02 13:12:59 -06:00
Riley Davis d8cb560755 add a tab for All/Rejected user detail comments 2017-06-02 13:02:22 -06:00
David Erwin ea3d8e141d Use config auth_token if present on http headers 2017-06-02 14:22:06 -04:00
gaba cf50a0e85c Translations missing. 2017-06-02 08:30:36 -07:00
gaba b9b62e5764 Use accepts library. 2017-06-02 08:24:21 -07:00
gaba eadbb03c15 Fix typo. 2017-06-02 06:54:01 -07:00
gaba b6dbb5975f Adds missing translations. 2017-06-01 17:26:49 -07:00
gaba fd1cf8121e Move start to the left. 2017-06-01 17:21:55 -07:00
gaba dcbd0fc167 Change signed in for logged in. 2017-06-01 17:13:55 -07:00
gaba 44d82f8b13 Merge branch 'master' into i18n-emails 2017-06-01 16:26:44 -07:00
gaba 27e6372fe2 Get language from the header. 2017-06-01 16:24:15 -07:00
gaba 686dc96c5f An attempt to guess language. In process. 2017-06-01 15:44:44 -07:00
Riley Davis 8d25b766ff Merge branch 'master' into user-comment-history 2017-06-01 15:47:54 -06:00
Riley Davis 555d54425a implement kiwi's pagination changes 2017-06-01 15:34:05 -06:00
Kim Gardner f3f7fad68f Merge pull request #635 from StephanieDClark/master
Add isReply to commentInputDetailArea api
2017-06-01 14:38:36 -04:00
Riley Davis 9483922781 Merge branch 'master' into master 2017-06-01 12:31:48 -06:00
Kim Gardner 91d415b434 Merge pull request #632 from coralproject/losowsky-patch-2
Updated description
2017-06-01 14:25:55 -04:00
Kim Gardner 1943b38544 Merge branch 'master' into losowsky-patch-2 2017-06-01 14:20:45 -04:00
Kim Gardner 9344490514 Merge pull request #631 from coralproject/losowsky-patch-1
Added iPhone 7
2017-06-01 14:20:28 -04:00
StephanieDClark 1bf2053cb8 Add isReply to commentInputDetailArea api 2017-06-01 11:01:57 -07:00
Andrew Losowsky 9fe7b961ca Updated description
Added mention of Plugins
2017-06-01 13:43:30 -04:00
Andrew Losowsky ac0db69c27 Added iPhone 7
What about the Android devices? It says Galaxy S5 but that's up to S7, same with Nexus.
2017-06-01 13:41:08 -04:00
Riley Davis d981b5a85b Merge branch 'master' into user-comment-history 2017-06-01 10:52:24 -06:00
Kim Gardner 1fe6c79d88 Merge pull request #627 from coralproject/bump-version-1-8-0
Bump version in prep for 1.8.0 release
2017-06-01 12:42:31 -04:00
Kim Gardner 8b3c1b275d Merge branch 'master' into bump-version-1-8-0 2017-06-01 12:24:34 -04:00
Kim Gardner c76e71ce31 Merge pull request #629 from coralproject/dec-inc-total-comment-count
Increase/Decrease totalCommentCount after mutation
2017-06-01 11:59:11 -04:00
Kim Gardner b8015506df Merge branch 'master' into dec-inc-total-comment-count 2017-06-01 11:54:49 -04:00
Kim Gardner 06e6730f04 Merge pull request #628 from coralproject/fix-translation-comment-count
Fix translation bug in CommentCount
2017-06-01 11:54:01 -04:00
Chi Vinh Le fa08450185 Increase/Decrease totalCommentCount after mutation 2017-06-01 22:39:05 +07:00
Chi Vinh Le d9acbbad96 Fix translation bug in CommentCount 2017-06-01 22:37:25 +07:00
David Erwin 4951527883 Merge pull request #626 from coralproject/pagination-refactor
Pagination refactor
2017-06-01 10:24:26 -04:00
Chi Vinh Le 33eff78a64 Always request comment id 2017-06-01 19:49:53 +07:00
Chi Vinh Le 5245755d49 Add some comments 2017-06-01 19:41:08 +07:00
Chi Vinh Le ebdd586d1e Fix mutation funkiness on permlink view 2017-06-01 18:47:07 +07:00
Chi Vinh Le 9a2b6b3ae1 Merge branch 'master' into pagination-refactor 2017-06-01 17:15:42 +07:00
gaba 276b2c7591 Merge branch 'master' into i18n-emails 2017-05-31 15:31:14 -07:00
gaba a126c94aa4 Adds service for translations in the backend. Clean yaml. 2017-05-31 13:55:27 -07:00
Kim Gardner 9bd75a5670 Bump version in prep for 1.8.0 release 2017-05-31 16:55:14 -04:00
Riley Davis 576cbed8e9 no more errors 2017-05-31 13:44:38 -06:00
Kim Gardner 4ce0431fba Merge pull request #623 from coralproject/add-trust-to-readme
Add trust to readme
2017-05-31 15:43:50 -04:00
Kim Gardner 93d8e0015b Remove space 2017-05-31 15:29:51 -04:00
Kim Gardner ac8e723e75 Copy changes 2017-05-31 15:29:50 -04:00
Kim Gardner c172260d74 Fix link 2017-05-31 15:29:49 -04:00
Kim Gardner 2a3941552d Update README with Trust info 2017-05-31 15:29:41 -04:00
Kim Gardner bf15354aa2 Merge branch 'master' into user-comment-history 2017-05-31 15:17:00 -04:00
Kim Gardner dd9e3247d2 Merge pull request #622 from coralproject/hide-comment-box-perm
Hide comment box during perm view
2017-05-31 15:12:41 -04:00
Chi Vinh Le b402f70f38 Hide comment box during perm view 2017-06-01 01:34:32 +07:00
Chi Vinh Le 30d4562383 Refactor pagination 2017-06-01 01:18:41 +07:00
riley 6e458e0149 resolve missing files 2017-05-31 10:54:34 -06:00
Riley Davis 259ce9c9fb merge master 2017-05-31 10:36:01 -06:00
Kim Gardner 93be1a91be Merge pull request #608 from coralproject/integrate-admin-graphql-framework
Integrate admin into GraphQL framework
2017-05-30 18:04:10 -04:00
Riley Davis 6599ed2b4c Merge branch 'master' into user-comment-history 2017-05-30 15:53:36 -06:00
Riley Davis 29753a958b show comments on the UserDetail drawer 2017-05-30 15:50:56 -06:00
Chi Vinh Le 109f4b2c0f Handle mutation errors 2017-05-31 00:44:16 +07:00
Kiwi 4f8ef88bd0 Merge branch 'master' into integrate-admin-graphql-framework 2017-05-31 00:24:06 +07:00
Kiwi 3160f6ae9e Merge pull request #604 from coralproject/graphql-errors-handling
Support response errors in the graphql framework
2017-05-31 00:21:14 +07:00
Kiwi 15a11dca4d Merge branch 'master' into graphql-errors-handling 2017-05-30 20:48:58 +07:00
Kiwi d28ba0028d Merge branch 'master' into integrate-admin-graphql-framework 2017-05-30 20:48:53 +07:00
Kiwi f42dd884c0 Merge pull request #617 from coralproject/forget-password-ports
Allow domains with ports
2017-05-30 20:48:42 +07:00
Kiwi 4a0785f6fe Merge branch 'master' into graphql-errors-handling 2017-05-30 20:18:32 +07:00
Kiwi 336e0373cd Merge branch 'master' into integrate-admin-graphql-framework 2017-05-30 20:16:09 +07:00
David Erwin bbed3e2a7f Merge branch 'master' into forget-password-ports 2017-05-30 08:56:07 -04:00
David Erwin c894e8eb1d Merge pull request #616 from coralproject/fix-redirect-uri
Use correct redirect url
2017-05-30 08:55:44 -04:00
Chi Vinh Le 68f6c8acb6 No shared store between popup and embed 2017-05-30 01:08:45 +07:00
Chi Vinh Le 1acf58182f Merge branch 'master' into integrate-admin-graphql-framework
Conflicts:
	client/coral-admin/src/containers/Community/Loading.js
	client/coral-admin/src/containers/Community/Table.js
	client/coral-admin/src/containers/Streams/Stories.js
	client/coral-admin/src/index.js
	client/coral-admin/src/routes/Community/components/FlaggedAccounts.js
	client/coral-admin/src/routes/Community/components/People.js
	client/coral-admin/src/routes/Configure/components/Configure.js
	client/coral-admin/src/routes/Configure/components/Domainlist.js
	client/coral-admin/src/routes/Configure/components/EmbedLink.js
	client/coral-admin/src/routes/Configure/components/ModerationSettings.js
	client/coral-admin/src/routes/Configure/components/StreamSettings.js
	client/coral-admin/src/routes/Configure/components/TechSettings.js
	client/coral-admin/src/routes/Configure/components/Wordlist.js
	client/coral-admin/src/routes/Dashboard/components/CountdownTimer.js
	client/coral-admin/src/routes/Install/components/Steps/AddOrganizationName.js
	client/coral-admin/src/routes/Install/components/Steps/CreateYourAccount.js
	client/coral-admin/src/routes/Install/components/Steps/FinalStep.js
	client/coral-admin/src/routes/Install/components/Steps/InitialStep.js
	client/coral-admin/src/routes/Install/components/Steps/PermittedDomainsStep.js
	client/coral-admin/src/routes/Install/components/translations.json
	client/coral-admin/src/routes/Moderation/components/Moderation.js
	client/coral-admin/src/routes/Moderation/components/ModerationQueue.js
	client/coral-admin/src/routes/Stories/components/Stories.js
	client/coral-embed-stream/src/index.js
2017-05-29 23:06:40 +07:00
Chi Vinh Le 04ef1c5be5 Use new translation service 2017-05-29 22:45:56 +07:00
Chi Vinh Le a598bca12b Allow domains with ports 2017-05-29 22:10:16 +07:00
Kiwi 810f337d8d Merge branch 'master' into fix-redirect-uri 2017-05-29 22:06:33 +07:00
Kiwi c314054143 Merge branch 'master' into graphql-errors-handling 2017-05-29 22:00:49 +07:00
Chi Vinh Le bd5e272f00 Use correct redirect url 2017-05-29 22:00:27 +07:00
Kiwi bdbc7c5ff2 Merge pull request #586 from coralproject/i18n-refactor
Refactor i18n
2017-05-29 21:59:52 +07:00
Chi Vinh Le 2d398fe452 Change not authorized error message 2017-05-29 20:36:21 +07:00
Chi Vinh Le 0b7432b75e Merge branch 'master' into i18n-refactor
Conflicts:
	client/coral-sign-in/components/FakeComment.js
	client/coral-sign-in/components/UserBox.js
2017-05-29 20:23:27 +07:00
Chi Vinh Le 9a6532ecea Merge branch 'master' into integrate-admin-graphql-framework
Conflicts:
	client/coral-embed-stream/src/index.js
2017-05-29 20:09:03 +07:00
Kiwi f3f6633e99 Merge branch 'master' into graphql-errors-handling 2017-05-29 19:42:26 +07:00
David Erwin 93f8a81678 Merge pull request #607 from coralproject/unified-docs
Unified docs
2017-05-27 09:59:08 -04:00
Kim Gardner b13d3adce0 Merge branch 'master' into unified-docs 2017-05-26 17:00:53 -04:00
Kim Gardner d213a4a26e Merge pull request #613 from coralproject/minor-stream-style-changes
Stream and mod queue style fixes
2017-05-26 17:00:09 -04:00
Kim Gardner 82d442d95b Merge branch 'master' into minor-stream-style-changes 2017-05-26 16:53:55 -04:00
Kim Gardner 1dcd254519 Merge branch 'master' into unified-docs 2017-05-26 16:53:36 -04:00
Kim Gardner 37262ad9f6 Merge branch 'master' into graphql-errors-handling 2017-05-26 16:53:13 -04:00
Kim Gardner e6c40a5839 Merge pull request #615 from coralproject/require-email-info
Display require email verification info
2017-05-26 16:24:06 -04:00
Chi Vinh Le 681e07306b Require email verification info 2017-05-27 03:13:00 +07:00
Kim Gardner 794af5a670 Merge pull request #611 from coralproject/auth-flow
FE Auth Flow and fix for Safari token workaround
2017-05-26 16:06:32 -04:00
Chi Vinh Le 81e8a593b3 Merge branch 'auth-flow' of ssh://github.com/coralproject/talk into auth-flow 2017-05-27 02:51:56 +07:00
Chi Vinh Le 89cb4c4502 Resolve infinite loop 2017-05-27 02:45:59 +07:00
Kim Gardner e9c8876a8f Merge branch 'master' into auth-flow 2017-05-26 15:44:12 -04:00
Kim Gardner e68124a426 Merge pull request #614 from coralproject/update-core-plugins
Update default plugins that ship with Coral core
2017-05-26 15:43:27 -04:00
Chi Vinh Le 8713a2ae87 Enable Linting 2017-05-27 02:08:54 +07:00
Kim Gardner 54e7956af5 Update default plugins that ship with Coral core 2017-05-26 15:08:47 -04:00
Chi Vinh Le ee2068f5f1 Merge branch 'master' into auth-flow
Conflicts:
	client/coral-admin/src/actions/auth.js
2017-05-27 01:07:19 +07:00
Chi Vinh Le 52b3dcab43 Fix changing username not updating 2017-05-27 01:05:12 +07:00
Chi Vinh Le a7cdcb0bf7 Fix request options and use better filename 2017-05-27 00:54:36 +07:00
Chi Vinh Le 99a9154d40 Remove unused dependency 2017-05-27 00:26:04 +07:00
IAmSamHankins 05e5200e79 moderation panel design cleanup PT 144120491 2017-05-26 12:48:15 -04:00
Kim Gardner 3b96d08b58 Merge pull request #612 from coralproject/losowsky-patch-1
added iphone 7 support in the list
2017-05-26 12:46:38 -04:00
Andrew Losowsky 82c5d140be added iphone 7 support in the list 2017-05-26 12:30:26 -04:00
David Erwin 69a9afe084 Remove old docs 2017-05-26 11:40:56 -04:00
David Erwin 1d3a75e425 Update doc menu title 2017-05-26 11:39:24 -04:00
David Erwin 5f83584e48 Update tooling and client architecture docs 2017-05-26 11:37:33 -04:00
David Erwin 1dbecab13e Add swagger user docs and tools page 2017-05-26 11:27:10 -04:00
David Erwin deea24d0c5 Add docs to .eslintignore 2017-05-26 11:12:16 -04:00
David Erwin ce46329e27 Create FAQ page 2017-05-26 11:07:10 -04:00
Chi Vinh Le 7b6b46f3e5 Sync username with store 2017-05-26 21:38:29 +07:00
Chi Vinh Le d4569b5f51 Set cookie for facebook login on safari 2017-05-26 21:37:11 +07:00
Chi Vinh Le 6a9f216c0f Detect mobile & desktop safari server side 2017-05-26 20:58:48 +07:00
Chi Vinh Le 6a1befc3f0 Detect mobile safari & desktop safari 2017-05-26 20:48:24 +07:00
Chi Vinh Le bab47c9d44 Separate store 2017-05-26 20:37:06 +07:00
Chi Vinh Le 276e58060a Fix change username dialog 2017-05-26 20:36:56 +07:00
Belen Curcio 8edc16ed85 Removing logs 2017-05-25 20:06:49 -03:00
Belen Curcio 8171cb53e1 Ádding another extractor 2017-05-25 20:04:32 -03:00
Belen Curcio cbf7cc67f4 Extracting token from cookie if safari 2017-05-25 18:30:01 -03:00
IAmSamHankins 32715d3903 initial style updates on comment stream for PT 142803055 ~ copy translations still needed 2017-05-25 17:21:32 -04:00
Kim Gardner d742d713cf Merge pull request #610 from coralproject/bump-version-1-7-0
Update version 1.7.0
2017-05-25 17:05:20 -04:00
Kim Gardner 178cecad05 Update version 1.7.0 2017-05-25 16:58:35 -04:00
Belen Curcio 460f3f292b Ádding dependencies 2017-05-25 17:41:35 -03:00
Belén Curcio 5285c84de3 Merge pull request #603 from coralproject/coral-plugin-auth
Coral plugin Auth
2017-05-25 17:09:29 -03:00
Chi Vinh Le a39fcee3f8 More error handling fixes 2017-05-26 03:04:06 +07:00
Chi Vinh Le 841735b787 Restore error functionality 2017-05-26 02:55:09 +07:00
Belen Curcio a8c361e2f7 by hostname 2017-05-25 16:53:12 -03:00
Belen Curcio 21644bda8a Linting 2017-05-25 16:24:39 -03:00
Belen Curcio 75080cfe30 Password reset and valid locations 2017-05-25 16:19:19 -03:00
David Erwin f5bd2a9db3 Update top nav 2017-05-25 15:17:50 -04:00
Chi Vinh Le 209005aff5 More key misspellings 2017-05-26 02:10:00 +07:00
Chi Vinh Le 0107aa67cd Correct keys and translations 2017-05-26 01:59:34 +07:00
gaba 77bfd55af3 Merge branch 'i18n-refactor' into i18n-emails 2017-05-25 14:35:49 -04:00
gaba 96985b4780 More strings. 2017-05-25 14:05:17 -04:00
Belen Curcio e510553d9a Sending cookies if safari 2017-05-25 13:55:03 -03:00
gaba 492f4a674c OMG. Strings. 2017-05-25 12:02:26 -04:00
Chi Vinh Le 4fe89257c2 Support store in withMutation 2017-05-25 22:19:16 +07:00
Belen Curcio bb6be9a734 BE implementation 2017-05-25 11:53:40 -03:00
gaba 09bd0a6735 Move templates to a folder for translations. 2017-05-25 10:43:34 -04:00
Chi Vinh Le 246ca117be Little cleanup for admin services 2017-05-25 19:22:59 +07:00
Chi Vinh Le 93e6c0af32 Use default response fragments 2 2017-05-25 18:57:42 +07:00
Chi Vinh Le b43a0f533b Harmonize naming in admin and embed-stream 2017-05-25 18:37:23 +07:00
Chi Vinh Le 512767e023 Use default response fragments 2017-05-25 17:49:30 +07:00
David Erwin 69b19d2c91 Jekyll Initial Commit 2017-05-24 16:48:00 -04:00
Belen Curcio bd21719ea5 Handling non safari browsers 2017-05-24 17:20:23 -03:00
gaba 4ff7da864e Still more strings. 2017-05-24 14:54:52 -04:00
Chi Vinh Le 48a8e394ef Use framework for mutations 2017-05-25 01:18:33 +07:00
Chi Vinh Le d9ee215d66 Remove obsolete fragment 2017-05-24 23:22:03 +07:00
gaba 846ac50b19 Clean out the spanish one. 2017-05-24 11:59:22 -04:00
gaba 03f70bcab9 Adds more missing translation. 2017-05-24 11:59:21 -04:00
Chi Vinh Le a3755b7505 Use unique names 2017-05-24 22:24:01 +07:00
Chi Vinh Le 5e2fa72466 Support extendable queries 2017-05-24 22:05:41 +07:00
Chi Vinh Le a9b4de1f5c Wrap queries with hocs 2017-05-24 21:00:17 +07:00
Chi Vinh Le 0231358075 Correctly set roles 2017-05-24 21:00:05 +07:00
Chi Vinh Le c35ce979f5 Move query logic to containers 2017-05-24 19:04:05 +07:00
Chi Vinh Le 3cde313ab4 Pass correct props to install step 2017-05-24 17:38:19 +07:00
Chi Vinh Le 26d6a97b20 Merge branch 'master' into extendable-queries-admin 2017-05-24 17:17:52 +07:00
Chi Vinh Le 8ab7047cfa Refactor admin 2017-05-24 17:09:21 +07:00
Chi Vinh Le db3f91cbcc Change to declarative API for plugins 2017-05-24 16:44:33 +07:00
Chi Vinh Le 1b3fe13e9b Fallback to default language for timeago 2017-05-24 16:33:39 +07:00
gaba 86258ba0c3 One more string to translate. 2017-05-23 16:06:07 -04:00
gaba 8da7df353c Adds a bunch of missing strings. 2017-05-23 16:06:04 -04:00
Chi Vinh Le b2798fd35f Merge branch 'i18n-refactor' of ssh://github.com/coralproject/talk into i18n-refactor 2017-05-24 01:39:09 +07:00
Chi Vinh Le 37b8fd8fe3 Simplify i18n + fallback to default language 2017-05-24 01:38:50 +07:00
gaba 2991af67f4 Adds more translation strings. 2017-05-23 14:03:34 -04:00
David Erwin a1a78334ea First pass docs restructure 2017-05-23 13:58:02 -04:00
Chi Vinh Le 5c66009d84 Change to import 2017-05-24 00:30:34 +07:00
Chi Vinh Le 8ae497366b Move locales to top level 2017-05-24 00:28:47 +07:00
Chi Vinh Le 48bef95a4d Simplify yaml loading 2017-05-24 00:26:55 +07:00
gaba adacafb586 Removed extra string. 2017-05-23 12:59:06 -04:00
Kim Gardner 4ad2cd76c0 Merge branch 'master' into coral-plugin-auth 2017-05-23 12:57:58 -04:00
Kim Gardner ac9e193c45 Merge branch 'master' into graphql-errors-handling 2017-05-23 12:57:53 -04:00
gaba 259b24faaa A few strings where using -. 2017-05-23 12:53:48 -04:00
gaba a184837ff8 Goes back to load all translations... 2017-05-23 12:46:53 -04:00
gaba 5757682732 Removes files that came from the merge and do not exist in master. 2017-05-23 11:57:51 -04:00
Gabriela Rodríguez Berón 6f7b8522c8 Merge branch 'master' into i18n-refactor 2017-05-23 11:47:58 -04:00
Riley Davis 3c4b510829 Merge pull request #605 from coralproject/missed-roles
hasRoles is no longer a function
2017-05-22 15:20:17 -06:00
riley add3cbf7b3 hasRoles is no longer a function 2017-05-22 15:10:56 -06:00
Chi Vinh Le 947ea66a77 Remove obsolete errors checking 2017-05-22 20:25:24 +07:00
Chi Vinh Le d1307eb5cd Handle response errors in the graphql framework 2017-05-22 20:11:16 +07:00
Belen Curcio 8266c65043 Merge Conflicts 2017-05-22 09:39:04 -03:00
Belen Curcio 317f7134f2 linting 2017-05-22 09:03:10 -03:00
Belen Curcio 9936b6ec47 Prettier 2017-05-22 08:59:34 -03:00
Belen Curcio 1d96f67db6 Merge branch 'master' of github.com:coralproject/talk into coral-plugin-auth 2017-05-22 08:58:33 -03:00
Belen Curcio 9d00a27f1d Auth as a plugin 2017-05-22 08:40:45 -03:00
Belen Curcio f364a1e0a1 Refactor 2017-05-22 08:23:58 -03:00
Belen Curcio 1aacb565d4 linting 2017-05-19 20:10:49 -03:00
Belen Curcio 801a6f8a53 External plugin auth fully working, now refactor 2017-05-19 20:00:33 -03:00
gaba f525af4c6e Added a few more translations that were missing. 2017-05-19 15:42:56 -07:00
Belen Curcio dbfd2aff7c SignInButton 2017-05-19 19:29:50 -03:00
Belen Curcio 3af49de0ce New login slots and auth plugins 2017-05-19 18:04:54 -03:00
gaba 97e9419f02 Missing translations. 2017-05-19 13:34:56 -07:00
Belen Curcio 904aef0afc Adding coral-plugin-auth 2017-05-19 17:32:54 -03:00
Belen Curcio 87ada30eff Ádding Stream Slot 2017-05-19 17:32:16 -03:00
gaba 67fb829717 A few more issues from the merge. 2017-05-19 13:29:23 -07:00
gaba 625362d51e Merge branch 'master' into i18n-refactor 2017-05-19 12:44:34 -07:00
gaba 9be443eda8 Moves i18n into coral-framework. 2017-05-19 12:28:44 -07:00
Riley Davis f32208b35b Merge pull request #585 from coralproject/multiple-roles
Multiple roles
2017-05-19 13:12:20 -06:00
gaba 88b5a4169d Remove promise 2017-05-19 10:48:47 -07:00
riley 2c620c868d merge master 2017-05-19 11:05:46 -06:00
Kiwi 04fbeededa Merge pull request #600 from coralproject/suspend-user
Suspend user
2017-05-19 23:29:13 +07:00
Kiwi 8cb9945e25 Merge branch 'master' into multiple-roles 2017-05-19 23:26:45 +07:00
riley 17ceadd8c9 move client-side perms to services 2017-05-19 09:18:24 -06:00
Chi Vinh Le 3688d3f970 Gracefully allow user with no email 2017-05-19 17:53:10 +07:00
Chi Vinh Le 1d6455058e Apply review suggestions 2017-05-19 17:51:58 +07:00
Chi Vinh Le 1374217680 Merge branch 'master' into suspend-user 2017-05-19 17:46:06 +07:00
gaba 8dddff25f9 Update es translation and add link to transifex. 2017-05-18 16:01:12 -07:00
gaba 12cb59ce30 Merge branch 'master' into i18n-refactor 2017-05-18 15:44:14 -07:00
Kim Gardner f35a9ec8cd Merge pull request #602 from coralproject/content-type-fix
added fix for chrome + content type negotiation
2017-05-18 18:40:35 -04:00
gaba 1a7ad410f5 Loads timeago translation when loading translations. 2017-05-18 15:38:53 -07:00
Wyatt Johnson 25230f2e9d added fix for chrome + content type negotiation 2017-05-18 16:30:28 -06:00
gaba 3ca22bd101 Fix translation keys. 2017-05-18 15:14:37 -07:00
Kim Gardner f29df23c07 Merge pull request #601 from coralproject/read-only-inputs
handle no-interaction input the correct way
2017-05-18 17:21:12 -04:00
Kim Gardner b3e494d279 Merge branch 'master' into read-only-inputs 2017-05-18 17:14:48 -04:00
Kim Gardner 13376504b5 Merge pull request #598 from gobengo/edit-comment-settings
Edit Comment Window Length Setting
2017-05-18 17:14:29 -04:00
Kim Gardner 12ec058588 Merge branch 'master' into edit-comment-settings 2017-05-18 17:07:37 -04:00
Kim Gardner 5cbe9029aa Merge pull request #596 from gobengo/fix-ignore-user
Ignored user tombstones work again
2017-05-18 16:43:46 -04:00
riley 6deee7cb80 add a perms utils file 2017-05-18 14:28:43 -06:00
Riley Davis c772cffc92 handle no-interaction input the correct way 2017-05-18 13:51:48 -06:00
Chi Vinh Le 89b7918e41 Tiny renaming 2017-05-19 02:29:59 +07:00
Chi Vinh Le b521934ee2 Remove unneeded refetch 2017-05-19 02:24:47 +07:00
Chi Vinh Le 061c18670b Merge branch 'master' into suspend-user
Conflicts:
	client/coral-admin/src/constants/moderation.js
	client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js
2017-05-19 02:19:24 +07:00
Chi Vinh Le 0040bc4c01 Remove remaining debug msgs 2017-05-19 02:12:27 +07:00
Chi Vinh Le 0588a8ab66 Use async / await :-) 2017-05-19 02:07:38 +07:00
Chi Vinh Le 859a0b1fbe Make until arg required 2017-05-19 02:03:36 +07:00
Chi Vinh Le d995cdde07 Make email message required 2017-05-19 02:01:47 +07:00
Chi Vinh Le f641a3ec40 Complete suspend user implementation 2017-05-19 01:52:03 +07:00
Kim Gardner e80e79f267 Merge branch 'master' into edit-comment-settings 2017-05-18 14:23:14 -04:00
riley ff75b9474a merge master 2017-05-18 12:18:00 -06:00
riley 056ba9a04c do the same thing for the Drawer 2017-05-18 12:11:11 -06:00
riley d98ce38bf5 show config tab to admins. hide menu items from users that can't access admin 2017-05-18 12:06:07 -06:00
Benjamin Goering 1d322d8c70 Merge branch 'master' into fix-ignore-user 2017-05-18 10:50:00 -07:00
Benjamin Goering aaa2da6c23 Stream container refetch then setCommentCountCache to asset.commentCount instead of silly zero 2017-05-18 10:43:38 -07:00
Wyatt Johnson 5a272413e6 Merge pull request #599 from coralproject/gzip
Added gzip compression to bundle assets
2017-05-18 11:34:05 -06:00
Wyatt Johnson 4dc83aaf63 added middleware wrap 2017-05-18 11:27:28 -06:00
Wyatt Johnson 12713dae86 Removed unused assets 2017-05-18 11:18:08 -06:00
Wyatt Johnson 555c593059 Added gzip compression to bundle assets 2017-05-18 11:08:46 -06:00
Benjamin Goering fb33eefe8e trivial changes requested by review 2017-05-18 08:19:52 -07:00
Benjamin Goering cfc6d4bfea Merge branch 'fix-ignore-user' of github.com:gobengo/talk into fix-ignore-user 2017-05-18 08:12:40 -07:00
Benjamin Goering 6bbeee3a6b StopIgnoringUser does not refetch EmbedQuery 2017-05-18 08:11:39 -07:00
Benjamin Goering 340d3cea62 contains/Stream setCommentCountCache waits for refetch promise 2017-05-18 08:10:20 -07:00
Kim Gardner e8e9dbe3ca Merge branch 'master' into fix-ignore-user 2017-05-18 09:49:54 -04:00
gaba 9e954f0ae3 Fix timeago with lang. 2017-05-17 18:05:41 -07:00
Benjamin Goering cb45f0a8b3 Merge branch 'master' into edit-comment-settings 2017-05-17 15:46:14 -07:00
Benjamin Goering cb1a4ee1cc remove extraneous console.log 2017-05-17 15:40:32 -07:00
Benjamin Goering d93ad38dd1 Admins can change Edit Comment Window length in Moderation Settings 2017-05-17 15:39:19 -07:00
riley c4210db307 staff should not see moderate tag. translations 2017-05-17 16:10:02 -06:00
riley 3fc1029a93 do not require auth in the Header 2017-05-17 16:00:01 -06:00
Riley Davis 54abaeb587 wrap the not-authorized warning in a template 2017-05-17 15:47:41 -06:00
Riley Davis 4a97db3357 emma's copy 2017-05-17 15:41:49 -06:00
Riley Davis 88377b3180 do not show Config tab for non-admins 2017-05-17 15:37:13 -06:00
Kim Gardner 0dfec6e619 Merge pull request #597 from coralproject/copy-button-should-work
user detail copy button should work
2017-05-17 17:35:08 -04:00
Riley Davis e343897526 user detail copy button regression 2017-05-17 15:11:00 -06:00
Benjamin Goering 294eb6c81d Merge branch 'master' into fix-ignore-user 2017-05-17 13:57:23 -07:00
Kim Gardner 413eef8834 Merge pull request #564 from coralproject/user-detail-ui
User detail ui
2017-05-17 16:41:00 -04:00
Benjamin Goering 9eac05c8fb Ignored user tombstones work again 2017-05-17 13:18:59 -07:00
gaba 8d492ca4e9 Adds a few missing keys. 2017-05-17 13:18:04 -07:00
gaba 3aceb0dc38 Merge branch 'master' into i18n-refactor 2017-05-17 12:59:24 -07:00
gaba 5bd9bc992b Move i18n into a service 2017-05-17 12:53:36 -07:00
Chi Vinh Le 492b973206 Add 1 extra suspension minute 2017-05-18 02:28:01 +07:00
Chi Vinh Le 2bdf413b88 Integrate into embed stream 2017-05-18 02:28:01 +07:00
Chi Vinh Le 76e87f4c34 Move previous suspendUser feature to rejectUsername 2017-05-18 02:28:01 +07:00
Riley Davis c66e3141e0 actually check permissions 2017-05-17 11:38:43 -06:00
Riley Davis a0f41bb19d show total comments and rejected % 2017-05-17 10:54:14 -06:00
Chi Vinh Le 056ff427a5 Merge branch 'master' into suspend-user 2017-05-17 21:50:28 +07:00
Chi Vinh Le 71c743dda7 Extend backend to support new suspend feature 2017-05-17 20:05:18 +07:00
Wyatt Johnson fde4dee52f Resolver cleanup 2017-05-16 17:26:34 -06:00
riley b49ace99eb add permission for EDIT_COMMENT 2017-05-16 16:38:30 -06:00
riley d081c0c5b5 remove context 2017-05-16 16:34:04 -06:00
riley 03ce044c53 merge master 2017-05-16 16:33:41 -06:00
riley 31647fb2f0 have function params in the correct order 2017-05-16 15:41:27 -06:00
Wyatt Johnson f4b9191476 Added author_id to comment count query 2017-05-16 14:20:20 -06:00
Riley Davis 4ca5c4bc09 Merge branch 'master' into user-detail-ui 2017-05-16 13:54:13 -06:00
Kiwi c21e500e58 Merge pull request #593 from coralproject/readd-last-comment
Readd lastComment field to asset resolver
2017-05-17 01:35:07 +07:00
Chi Vinh Le 7d858c7b3f Readd lastComment field to asset resolver 2017-05-17 01:25:06 +07:00
riley c7e9fe3f5f update backend with the can() method 2017-05-16 10:50:09 -06:00
Wyatt Johnson e90ce7f4c3 fixed merge issue 2017-05-16 10:20:16 -06:00
riley 62e8e4c5c5 change how constants are exposed 2017-05-16 10:15:43 -06:00
Wyatt Johnson 3e2ed222ed Merge branch 'trust-merge' into user-detail-ui 2017-05-16 09:53:35 -06:00
riley 7896b3f33b merge master 2017-05-16 09:43:49 -06:00
Chi Vinh Le 97121382c7 Merge branch 'master' into suspend-user
Conflicts:
	client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js
	client/coral-admin/src/containers/ModerationQueue/components/Comment.js
	client/coral-framework/utils/index.js
	package.json
2017-05-16 21:02:33 +07:00
Belén Curcio e561819c8d Merge pull request #592 from coralproject/invalidate-old-data
Invalidate old user data
2017-05-16 08:57:32 -03:00
Chi Vinh Le c7e0577708 Merge branch 'master' into invalidate-old-data 2017-05-16 18:17:45 +07:00
Chi Vinh Le 2ab8cc9481 Allow Apollo to invalidate old user data 2017-05-16 18:17:43 +07:00
Kiwi acdc00af18 Merge pull request #591 from coralproject/refetch-profile-only-after-login
Only refetch for login on `My Profile`.
2017-05-16 18:12:54 +07:00
Belén Curcio f9cf5fb744 Merge branch 'master' into refetch-profile-only-after-login 2017-05-16 07:57:20 -03:00
Chi Vinh Le e1b80c3317 Only refetch for login 2017-05-16 17:50:17 +07:00
Belén Curcio f37c1c3b5d Merge pull request #590 from coralproject/auth-login-fixes
Auth login fixes
2017-05-16 07:42:32 -03:00
Chi Vinh Le ec19618052 Readd login fixes 2017-05-16 17:26:53 +07:00
Chi Vinh Le 81f51b69ec Clear token before dispatching logout action 2017-05-16 17:13:19 +07:00
Belén Curcio 084bd6710f Merge pull request #589 from coralproject/fix
Updated Lock File
2017-05-16 00:14:02 -03:00
Belen Curcio df843a23dd updated loc 2017-05-16 00:09:33 -03:00
Kim Gardner 95e770aff8 Merge pull request #588 from coralproject/fix
Fix for FB login.
2017-05-15 22:57:30 -04:00
Belen Curcio d3252b8c87 Done :) 2017-05-15 23:47:29 -03:00
Belen Curcio 1eada688fe Prettier 2017-05-15 23:23:22 -03:00
Belen Curcio 4b6e562492 Missing "" to send strings instead of objects 2017-05-15 23:22:36 -03:00
gaba 35c941d4d0 Add missing translations from commentbox. 2017-05-15 16:17:53 -07:00
gaba 61856c3cf6 Use timeago. 2017-05-15 16:04:10 -07:00
riley 4d3788e4c9 saving my place so i dont have too many threads 2017-05-15 16:25:32 -06:00
Wyatt Johnson 50db2d1dda Initial merge of trust functionality 2017-05-15 15:28:57 -06:00
gaba c0c6dd6252 The merge got back some code to the coral-framework. 2017-05-15 14:23:56 -07:00
gaba 423cb3cade Merge branch 'master' into i18n-refactor 2017-05-15 14:02:34 -07:00
Kim Gardner 297dee6da8 Merge pull request #587 from coralproject/edit-changes
Edit Consistency
2017-05-15 16:47:33 -04:00
gaba 54e103b55a Change a few translations that had wrong key. 2017-05-15 13:44:46 -07:00
Belen Curcio 2b7f545c2d lint 2017-05-15 17:31:53 -03:00
gaba 0ead2cb610 Adds sign in translations. 2017-05-15 13:25:09 -07:00
Belen Curcio b789a8e107 Removing kiwis fix since this was fixed in auth tokens branch 2017-05-15 17:23:57 -03:00
Belen Curcio b2e5c0452a The merge conficts 2017-05-15 17:13:48 -03:00
gaba f32eac4eab Lint YAML and notations 2017-05-15 12:53:28 -07:00
Belén Curcio afa3123829 Merge pull request #578 from coralproject/auth-tokens
JWT Auth
2017-05-15 16:51:10 -03:00
Wyatt Johnson 5aca83993b fixed build process 2017-05-15 13:35:51 -06:00
Wyatt Johnson 8ff0c3db51 Merge branch 'auth-tokens' of github.com:coralproject/talk into auth-tokens 2017-05-15 13:14:10 -06:00
Chi Vinh Le 74e1436ae4 Use correct error key 2017-05-16 01:09:33 +07:00
Chi Vinh Le def35f0a93 Fix login issues 2017-05-16 00:55:12 +07:00
Chi Vinh Le 06001763ff Remove unused files 2017-05-16 00:52:37 +07:00
Belen Curcio 75aa8d79df linting 2017-05-15 14:50:26 -03:00
Belen Curcio 843c3a16c8 Admin share same network interface, and unifying actions 2017-05-15 14:48:12 -03:00
Kiwi 963827204e Merge branch 'master' into edit-changes 2017-05-15 23:22:30 +07:00
Belen Curcio 4e86e4197c handling logout 2017-05-15 13:13:28 -03:00
Belen Curcio 5dae7bf4ac Merge branch 'master' of github.com:coralproject/talk into auth-tokens 2017-05-15 13:12:11 -03:00
Belen Curcio 48370db09a Merge branch 'auth-tokens' of github.com:coralproject/talk into auth-tokens 2017-05-15 13:11:32 -03:00
Chi Vinh Le a9207428fe Calculate "until" 2017-05-15 23:07:46 +07:00
Wyatt Johnson 9bee31198e Added logout routes 2017-05-15 10:03:09 -06:00
Kim Gardner 2a95c1eee2 Merge pull request #583 from coralproject/hooks-docs
[DOCS] - Hooks and Reactions
2017-05-15 11:55:41 -04:00
Belen Curcio 57ced201eb WebStorage events 2017-05-15 12:52:54 -03:00
Belen Curcio 370cdf8c09 Ádding middlewares to our network interface 2017-05-15 12:51:07 -03:00
Kim Gardner cb64d599fe Merge branch 'master' into hooks-docs 2017-05-15 11:50:46 -04:00
gaba b31212f847 Second run of notation change for translations. 2017-05-15 08:35:55 -07:00
Chi Vinh Le 63fa3c4de7 Implement suspend user components 2017-05-15 22:28:04 +07:00
Belen Curcio 292f758ac9 Comment history relies on authtokens 2017-05-15 12:17:30 -03:00
Belen Curcio 76b96a66a2 Adding Bearer token to the Graph Client 2017-05-15 11:41:36 -03:00
gaba 633086cfa3 Fix a few more strings and translations. 2017-05-15 07:11:11 -07:00
Belen Curcio 8754ade5a4 merge 2017-05-12 21:52:29 -03:00
Wyatt Johnson e218de811b removed csrf reference 2017-05-12 15:53:25 -06:00
Wyatt Johnson 9403280c56 Merge branch 'master' into edit-changes 2017-05-12 15:44:19 -06:00
Belen Curcio 964cc362e7 Login, logout with tokens. WIP 2017-05-12 18:26:24 -03:00
Wyatt Johnson a5c9a8e4b0 cleaned up graph, standardised mutation 2017-05-12 14:04:09 -06:00
David Erwin 7c5e04e820 Merge pull request #584 from coralproject/prevent-empty-edit
Prevent empty edit on the Front-End
2017-05-12 15:44:14 -04:00
Belen Curcio 7fd5509490 Prettier 2017-05-12 15:48:19 -03:00
Belen Curcio 5e8a02c461 Removing CSRF 2017-05-12 15:40:53 -03:00
Wyatt Johnson ffd96f57e9 Comment too short fixes 2017-05-12 11:16:52 -06:00
Wyatt Johnson e3017efebf Front end edits to accomedate ignoredUsers 2017-05-12 10:25:59 -06:00
Wyatt Johnson ed27209de9 More edit changes 2017-05-12 10:09:25 -06:00
riley e32ab99edf remove hasRoles 2017-05-12 09:57:07 -06:00
Chi Vinh Le 072437b0fd Prevent empty edit 2017-05-12 22:45:33 +07:00
Belen Curcio 674ac50035 Ádding reaction docs 2017-05-12 12:29:02 -03:00
Belen Curcio 0eb88b30eb Merge branch 'master' of github.com:coralproject/talk into hooks-docs 2017-05-12 12:19:26 -03:00
Wyatt Johnson f4dfb21e15 reverted pagination work 2017-05-12 09:14:25 -06:00
Belen Curcio e5a4fbc1cd DOCS Hooks 2017-05-12 12:07:55 -03:00
David Erwin ce583142ef Merge pull request #567 from coralproject/query-mutation-api
Extendable GraphQL framework
2017-05-12 09:43:50 -04:00
Chi Vinh Le 95a7a1ca47 Rename registry 2017-05-12 20:15:04 +07:00
Chi Vinh Le 7857cadef5 Merge branch 'master' into query-mutation-api
Conflicts:
	client/coral-embed-stream/src/components/Comment.js
	client/coral-embed-stream/src/containers/Embed.js
	client/coral-embed-stream/src/containers/Stream.js
	client/coral-embed-stream/src/index.js
	client/coral-framework/graphql/fragments/commentView.graphql
	client/coral-framework/graphql/mutations/index.js
	client/coral-framework/hocs/index.js
	client/coral-framework/hocs/withFragments.js
2017-05-12 19:50:36 +07:00
Wyatt Johnson 47186c4eac some changes to loaders 2017-05-11 17:52:07 -06:00
Wyatt Johnson ae5da93730 linting fixes 2017-05-11 17:44:51 -06:00
Wyatt Johnson a65d045c65 lint fixes 2017-05-11 17:38:49 -06:00
Wyatt Johnson 08e7a90d69 lint fixes 2017-05-11 17:34:47 -06:00
Wyatt Johnson 547ba126be cleanup to mutators 2017-05-11 17:31:22 -06:00
Wyatt Johnson d497ad3369 initial pagination rewrite, cleanups to comment edit 2017-05-11 17:27:02 -06:00
gaba 3b80ee8b13 Add YAML loader. Fix i18n module to get YAML files. 2017-05-11 15:05:09 -07:00
Riley Davis 14b483d089 create roles helper 2017-05-11 14:23:02 -06:00
Kim Gardner 5c5d014e23 Merge pull request #563 from gobengo/edit-comment
Edit comment
2017-05-11 14:28:33 -04:00
Benjamin Goering 923e20f867 Merge branch 'master' into edit-comment 2017-05-11 10:42:41 -07:00
Benjamin Goering cd7b1f2b2b editComment mutation doesn't refetch streamQuery. Instead a reducer updates streamQuery client-side 2017-05-11 10:38:48 -07:00
Kim Gardner c44eb373c3 Merge pull request #559 from coralproject/config-embed
Config via Embed - Add external config passed into the script tag
2017-05-11 12:56:47 -04:00
Kim Gardner 49d0c9bd10 Merge branch 'master' into config-embed 2017-05-11 12:40:11 -04:00
Benjamin Goering cb90802896 Fix bad merge when CommentBox calls setCommentCountCache 2017-05-11 09:34:33 -07:00
Kim Gardner 30bb954e44 Merge pull request #582 from coralproject/losowsky-patch-1
removed the beta tag
2017-05-11 12:17:41 -04:00
Kim Gardner 4cd2a15f35 Merge branch 'master' into losowsky-patch-1 2017-05-11 12:05:32 -04:00
gaba 653091fdf9 Merge branch 'master' into i18n-refactor 2017-05-11 09:02:21 -07:00
Kim Gardner a1f3f550db Merge pull request #580 from coralproject/dont-unreport
remove ability to un-flag a comment
2017-05-11 11:42:15 -04:00
Andrew Losowsky 604894e43c removed the beta tag
we left beta a while ago!
2017-05-11 11:11:37 -04:00
Riley Davis ebf4f7ecc9 Merge branch 'master' into dont-unreport 2017-05-11 09:00:57 -06:00
riley 964b934efb Merge branch 'master' into multiple-roles 2017-05-11 08:51:06 -06:00
Wyatt Johnson db94158426 Merge pull request #581 from coralproject/license-update
Update LICENSE
2017-05-11 07:59:29 -06:00
Kim Gardner ef502bf7a8 Update LICENSE 2017-05-11 09:46:04 -04:00
Belén Curcio 06b90041af Merge branch 'master' into config-embed 2017-05-11 09:46:58 -03:00
Riley Davis c3048e599d remove ability to un-flag a comment 2017-05-10 20:57:20 -06:00
Kim Gardner 1314f1972a Merge branch 'master' into edit-comment 2017-05-10 15:25:27 -04:00
Belén Curcio 0c07e39cc0 Merge pull request #571 from coralproject/coral-reaction
Coral Reactions and Coral Plugin Love
2017-05-10 16:12:32 -03:00
Belen Curcio 57d2b81b05 missing _ 2017-05-10 16:05:52 -03:00
Belen Curcio a75070cf2e Merge branch 'config-embed' of github.com:coralproject/talk into config-embed 2017-05-10 16:05:16 -03:00
Belén Curcio 2d6c26887a Merge branch 'master' into config-embed 2017-05-10 16:05:04 -03:00
Belén Curcio 7626330ee1 Merge branch 'master' into coral-reaction 2017-05-10 16:02:01 -03:00
Belen Curcio 2fc54ac529 Merge branch 'master' of github.com:coralproject/talk into config-embed 2017-05-10 15:59:09 -03:00
Belen Curcio 10e8a32c21 Changes 2017-05-10 15:57:21 -03:00
Belen Curcio 0a2b26b599 Exports 2017-05-10 15:53:33 -03:00
David Erwin 4f74d28602 Merge pull request #579 from coralproject/action-fix
Patched bug with adding action
2017-05-10 14:39:25 -04:00
Belen Curcio c3dff79e6e Updated 2017-05-10 15:35:32 -03:00
riley 602c3d0be2 use a slot instead of trying to use facebook directly 2017-05-10 12:28:33 -06:00
Wyatt Johnson a3a8d23797 patched bug with adding action 2017-05-10 12:18:42 -06:00
Belen Curcio 7313aaa473 Merge branch 'config-embed' of github.com:coralproject/talk into config-embed 2017-05-10 15:09:19 -03:00
Belen Curcio 74ffc00c20 Adding changes 2017-05-10 15:02:43 -03:00
Belen Curcio 2673de5059 lintin 2017-05-10 14:59:10 -03:00
Belen Curcio 644d00d5d8 Adding coral-plugin-api 2017-05-10 14:57:24 -03:00
Riley Davis 75fb7b6dc2 Merge branch 'master' into user-detail-ui 2017-05-10 11:44:36 -06:00
Belén Curcio 07778844dc Merge branch 'master' into config-embed 2017-05-10 14:17:23 -03:00
Belen Curcio cb45e33b41 merge 2017-05-10 14:15:24 -03:00
Belen Curcio 26e5631f52 Changing path for hocs 2017-05-10 14:13:32 -03:00
Belen Curcio 3e1b7591e0 Adds displayName for WrappedReactions and alreadyReacted 2017-05-10 14:07:58 -03:00
Riley Davis 40ff265ab1 merge master 2017-05-10 11:07:48 -06:00
Belen Curcio 19bf7f6cf8 Adds displayName for WrappedReactions 2017-05-10 13:58:05 -03:00
Belén Curcio 67c202d89f Merge pull request #577 from coralproject/admin-slots
Admin Mod Queue Slots and Coral Plugin Mod example
2017-05-10 13:53:20 -03:00
Belen Curcio ad24ff78d2 Merge branch 'master' of github.com:coralproject/talk into coral-reaction 2017-05-10 13:46:11 -03:00
Wyatt Johnson f8b207e563 Return a meaningful error 2017-05-10 10:29:20 -06:00
Riley Davis fe279587b5 add staff to dropdown 2017-05-10 09:25:39 -06:00
Belén Curcio ca51821d7b Merge branch 'master' into config-embed 2017-05-10 12:01:29 -03:00
Belen Curcio 250a578dd7 lint, and merge conficts 2017-05-10 11:05:21 -03:00
Wyatt Johnson 17b9e43c14 moved webpack config 2017-05-09 16:53:30 -06:00
Wyatt Johnson 785e5a4ac8 Collected config 2017-05-09 16:49:11 -06:00
Benjamin Goering 650e8e205e Merge branch 'edit-comment' of github.com:gobengo/talk into edit-comment 2017-05-09 15:03:19 -07:00
Benjamin Goering f37a210479 Only use errors from errors.js for EditWindowHasEnded 2017-05-09 15:02:26 -07:00
Wyatt Johnson 76d0fdfd67 Added docs 2017-05-09 15:32:19 -06:00
Wyatt Johnson 3649605629 Merge branch 'master' into auth-tokens 2017-05-09 15:21:38 -06:00
Belén Curcio af89ef45f2 Merge branch 'master' into coral-reaction 2017-05-09 15:54:36 -03:00
Belen Curcio 8c219c1c4d Adding config with initial 2017-05-09 15:53:57 -03:00
Kim Gardner b81b789afa Merge branch 'master' into query-mutation-api 2017-05-09 14:29:27 -04:00
Kim Gardner fa8d96b6be Merge branch 'master' into edit-comment 2017-05-09 14:19:50 -04:00
Kim Gardner d8e7b25d0e Merge pull request #576 from coralproject/FE_Plugin_DOCS
FE Plugin Docs cleanup
2017-05-09 13:49:49 -04:00
Belen Curcio 52b0819e78 Adding example for plugins within the Admin Comment Queue 2017-05-09 14:02:35 -03:00
Benjamin Goering 994b5006b6 Merge branch 'master' into edit-comment 2017-05-09 09:12:14 -07:00
riley a187472d5c merge master 2017-05-09 10:11:04 -06:00
Kim Gardner a20bacd78d Merge branch 'master' into FE_Plugin_DOCS 2017-05-09 12:07:27 -04:00
Riley Davis 084f6b28ed merge master 2017-05-09 10:06:41 -06:00
Kim Gardner 87bc3e0a72 Merge pull request #565 from coralproject/approve-reject-noop
Don't redo actions on comments
2017-05-09 12:06:21 -04:00
Belen Curcio 3c06ee9360 Adds slots to admin stream 2017-05-09 12:21:21 -03:00
Belén Curcio 5b22bfbac2 Merge branch 'master' into coral-reaction 2017-05-09 11:40:30 -03:00
Belén Curcio c020008fad Merge branch 'master' into config-embed 2017-05-09 10:54:52 -03:00
Kiwi 4eb20108b1 Merge branch 'master' into approve-reject-noop 2017-05-09 20:06:11 +07:00
Kim Gardner 42db896d33 Merge branch 'master' into FE_Plugin_DOCS 2017-05-09 08:09:36 -04:00
Kim Gardner c0b526e98d Fix typo 2017-05-09 08:03:18 -04:00
Belen Curcio 743580fd08 Merge branch 'coral-reaction' of github.com:coralproject/talk into coral-reaction 2017-05-09 09:02:32 -03:00
Belen Curcio 788610a5f6 Like button params 2017-05-09 09:02:04 -03:00
Kim Gardner 3129828f83 Merge pull request #575 from coralproject/suspect-partial
do not highlight partial word matches in admin since this is not how the backend works
2017-05-09 07:53:11 -04:00
Belén Curcio 58ce5d5055 Merge branch 'master' into coral-reaction 2017-05-09 08:52:04 -03:00
Kiwi f9259ead50 Merge branch 'master' into query-mutation-api 2017-05-09 17:49:50 +07:00
Kiwi 6fb227eb72 Merge branch 'master' into approve-reject-noop 2017-05-09 17:49:30 +07:00
Benjamin Goering 8af7168f4f Merge branch 'master' into edit-comment 2017-05-08 19:26:38 -07:00
Riley Davis d77fcfe9de Merge branch 'master' into suspect-partial 2017-05-08 17:13:50 -06:00
Riley Davis 2490e65981 merge master 2017-05-08 17:09:23 -06:00
Riley Davis 242f3ea5ea do not highlight partial word matches in admin since this is not how the backend works 2017-05-08 17:01:36 -06:00
Wyatt Johnson e30bdd1cdc Merge branch 'master' into auth-tokens 2017-05-08 16:11:27 -06:00
Kim Gardner 5625f5b4b8 Merge pull request #566 from coralproject/context-from-comment
open the comment in context when clicked
2017-05-08 17:38:42 -04:00
Kim Gardner b2c8e3b254 Merge branch 'master' into context-from-comment 2017-05-08 17:34:55 -04:00
Kim Gardner 3dff07de40 Merge pull request #572 from coralproject/mod-is-main-tab
default view is moderate > all
2017-05-08 17:34:43 -04:00
Kim Gardner 19d7a3323e Merge branch 'master' into mod-is-main-tab 2017-05-08 17:30:56 -04:00
Wyatt Johnson dc86b87a62 Merge pull request #574 from coralproject/sub-fix
Fix for incorrect options passed to pubsub
2017-05-08 15:29:56 -06:00
Kim Gardner 6dd01b4334 Merge branch 'master' into mod-is-main-tab 2017-05-08 17:26:55 -04:00
Wyatt Johnson b6e3796afe Merge branch 'master' into sub-fix 2017-05-08 15:25:57 -06:00
Kim Gardner 34ee1c56ea Merge pull request #573 from coralproject/move-queues
move approved tab to be next to rejected tab
2017-05-08 17:25:47 -04:00
Wyatt Johnson 85d634c221 Merge branch 'master' into sub-fix 2017-05-08 15:21:43 -06:00
Belén Curcio 513a841aac Merge branch 'master' into coral-reaction 2017-05-08 18:19:05 -03:00
Belen Curcio 88861754f1 Adding full example with translations 2017-05-08 18:05:54 -03:00
Belen Curcio fe58a5076e Adding coral-plugin-love 2017-05-08 18:05:39 -03:00
Riley Davis 3e258b1787 move approved tab 2017-05-08 14:59:23 -06:00
Belen Curcio b82cab0655 Lint 2017-05-08 17:50:15 -03:00
Belen Curcio b547ad44f1 Better and more friendly API 2017-05-08 17:46:56 -03:00
Kim Gardner e04bf7f9bc Merge branch 'master' into approve-reject-noop 2017-05-08 16:22:42 -04:00
David Erwin 50d832c2f8 Remove pseudocode 2017-05-08 16:21:24 -04:00
Kim Gardner 0b06c233a8 Merge pull request #523 from coralproject/FE_Plugin_DOCS
Frontend Plugins DOCS
2017-05-08 16:20:27 -04:00
Kim Gardner 7a3b36433a Merge branch 'master' into FE_Plugin_DOCS 2017-05-08 16:16:34 -04:00
Belén Curcio d478910a81 Merge pull request #570 from coralproject/add-supported-browsers-docs
Supported Browsers (docs)
2017-05-08 17:15:16 -03:00
Chi Vinh Le 028e13761f Complete graphql code refactor in framework 2017-05-09 03:05:19 +07:00
Chi Vinh Le 57e7396997 Use correct fragment name 2017-05-09 02:58:50 +07:00
Chi Vinh Le 80d08bbe2e Port StopIgnoringUser Mutation 2017-05-09 02:50:52 +07:00
Chi Vinh Le 5c44922d2b Port IgnoreUser mutation 2017-05-09 02:46:42 +07:00
Chi Vinh Le 7077300dbc Fix refetchQueries 2017-05-09 02:45:28 +07:00
Riley Davis c00e6c1ece default view is moderate > all 2017-05-08 13:40:24 -06:00
Wyatt Johnson bc3c73a992 Fix for incorrect options passed to pubsub 2017-05-08 13:26:07 -06:00
Chi Vinh Le 774a6f68ac Port RemoveCommentTag Mutation 2017-05-09 02:22:44 +07:00
Chi Vinh Le b87c36078a Port AddCommentTag Mutation 2017-05-09 02:19:55 +07:00
Belen Curcio 6934263f71 Ádding uuid v4 2017-05-08 15:59:52 -03:00
Belen Curcio cd18a7e76f Fully working. replaced typename by typereaction. Thanks kiwi 😂 2017-05-08 15:51:17 -03:00
Belen Curcio b7de01b0ad no console 2017-05-08 15:47:08 -03:00
Belen Curcio 011e5da26f Almost fully working 2017-05-08 15:44:11 -03:00
Chi Vinh Le 0e931d023d Port DeleteAction Mutation 2017-05-09 01:15:07 +07:00
Benjamin Goering 295de61f36 Merge branch 'master' into edit-comment 2017-05-08 10:00:58 -07:00
Benjamin Goering 096025b72a Add asset_id to editComment mutation to allow mongo query happy path to be atomic 2017-05-08 09:57:52 -07:00
David Erwin e2ed21e113 Adding building block documentation 2017-05-08 12:00:22 -04:00
Chi Vinh Le 83ef41000c Port PostDontAgree mutation 2017-05-08 22:56:01 +07:00
Chi Vinh Le 10796ed4b3 Port PostFlag mutation 2017-05-08 22:35:59 +07:00
Chi Vinh Le 7f0b3c2ddd Merge branch 'master' into query-mutation-api
Conflicts:
	client/coral-embed-stream/src/components/Comment.js
	client/coral-embed-stream/src/containers/Stream.js
2017-05-08 21:44:35 +07:00
David Erwin b019c5e180 Separate supported and experimental plugin guildes 2017-05-08 10:36:36 -04:00
Belen Curcio a5f6e1f343 Adding coral-reaction 2017-05-08 11:32:46 -03:00
Chi Vinh Le 4c17cec4fd Lazily resolve fragments in queries and mutations 2017-05-08 21:30:25 +07:00
Chi Vinh Le ce38b9da64 Rename argument name 2017-05-08 19:41:14 +07:00
Belén Curcio c920c7e9bc Merge branch 'master' into FE_Plugin_DOCS 2017-05-08 08:27:04 -03:00
Benjamin Goering 81879c9bb9 Move getEditableUntilDate into util file 2017-05-08 00:05:14 -07:00
Benjamin Goering 9fb76d35c8 shorten some syntax that could be shorter 2017-05-07 23:54:51 -07:00
Benjamin Goering a7099295d6 CountdownSeconds component has its own file 2017-05-07 23:47:59 -07:00
Benjamin Goering 3d8c521928 CommentForm component is in its own file 2017-05-07 23:44:41 -07:00
Wyatt Johnson 95f9bac254 Initial migration to JWT 2017-05-05 15:42:34 -06:00
Kim Gardner 70bb6f6632 Merge branch 'master' into approve-reject-noop 2017-05-05 16:53:14 -04:00
Kim Gardner 19d62a8c63 Merge branch 'master' into add-supported-browsers-docs 2017-05-05 16:46:21 -04:00
Kim Gardner b15a2af38c Update formatting of License info 2017-05-05 16:45:15 -04:00
Riley Davis 4ff42385e3 remove dead code 2017-05-05 14:41:19 -06:00
Kim Gardner dc81a59908 Supported Browsers 2017-05-05 16:40:17 -04:00
Kim Gardner fe5ddbe323 Merge pull request #569 from coralproject/ui-overlaps
Apply button overlapped text
2017-05-05 16:16:06 -04:00
Riley Davis f8e8eef989 float: right; in css is just fine. 2017-05-05 14:05:52 -06:00
Riley Davis 9c4b636645 Merge branch 'master' into user-detail-ui 2017-05-05 13:56:45 -06:00
Riley Davis 8212a7e11b Merge branch 'master' into approve-reject-noop 2017-05-05 13:56:38 -06:00
Riley Davis 3fc19df240 Merge branch 'master' into context-from-comment 2017-05-05 13:56:28 -06:00
Chi Vinh Le 13e2382cd7 More code comments 2017-05-06 02:33:23 +07:00
Wyatt Johnson d0cca476e6 Merge pull request #568 from coralproject/user-fix
Added privacy fix
2017-05-05 13:19:59 -06:00
Wyatt Johnson 7ccf9552c2 Added privacy fix 2017-05-05 13:14:34 -06:00
Riley Davis 519ca7beb5 en español 2017-05-05 11:55:28 -06:00
Riley Davis 5db48e8c0f make it a blue link instead of the whole thing 2017-05-05 11:35:18 -06:00
Chi Vinh Le 1b7eedfd8d Implement extendable GraphQL framework 2017-05-05 22:51:19 +07:00
Chi Vinh Le 8b3f69d964 Use getDisplayName from recompose 2017-05-05 22:40:54 +07:00
Riley Davis 5f9240f201 open the comment in context when clicked 2017-05-04 16:32:07 -06:00
Riley Davis f3f0b9c858 change mouse cursor for disabled buttons 2017-05-04 15:55:46 -06:00
Riley Davis 4507059a04 same thing for BanUserDialog and the keyboard shortcuts 2017-05-04 15:43:23 -06:00
Riley Davis 67b17160cb don't accept/reject when a comment is already accepted/rejected respectively 2017-05-04 14:42:43 -06:00
riley 57b0b5ec67 add a drawer for the user details 2017-05-04 13:58:43 -06:00
Riley Davis d255ea84b1 merge master 2017-05-04 11:19:01 -06:00
Belén Curcio 04812797a0 Merge branch 'master' into config-embed 2017-05-04 13:40:39 -03:00
Benjamin Goering 636d29af9f When max char count is disabled, allow posting long comments in CommentBox 2017-05-03 19:41:29 -07:00
Benjamin Goering 9b94406763 Remove old comments 2017-05-03 19:32:42 -07:00
Benjamin Goering 9b659b024e Add spanish translations for 2 new error strings 2017-05-03 19:27:32 -07:00
Benjamin Goering b97fa228b1 merge with master after huge coral-embed-stream refactor 2017-05-03 19:19:03 -07:00
Benjamin Goering 0ba973fb44 editComment returns status of comment after edit. UI shows appropriate notifications if PREMOD or REJECTED 2017-05-03 18:05:06 -07:00
Benjamin Goering 3ac8f09619 Notify on unexpected error when saving edit changes 2017-05-03 17:31:36 -07:00
Benjamin Goering ab9c2a89b7 Edit Window countdown is bold when < 10 seconds left 2017-05-03 17:27:36 -07:00
Benjamin Goering e31961716e Remove done todo comments 2017-05-03 17:14:36 -07:00
Benjamin Goering b83381719c Style editCommentWindow messages and i18n 2017-05-03 15:37:02 -07:00
Kim Gardner 5168f563ef Merge pull request #557 from coralproject/admin-queue-polish
load more comments to moderate if available
2017-05-03 18:02:35 -04:00
Kim Gardner 7d0d4aa397 Merge branch 'master' into admin-queue-polish 2017-05-03 17:57:34 -04:00
Kim Gardner 4f2126ef74 Merge pull request #562 from coralproject/flag-queue-loadmore
Flag queue Load More fix
2017-05-03 17:35:53 -04:00
Benjamin Goering 92fd146a8c Add cancel button to editing CommentForm 2017-05-03 14:22:15 -07:00
Benjamin Goering c3f3ed8a50 Comment edit is no longer extended one ach edit 2017-05-03 14:17:36 -07:00
Benjamin Goering 3cb84222b2 Add new padding, color, border-color to CommentBox textarea 2017-05-03 14:14:23 -07:00
Benjamin Goering 818c09a9b8 Edit window is now 30s instead of 5min 2017-05-03 14:06:07 -07:00
Benjamin Goering c8e7ec6cbf streamQuery reduces editComment mutations to reflect edits without contacting server 2017-05-03 13:35:51 -07:00
riley d02c82d0cd Merge branch 'master' into admin-queue-polish 2017-05-03 14:25:46 -06:00
riley 26ebdde244 Merge branch 'master' into user-detail-ui 2017-05-03 14:25:40 -06:00
Riley Davis 1cecad4d32 action_type must be passed to the load more query 2017-05-03 14:13:58 -06:00
Belén Curcio 64c79cf5f2 Merge branch 'master' into config-embed 2017-05-03 16:52:30 -03:00
Riley Davis 6b4505fa3d Merge branch 'master' into flag-queue-loadmore 2017-05-03 13:42:25 -06:00
Riley Davis f03c87c26d Merge pull request #561 from coralproject/like-fix
Removed LikeAction from core typeName interface resolver
2017-05-03 13:42:01 -06:00
riley c15c312c2c typo 2017-05-03 13:35:33 -06:00
Benjamin Goering ae3cbe990b Edit Comment UI reflects expired edit comment window 2017-05-03 12:34:22 -07:00
Wyatt Johnson d9a4653484 Removed LikeAction from core typeName interface resolver 2017-05-03 13:31:57 -06:00
Riley Davis e993328dc4 load only flagged comments in mod queue load more 2017-05-03 13:15:29 -06:00
riley 4a42436b7b load user via HOC UserDetail 2017-05-03 12:54:02 -06:00
Belén Curcio 15afce516c Merge pull request #556 from coralproject/coral-plugin-like
Coral Plugin Like
2017-05-03 15:50:09 -03:00
riley 3c6391e741 count should never be less than 0 2017-05-03 12:49:22 -06:00
riley 39bd0eca6f remove pointless change 2017-05-03 12:45:49 -06:00
Belen Curcio 99b3d0021a Linting 2017-05-03 15:45:31 -03:00
Belén Curcio 6716362b08 Merge branch 'master' into config-embed 2017-05-03 15:40:27 -03:00
Belén Curcio 68ea670ecd Merge branch 'master' into FE_Plugin_DOCS 2017-05-03 15:40:14 -03:00
Belen Curcio 13a6ee67e9 Merge branch 'coral-plugin-like' of github.com:coralproject/talk into coral-plugin-like 2017-05-03 15:39:41 -03:00
Belen Curcio 32fb0714ce updated tests 2017-05-03 15:37:56 -03:00
Belén Curcio 7cc8176cc4 Merge branch 'master' into coral-plugin-like 2017-05-03 15:31:04 -03:00
riley 354b51b4fe use a reduce instead 2017-05-03 11:14:21 -06:00
Riley Davis ae52ec983e Merge remote-tracking branch 'origin/admin-queue-polish' into admin-queue-polish 2017-05-03 10:55:43 -06:00
Riley Davis c78e00711a remove if statements 2017-05-03 10:54:52 -06:00
Riley Davis b8ddade518 Merge branch 'master' into admin-queue-polish 2017-05-03 10:28:52 -06:00
Riley Davis 324e82c070 not pretty, but it works 2017-05-03 10:20:03 -06:00
Kim Gardner e6651086d5 Merge pull request #560 from coralproject/bump-version-1-6-0
Bump version to 1.6.0
2017-05-03 12:17:51 -04:00
Kim Gardner 28ea498df2 Bump version to 1.6.0 2017-05-03 12:12:25 -04:00
riley 9e1b470cb5 saving my place 2017-05-03 09:32:05 -06:00
Benjamin Goering b9a3466e2e Edit UI sends editComment mutation, handles errors 2017-05-02 22:07:23 -05:00
riley e60bcb9caf make sure load more on approve/reject queues doesn't cause a bug 2017-05-02 15:58:57 -06:00
Benjamin Goering aa18a433f8 Can't edit comment outside of edit window 2017-05-02 16:47:00 -05:00
riley b7d3113677 apparently you can't make a fragment on RootQuery 2017-05-02 15:18:48 -06:00
Benjamin Goering 756b5f8b45 editComment only allows editing real comments authored by the requesting user 2017-05-02 16:09:09 -05:00
Benjamin Goering 860030a57c Test some editComment state transitions 2017-05-02 15:47:32 -05:00
Benjamin Goering a46773887f Initial working editComment mutation 2017-05-02 14:27:16 -05:00
Belén Curcio ea7888809e Merge branch 'master' into config-embed 2017-05-02 15:47:23 -03:00
Belen Curcio cc0a23c295 Deconstruct plugin config 2017-05-02 15:40:37 -03:00
Belen Curcio b444316e1c Adding debug plugins 2017-05-02 15:31:58 -03:00
Belen Curcio 17128e9a47 Adds redux to handle external config data 2017-05-02 15:18:04 -03:00
Belen Curcio f0c846493a Passing data from script tag, into Talk 2017-05-02 14:51:09 -03:00
Kim Gardner f6e2caf65f Merge branch 'master' into admin-queue-polish 2017-05-02 12:38:48 -04:00
Kim Gardner cdc1835f72 Merge branch 'master' into coral-plugin-like 2017-05-02 12:37:55 -04:00
Kim Gardner 9d2b47f02b Merge pull request #549 from coralproject/count-abbr
format mod queue counts
2017-05-02 12:37:34 -04:00
Benjamin Goering 00a2a65d31 Edit Comment UI 2017-05-01 16:58:24 -05:00
gaba c0fc87ea21 Merge branch 'master' into i18n-refactor 2017-05-01 11:28:06 -07:00
Riley Davis da5e8cda99 Merge branch 'master' into admin-queue-polish 2017-05-01 11:13:13 -06:00
Riley Davis 32dd554331 load more comments if the mod has moderated them all and there are more availabile 2017-05-01 10:30:18 -06:00
Riley Davis 8293408c52 pull some custom code out of ActionButton 2017-05-01 10:22:11 -06:00
Belen Curcio 23a5b236a2 Linting 2017-05-01 12:05:45 -03:00
Belen Curcio b02088e329 Like color 2017-05-01 12:04:14 -03:00
Belen Curcio 1a50b6cc85 Ádding like as a reaction 2017-05-01 12:00:44 -03:00
Belen Curcio f1bebaa627 Merge 2017-05-01 11:54:00 -03:00
Belen Curcio 1250054fb7 Prettier 2017-05-01 11:45:23 -03:00
Belen Curcio f3980a03b2 Removing like from core action summary 2017-05-01 11:44:24 -03:00
Belen Curcio a90802a046 Coral-Plugin-Like 2017-05-01 11:43:59 -03:00
Belen Curcio 400615cc58 Adding translations 2017-05-01 11:43:40 -03:00
David Erwin a94f6220f9 Merge branch 'master' into count-abbr 2017-05-01 10:40:20 -04:00
Belén Curcio c65467fedf Merge branch 'master' into FE_Plugin_DOCS 2017-05-01 11:28:15 -03:00
Belén Curcio f509d29a94 Merge pull request #540 from coralproject/slots-b
Slots
2017-05-01 11:28:02 -03:00
Belen Curcio 8bed64373e Removing LIKE from talk 2017-05-01 11:15:53 -03:00
Belen Curcio 322434f751 Removing LIKE from talk 2017-05-01 11:13:35 -03:00
Belen Curcio 9ee749edb2 Removing LIKE from the core graph 2017-05-01 11:00:37 -03:00
Belen Curcio 5c14ac3f67 Ádding LIKE to the plugin graph 2017-05-01 10:58:29 -03:00
Belen Curcio e1929f148a Removing likes from the core graph 2017-05-01 10:58:14 -03:00
Belen Curcio 717ebf40b7 Adding like plugin to the ignore 2017-05-01 10:56:10 -03:00
Belen Curcio ef40174be9 Adding Coral-Plugin-Like 2017-05-01 10:55:50 -03:00
Belen Curcio 3b819144e0 Merge branch 'slots-b' of github.com:coralproject/talk into slots-b 2017-05-01 10:48:04 -03:00
Belen Curcio c58813cf48 merge 2017-05-01 10:47:56 -03:00
Belen Curcio d14b965f54 Adding fragment slots 2017-05-01 10:46:37 -03:00
Belén Curcio ed88a59ef1 Merge branch 'master' into slots-b 2017-05-01 10:41:21 -03:00
Kim Gardner ffcb1b464f Merge pull request #548 from coralproject/action-count-fix
don't double count no-ops
2017-04-28 15:13:37 -04:00
Kim Gardner fd11cc5249 Merge branch 'master' into action-count-fix 2017-04-28 15:09:44 -04:00
Kim Gardner 9b155833a1 Merge branch 'master' into count-abbr 2017-04-28 15:07:18 -04:00
Kim Gardner 2484141ecf Merge pull request #553 from coralproject/load-more-accepted
enable load more on accepted queue
2017-04-28 15:07:06 -04:00
Kim Gardner 78ea42f34f Merge branch 'master' into load-more-accepted 2017-04-28 15:03:02 -04:00
Kim Gardner 3a1e78579a Merge pull request #554 from coralproject/yarn-fix
Updated yarn.lock
2017-04-28 15:02:48 -04:00
Riley Davis c85596a9bf Merge branch 'master' into load-more-accepted 2017-04-28 12:59:01 -06:00
David Erwin 211a6fd868 Merge branch 'master' into yarn-fix 2017-04-28 14:58:02 -04:00
David Erwin 59b048002b Merge pull request #555 from coralproject/fix-more-reply-count
Fix reply count polling
2017-04-28 14:57:50 -04:00
Kim Gardner 5506481182 Merge branch 'master' into load-more-accepted 2017-04-28 14:57:07 -04:00
Kim Gardner 12e6501d4d Merge branch 'master' into fix-more-reply-count 2017-04-28 14:51:01 -04:00
Kim Gardner 7a53cab2f5 Merge branch 'master' into action-count-fix 2017-04-28 14:44:28 -04:00
Kim Gardner cfbff62d1c Merge pull request #550 from coralproject/losowsky-patch-1
tiny typo that was bugging me
2017-04-28 14:43:41 -04:00
Wyatt Johnson 5d4c813800 removed empty gif 2017-04-28 12:03:29 -06:00
Chi Vinh Le e486d48556 postComment should increase replyCount 2017-04-29 01:02:59 +07:00
Chi Vinh Le 8663aa0cb5 Fix polling reply count 2017-04-29 01:02:11 +07:00
Wyatt Johnson f1e70102d0 Updated yarn.lock 2017-04-28 11:55:28 -06:00
Riley Davis 41d4bd1012 counts update 2017-04-28 11:52:07 -06:00
riley ace3e2398b enable load more on accepted queue 2017-04-28 11:41:03 -06:00
riley 521082eb3e add new query for counts 2017-04-28 11:39:37 -06:00
Riley Davis a6dd03beef Merge branch 'master' into action-count-fix 2017-04-28 10:45:34 -06:00
Riley Davis 7246adc467 Merge branch 'master' into count-abbr 2017-04-28 10:45:27 -06:00
Kim Gardner 4d0b5b7149 Merge branch 'master' into losowsky-patch-1 2017-04-28 11:24:27 -04:00
Kiwi bfb2eb30e2 Merge pull request #552 from coralproject/fix-empty-slot-fragments
Ret empty string when encountering undefined fragment
2017-04-28 22:04:44 +07:00
Chi Vinh Le 5d26f8e3de Ret empty string when encountering undefined fragment 2017-04-28 21:59:02 +07:00
Andrew Losowsky a46c8528e1 tiny typo that was bugging me 2017-04-28 07:19:44 -04:00
Kim Gardner e3d5850af6 Merge branch 'master' into FE_Plugin_DOCS 2017-04-27 18:05:59 -04:00
riley cd9648b251 format mod queue counts 2017-04-27 15:01:59 -06:00
riley 59ddde1856 semi 2017-04-27 14:07:01 -06:00
riley 862355b0cd don't double count no-ops 2017-04-27 14:02:29 -06:00
Kim Gardner 78878b4295 Merge pull request #539 from coralproject/approved-comments-queue
Approved comments queue
2017-04-27 15:28:00 -04:00
Riley Davis b1d4fff929 Merge branch 'master' into approved-comments-queue 2017-04-27 13:12:40 -06:00
riley 8cf11d83c8 Merge branch 'approved-comments-queue' of github.com:coralproject/talk into approved-comments-queue 2017-04-27 13:10:50 -06:00
riley a3ec23c273 mange counts and such for all queue 2017-04-27 13:09:00 -06:00
Kim Gardner af9f143b31 Merge pull request #547 from coralproject/lock-fix
Updated yarn.lock
2017-04-27 15:05:52 -04:00
Wyatt Johnson 48bffdbb3b Updated yarn.lock 2017-04-27 13:00:30 -06:00
Kiwi 8f1448823c Merge pull request #543 from coralproject/no-logic-user-box
Remove embed stream logic from UserBox
2017-04-28 01:07:56 +07:00
Kim Gardner 6a46fb822d Merge branch 'master' into approved-comments-queue 2017-04-27 13:56:15 -04:00
Kiwi b186a74199 Merge branch 'master' into no-logic-user-box 2017-04-28 00:55:50 +07:00
David Erwin e96c5bbc8f Merge pull request #542 from coralproject/optimise-initial-query
Only query once during initial render
2017-04-27 13:53:56 -04:00
David Erwin 06378209a2 Merge branch 'master' into optimise-initial-query 2017-04-27 13:49:12 -04:00
riley f6cede3fda add accepted to propTypes 2017-04-27 11:23:27 -06:00
riley d5b800f590 add accepted rejected aciton buttons 2017-04-27 11:17:53 -06:00
Riley Davis 8cade04431 Merge branch 'master' into approved-comments-queue 2017-04-27 11:07:43 -06:00
David Erwin efda925efc Merge pull request #546 from coralproject/sub-fix
Moved subscription dep to devDeps
2017-04-27 12:53:04 -04:00
Wyatt Johnson ec915208e5 Moved dep to devDeps 2017-04-27 10:48:03 -06:00
Kim Gardner d069cf9d8e Merge branch 'master' into FE_Plugin_DOCS 2017-04-27 11:59:39 -04:00
Kim Gardner af80c4d8ad Merge branch 'master' into approved-comments-queue 2017-04-27 11:59:30 -04:00
Kim Gardner 1de3614fe8 Merge branch 'master' into slots-b 2017-04-27 11:59:23 -04:00
Kim Gardner 663bce2875 Merge branch 'master' into no-logic-user-box 2017-04-27 11:59:08 -04:00
Kim Gardner d0090283c0 Merge pull request #535 from coralproject/report-popup-fix
position the reporting popup in a more reliable way
2017-04-27 11:58:43 -04:00
Chi Vinh Le 8c53bc2d22 Postpone first query until checked login 2017-04-27 22:55:36 +07:00
Kim Gardner f47bd269e5 Merge branch 'master' into report-popup-fix 2017-04-27 11:48:17 -04:00
Kim Gardner 7a99c9358a Merge pull request #533 from coralproject/143530761-remove-loading-when-searching
Only shows the Loading component when there is no search value
2017-04-27 11:47:50 -04:00
Riley Davis 6330d69649 Merge branch 'master' into approved-comments-queue 2017-04-27 09:42:28 -06:00
Kim Gardner 6e98d176e7 Merge branch 'master' into 143530761-remove-loading-when-searching 2017-04-27 11:41:51 -04:00
Kim Gardner 7b84b3daf1 Merge pull request #537 from coralproject/profanity-verbiage
update bad username copy
2017-04-27 11:41:24 -04:00
Riley Davis 40b7669ed8 Merge branch 'master' into approved-comments-queue 2017-04-27 09:40:30 -06:00
Kim Gardner 3bb994c562 Merge branch 'master' into profanity-verbiage 2017-04-27 11:35:47 -04:00
Belén Curcio fab14d896b Merge branch 'master' into FE_Plugin_DOCS 2017-04-27 12:32:20 -03:00
Belén Curcio 9c97d85859 Merge branch 'master' into slots-b 2017-04-27 12:31:07 -03:00
Riley Davis ea8e469c1c Merge branch 'master' into report-popup-fix 2017-04-27 09:28:00 -06:00
David Erwin 6e3159c7e1 Merge pull request #545 from coralproject/docker-fix
Fixed Dockerfile for regression with yarn
2017-04-27 10:34:26 -04:00
Wyatt Johnson 5559940967 Fixed dockerfile temp, updated yarn.lock 2017-04-27 08:29:16 -06:00
David Erwin 64eb16c3d6 Merge pull request #519 from coralproject/more-fragment-matcher
more matching on the fragment
2017-04-27 10:17:58 -04:00
Belén Curcio f779c5fe01 Merge branch 'master' into no-logic-user-box 2017-04-27 11:12:55 -03:00
David Erwin 6972b87b0b Merge branch 'master' into more-fragment-matcher 2017-04-27 10:10:19 -04:00
Belén Curcio 8c320d09da Merge branch 'master' into optimise-initial-query 2017-04-27 11:04:11 -03:00
David Erwin 279ff0655f Merge pull request #544 from coralproject/login-ios-safari
More reliable login support including IOS browsers
2017-04-27 10:03:29 -04:00
Chi Vinh Le 794cc0fc6c Support login on all IOS browsers 2017-04-27 19:28:54 +07:00
Chi Vinh Le 7b16a71e9b Remove embed stream logic from UserBox 2017-04-27 18:20:55 +07:00
Chi Vinh Le 20b4c4e2d0 Only query once during initial render 2017-04-27 17:30:43 +07:00
Belen Curcio 37e093f60a Linting 2017-04-26 23:15:40 -03:00
Belen Curcio de6492a26d Ádding reactions, commentContent and updating current Slot 2017-04-26 23:06:09 -03:00
Belen Curcio c60db41047 Updating slot name 2017-04-26 23:04:22 -03:00
Belen Curcio 00fe4b7c83 Úpdating slot names 2017-04-26 23:03:51 -03:00
Belen Curcio e0b177d955 Updated slot name 2017-04-26 23:02:09 -03:00
Belen Curcio 29e398c51d Rename Slot to commentInputDetailArea in Coral Plugin Offtopic 2017-04-26 22:37:37 -03:00
Belen Curcio 3dd2da96e8 Adding Slots to QuestionBox, ref 2017-04-26 22:35:30 -03:00
Belen Curcio 1fea1405ef Adding Slots, CommentBox ref 2017-04-26 22:34:38 -03:00
Belen Curcio 9fa3e361b5 Ref Stream 2017-04-26 22:34:17 -03:00
Belen Curcio 06ba5a53c1 Stateless Slot 2017-04-26 22:33:49 -03:00
David Erwin bb532b5eb2 Merge pull request #531 from coralproject/shortcuts-in-cog
shortcuts list should be accessible from the cog
2017-04-26 17:41:04 -04:00
David Erwin 5eb26946cb Merge branch 'master' into profanity-verbiage 2017-04-26 17:21:34 -04:00
David Erwin 81680442f0 Merge branch 'master' into shortcuts-in-cog 2017-04-26 17:20:37 -04:00
David Erwin c86f9877f3 Merge pull request #534 from coralproject/143202319-mod-queue-shortcuts
Recover the scroll.
2017-04-26 17:20:17 -04:00
David Erwin 1b3868edec Merge branch 'master' into 143202319-mod-queue-shortcuts 2017-04-26 17:13:46 -04:00
David Erwin 4936003f5f Merge pull request #536 from coralproject/fix-case
make Comment comment
2017-04-26 17:13:28 -04:00
David Erwin 5c4696ed61 Merge branch 'master' into fix-case 2017-04-26 17:08:56 -04:00
David Erwin bf898fbaec Merge pull request #460 from coralproject/subscriptions
Subscriptions
2017-04-26 17:05:58 -04:00
David Erwin 41065ba24a Merge branch 'master' into subscriptions 2017-04-26 17:01:27 -04:00
David Erwin 0e77c93ae5 Merge pull request #521 from coralproject/user-metadata
Added user metadata
2017-04-26 17:01:15 -04:00
David Erwin 2756b794ee Merge branch 'master' into more-fragment-matcher 2017-04-26 16:57:37 -04:00
David Erwin 626f5cd1e1 Merge branch 'master' into user-metadata 2017-04-26 16:56:50 -04:00
David Erwin 077daeb793 Merge branch 'master' into subscriptions 2017-04-26 16:55:32 -04:00
Riley Davis fc567e8a92 Merge branch 'master' into shortcuts-in-cog 2017-04-26 13:34:13 -06:00
gaba 60d2735fa5 Remove isfetching all together. 2017-04-26 14:26:22 -05:00
gaba 6f58754617 Removing the Loading all together. 2017-04-26 14:26:21 -05:00
Gabriela Rodríguez Berón e935fff8ac Merge branch 'master' into 143530761-remove-loading-when-searching 2017-04-26 12:52:30 -05:00
Gabriela Rodríguez Berón 3ad8d9ffec Merge branch 'master' into 143202319-mod-queue-shortcuts 2017-04-26 12:51:30 -05:00
Riley Davis 0df40c7e35 make the popup not full width like before 2017-04-26 11:50:17 -06:00
Riley Davis a793d63f65 Merge branch 'master' into profanity-verbiage 2017-04-26 11:45:20 -06:00
Riley Davis ccc512cddd if there is no available translation, do not show error.whatever in the UI 2017-04-26 11:43:34 -06:00
Benjamin Goering 84016e362d Delete Comment UI 2017-04-26 12:37:33 -05:00
David Erwin e20b6e1b25 Merge branch 'master' into fix-case 2017-04-26 13:19:50 -04:00
Riley Davis 4ff37d9063 Merge branch 'master' into approved-comments-queue 2017-04-26 11:01:41 -06:00
David Erwin c02890af00 Merge pull request #526 from coralproject/query-composition
Query composition
2017-04-26 12:58:51 -04:00
Benjamin Goering add7bfc170 Remove commented out css from TopRightMenu.css 2017-04-26 10:33:24 -05:00
Riley Davis cea0b4942a prevent text overflow 2017-04-26 09:32:00 -06:00
Riley Davis 4ddaca7655 español 2017-04-26 09:20:23 -06:00
Riley Davis 03e0c62b72 accepted => approved 2017-04-26 08:45:37 -06:00
Riley Davis a21d73dcad accepted queue 2017-04-26 08:26:29 -06:00
Kiwi b20d8c18a3 Merge branch 'master' into report-popup-fix 2017-04-26 21:22:23 +07:00
David Erwin 85674b3ef5 Merge branch 'master' into query-composition 2017-04-26 10:09:14 -04:00
David Erwin 80f695e23d Merge branch 'master' into profanity-verbiage 2017-04-26 09:53:19 -04:00
Chi Vinh Le d56c35ea64 Merge branch 'master' into query-composition 2017-04-26 19:28:46 +07:00
riley 0807663965 add z-index to popup 2017-04-25 16:31:33 -06:00
riley f296fe2abd update bad username copy 2017-04-25 16:22:31 -06:00
Kim Gardner 2654e3d452 Merge branch 'master' into user-metadata 2017-04-25 18:21:45 -04:00
riley aad66ec7e0 fix casing 2017-04-25 16:18:21 -06:00
Riley Davis 7db5e4d68b Merge branch 'master' into report-popup-fix 2017-04-25 16:14:56 -06:00
riley f3822d09b2 position the reporting popup in a more reliable way 2017-04-25 15:54:18 -06:00
gaba 9e41f0bd65 Merge branch 'master' into i18n-refactor 2017-04-25 16:10:45 -05:00
gaba 527cbc7d63 Recover the scroll. 2017-04-25 16:10:32 -05:00
Gabriela Rodríguez Berón 9e35b7b39f Merge branch 'master' into 143202319-mod-queue-shortcuts 2017-04-25 16:10:23 -05:00
gaba 33d71df049 Recover the scroll. 2017-04-25 15:52:52 -05:00
gaba 10cd53b40b Only shows the Loading component when there is no search value 2017-04-25 14:28:37 -05:00
Chi Vinh Le cb5228a423 Document getSlotFragments 2017-04-26 01:58:07 +07:00
Kim Gardner bd91f898f5 Merge branch 'master' into FE_Plugin_DOCS 2017-04-25 14:54:29 -04:00
Kim Gardner 4f70a24a32 Merge branch 'master' into subscriptions 2017-04-25 14:54:07 -04:00
Kim Gardner 62835acc76 Merge branch 'master' into user-metadata 2017-04-25 14:53:30 -04:00
Riley Davis a94e6a0ada have default...just in case 2017-04-25 12:40:28 -06:00
Riley Davis 89f0663723 shortcuts list should be accessible from the cog 2017-04-25 12:38:00 -06:00
Chi Vinh Le eb9846ba40 Merge branch 'master' into query-composition
Conflicts:
	client/coral-embed-stream/src/Embed.js
	client/coral-embed-stream/src/Stream.js
2017-04-26 01:22:14 +07:00
Chi Vinh Le 9d7524644c Merge branch 'master' into query-composition 2017-04-26 01:11:07 +07:00
Chi Vinh Le f142f3a27f Introduce separateDataAndRoot 2017-04-26 01:10:16 +07:00
Chi Vinh Le df2c33ac35 Introduce getDefinitionName 2017-04-26 01:07:07 +07:00
Chi Vinh Le f79af56468 Better API for slot fragments 2017-04-26 00:44:02 +07:00
gaba 0f7b4ddaf6 Removes timeago from i18n module. 2017-04-25 11:43:04 -05:00
Chi Vinh Le 15d410ba12 Workaround weird Apollo bug 2017-04-25 23:20:23 +07:00
Chi Vinh Le 3a7b17750e Use unique name for fragment 2017-04-25 23:00:11 +07:00
Chi Vinh Le 4bacc2b0c2 Update Apollo 2017-04-25 22:31:59 +07:00
Chi Vinh Le 3d10534da1 RespectPlugin use fat query 2017-04-25 19:54:54 +07:00
Chi Vinh Le 54ea71bedf Support fragments in plugins 2017-04-25 18:24:25 +07:00
gaba 59e23ffd60 Moves into YAML and own module. 2017-04-24 18:09:13 -05:00
Belén Curcio 7d56404e84 Merge branch 'master' into subscriptions 2017-04-24 18:09:34 -03:00
gaba 5aacdc3a74 Merge branch 'master' into i18n-refactor 2017-04-24 12:56:32 -05:00
Chi Vinh Le 027358913d Use container 2017-04-24 23:35:49 +07:00
Chi Vinh Le a91db35f91 Add comments for filter 2017-04-24 23:34:53 +07:00
Chi Vinh Le c261cdc0c6 Compose comment fragments 2017-04-24 22:49:52 +07:00
gaba 05bf21fe09 Refactoring 2017-04-24 10:08:33 -05:00
Chi Vinh Le 11fb5421b5 Implement Stream Container 2017-04-24 19:27:54 +07:00
Chi Vinh Le 4dc3b0c2f4 Merge branch 'master' into query-composition-2
Conflicts:
	client/coral-embed-stream/src/Embed.js
	client/coral-embed-stream/src/components/Comment.js
	client/coral-embed-stream/src/index.js
	client/coral-framework/services/store.js
	client/coral-settings/containers/ProfileContainer.js
	graph/resolvers/root_query.js
2017-04-24 15:24:34 +07:00
Belen Curcio f18191793b fe plugins 2017-04-23 13:09:52 -03:00
Gabriela Rodríguez Berón e337a0d18b Merge branch 'master' into subscriptions 2017-04-21 14:35:21 -07:00
Wyatt Johnson 441ea12a65 Added user metadata 2017-04-21 15:22:52 -06:00
Riley Davis 387e52b510 Merge branch 'master' into more-fragment-matcher 2017-04-21 12:56:47 -06:00
Riley Davis 2a2a069cea more matching on the fragment 2017-04-21 12:50:29 -06:00
Wyatt Johnson b559b81198 Removed some demo code 2017-04-20 15:20:07 -06:00
Wyatt Johnson 1f562c8fad Merge branch 'master' into subscriptions 2017-04-20 15:17:44 -06:00
Chi Vinh Le 3cd9e802dd WIP 2017-04-20 00:37:45 +07:00
Chi Vinh Le 34fee9439f Move active tab to redux 2017-04-19 23:26:26 +07:00
Chi Vinh Le 0e6b0c01fd Fix issue with ignoredUsers 2017-04-19 21:06:57 +07:00
Chi Vinh Le 6fb2a95bf2 Move query logic to coral-embed-stream 2017-04-19 20:28:14 +07:00
Chi Vinh Le d5d424bfc5 Merge branch 'master' into embed-refactor 2017-04-19 16:16:14 +07:00
Wyatt Johnson ecbb66e270 Fix linting 2017-04-18 15:53:15 -06:00
Wyatt Johnson 45094fd176 Optimized sub model 2017-04-18 15:48:33 -06:00
Wyatt Johnson e1c8e75405 Merge branch 'master' into subscriptions 2017-04-18 15:43:25 -06:00
Chi Vinh Le e9331e90d3 Add missing check 2017-04-19 01:07:49 +07:00
Chi Vinh Le d3b81dff35 Merge branch 'master' into embed-refactor
Conflicts:
	client/coral-plugin-commentbox/CommentBox.js
2017-04-19 00:18:50 +07:00
Chi Vinh Le af5be0469f Refactor embed 2017-04-18 23:20:39 +07:00
Chi Vinh Le b40eed4751 Move to components folder 2017-04-18 23:14:28 +07:00
Wyatt Johnson 7fac8ef073 Merge branch 'master' into subscriptions 2017-04-17 08:03:14 -06:00
Wyatt Johnson 9f8c9c7eb1 Merge branch 'master' into subscriptions 2017-04-12 10:37:15 -06:00
David Erwin ab74ebdc52 Merge branch 'master' into subscriptions 2017-04-11 11:58:55 -04:00
Wyatt Johnson 97e3d7220e Removed test code 2017-04-10 14:39:50 -06:00
Wyatt Johnson 7acaaadcd6 Merge branch 'master' into subscriptions 2017-04-10 14:33:08 -06:00
Wyatt Johnson c12660be3b Merge branch 'master' into subscriptions 2017-04-06 15:39:24 -06:00
Wyatt Johnson ffb0ee20e8 Cleanup of subscriptions 2017-04-05 16:15:22 -06:00
Wyatt Johnson e6dba11984 Merge branch 'master' into subscriptions 2017-04-05 15:31:08 -06:00
David Erwin b335cb3493 Document subscription plugins 2017-04-05 17:26:12 -04:00
David Erwin 6735296c3c Abstract setupFunctions 2017-04-05 17:07:14 -04:00
David Erwin 350d9e74f2 Get plugin setupFuncitons for subscriptions 2017-04-05 16:56:32 -04:00
Wyatt Johnson b3582025b7 Fixed import 2017-04-05 13:37:32 -06:00
Wyatt Johnson 3c91b9cda1 Merge branch 'master' into subscriptions 2017-04-05 13:36:57 -06:00
Wyatt Johnson 1fecd4589b Removed unused file 2017-04-05 09:55:15 -06:00
David Erwin 48b7a67665 Add comments 2017-04-05 11:24:52 -04:00
Wyatt Johnson 45c7cbad9e Merge branch 'master' into subscriptions 2017-04-05 08:08:56 -06:00
Wyatt Johnson 75c88df8f1 Fix for build 2017-04-04 10:12:25 -06:00
Wyatt Johnson 07d1f9d3cf Merge branch 'master' into subscriptions 2017-04-04 09:58:50 -06:00
Wyatt Johnson dd3d1e9fe7 fix for session service 2017-03-29 12:45:57 -06:00
Wyatt Johnson ffbe976760 working websockets 2017-03-29 09:35:56 -06:00
Wyatt Johnson 0e0c3f19aa Fixed tests 2017-03-23 11:11:57 -06:00
Wyatt Johnson 63ef49d595 Initial subscription impl 2017-03-23 11:09:14 -06:00
616 changed files with 29251 additions and 9429 deletions
+7
View File
@@ -1,7 +1,14 @@
dist
docs
client/lib
**/*.html
plugins/*
!plugins/coral-plugin-facebook-auth
!plugins/coral-plugin-auth
!plugins/coral-plugin-respect
!plugins/coral-plugin-offtopic
!plugins/coral-plugin-like
!plugins/coral-plugin-mod
!plugins/coral-plugin-love
!plugins/coral-plugin-viewing-options
node_modules
+7
View File
@@ -20,6 +20,8 @@
"no-template-curly-in-string": [1],
"no-unsafe-negation": [1],
"array-callback-return": [1],
"arrow-parens": ["warn", "always"],
"template-curly-spacing": "warn",
"eqeqeq": [2, "smart"],
"no-eval": [2],
"no-global-assign": [2],
@@ -36,6 +38,11 @@
"no-unneeded-ternary": [1],
"object-curly-spacing": [1],
"space-infix-ops": ["error"],
"space-in-parens": ["error", "never"],
"space-unary-ops": ["error", {
"words": true,
"nonwords": false
}],
"no-const-assign": [2],
"no-duplicate-imports": [2],
"prefer-template": [1],
+5
View File
@@ -17,7 +17,12 @@ coverage/
plugins.json
plugins/*
!plugins/coral-plugin-facebook-auth
!plugins/coral-plugin-auth
!plugins/coral-plugin-respect
!plugins/coral-plugin-offtopic
!plugins/coral-plugin-like
!plugins/coral-plugin-mod
!plugins/coral-plugin-love
!plugins/coral-plugin-viewing-options
**/node_modules/*
+2 -1
View File
@@ -13,7 +13,8 @@ EXPOSE 5000
COPY . /usr/src/app
# Install app dependencies and build static assets.
RUN yarn install --frozen-lockfile && \
RUN yarn global add node-gyp && \
yarn install --frozen-lockfile && \
cli plugins reconcile && \
yarn build && \
yarn install --production && \
+1 -1
View File
@@ -243,7 +243,7 @@ file under the `scripts` key including:
# Setup
Once you've installed Talk (either via Docker or source), you still need to
setup the application. If you are unfamiliar with any terminoligy used in the
setup the application. If you are unfamiliar with any terminology used in the
setup process, refer to the `TERMINOLOGY.md` document.
## Via Web
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright 2016 Mozilla Foundation
Copyright 2017 Mozilla Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+67
View File
@@ -145,6 +145,10 @@ type RootMutation {
type RootQuery {
people: [Person!]
}
type Subscription {
leader: Person
}
```
Thanks to [gql-merge](https://www.npmjs.com/package/gql-merge) the contents of
@@ -259,6 +263,58 @@ If your post function accepts four parameters, then it can modify the field
result. It is *required* that the function resolves a promise (or returns) with
the modified value or simply the original if you didn't modify it.
#### Field: `setupFunctions`
```js
setupFunctions: {
leader: (options, args) => ({
leader: {
filter: (person) => person.place === 1
},
}),
}
```
Setup functions allow you to create filters that control which pubsub.publish() events
send data to the client. If the type in question contains args, clients may subscribe using those arguments to further filter their subscription.
For more information, see the [Apollo Docs](https://github.com/apollographql/graphql-subscriptions).
#### Field: `tokenUserNotFound`
```js
tokenUserNotFound: async ({jwt, token}) => {
let profile = await someExternalService(token);
if (!profile) {
return null;
}
let user = await UserModel.findOneAndUpdate({
id: profile.id
}, {
id: profile.id,
username: profile.username,
lowercaseUsername: profile.username.toLowerCase(),
roles: [],
profiles: []
}, {
setDefaultsOnInsert: true,
new: true,
upsert: true
});
return user;
}
```
The `tokenUserNotFound` hook allows auth integrations to hook into the event
when a valid token is provided but a user can't be found in the database that
matches the provided id.
The function is async, and should return the user object that was created in the
database, or null if the user wasn't found. The `jwt` paramenter of the object
is the unpacked token, while `token` is the original jwt token string.
#### Field: `router`
```js
@@ -375,6 +431,10 @@ module.exports = {
type RootQuery {
people: [Person!]
}
type Subscription {
leader: Person
}
`,
context: {
Slack: () => ({
@@ -430,6 +490,13 @@ module.exports = {
}
}
}
},
setupFunctions: {
leader: (options, args) => ({
leader: {
filter: (person) => person.place === 1
}
}
}
};
+50 -6
View File
@@ -1,6 +1,6 @@
# Talk [![CircleCI](https://circleci.com/gh/coralproject/talk.svg?style=svg)](https://circleci.com/gh/coralproject/talk)
Talk is currently in Beta! [Read more about Talk here.](https://coralproject.net/products/talk.html)
Online comments are broken. Our open-source Talk tool rethinks how moderation, comment display, and conversation function, creating the opportunity for safer, smarter discussions around your work. [Read more about Talk here.](https://coralproject.net/products/talk.html)
Third party licenses are available via the `/client/3rdpartylicenses.txt`
endpoint when the server is running with built assets.
@@ -17,17 +17,19 @@ To set up a development environment or build from source, see [INSTALL.md](https
To launch a Talk server of your own from your browser without any need to muck about in a terminal or think about engineering concepts, stay tuned. We will launch [our installer](https://github.com/coralproject/talk-install) shortly!
### Configuration
The Talk application looks for the following configuration values either as environment variables:
- `TALK_MONGO_URL` (*required*) - the database connection string for the MongoDB database.
- `TALK_REDIS_URL` (*required*) - the database connection string for the Redis database.
- `TALK_SESSION_SECRET` (*required*) - a random string which will be used to
secure cookies.
- `TALK_ROOT_URL` (*required*) - root url of the installed application externally
available in the format: `<scheme>://<host>` without the path.
- `TALK_JWT_SECRET` (*required*) - a long and cryptographical secure random string which will be used to
sign and verify tokens via a `HS256` algorithm.
- `TALK_JWT_EXPIRY` (_optional_) - the expiry duration (`exp`) for the tokens issued for logged in sessions (Default `1 day`)
- `TALK_JWT_ISSUER` (_optional_) - the issuer (`iss`) claim for login JWT tokens (Default `process.env.TALK_ROOT_URL`)
- `TALK_JWT_AUDIENCE` (_optional_) - the audience (`aud`) claim for login JWT tokens (Default `talk`)
- `TALK_SMTP_EMAIL` (*required for email*) - the address to send emails from using the
SMTP provider.
- `TALK_SMTP_USERNAME` (*required for email*) - username of the SMTP provider you are using.
@@ -42,9 +44,51 @@ available in the format: `<scheme>://<host>` without the path.
Refer to the wiki page on [Configuration Loading](https://github.com/coralproject/talk/wiki/Configuration-Loading) for
alternative methods of loading configuration during development.
### License
### Using Trust
Copyright 2016 Mozilla Foundation
Talk ships with core components we call "Trust". This allows Talk to automate certain actions based on previous user behavior.
Our first feature is the notion of Karma. Talk will automatically pre-moderate comments of users who have a negative karma score. You can [see more how karma works here](/services/karma.js).
## Supported Browsers
### Web
- Chrome: latest 2 versions
- Firefox: latest 2 versions, and most recent extended support version, if any
- Safari: latest 2 versions
- Internet Explorer: IE Edge, 11
### iOS Devices
- iPad
- iPad Pro
- iPhone 7 Plus
- iPhone 7
- iPhone 6 Plus
- iPhone 6
- iPhone 5
### iOS Browsers
- Chrome for iOS: latest version
- Firefox for iOS: latest version
- Safari for iOS: latest version
### Android Devices
- Galaxy S5
- Nexus 5X
- Nexus 6P
### Android Browsers
- Chrome for Android: latest version
- Firefox for Android: latest version
## License
Copyright 2017 Mozilla Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+46 -61
View File
@@ -3,16 +3,17 @@ const bodyParser = require('body-parser');
const morgan = require('morgan');
const path = require('path');
const helmet = require('helmet');
const authentication = require('./middleware/authentication');
const {passport} = require('./services/passport');
const plugins = require('./services/plugins');
const session = require('express-session');
const i18n = require('./services/i18n');
const enabled = require('debug').enabled;
const RedisStore = require('connect-redis')(session);
const redis = require('./services/redis');
const csrf = require('csurf');
const errors = require('./errors');
const graph = require('./graph');
const {createGraphOptions} = require('./graph');
const apollo = require('graphql-server-express');
const accepts = require('accepts');
const compression = require('compression');
const cookieParser = require('cookie-parser');
const app = express();
@@ -33,44 +34,44 @@ app.set('trust proxy', 1);
app.use(helmet({
frameguard: false
}));
app.use(compression());
app.use(cookieParser());
app.use(bodyParser.json());
app.use('/client', express.static(path.join(__dirname, 'dist')));
app.use('/public', express.static(path.join(__dirname, 'public')));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
//==============================================================================
// SESSION MIDDLEWARE
// STATIC FILES
//==============================================================================
const session_opts = {
secret: process.env.TALK_SESSION_SECRET,
httpOnly: true,
rolling: true,
saveUninitialized: true,
resave: true,
unset: 'destroy',
name: 'talk.sid',
cookie: {
secure: false,
maxAge: 8.64e+7, // 24 hours for session token expiry
},
store: new RedisStore({
client: redis.createClient(),
})
};
// If the application is in production mode, then add gzip rewriting for the
// content.
if (process.env.NODE_ENV === 'production') {
app.get('*.js', (req, res, next) => {
const accept = accepts(req);
if (accept.encoding(['gzip']) === 'gzip') {
if (app.get('env') === 'production') {
// Adjsut the headers on the request by adding a content type header
// because express won't be able to detect the mime-type with the .gz
// extension and we need to decalre support for the gzip encoding.
res.set('Content-Type', 'application/javascript');
res.set('Content-Encoding', 'gzip');
// Enable the secure cookie when we are in production mode.
session_opts.cookie.secure = true;
} else if (app.get('env') === 'test') {
// Rewrite the url so that the gzip version will be served instead.
req.url = `${req.url}.gz`;
}
// Add in the secret during tests.
session_opts.secret = 'keyboard cat';
next();
});
}
app.use(session(session_opts));
app.use('/client', express.static(path.join(__dirname, 'dist')));
app.use('/public', express.static(path.join(__dirname, 'public')));
//==============================================================================
// VIEW CONFIGURATION
//==============================================================================
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
//==============================================================================
// PASSPORT MIDDLEWARE
@@ -89,22 +90,27 @@ plugins.get('server', 'passport').forEach((plugin) => {
// Setup the PassportJS Middleware.
app.use(passport.initialize());
app.use(passport.session());
// Attach the authentication middleware, this will be responsible for decoding
// (if present) the JWT on the request.
app.use('/api', authentication);
//==============================================================================
// GraphQL Router
//==============================================================================
// GraphQL endpoint.
app.use('/api/v1/graph/ql', apollo.graphqlExpress(graph.createGraphOptions));
app.use('/api/v1/graph/ql', apollo.graphqlExpress(createGraphOptions));
// Only include the graphiql tool if we aren't in production mode.
if (app.get('env') !== 'production') {
// Interactive graphiql interface.
app.use('/api/v1/graph/iql', apollo.graphiqlExpress({
endpointURL: '/api/v1/graph/ql'
}));
app.use('/api/v1/graph/iql', (req, res) => {
res.render('graphiql', {
endpointURL: '/api/v1/graph/ql'
});
});
// GraphQL documention.
app.get('/admin/docs', (req, res) => {
@@ -113,29 +119,6 @@ if (app.get('env') !== 'production') {
}
//==============================================================================
// CSRF MIDDLEWARE
//==============================================================================
if (process.env.TEST_MODE === 'unit') {
// Add this fake test token in the event we are in unit test mode, and don't
// include the CSRF protection.
app.locals.csrfToken = 'UNIT_TESTS';
} else {
// Setup route middlewares for CSRF protection.
// Default ignore methods are GET, HEAD, OPTIONS
app.use(csrf({}));
app.use((req, res, next) => {
res.locals.csrfToken = req.csrfToken();
next();
});
}
//==============================================================================
// ROUTES
//==============================================================================
@@ -175,6 +158,8 @@ app.use('/', (err, req, res, next) => {
console.error(err);
}
i18n.init(req);
if (err instanceof errors.APIError) {
res.status(err.status);
res.render('error', {
+1 -1
View File
@@ -5,7 +5,7 @@
*/
const program = require('./commander');
const parseDuration = require('parse-duration');
const parseDuration = require('ms');
const Table = require('cli-table');
const AssetModel = require('../models/asset');
const mongoose = require('../services/mongoose');
+24 -11
View File
@@ -1,26 +1,29 @@
#!/usr/bin/env node
const app = require('../app');
const program = require('./commander');
const http = require('http');
const app = require('../app');
const {createServer} = require('http');
const scraper = require('../services/scraper');
const mailer = require('../services/mailer');
const kue = require('../services/kue');
const mongoose = require('../services/mongoose');
const util = require('./util');
const {createSubscriptionManager} = require('../graph/subscriptions');
const {
PORT
} = require('../config');
/**
* Get port from environment and store in Express.
*/
const port = normalizePort(process.env.TALK_PORT || '3000');
const port = normalizePort(PORT);
app.set('port', port);
/**
* Create HTTP server.
*/
const server = http.createServer(app);
const server = createServer(app);
/**
* Event listener for HTTP server "error" event.
@@ -76,20 +79,29 @@ function normalizePort(val) {
function onListening() {
let addr = server.address();
let bind = typeof addr === 'string'
? `pipe ${ addr}`
: `port ${ addr.port}`;
console.log(`Listening on ${ bind}`);
? `pipe ${addr}`
: `port ${addr.port}`;
console.log(`API Server Listening on ${bind}`);
}
/**
* Start the app.
*/
function startApp() {
function startApp(program) {
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.listen(port, () => {
// Mount the websocket server if requested.
if (program.websockets) {
console.log(`Websocket Server Listening on ${port}`);
// Mount the subscriptions server on the application server.
createSubscriptionManager(server);
}
});
server.on('error', onError);
server.on('listening', onListening);
}
@@ -100,10 +112,11 @@ function startApp() {
program
.option('-j, --jobs', 'enable job processing on this thread')
.option('-w, --websockets', 'enable the websocket (subscriptions) handler on this thread')
.parse(process.argv);
// Start the application serving.
startApp();
startApp(program);
// Enable job processing on the thread if enabled.
if (program.jobs) {
-5
View File
@@ -3,11 +3,6 @@ const dotenv = require('dotenv');
const fs = require('fs');
const program = require('commander');
// Perform rewrites to the runtime environment variables based on the contents
// of the process.env.REWRITE_ENV if it exists. This is done here as it is the
// entrypoint for the entire application.
require('env-rewrite').rewrite();
//==============================================================================
// Setting up the program command line arguments.
//==============================================================================
+5 -6
View File
@@ -4,21 +4,20 @@
"es6": true,
"mocha": true
},
"extends": "../.eslintrc.json",
"parserOptions": {
"sourceType": "module",
"ecmaFeatures": {
"experimentalObjectRestSpread": true,
"jsx": true
},
"sourceType": "module"
}
},
"parser": "babel-eslint",
"plugins": [
"react"
],
"rules": {
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
"no-console": ["warn", { "allow": ["warn", "error"] }]
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
"no-console": ["warn", { "allow": ["warn", "error"] }]
}
}
-3
View File
@@ -1,3 +0,0 @@
{
"basePath": "admin"
}
+27 -29
View File
@@ -1,25 +1,20 @@
import React from 'react';
import {Router, Route, IndexRoute, IndexRedirect, browserHistory} from 'react-router';
import {Router, Route, IndexRedirect, browserHistory} from 'react-router';
import Stories from 'containers/Stories/Stories';
import Configure from 'containers/Configure/Configure';
import LayoutContainer from 'containers/LayoutContainer';
import InstallContainer from 'containers/Install/InstallContainer';
import Configure from 'routes/Configure';
import Dashboard from 'routes/Dashboard';
import Install from 'routes/Install';
import Stories from 'routes/Stories';
import {CommunityLayout, Community} from 'routes/Community';
import {ModerationLayout, Moderation} from 'routes/Moderation';
import CommunityLayout from 'containers/Community/CommunityLayout';
import CommunityContainer from 'containers/Community/CommunityContainer';
import ModerationLayout from 'containers/ModerationQueue/ModerationLayout';
import ModerationContainer from 'containers/ModerationQueue/ModerationContainer';
import Dashboard from 'containers/Dashboard/Dashboard';
import Layout from 'containers/Layout';
const routes = (
<div>
<Route exact path="/admin/install" component={InstallContainer}/>
<Route path='/admin' component={LayoutContainer}>
<IndexRoute component={Dashboard} />
<Route path='community' component={CommunityContainer} />
<Route exact path="/admin/install" component={Install}/>
<Route path='/admin' component={Layout}>
<IndexRedirect to='/admin/moderate/all' />
<Route path='configure' component={Configure} />
<Route path='stories' component={Stories} />
<Route path='dashboard' component={Dashboard} />
@@ -27,11 +22,11 @@ const routes = (
{/* Community Routes */}
<Route path='community' component={CommunityLayout}>
<Route path='flagged' components={CommunityContainer}>
<Route path=':id' components={CommunityContainer} />
<Route path='flagged' components={Community}>
<Route path=':id' components={Community} />
</Route>
<Route path='people' components={CommunityContainer}>
<Route path=':id' components={CommunityContainer} />
<Route path='people' components={Community}>
<Route path=':id' components={Community} />
</Route>
<IndexRedirect to='flagged' />
</Route>
@@ -39,19 +34,22 @@ const routes = (
{/* Moderation Routes */}
<Route path='moderate' component={ModerationLayout}>
<Route path='all' components={ModerationContainer}>
<Route path=':id' components={ModerationContainer} />
<Route path='all' components={Moderation}>
<Route path=':id' components={Moderation} />
</Route>
<Route path='premod' components={ModerationContainer}>
<Route path=':id' components={ModerationContainer} />
<Route path='accepted' components={Moderation}>
<Route path=':id' components={Moderation} />
</Route>
<Route path='rejected' components={ModerationContainer}>
<Route path=':id' components={ModerationContainer} />
<Route path='premod' components={Moderation}>
<Route path=':id' components={Moderation} />
</Route>
<Route path='flagged' components={ModerationContainer}>
<Route path=':id' components={ModerationContainer} />
<Route path='rejected' components={Moderation}>
<Route path=':id' components={Moderation} />
</Route>
<Route path=':id' components={ModerationContainer} />
<Route path='flagged' components={Moderation}>
<Route path=':id' components={Moderation} />
</Route>
<Route path=':id' components={Moderation} />
<IndexRedirect to='premod' />
</Route>
</Route>
+4 -4
View File
@@ -8,7 +8,7 @@ import {
UPDATE_ASSETS
} from '../constants/assets';
import coralApi from '../../../coral-framework/helpers/response';
import coralApi from '../../../coral-framework/helpers/request';
/**
* Action disptacher related to assets
@@ -24,7 +24,7 @@ export const fetchAssets = (skip = '', limit = '', search = '', sort = '', filte
assets: result,
count
}))
.catch(error => dispatch({type: FETCH_ASSETS_FAILURE, error}));
.catch((error) => dispatch({type: FETCH_ASSETS_FAILURE, error}));
};
// Update an asset state
@@ -34,9 +34,9 @@ export const updateAssetState = (id, closedAt) => (dispatch) => {
return coralApi(`/assets/${id}/status`, {method: 'PUT', body: {closedAt}})
.then(() =>
dispatch({type: UPDATE_ASSET_STATE_SUCCESS}))
.catch(error => dispatch({type: UPDATE_ASSET_STATE_FAILURE, error}));
.catch((error) => dispatch({type: UPDATE_ASSET_STATE_FAILURE, error}));
};
export const updateAssets = assets => dispatch => {
export const updateAssets = (assets) => (dispatch) => {
dispatch({type: UPDATE_ASSETS, assets});
};
+77 -38
View File
@@ -1,75 +1,114 @@
import bowser from 'bowser';
import * as actions from '../constants/auth';
import coralApi from 'coral-framework/helpers/response';
import coralApi from 'coral-framework/helpers/request';
import * as Storage from 'coral-framework/helpers/storage';
import {handleAuthToken} from 'coral-framework/actions/auth';
// Log In.
export const handleLogin = (email, password, recaptchaResponse) => dispatch => {
//==============================================================================
// SIGN IN
//==============================================================================
export const handleLogin = (email, password, recaptchaResponse) => (dispatch) => {
dispatch({type: actions.LOGIN_REQUEST});
const params = {method: 'POST', body: {email, password}};
const params = {
method: 'POST',
body: {
email,
password
}
};
if (recaptchaResponse) {
params.headers = {'X-Recaptcha-Response': recaptchaResponse};
params.headers = {
'X-Recaptcha-Response': recaptchaResponse
};
}
return coralApi('/auth/local', params)
.then(({user}) => {
.then(({user, token}) => {
if (!user) {
if (!bowser.safari && !bowser.ios) {
Storage.removeItem('token');
}
return dispatch(checkLoginFailure('not logged in'));
}
const isAdmin = !!user.roles.filter(i => i === 'ADMIN').length;
dispatch(checkLoginSuccess(user, isAdmin));
dispatch(handleAuthToken(token));
dispatch(checkLoginSuccess(user));
})
.catch(error => {
.catch((error) => {
if (error.translation_key === 'LOGIN_MAXIMUM_EXCEEDED') {
dispatch({type: actions.LOGIN_MAXIMUM_EXCEEDED, message: error.translation_key});
dispatch({
type: actions.LOGIN_MAXIMUM_EXCEEDED,
message: error.translation_key
});
} else {
dispatch({type: actions.LOGIN_FAILURE, message: error.translation_key});
}
});
};
const forgotPassowordRequest = () => ({type: actions.FETCH_FORGOT_PASSWORD_REQUEST});
const forgotPassowordSuccess = () => ({type: actions.FETCH_FORGOT_PASSWORD_SUCCESS});
const forgotPassowordFailure = () => ({type: actions.FETCH_FORGOT_PASSWORD_FAILURE});
//==============================================================================
// FORGOT PASSWORD
//==============================================================================
export const requestPasswordReset = email => dispatch => {
const forgotPassowordRequest = () => ({
type: actions.FETCH_FORGOT_PASSWORD_REQUEST
});
const forgotPassowordSuccess = () => ({
type: actions.FETCH_FORGOT_PASSWORD_SUCCESS
});
const forgotPassowordFailure = () => ({
type: actions.FETCH_FORGOT_PASSWORD_FAILURE
});
export const requestPasswordReset = (email) => (dispatch) => {
dispatch(forgotPassowordRequest(email));
return coralApi('/account/password/reset', {method: 'POST', body: {email}})
const redirectUri = location.href;
return coralApi('/account/password/reset', {method: 'POST', body: {email, loc: redirectUri}})
.then(() => dispatch(forgotPassowordSuccess()))
.catch(error => dispatch(forgotPassowordFailure(error)));
.catch((error) => dispatch(forgotPassowordFailure(error)));
};
// Check Login
//==============================================================================
// CHECK LOGIN
//==============================================================================
const checkLoginRequest = () => ({type: actions.CHECK_LOGIN_REQUEST});
const checkLoginSuccess = (user, isAdmin) => ({type: actions.CHECK_LOGIN_SUCCESS, user, isAdmin});
const checkLoginFailure = error => ({type: actions.CHECK_LOGIN_FAILURE, error});
const checkLoginRequest = () => ({
type: actions.CHECK_LOGIN_REQUEST
});
export const checkLogin = () => dispatch => {
const checkLoginSuccess = (user, isAdmin) => ({
type: actions.CHECK_LOGIN_SUCCESS,
user,
isAdmin
});
const checkLoginFailure = (error) => ({
type: actions.CHECK_LOGIN_FAILURE,
error
});
export const checkLogin = () => (dispatch) => {
dispatch(checkLoginRequest());
return coralApi('/auth')
.then(({user}) => {
if (!user) {
if (!bowser.safari && !bowser.ios) {
Storage.removeItem('token');
}
return dispatch(checkLoginFailure('not logged in'));
}
const isAdmin = !!user.roles.filter(i => i === 'ADMIN').length;
dispatch(checkLoginSuccess(user, isAdmin));
dispatch(checkLoginSuccess(user));
})
.catch(error => {
.catch((error) => {
console.error(error);
dispatch(checkLoginFailure(`${error.translation_key}`));
});
};
// LogOut Actions
const logOutRequest = () => ({type: actions.LOGOUT_REQUEST});
const logOutSuccess = () => ({type: actions.LOGOUT_SUCCESS});
const logOutFailure = () => ({type: actions.LOGOUT_FAILURE});
export const logout = () => dispatch => {
dispatch(logOutRequest());
return coralApi('/auth', {method: 'DELETE'})
.then(() => dispatch(logOutSuccess()))
.catch(error => dispatch(logOutFailure(error)));
};
+4 -4
View File
@@ -14,9 +14,9 @@ import {
HIDE_SUSPENDUSER_DIALOG
} from '../constants/community';
import coralApi from '../../../coral-framework/helpers/response';
import coralApi from '../../../coral-framework/helpers/request';
export const fetchAccounts = (query = {}) => dispatch => {
export const fetchAccounts = (query = {}) => (dispatch) => {
dispatch(requestFetchAccounts());
coralApi(`/users?${qs.stringify(query)}`)
@@ -30,14 +30,14 @@ export const fetchAccounts = (query = {}) => dispatch => {
totalPages
});
})
.catch(error => dispatch({type: FETCH_COMMENTERS_FAILURE, error}));
.catch((error) => dispatch({type: FETCH_COMMENTERS_FAILURE, error}));
};
const requestFetchAccounts = () => ({
type: FETCH_COMMENTERS_REQUEST
});
export const updateSorting = sort => ({
export const updateSorting = (sort) => ({
type: SORT_UPDATE,
sort
});
+1 -1
View File
@@ -1,6 +1,6 @@
export const CONFIG_UPDATED = 'CONFIG_UPDATED';
export const fetchConfig = () => dispatch => {
export const fetchConfig = () => (dispatch) => {
let json = document.getElementById('data');
let data = JSON.parse(json.textContent);
dispatch({type: CONFIG_UPDATED, data});
+12 -12
View File
@@ -1,18 +1,18 @@
import coralApi from 'coral-framework/helpers/response';
import coralApi from 'coral-framework/helpers/request';
import * as actions from '../constants/install';
import validate from 'coral-framework/helpers/validate';
import errorMsj from 'coral-framework/helpers/error';
export const nextStep = () => ({type: actions.NEXT_STEP});
export const previousStep = () => ({type: actions.PREVIOUS_STEP});
export const goToStep = step => ({type: actions.GO_TO_STEP, step});
export const goToStep = (step) => ({type: actions.GO_TO_STEP, step});
const installRequest = () => ({type: actions.INSTALL_REQUEST});
const installSuccess = () => ({type: actions.INSTALL_SUCCESS});
const installFailure = error => ({type: actions.INSTALL_FAILURE, error});
const installFailure = (error) => ({type: actions.INSTALL_FAILURE, error});
const addError = (name, error) => ({type: actions.ADD_ERROR, name, error});
const hasError = error => ({type: actions.HAS_ERROR, error});
const hasError = (error) => ({type: actions.HAS_ERROR, error});
const clearErrors = () => ({type: actions.CLEAR_ERRORS});
const validation = (formData, dispatch, next) => {
@@ -21,11 +21,11 @@ const validation = (formData, dispatch, next) => {
}
const validKeys = Object.keys(formData)
.filter(name => name !== 'domains');
.filter((name) => name !== 'domains');
// Required Validation
const empty = validKeys
.filter(name => {
.filter((name) => {
const cond = !formData[name].length;
if (cond) {
@@ -45,7 +45,7 @@ const validation = (formData, dispatch, next) => {
// RegExp Validation
const validation = validKeys
.filter(name => {
.filter((name) => {
const cond = !validate[name](formData[name]);
if (cond) {
@@ -88,7 +88,7 @@ export const finishInstall = () => (dispatch, getState) => {
dispatch(installSuccess());
dispatch(nextStep());
})
.catch(error => {
.catch((error) => {
console.error(error);
dispatch(installFailure(`${error.translation_key}`));
});
@@ -99,10 +99,10 @@ export const updateUserFormData = (name, value) => ({type: actions.UPDATE_FORMDA
export const updatePermittedDomains = (value) => ({type: actions.UPDATE_PERMITTED_DOMAINS_SETTINGS, value});
const checkInstallRequest = () => ({type: actions.CHECK_INSTALL_REQUEST});
const checkInstallSuccess = installed => ({type: actions.CHECK_INSTALL_SUCCESS, installed});
const checkInstallFailure = error => ({type: actions.CHECK_INSTALL_FAILURE, error});
const checkInstallSuccess = (installed) => ({type: actions.CHECK_INSTALL_SUCCESS, installed});
const checkInstallFailure = (error) => ({type: actions.CHECK_INSTALL_FAILURE, error});
export const checkInstall = next => dispatch => {
export const checkInstall = (next) => (dispatch) => {
dispatch(checkInstallRequest());
coralApi('/setup')
.then(({installed}) => {
@@ -111,7 +111,7 @@ export const checkInstall = next => dispatch => {
next();
}
})
.catch(error => {
.catch((error) => {
console.error(error);
dispatch(checkInstallFailure(`${error.translation_key}`));
});
+36 -3
View File
@@ -1,11 +1,17 @@
import * as actions from 'constants/moderation';
export const toggleModal = open => ({type: actions.TOGGLE_MODAL, open});
export const toggleModal = (open) => ({type: actions.TOGGLE_MODAL, open});
export const singleView = () => ({type: actions.SINGLE_VIEW});
// Ban User Dialog
export const showBanUserDialog = (user, commentId, showRejectedNote) => ({type: actions.SHOW_BANUSER_DIALOG, user, commentId, showRejectedNote});
export const hideBanUserDialog = (showDialog) => ({type: actions.HIDE_BANUSER_DIALOG, showDialog});
export const showBanUserDialog = (user, commentId, commentStatus, showRejectedNote) => ({type: actions.SHOW_BANUSER_DIALOG, user, commentId, commentStatus, showRejectedNote});
export const hideBanUserDialog = () => ({type: actions.HIDE_BANUSER_DIALOG});
// Suspend User Dialog
export const showSuspendUserDialog = (userId, username, commentId, commentStatus) =>
({type: actions.SHOW_SUSPEND_USER_DIALOG, userId, username, commentId, commentStatus});
export const hideSuspendUserDialog = () => ({type: actions.HIDE_SUSPEND_USER_DIALOG});
// hide shortcuts note
export const hideShortcutsNote = () => {
@@ -18,3 +24,30 @@ export const hideShortcutsNote = () => {
return {type: actions.HIDE_SHORTCUTS_NOTE};
};
export const viewUserDetail = (userId) => ({type: actions.VIEW_USER_DETAIL, userId});
export const hideUserDetail = () => ({type: actions.HIDE_USER_DETAIL});
export const setSortOrder = (order) => ({
type: actions.SET_SORT_ORDER,
order
});
export const changeUserDetailStatuses = (tab) => {
let statuses;
if (tab === 'all') {
statuses = ['NONE', 'ACCEPTED', 'REJECTED', 'PREMOD'];
} else if (tab === 'rejected') {
statuses = ['REJECTED'];
}
return {type: actions.CHANGE_USER_DETAIL_STATUSES, tab, statuses};
};
export const clearUserDetailSelections = () => ({type: actions.CLEAR_USER_DETAIL_SELECTIONS});
export const toggleSelectCommentInUserDetail = (id, active) => {
return {
type: active ? actions.SELECT_USER_DETAIL_COMMENT : actions.UNSELECT_USER_DETAIL_COMMENT,
id
};
};
+6 -6
View File
@@ -1,4 +1,4 @@
import coralApi from '../../../coral-framework/helpers/response';
import coralApi from '../../../coral-framework/helpers/request';
export const SETTINGS_LOADING = 'SETTINGS_LOADING';
export const SETTINGS_RECEIVED = 'SETTINGS_RECEIVED';
@@ -13,19 +13,19 @@ export const SAVE_SETTINGS_FAILED = 'SAVE_SETTINGS_FAILED';
export const WORDLIST_UPDATED = 'WORDLIST_UPDATED';
export const DOMAINLIST_UPDATED = 'DOMAINLIST_UPDATED';
export const fetchSettings = () => dispatch => {
export const fetchSettings = () => (dispatch) => {
dispatch({type: SETTINGS_LOADING});
coralApi('/settings')
.then(settings => {
.then((settings) => {
dispatch({type: SETTINGS_RECEIVED, settings});
})
.catch(error => {
.catch((error) => {
dispatch({type: SETTINGS_FETCH_ERROR, error});
});
};
// for updating top-level settings
export const updateSettings = settings => {
export const updateSettings = (settings) => {
return {type: SETTINGS_UPDATED, settings};
};
@@ -48,7 +48,7 @@ export const saveSettingsToServer = () => (dispatch, getState) => {
.then(() => {
dispatch({type: SAVE_SETTINGS_SUCCESS, settings});
})
.catch(error => {
.catch((error) => {
dispatch({type: SAVE_SETTINGS_FAILED, error});
});
};
+5 -5
View File
@@ -1,4 +1,4 @@
import coralApi from '../../../coral-framework/helpers/response';
import coralApi from '../../../coral-framework/helpers/request';
import * as userTypes from '../constants/users';
/**
@@ -9,8 +9,8 @@ export const userStatusUpdate = (status, userId, commentId) => {
return (dispatch) => {
dispatch({type: userTypes.UPDATE_STATUS_REQUEST});
return coralApi(`/users/${userId}/status`, {method: 'POST', body: {status: status, comment_id: commentId}})
.then(res => dispatch({type: userTypes.UPDATE_STATUS_SUCCESS, res}))
.catch(error => dispatch({type: userTypes.UPDATE_STATUS_FAILURE, error}));
.then((res) => dispatch({type: userTypes.UPDATE_STATUS_SUCCESS, res}))
.catch((error) => dispatch({type: userTypes.UPDATE_STATUS_FAILURE, error}));
};
};
@@ -18,7 +18,7 @@ export const userStatusUpdate = (status, userId, commentId) => {
export const sendNotificationEmail = (userId, subject, body) => {
return (dispatch) => {
return coralApi(`/users/${userId}/email`, {method: 'POST', body: {subject, body}})
.catch(error => dispatch({type: userTypes.USER_EMAIL_FAILURE, error}));
.catch((error) => dispatch({type: userTypes.USER_EMAIL_FAILURE, error}));
};
};
@@ -26,6 +26,6 @@ export const sendNotificationEmail = (userId, subject, body) => {
export const enableUsernameEdit = (userId) => {
return (dispatch) => {
return coralApi(`/users/${userId}/username-enable`, {method: 'POST'})
.catch(error => dispatch({type: userTypes.USERNAME_ENABLE_FAILURE, error}));
.catch((error) => dispatch({type: userTypes.USERNAME_ENABLE_FAILURE, error}));
};
};
@@ -1,24 +1,32 @@
import React, {PropTypes} from 'react';
import styles from './ModerationList.css';
import {Button} from 'coral-ui';
import {menuActionsMap} from '../containers/ModerationQueue/helpers/moderationQueueActionsMap';
import {menuActionsMap} from '../routes/Moderation/helpers/moderationQueueActionsMap';
const ActionButton = ({type = '', status, ...props}) => {
import t from 'coral-framework/services/i18n';
const ActionButton = ({type = '', active, ...props}) => {
const typeName = type.toLowerCase();
const active = ((type === 'REJECT' && status === 'REJECTED') || (type === 'APPROVE' && status === 'ACCEPTED'));
let text = menuActionsMap[type].text;
if (text === 'approve' && active) {
text = 'approved';
} else if (text === 'reject' && active) {
text = 'rejected';
}
return (
<Button
className={`${typeName} ${styles.actionButton} ${active ? styles[`${typeName}__active`] : ''}`}
className={`${typeName} ${styles.actionButton} ${props.minimal ? styles.minimal : ''} ${active ? styles[`${typeName}__active`] : ''}`}
cStyle={typeName}
icon={menuActionsMap[type].icon}
onClick={type === 'APPROVE' ? props.acceptComment : props.rejectComment}
>{menuActionsMap[type].text}</Button>
>{props.minimal ? '' : t(`modqueue.${text}`)}</Button>
);
};
ActionButton.propTypes = {
status: PropTypes.string
active: PropTypes.bool
};
export default ActionButton;
@@ -0,0 +1,53 @@
.button {
-webkit-transform: scale(.8);
transform: scale(.8);
margin: 0;
}
.root {
color: black;
> :global(.mdl-menu__container) {
margin-left: 10px;
> :global(.mdl-menu__outline) {
box-shadow: none;
}
}
}
.buttonOpen {
box-shadow: none;
color: white;
background-color: #616161;
}
.arrowIcon {
margin-left: 6px;
margin-right: 0;
vertical-align: middle;
margin-right: 0;
font-size: 14px;
}
.menu {
padding: 0;
}
.menuItem {
background-color: #2a2a2a;
color: white;
&:first-child {
margin-bottom: 1px;
border-radius: 2px 2px 0px 0px;
}
&:last-child {
border-radius: 0px 0px 2px 2px;
}
&:hover, &:active, &:focus {
background-color: #767676;
}
&[disabled], &[disabled]:hover, &[disabled]:focus, &[disabled]:active {
background-color: #262626;
color: rgba(255, 255, 255, 0.5);
}
}
@@ -0,0 +1,62 @@
import React, {PropTypes} from 'react';
import {Button, Icon} from 'coral-ui';
import {Menu} from 'react-mdl';
import cn from 'classnames';
import {findDOMNode} from 'react-dom';
import styles from './ActionsMenu.css';
import t from 'coral-framework/services/i18n';
let count = 0;
class ActionsMenu extends React.Component {
id = `actions-dropdown-${count++}`;
menu = null;
state = {open: false};
timeout = null;
componentWillUnmount() {
clearTimeout(this.timeout);
}
handleRef = (ref) => {
this.menu = ref ? findDOMNode(ref).parentNode : null;
}
syncOpenState = () => {
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
this.setState({open: this.menu.className.indexOf('is-visible') >= 0});
}, 150);
};
render() {
return (
<div className={styles.root} onBlur={this.syncOpenState} >
<Button
cStyle='actions'
className={cn(styles.button, {[styles.buttonOpen]: this.state.open})}
disabled={false}
id={this.id}
onClick={this.syncOpenState}
icon={this.props.icon}
raised>
{t('modqueue.actions')}
<Icon
name={this.state.open ? 'keyboard_arrow_up' : 'keyboard_arrow_down'}
className={styles.arrowIcon}
/>
</Button>
<Menu target={this.id} className={styles.menu} ref={this.handleRef}>
{this.props.children}
</Menu>
</div>
);
}
}
ActionsMenu.propTypes = {
icon: PropTypes.string,
};
export default ActionsMenu;
@@ -0,0 +1,9 @@
import React from 'react';
import cn from 'classnames';
import {MenuItem} from 'react-mdl';
import styles from './ActionsMenu.css';
const ActionsMenuItem = (props) =>
<MenuItem className={cn(styles.menuItem, props.className)} {...props} />;
export default ActionsMenuItem;
@@ -2,10 +2,8 @@ import React, {PropTypes} from 'react';
import Layout from 'coral-admin/src/components/ui/Layout';
import styles from './NotFound.css';
import {Button, TextField, Alert, Success} from 'coral-ui';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../translations';
import t from 'coral-framework/services/i18n';
import Recaptcha from 'react-recaptcha';
const lang = new I18n(translations);
class AdminLogin extends React.Component {
@@ -14,7 +12,7 @@ class AdminLogin extends React.Component {
this.state = {email: '', password: '', requestPassword: false};
}
handleSignIn = e => {
handleSignIn = (e) => {
e.preventDefault();
this.props.handleLogin(this.state.email, this.state.password);
}
@@ -28,7 +26,7 @@ class AdminLogin extends React.Component {
this.props.handleLogin(this.state.email, this.state.password, recaptchaResponse);
}
handleRequestPassword = e => {
handleRequestPassword = (e) => {
e.preventDefault();
this.props.requestPasswordReset(this.state.email);
}
@@ -37,15 +35,15 @@ class AdminLogin extends React.Component {
const {errorMessage, loginMaxExceeded, recaptchaPublic} = this.props;
const signInForm = (
<form onSubmit={this.handleSignIn}>
{errorMessage && <Alert>{lang.t(`errors.${errorMessage}`)}</Alert>}
{errorMessage && <Alert>{t(`error.${errorMessage}`)}</Alert>}
<TextField
label='Email Address'
value={this.state.email}
onChange={e => this.setState({email: e.target.value})} />
onChange={(e) => this.setState({email: e.target.value})} />
<TextField
label='Password'
value={this.state.password}
onChange={e => this.setState({password: e.target.value})}
onChange={(e) => this.setState({password: e.target.value})}
type='password' />
<div style={{height: 10}}></div>
<Button
@@ -54,7 +52,7 @@ class AdminLogin extends React.Component {
full
onClick={this.handleSignIn}>Sign In</Button>
<p className={styles.forgotPasswordCTA}>
Forgot your password? <a href="#" className={styles.forgotPasswordLink} onClick={e => {
Forgot your password? <a href="#" className={styles.forgotPasswordLink} onClick={(e) => {
e.preventDefault();
this.setState({requestPassword: true});
}}>Request a new one.</a>
@@ -82,7 +80,7 @@ class AdminLogin extends React.Component {
<TextField
label='Email Address'
value={this.state.email}
onChange={e => this.setState({email: e.target.value})} />
onChange={(e) => this.setState({email: e.target.value})} />
<Button
type='submit'
cStyle='black'
+5 -5
View File
@@ -1,16 +1,16 @@
import React from 'react';
import {Provider} from 'react-redux';
import ToastContainer from './ToastContainer';
import 'material-design-lite';
import store from 'services/store';
import AppRouter from '../AppRouter';
export default class App extends React.Component {
render () {
return (
<Provider store={store}>
<AppRouter store={store} />
</Provider>
<div>
<ToastContainer />
<AppRouter />
</div>
);
}
}
@@ -1,7 +1,7 @@
import React, {PropTypes} from 'react';
import {Card} from 'coral-ui';
const EmptyCard = props => (
const EmptyCard = (props) => (
<Card style={{textAlign: 'center', maxWidth: 400, margin: '0 auto'}}>
{props.children}
</Card>
@@ -1,17 +1,14 @@
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../translations.json';
import React, {PropTypes} from 'react';
import Modal from 'components/Modal';
import styles from './ModerationKeysModal.css';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const shortcuts = [
{
title: 'modqueue.navigation',
shortcuts: {
'j': 'modqueue.nextcomment',
'k': 'modqueue.prevcomment',
'j': 'modqueue.next_comment',
'k': 'modqueue.prev_comment',
's': 'modqueue.singleview',
'?': 'modqueue.thismenu'
}
@@ -28,6 +25,8 @@ const shortcuts = [
export default class ModerationKeysModal extends React.Component {
static propTypes = {
open: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
hideShortcutsNote: PropTypes.func.isRequired,
shortcutsNoteVisible: PropTypes.string.isRequired
}
@@ -38,29 +37,29 @@ export default class ModerationKeysModal extends React.Component {
<div>
<div className={styles.callToAction} style={{display: shortcutsNoteVisible === 'show' ? 'block' : 'none'}}>
<div onClick={hideShortcutsNote} className={styles.closeButton}>×</div>
<p className={styles.ctaHeader}>{lang.t('modqueue.mod-faster')}</p>
<p><strong>{lang.t('modqueue.try-these')}:</strong></p>
<p className={styles.ctaHeader}>{t('modqueue.mod_faster')}</p>
<p><strong>{t('modqueue.try_these')}:</strong></p>
<ul>
<li><span>{lang.t('modqueue.approve')}</span> <span className={styles.smallKey}>t</span></li>
<li><span>{lang.t('modqueue.reject')}</span> <span className={styles.smallKey}>r</span></li>
<li><span>{t('modqueue.approve')}</span> <span className={styles.smallKey}>t</span></li>
<li><span>{t('modqueue.reject')}</span> <span className={styles.smallKey}>r</span></li>
</ul>
<p><span>{lang.t('modqueue.view-more-shortcuts')}</span> <span className={styles.smallKey}>{lang.t('modqueue.shift-key')}</span> + <span className={styles.smallKey}>/</span></p>
<p><span>{t('modqueue.view_more_shortcuts')}</span> <span className={styles.smallKey}>{t('modqueue.shift_key')}</span> + <span className={styles.smallKey}>/</span></p>
</div>
<Modal open={open} onClose={onClose}>
<h3>{lang.t('modqueue.shortcuts')}</h3>
<h3>{t('modqueue.shortcuts')}</h3>
<div className={styles.container}>
{shortcuts.map((shortcut, i) => (
<table className={styles.table} key={i}>
<thead>
<tr>
<th>{lang.t(shortcut.title)}</th>
<th>{t(shortcut.title)}</th>
</tr>
</thead>
<tbody>
{Object.keys(shortcut.shortcuts).map(key => (
<tr key={`${key }tr`}>
{Object.keys(shortcut.shortcuts).map((key) => (
<tr key={`${key}tr`}>
<td className={styles.shortcut}><span className={styles.key}>{key}</span></td>
<td>{lang.t(shortcut.shortcuts[key])}</td>
<td>{t(shortcut.shortcuts[key])}</td>
</tr>
))}
</tbody>
@@ -189,14 +189,22 @@
width: 140px;
}
.minimal {
width: 45px;
min-width: 0;
float: left;
}
.approve__active {
box-shadow: none;
color: white;
background-color: #519954;
cursor: not-allowed;
}
.reject__active, .rejected__active {
color: white;
background-color: #D03235;
box-shadow: none;
cursor: not-allowed;
}
@@ -72,7 +72,7 @@ export default class ModerationList extends React.Component {
// Add key handlers. Each action has one and added j/k for moving around
bindKeyHandlers () {
const {modActions, isActive} = this.props;
modActions.filter(action => menuOptionsMap[action].key).forEach(action => {
modActions.filter((action) => menuOptionsMap[action].key).forEach((action) => {
key(menuOptionsMap[action].key, 'moderationList', () => isActive && this.actionKeyHandler(menuOptionsMap[action].status));
});
key('j', 'moderationList', () => isActive && this.moveKeyHandler('down'));
@@ -0,0 +1,226 @@
@keyframes :global(bounceInRight) {
from, 60%, 75%, 90%, to {
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); }
from {
opacity: 0;
transform: translate3d(3000px, 0, 0); }
60% {
opacity: 1;
transform: translate3d(-25px, 0, 0); }
75% {
transform: translate3d(10px, 0, 0); }
90% {
transform: translate3d(-5px, 0, 0); }
to {
transform: none; } }
@keyframes :global(bounceOutRight) {
20% {
opacity: 1;
transform: translate3d(-20px, 0, 0); }
to {
opacity: 0;
transform: translate3d(2000px, 0, 0); } }
@keyframes :global(bounceInLeft) {
from, 60%, 75%, 90%, to {
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); }
0% {
opacity: 0;
transform: translate3d(-3000px, 0, 0); }
60% {
opacity: 1;
transform: translate3d(25px, 0, 0); }
75% {
transform: translate3d(-10px, 0, 0); }
90% {
transform: translate3d(5px, 0, 0); }
to {
transform: none; } }
@keyframes :global(bounceOutLeft) {
20% {
opacity: 1;
transform: translate3d(20px, 0, 0); }
to {
opacity: 0;
transform: translate3d(-2000px, 0, 0); } }
@keyframes :global(bounceInUp) {
from, 60%, 75%, 90%, to {
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); }
from {
opacity: 0;
transform: translate3d(0, 3000px, 0); }
60% {
opacity: 1;
transform: translate3d(0, -20px, 0); }
75% {
transform: translate3d(0, 10px, 0); }
90% {
transform: translate3d(0, -5px, 0); }
to {
transform: translate3d(0, 0, 0); } }
@keyframes :global(bounceOutUp) {
20% {
transform: translate3d(0, -10px, 0); }
40%, 45% {
opacity: 1;
transform: translate3d(0, 20px, 0); }
to {
opacity: 0;
transform: translate3d(0, -2000px, 0); } }
@keyframes :global(bounceInDown) {
from, 60%, 75%, 90%, to {
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); }
0% {
opacity: 0;
transform: translate3d(0, -3000px, 0); }
60% {
opacity: 1;
transform: translate3d(0, 25px, 0); }
75% {
transform: translate3d(0, -10px, 0); }
90% {
transform: translate3d(0, 5px, 0); }
to {
transform: none; } }
@keyframes :global(bounceOutDown) {
20% {
transform: translate3d(0, 10px, 0); }
40%, 45% {
opacity: 1;
transform: translate3d(0, -20px, 0); }
to {
opacity: 0;
transform: translate3d(0, 2000px, 0); } }
@keyframes :global(track-progress) {
0% {
width: 100%; }
100% {
width: 0; } }
:global {
.bounceOutRight, .toast-exit--top-right, .toast-exit--bottom-right {
animation-name: bounceOutRight; }
.bounceInRight, .toast-enter--top-right, .toast-enter--bottom-right {
animation-name: bounceInRight; }
.bounceInLeft, .toast-enter--top-left, .toast-enter--bottom-left {
animation-name: bounceInLeft; }
.bounceOutLeft, .toast-exit--top-left, .toast-exit--bottom-left {
animation-name: bounceOutLeft; }
.bounceInUp, .toast-enter--bottom-center {
animation-name: bounceInUp; }
.bounceOutUp, .toast-exit--top-center {
animation-name: bounceOutUp; }
.bounceInDown, .toast-enter--top-center {
animation-name: bounceInDown; }
.bounceOutDown, .toast-exit--bottom-center {
animation-name: bounceOutDown; }
.animated {
animation-duration: 0.75s;
animation-fill-mode: both; }
.toastify {
z-index: 999;
position: fixed;
padding: 4px;
width: 350px;
max-width: 98%;
color: #999;
box-sizing: border-box; }
.toastify--top-left {
top: 1em;
left: 1em; }
.toastify--top-center {
top: 1em;
left: 50%;
margin-left: -175px; }
.toastify--top-right {
top: 1em;
right: 2em; }
.toastify--bottom-left {
bottom: 1em;
left: 1em; }
.toastify--bottom-center {
bottom: 1em;
left: 50%;
margin-left: -175px; }
.toastify--bottom-right {
bottom: 1em;
right: 2em; }
.toastify__img {
float: left;
margin-right: 8px;
vertical-align: middle; }
.toastify__close {
position: absolute;
top: 18px;
left: 12px;
width: 20px;
height: 16px;
padding: 0;
text-align: center;
text-decoration: none;
color: white;
font-weight: bold;
font-size: 14px;
background: transparent;
outline: none;
border: none;
cursor: pointer;
opacity: 0.8;
transition: .3s ease; }
.toastify__close:hover, .toastify__close:focus {
opacity: 1;
}
.toastify-content {
position: relative;
width: 100%;
margin-bottom: 12px;
padding: 18px 24px 20px 48px;
box-sizing: border-box;
background: #404040;
border-radius: 2px;
box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1), 0 3px 20px 0 rgba(0, 0, 0, 0.05); }
.toastify-content--info {
background: #2488cb; }
.toastify-content--success {
background: #008577; }
.toastify-content--warning {
background: #ef6c2b; }
.toastify-content--error {
background: #ef342b; }
.toastify__body {
color: white;
font-size: 15px;
font-weight: 400;
}
.toastify__progress {
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 4px;
z-index: 999;
opacity: 0.8;
border-radius: 2px;
animation: track-progress linear 1;
background-color: white;
}
}
@@ -0,0 +1,7 @@
import './ToastContainer.css';
import {defaultProps} from 'recompose';
import {ToastContainer} from 'react-toastify';
export default defaultProps({
autoClose: 5000,
})(ToastContainer);
+31 -24
View File
@@ -2,42 +2,51 @@ import React, {PropTypes} from 'react';
import {Navigation, Drawer} from 'react-mdl';
import {IndexLink, Link} from 'react-router';
import styles from './Drawer.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
import t from 'coral-framework/services/i18n';
import {can} from 'coral-framework/services/perms';
const CoralDrawer = ({handleLogout, restricted = false}) => (
const CoralDrawer = ({handleLogout, auth}) => (
<Drawer className={styles.header}>
{ !restricted ?
{ auth && auth.user && can(auth.user, 'ACCESS_ADMIN') ?
<div>
<Navigation className={styles.nav}>
<IndexLink
className={styles.navLink}
to="/admin/dashboard"
activeClassName={styles.active}>
{lang.t('configure.dashboard')}
{t('configure.dashboard')}
</IndexLink>
<Link
className={styles.navLink}
to="/admin/moderate"
{
can(auth.user, 'MODERATE_COMMENTS') && (
<Link
className={styles.navLink}
to="/admin/moderate"
activeClassName={styles.active}>
{t('configure.moderate')}
</Link>
)
}
<Link className={styles.navLink}
to="/admin/stories"
activeClassName={styles.active}>
{lang.t('configure.moderate')}
{t('configure.stories')}
</Link>
<Link className={styles.navLink}
to="/admin/stories"
activeClassName={styles.active}>
{lang.t('configure.stories')}
</Link>
<Link className={styles.navLink}
to="/admin/community"
activeClassName={styles.active}>
{lang.t('configure.community')}
</Link>
<Link
className={styles.navLink}
to="/admin/configure"
to="/admin/community"
activeClassName={styles.active}>
{lang.t('configure.configure')}
{t('configure.community')}
</Link>
{
can(auth.user, 'UPDATE_CONFIG') &&
(
<Link
className={styles.navLink}
to="/admin/configure"
activeClassName={styles.active}>
{t('configure.configure')}
</Link>
)
}
<a onClick={handleLogout}>Sign Out</a>
<span>{`v${process.env.VERSION}`}</span>
</Navigation>
@@ -50,6 +59,4 @@ CoralDrawer.propTypes = {
restricted: PropTypes.bool // hide app elements from a logged out user
};
const lang = new I18n(translations);
export default CoralDrawer;
@@ -73,6 +73,8 @@
font-weight: 500;
background-color: transparent;
transition: background-color 200ms;
font-weight: 100;
letter-spacing: .8;
&:hover {
background-color: #232323;
@@ -80,6 +82,7 @@
&.active {
background-color: #232323;
font-weight: 400;
}
}
+62 -50
View File
@@ -2,60 +2,76 @@ import React, {PropTypes} from 'react';
import {Navigation, Header, IconButton, MenuItem, Menu} from 'react-mdl';
import {Link, IndexLink} from 'react-router';
import styles from './Header.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
import t from 'coral-framework/services/i18n';
import {Logo} from './Logo';
import {can} from 'coral-framework/services/perms';
const CoralHeader = ({handleLogout, restricted = false}) => (
const CoralHeader = ({
handleLogout,
showShortcuts = () => {},
auth
}) => (
<Header className={styles.header}>
<Logo className={styles.logo} />
{
!restricted ?
<div>
<Navigation className={styles.nav}>
<IndexLink
id='dashboardNav'
className={styles.navLink}
to="/admin/dashboard"
activeClassName={styles.active}>
{lang.t('configure.dashboard')}
</IndexLink>
<Link
id='moderateNav'
className={styles.navLink}
to="/admin/moderate"
activeClassName={styles.active}>
{lang.t('configure.moderate')}
</Link>
<Link
id='streamsNav'
className={styles.navLink}
to="/admin/stories"
activeClassName={styles.active}>
{lang.t('configure.stories')}
</Link>
<Link
id='communityNav'
className={styles.navLink}
to="/admin/community"
activeClassName={styles.active}>
{lang.t('configure.community')}
</Link>
<Link
id='configureNav'
className={styles.navLink}
to="/admin/configure"
activeClassName={styles.active}>
{lang.t('configure.configure')}
</Link>
</Navigation>
{
auth && auth.user && can(auth.user, 'ACCESS_ADMIN') ?
<Navigation className={styles.nav}>
<IndexLink
id='dashboardNav'
className={styles.navLink}
to="/admin/dashboard"
activeClassName={styles.active}>
{t('configure.dashboard')}
</IndexLink>
{
can(auth.user, 'MODERATE_COMMENTS') && (
<Link
id='moderateNav'
className={styles.navLink}
to="/admin/moderate"
activeClassName={styles.active}>
{t('configure.moderate')}
</Link>
)
}
<Link
id='streamsNav'
className={styles.navLink}
to="/admin/stories"
activeClassName={styles.active}>
{t('configure.stories')}
</Link>
<Link
id='communityNav'
className={styles.navLink}
to="/admin/community"
activeClassName={styles.active}>
{t('configure.community')}
</Link>
{
can(auth.user, 'UPDATE_CONFIG') && (
<Link
id='configureNav'
className={styles.navLink}
to="/admin/configure"
activeClassName={styles.active}>
{t('configure.configure')}
</Link>
)
}
</Navigation>
:
null
}
<div className={styles.rightPanel}>
<ul>
<li className={styles.settings}>
<div>
<IconButton name="settings" id="menu-settings"/>
<Menu target="menu-settings" align="right">
<MenuItem onClick={handleLogout}>Sign Out</MenuItem>
<MenuItem onClick={() => showShortcuts(true)}>{t('configure.shortcuts')}</MenuItem>
<MenuItem onClick={handleLogout}>{t('configure.sign_out')}</MenuItem>
</Menu>
</div>
</li>
@@ -65,17 +81,13 @@ const CoralHeader = ({handleLogout, restricted = false}) => (
</ul>
</div>
</div>
:
null
}
</Header>
);
CoralHeader.propTypes = {
handleLogout: PropTypes.func.isRequired,
restricted: PropTypes.bool // hide elemnts from a user that's logged out
auth: PropTypes.object,
showShortcuts: PropTypes.func,
handleLogout: PropTypes.func.isRequired
};
const lang = new I18n(translations);
export default CoralHeader;
+11 -2
View File
@@ -4,9 +4,17 @@ import Header from './Header';
import Drawer from './Drawer';
import styles from './Layout.css';
const Layout = ({children, handleLogout = () => {}, restricted = false, ...props}) => (
const Layout = ({
children,
handleLogout = () => {},
toggleShortcutModal,
restricted = false,
...props}) => (
<LayoutMDL fixedDrawer>
<Header handleLogout={handleLogout} restricted={restricted} {...props} />
<Header
handleLogout={handleLogout}
showShortcuts={toggleShortcutModal}
{...props} />
<Drawer handleLogout={handleLogout} restricted={restricted} {...props} />
<div className={styles.layout}>
{children}
@@ -16,6 +24,7 @@ const Layout = ({children, handleLogout = () => {}, restricted = false, ...props
Layout.propTypes = {
handleLogout: PropTypes.func,
toggleShortcutModal: PropTypes.func,
restricted: PropTypes.bool // hide elements from a user that's logged out
};
+1 -5
View File
@@ -2,11 +2,7 @@ export const CHECK_LOGIN_REQUEST = 'CHECK_LOGIN_REQUEST';
export const CHECK_LOGIN_SUCCESS = 'CHECK_LOGIN_SUCCESS';
export const CHECK_LOGIN_FAILURE = 'CHECK_LOGIN_FAILURE';
export const CHECK_CSRF_TOKEN = 'CHECK_CSRF_TOKEN';
export const LOGOUT_REQUEST = 'LOGOUT_REQUEST';
export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS';
export const LOGOUT_FAILURE = 'LOGOUT_FAILURE';
export const LOGOUT = 'LOGOUT';
export const LOGIN_REQUEST = 'LOGIN_REQUEST';
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
@@ -3,3 +3,12 @@ export const SINGLE_VIEW = 'SINGLE_VIEW';
export const SHOW_BANUSER_DIALOG = 'SHOW_BANUSER_DIALOG';
export const HIDE_BANUSER_DIALOG = 'HIDE_BANUSER_DIALOG';
export const HIDE_SHORTCUTS_NOTE = 'HIDE_SHORTCUTS_NOTE';
export const SHOW_SUSPEND_USER_DIALOG = 'SHOW_SUSPEND_USER_DIALOG';
export const HIDE_SUSPEND_USER_DIALOG = 'HIDE_SUSPEND_USER_DIALOG';
export const VIEW_USER_DETAIL = 'VIEW_USER_DETAIL';
export const HIDE_USER_DETAIL = 'HIDE_USER_DETAIL';
export const SET_SORT_ORDER = 'MODERATION_SET_SORT_ORDER';
export const CHANGE_USER_DETAIL_STATUSES = 'CHANGE_USER_DETAIL_STATUSES';
export const SELECT_USER_DETAIL_COMMENT = 'SELECT_USER_DETAIL_COMMENT';
export const UNSELECT_USER_DETAIL_COMMENT = 'UNSELECT_USER_DETAIL_COMMENT';
export const CLEAR_USER_DETAIL_SELECTIONS = 'CLEAR_USER_DETAIL_SELECTIONS';
@@ -1,7 +0,0 @@
import React from 'react';
const Loading = () => (
<h1> Loading results </h1>
);
export default Loading;
@@ -1,80 +0,0 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {SelectField, Option} from 'react-mdl-selectfield';
import styles from './Community.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations';
import {setRole, setCommenterStatus} from '../../actions/community';
const lang = new I18n(translations);
class Table extends Component {
constructor (props) {
super(props);
this.onRoleChange = this.onRoleChange.bind(this);
}
onRoleChange (id, role) {
this.props.dispatch(setRole(id, role));
}
onCommenterStatusChange (id, status) {
this.props.dispatch(setCommenterStatus(id, status));
}
render () {
const {headers, commenters, onHeaderClickHandler} = this.props;
return (
<table className={`mdl-data-table ${styles.dataTable}`}>
<thead>
<tr>
{headers.map((header, i) =>(
<th
key={i}
className="mdl-data-table__cell--non-numeric"
onClick={() => onHeaderClickHandler({field: header.field})}>
{header.title}
</th>
))}
</tr>
</thead>
<tbody>
{commenters.map((row, i)=> (
<tr key={i}>
<td className="mdl-data-table__cell--non-numeric">
{row.username}
<span className={styles.email}>{row.profiles.map(({id}) => id)}</span>
</td>
<td className="mdl-data-table__cell--non-numeric">
{row.created_at}
</td>
<td className="mdl-data-table__cell--non-numeric">
<SelectField label={'Select me'} value={row.status || ''}
className={styles.selectField}
label={lang.t('community.status')}
onChange={status => this.onCommenterStatusChange(row.id, status)}>
<Option value={'ACTIVE'}>{lang.t('community.active')}</Option>
<Option value={'BANNED'}>{lang.t('community.banned')}</Option>
</SelectField>
</td>
<td className="mdl-data-table__cell--non-numeric">
<SelectField label={'Select me'} value={row.roles[0] || ''}
className={styles.selectField}
label={lang.t('community.role')}
onChange={role => this.onRoleChange(row.id, role)}>
<Option value={''}>.</Option>
<Option value={'MODERATOR'}>{lang.t('community.moderator')}</Option>
<Option value={'ADMIN'}>{lang.t('community.admin')}</Option>
</SelectField>
</td>
</tr>
))}
</tbody>
</table>
);
}
}
export default connect(state => ({commenters: state.community.get('accounts')}))(Table);
@@ -1,54 +0,0 @@
import React from 'react';
import styles from './Dashboard.css';
import {compose} from 'react-apollo';
import {connect} from 'react-redux';
import {getMetrics} from 'coral-admin/src/graphql/queries';
import FlagWidget from './FlagWidget';
import ActivityWidget from './ActivityWidget';
import CountdownTimer from 'coral-admin/src/components/CountdownTimer';
import {showBanUserDialog, hideBanUserDialog} from 'coral-admin/src/actions/moderation';
import {Spinner} from 'coral-ui';
class Dashboard extends React.Component {
reloadData = () => {
this.props.data.refetch();
}
render () {
if (this.props.data && this.props.data.loading) {
return <Spinner />;
}
const {data: {assetsByActivity, assetsByFlag}} = this.props;
return (
<div>
<CountdownTimer handleTimeout={this.reloadData} />
<div className={styles.Dashboard}>
<FlagWidget assets={assetsByFlag} />
<ActivityWidget assets={assetsByActivity} />
</div>
</div>
);
}
}
const mapStateToProps = state => {
return {
settings: state.settings.toJS(),
moderation: state.moderation.toJS()
};
};
const mapDispatchToProps = dispatch => ({
showBanUserDialog: (user, commentId) => dispatch(showBanUserDialog(user, commentId)),
hideBanUserDialog: () => dispatch(hideBanUserDialog(false))
});
export default compose(
connect(mapStateToProps, mapDispatchToProps),
getMetrics
)(Dashboard);
@@ -1,101 +0,0 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import styles from './style.css';
import {Wizard, WizardNav} from 'coral-ui';
import Layout from 'coral-admin/src/components/ui/Layout';
import {
goToStep,
nextStep,
submitUser,
checkInstall,
previousStep,
finishInstall,
submitSettings,
updateUserFormData,
updateSettingsFormData,
updatePermittedDomains
} from '../../actions/install';
import InitialStep from './components/Steps/InitialStep';
import AddOrganizationName from './components/Steps/AddOrganizationName';
import CreateYourAccount from './components/Steps/CreateYourAccount';
import PermittedDomainsStep from './components/Steps/PermittedDomainsStep';
import FinalStep from './components/Steps/FinalStep';
class InstallContainer extends Component {
componentDidMount() {
const {checkInstall} = this.props;
checkInstall(() => {
this.context.router.push('/admin');
});
}
render() {
const {install} = this.props;
return (
<Layout restricted={true}>
<div className={styles.Install}>
{
!install.alreadyInstalled ? (
<div>
<h2>Welcome to the Coral Project</h2>
{ install.step !== 0 ? <WizardNav items={install.navItems} currentStep={install.step} icon='check'/> : null }
<Wizard currentStep={install.step} {...this.props}>
<InitialStep/>
<AddOrganizationName/>
<CreateYourAccount/>
<PermittedDomainsStep/>
<FinalStep/>
</Wizard>
</div>
) : (
<div>Talk is already installed</div>
)
}
</div>
</Layout>
);
}
}
InstallContainer.contextTypes = {
router: React.PropTypes.object
};
const mapStateToProps = state => ({
install: state.install.toJS()
});
const mapDispatchToProps = dispatch => ({
nextStep: () => dispatch(nextStep()),
goToStep: step => dispatch(goToStep(step)),
previousStep: () => dispatch(previousStep()),
finishInstall: () => dispatch(finishInstall()),
checkInstall: next => dispatch(checkInstall(next)),
handleDomainsChange: value => {
dispatch(updatePermittedDomains(value));
},
handleSettingsChange: e => {
const {name, value} = e.currentTarget;
dispatch(updateSettingsFormData(name, value));
},
handleUserChange: e => {
const {name, value} = e.currentTarget;
dispatch(updateUserFormData(name, value));
},
handleSettingsSubmit: e => {
e.preventDefault();
dispatch(submitSettings());
},
handleUserSubmit: e => {
e.preventDefault();
dispatch(submitUser());
}
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(InstallContainer);
@@ -1,19 +0,0 @@
import React from 'react';
import styles from './style.css';
import {Button} from 'coral-ui';
const lang = new I18n(translations);
import translations from '../../translations.json';
import I18n from 'coral-framework/modules/i18n/i18n';
const InitialStep = props => {
const {nextStep} = props;
return (
<div className={styles.step}>
<p>{lang.t('INITIAL.DESCRIPTION')}</p>
<Button cStyle='green' onClick={nextStep} raised>{lang.t('INITIAL.SUBMIT')}</Button>
</div>
);
};
export default InitialStep;
@@ -1,58 +0,0 @@
{
"en": {
"INITIAL" : {
"DESCRIPTION": "Let's set up your Talk community in just a few short steps.",
"SUBMIT": "Get Started"
},
"ADD_ORGANIZATION": {
"DESCRIPTION": "Please tell us the name of your organization. This will appear in emails when inviting new team members.",
"LABEL": "Organization Name",
"SAVE": "Save"
},
"CREATE": {
"EMAIL": "Email address",
"USERNAME": "Username",
"PASSWORD": "Password",
"CONFIRM_PASSWORD": "Confirm Password",
"SAVE": "Save"
},
"PERMITTED_DOMAINS": {
"TITLE": "Permitted domains",
"DESCRIPTION": "Enter the domains you would like to permit for Talk, e.g. your local, staging and production environments (ex. localhost:3000, staging.domain.com, domain.com).",
"SUBMIT": "Finish install"
},
"FINAL": {
"DESCRIPTION": "Thanks for installing Talk! We sent an email to verify your email address. While you finish setting up the account, you can start engaging with your readers now.",
"LAUNCH": "Launch Talk",
"CLOSE": "Close this Installer"
}
},
"es": {
"INITIAL" : {
"DESCRIPTION": "Configuremos tu comunidad de Talk en sólo algunos pasos.",
"SUBMIT": "Empezá!"
},
"ADD_ORGANIZATION": {
"DESCRIPTION": "Por favor, dinos el nombre de tu organización. Este aparecerá en los emails cuando invites nuevos miembros.",
"LABEL": "Nombre de la Organización",
"SAVE": "Guardar"
},
"CREATE": {
"EMAIL": "Dirección de E-Mail",
"USERNAME": "Usuario",
"PASSWORD": "Contraseña",
"CONFIRM_PASSWORD": "Confirmar contraseña",
"SAVE": "Guardar"
},
"PERMITTED_DOMAINS": {
"TITLE": "Dominios Permitidos",
"DESCRIPTION": "Agrega dominios permitidos a Talk, e.g. tu localhost, staging y ambientes de production (ex. localhost:3000, staging.domain.com, domain.com).",
"SUBMIT": "Finalizar instalación"
},
"FINAL": {
"DESCRIPTION": "Gracias por instalar Talk! Te enviamos un email para verificar tu identidad. Mientras se termina de configurar la cuenta, ya puedes empezar a interactuar con tus lectores",
"LAUNCH": "Lanzar Talk",
"CLOSE": "Cerrar este instalador"
}
}
}
@@ -0,0 +1,85 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import Layout from '../components/ui/Layout';
import {fetchConfig} from '../actions/config';
import AdminLogin from '../components/AdminLogin';
import {logout} from 'coral-framework/actions/auth';
import {FullLoading} from '../components/FullLoading';
import {toggleModal as toggleShortcutModal} from '../actions/moderation';
import {checkLogin, handleLogin, requestPasswordReset} from '../actions/auth';
import {can} from 'coral-framework/services/perms';
class LayoutContainer extends Component {
componentWillMount() {
const {checkLogin, fetchConfig} = this.props;
checkLogin();
fetchConfig();
}
render() {
const {
user,
loggedIn,
loadingUser,
loginError,
loginMaxExceeded,
passwordRequestSuccess
} = this.props.auth;
const {
handleLogout,
toggleShortcutModal,
TALK_RECAPTCHA_PUBLIC
} = this.props;
if (loadingUser) {
return <FullLoading />;
}
if (!loggedIn) {
return (
<AdminLogin
loginMaxExceeded={loginMaxExceeded}
handleLogin={this.props.handleLogin}
requestPasswordReset={this.props.requestPasswordReset}
passwordRequestSuccess={passwordRequestSuccess}
recaptchaPublic={TALK_RECAPTCHA_PUBLIC}
errorMessage={loginError}
/>
);
}
if (can(user, 'ACCESS_ADMIN') && loggedIn) {
return (
<Layout
handleLogout={handleLogout}
toggleShortcutModal={toggleShortcutModal}
{...this.props}
/>
);
} else if (loggedIn) {
return (
<Layout {...this.props}>
<p>This page is for team use only. Please contact an administrator if you want to join this team.</p>
</Layout>
);
}
return <FullLoading />;
}
}
const mapStateToProps = (state) => ({
auth: state.auth.toJS(),
TALK_RECAPTCHA_PUBLIC: state.config
.get('data')
.get('TALK_RECAPTCHA_PUBLIC', null)
});
const mapDispatchToProps = (dispatch) => ({
checkLogin: () => dispatch(checkLogin()),
fetchConfig: () => dispatch(fetchConfig()),
handleLogin: (username, password, recaptchaResponse) =>
dispatch(handleLogin(username, password, recaptchaResponse)),
requestPasswordReset: (email) => dispatch(requestPasswordReset(email)),
toggleShortcutModal: (toggle) => dispatch(toggleShortcutModal(toggle)),
handleLogout: () => dispatch(logout())
});
export default connect(mapStateToProps, mapDispatchToProps)(LayoutContainer);
@@ -1,58 +0,0 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import Layout from '../components/ui/Layout';
import {checkLogin, handleLogin, logout, requestPasswordReset} from '../actions/auth';
import {fetchConfig} from '../actions/config';
import {FullLoading} from '../components/FullLoading';
import AdminLogin from '../components/AdminLogin';
class LayoutContainer extends Component {
componentWillMount () {
const {checkLogin, fetchConfig} = this.props;
checkLogin();
fetchConfig();
}
render () {
const {
isAdmin,
loggedIn,
loadingUser,
loginError,
loginMaxExceeded,
passwordRequestSuccess
} = this.props.auth;
const {handleLogout, TALK_RECAPTCHA_PUBLIC} = this.props;
if (loadingUser) { return <FullLoading />; }
if (!isAdmin) {
return <AdminLogin
loginMaxExceeded={loginMaxExceeded}
handleLogin={this.props.handleLogin}
requestPasswordReset={this.props.requestPasswordReset}
passwordRequestSuccess={passwordRequestSuccess}
recaptchaPublic={TALK_RECAPTCHA_PUBLIC}
errorMessage={loginError} />;
}
if (isAdmin && loggedIn) { return <Layout handleLogout={handleLogout} {...this.props} />; }
return <FullLoading />;
}
}
const mapStateToProps = state => ({
auth: state.auth.toJS(),
TALK_RECAPTCHA_PUBLIC: state.config.get('data').get('TALK_RECAPTCHA_PUBLIC', null)
});
const mapDispatchToProps = dispatch => ({
checkLogin: () => dispatch(checkLogin()),
fetchConfig: () => dispatch(fetchConfig()),
handleLogin: (username, password, recaptchaResponse) => dispatch(handleLogin(username, password, recaptchaResponse)),
requestPasswordReset: email => dispatch(requestPasswordReset(email)),
handleLogout: () => dispatch(logout())
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(LayoutContainer);
@@ -1,59 +0,0 @@
import React, {PropTypes} from 'react';
import Comment from './components/Comment';
import styles from './components/styles.css';
import EmptyCard from '../../components/EmptyCard';
import {actionsMap} from './helpers/moderationQueueActionsMap';
import I18n from 'coral-framework/modules/i18n/i18n';
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}) => {
return (
<div id="moderationList" className={`${styles.list} ${singleView ? styles.singleView : ''}`}>
<ul style={{paddingLeft: 0}}>
{
comments.length
? comments.map((comment, i) => {
const status = comment.action_summaries ? 'FLAGGED' : comment.status;
return <Comment
key={i}
index={i}
comment={comment}
selected={i === selectedIndex}
suspectWords={props.suspectWords}
bannedWords={props.bannedWords}
actions={actionsMap[status]}
showBanUserDialog={props.showBanUserDialog}
acceptComment={props.acceptComment}
rejectComment={props.rejectComment}
currentAsset={props.currentAsset}
/>;
})
: <EmptyCard>{lang.t('modqueue.emptyqueue')}</EmptyCard>
}
</ul>
<LoadMore
comments={comments}
loadMore={loadMore}
sort={sort}
tab={activeTab}
showLoadMore={comments.length < commentCount}
assetId={props.assetId}
/>
</div>
);
};
ModerationQueue.propTypes = {
bannedWords: PropTypes.arrayOf(PropTypes.string).isRequired,
suspectWords: PropTypes.arrayOf(PropTypes.string).isRequired,
currentAsset: PropTypes.object,
showBanUserDialog: PropTypes.func.isRequired,
rejectComment: PropTypes.func.isRequired,
acceptComment: PropTypes.func.isRequired,
comments: PropTypes.array.isRequired
};
export default ModerationQueue;
@@ -1,112 +0,0 @@
import React, {PropTypes} from 'react';
import timeago from 'timeago.js';
import Linkify from 'react-linkify';
import Highlighter from 'react-highlight-words';
import {Link} from 'react-router';
import styles from './styles.css';
import {Icon} from 'coral-ui';
import FlagBox from './FlagBox';
import CommentType from './CommentType';
import ActionButton from 'coral-admin/src/components/ActionButton';
import BanUserButton from 'coral-admin/src/components/BanUserButton';
import {getActionSummary} from 'coral-framework/utils';
const linkify = new Linkify();
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 links = linkify.getMatches(comment.body);
const linkText = links ? links.map(link => link.raw) : [];
const flagActionSummaries = getActionSummary('FlagActionSummary', comment);
const flagActions = comment.actions && comment.actions.filter(a => a.__typename === 'FlagAction');
let commentType = '';
if (comment.status === 'PREMOD') {
commentType = 'premod';
} else if (flagActions && flagActions.length) {
commentType = 'flagged';
}
return (
<li tabIndex={props.index} className={`mdl-card ${props.selected ? 'mdl-shadow--8dp' : 'mdl-shadow--2dp'} ${styles.Comment} ${styles.listItem}`}>
<div className={styles.container}>
<div className={styles.itemHeader}>
<div className={styles.author}>
<span>
{comment.user.name}
</span>
<span className={styles.created}>
{timeago().format(comment.created_at || (Date.now() - props.index * 60 * 1000), lang.getLocale().replace('-', '_'))}
</span>
<BanUserButton user={comment.user} onClick={() => props.showBanUserDialog(comment.user, comment.id, comment.status !== 'REJECTED')} />
<CommentType type={commentType} />
</div>
{comment.user.status === 'banned' ?
<span className={styles.banned}>
<Icon name='error_outline'/>
{lang.t('comment.banned_user')}
</span>
: null}
</div>
<div className={styles.moderateArticle}>
Story: {comment.asset.title}
{!props.currentAsset && (
<Link to={`/admin/moderate/${comment.asset.id}`}>Moderate </Link>
)}
</div>
<div className={styles.itemBody}>
<p className={styles.body}>
<Highlighter
searchWords={[...props.suspectWords, ...props.bannedWords, ...linkText]}
textToHighlight={comment.body} />
</p>
<div className={styles.sideActions}>
{links ? <span className={styles.hasLinks}><Icon name='error_outline'/> Contains Link</span> : null}
<div className={`actions ${styles.actions}`}>
{actions.map((action, i) =>
<ActionButton key={i}
type={action}
user={comment.user}
status={comment.status}
acceptComment={() => props.acceptComment({commentId: comment.id})}
rejectComment={() => props.rejectComment({commentId: comment.id})}
/>
)}
</div>
</div>
</div>
</div>
{
flagActions && flagActions.length
? <FlagBox actions={flagActions} actionSummaries={flagActionSummaries} />
: null
}
</li>
);
};
Comment.propTypes = {
acceptComment: PropTypes.func.isRequired,
rejectComment: PropTypes.func.isRequired,
suspectWords: PropTypes.arrayOf(PropTypes.string).isRequired,
bannedWords: PropTypes.arrayOf(PropTypes.string).isRequired,
currentAsset: PropTypes.object,
comment: PropTypes.shape({
body: PropTypes.string.isRequired,
action_summaries: PropTypes.array,
actions: PropTypes.array,
created_at: PropTypes.string.isRequired,
user: PropTypes.shape({
status: PropTypes.string
}),
asset: PropTypes.shape({
title: PropTypes.string,
id: PropTypes.string
})
})
};
export default Comment;
@@ -1,12 +0,0 @@
import React, {PropTypes} from 'react';
import styles from './CommentCount.css';
const CommentCount = props => (
<span className={styles.count}>{props.count}</span>
);
CommentCount.propTypes = {
count: PropTypes.number.isRequired
};
export default CommentCount;
@@ -1,31 +0,0 @@
import React, {PropTypes} from 'react';
import {Button} from 'coral-ui';
import styles from './styles.css';
const LoadMore = ({comments, loadMore, sort, tab, assetId, showLoadMore}) =>
<div className={styles.loadMoreContainer}>
{
showLoadMore && <Button
className={styles.loadMore}
onClick={() =>
loadMore({
cursor: comments[comments.length - 1].created_at,
sort,
tab,
asset_id: assetId
})}>
Load More
</Button>
}
</div>;
LoadMore.propTypes = {
comments: PropTypes.array.isRequired,
loadMore: PropTypes.func.isRequired,
sort: PropTypes.oneOf(['CHRONOLOGICAL', 'REVERSE_CHRONOLOGICAL']).isRequired,
tab: PropTypes.oneOf(['rejected', 'premod', 'flagged', 'all']).isRequired,
assetId: PropTypes.string,
showLoadMore: PropTypes.bool.isRequired
};
export default LoadMore;
@@ -1,14 +0,0 @@
export const actionsMap = {
PREMOD: ['APPROVE', 'REJECT'],
FLAGGED: ['APPROVE', 'REJECT'],
REJECTED: ['APPROVE', 'REJECTED']
};
export const menuActionsMap = {
'REJECT': {status: 'REJECTED', text: 'Reject', icon: 'close', key: 'r'},
'REJECTED': {status: 'REJECTED', text: 'Rejected', icon: 'close'},
'APPROVE': {status: 'ACCEPTED', text: 'Approve', icon: 'done', key: 't'},
'FLAGGED': {status: 'FLAGGED', text: 'Flag', icon: 'flag', filter: 'Untouched'},
'BAN': {status: 'BANNED', text: 'Ban User', icon: 'not interested'},
'': {icon: 'done'}
};
@@ -1,187 +0,0 @@
import React, {Component} from 'react';
import styles from './Stories.css';
import {connect} from 'react-redux';
import I18n from 'coral-framework/modules/i18n/i18n';
import {fetchAssets, updateAssetState} from '../../actions/assets';
import translations from '../../translations.json';
import {Link} from 'react-router';
import {Pager, Icon} from 'coral-ui';
import {DataTable, TableHeader, RadioGroup, Radio} from 'react-mdl';
import EmptyCard from 'coral-admin/src/components/EmptyCard';
const limit = 25;
class Stories extends Component {
state = {
search: '',
sort: 'desc',
filter: 'all',
statusMenus: {},
timer: null,
page: 0
}
componentDidMount () {
this.props.fetchAssets(0, limit, '', this.state.sortBy);
}
onSettingChange = (setting) => (e) => {
let options = this.state;
this.setState({[setting]: e.target.value});
options[setting] = e.target.value;
this.props.fetchAssets(0, limit, options.search, options.sort, options.filter);
}
onSearchChange = (e) => {
const search = e.target.value;
this.setState((prevState) => {
prevState.search = search;
clearTimeout(prevState.timer);
const fetchAssets = this.props.fetchAssets;
prevState.timer = setTimeout(() => {
fetchAssets(0, limit, search, this.state.sort, this.state.filter);
}, 350);
return prevState;
});
}
renderDate = (date) => {
const d = new Date(date);
return `${d.getMonth() + 1}/${d.getDate()}/${d.getFullYear()}`;
}
onStatusClick = (closeStream, id, statusMenuOpen) => () => {
if (statusMenuOpen) {
this.setState(prev => {
prev.statusMenus[id] = false;
return prev;
});
this.props.updateAssetState(id, closeStream ? Date.now() : null)
.then(() => {
const {search, sort, filter, page} = this.state;
this.props.fetchAssets(page, limit, search, sort, filter);
});
} else {
this.setState(prev => {
prev.statusMenus[id] = true;
return prev;
});
}
}
renderTitle = (title, {id}) => <Link to={`/admin/moderate/${id}`}>{title}</Link>
renderStatus = (closedAt, {id}) => {
const closed = closedAt && new Date(closedAt).getTime() < Date.now();
const statusMenuOpen = this.state.statusMenus[id];
return <div className={styles.statusMenu}>
<div
className={closed ? styles.statusMenuClosed : styles.statusMenuOpen}
onClick={this.onStatusClick(closed, id, statusMenuOpen)}>
{!statusMenuOpen && <Icon className={styles.statusMenuIcon} name='keyboard_arrow_down'/>}
{closed ? lang.t('streams.closed') : lang.t('streams.open')}
</div>
{
statusMenuOpen &&
<div
className={!closed ? styles.statusMenuClosed : styles.statusMenuOpen}
onClick={this.onStatusClick(!closed, id, statusMenuOpen)}>
{!closed ? lang.t('streams.closed') : lang.t('streams.open')}
</div>
}
</div>;
}
onPageClick = (page) => {
this.setState({page});
const {search, sort, filter} = this.state;
this.props.fetchAssets((page - 1) * limit, limit, search, sort, filter);
}
render () {
const {search, sort, filter} = this.state;
const {assets} = this.props;
const assetsIds = assets.ids.map((id) => assets.byId[id]);
return (
<div className={styles.container}>
<div className={styles.leftColumn}>
<div className={styles.searchBox}>
<Icon name='search' className={styles.searchIcon}/>
<input
type='text'
value={search}
className={styles.searchBoxInput}
onChange={this.onSearchChange}
placeholder={lang.t('streams.search')}/>
</div>
<div className={styles.optionHeader}>{lang.t('streams.filter-streams')}</div>
<div className={styles.optionDetail}>{lang.t('streams.stream-status')}</div>
<RadioGroup
name='status filter'
value={filter}
childContainer='div'
onChange={this.onSettingChange('filter')}
className={styles.radioGroup}
>
<Radio value='all'>{lang.t('streams.all')}</Radio>
<Radio value='open'>{lang.t('streams.open')}</Radio>
<Radio value='closed'>{lang.t('streams.closed')}</Radio>
</RadioGroup>
<div className={styles.optionHeader}>{lang.t('streams.sort-by')}</div>
<RadioGroup
name='sort by'
value={sort}
childContainer='div'
onChange={this.onSettingChange('sort')}
className={styles.radioGroup}
>
<Radio value='desc'>{lang.t('streams.newest')}</Radio>
<Radio value='asc'>{lang.t('streams.oldest')}</Radio>
</RadioGroup>
</div>
{
assetsIds.length
? <div className={styles.mainContent}>
<DataTable className={styles.streamsTable} rows={assetsIds} onClick={this.goToModeration}>
<TableHeader name="title" cellFormatter={this.renderTitle}>{lang.t('streams.article')}</TableHeader>
<TableHeader name="publication_date" cellFormatter={this.renderDate}>
{lang.t('streams.pubdate')}
</TableHeader>
<TableHeader name="closedAt" cellFormatter={this.renderStatus} className={styles.status}>
{lang.t('streams.status')}
</TableHeader>
</DataTable>
<Pager
totalPages={Math.ceil((assets.count || 0) / limit)}
page={this.state.page}
onNewPageHandler={this.onPageClick} />
</div>
: <EmptyCard>{lang.t('streams.empty_result')}</EmptyCard>
}
</div>
);
}
}
const mapStateToProps = ({assets}) => {
return {
assets: assets.toJS()
};
};
const mapDispatchToProps = (dispatch) => {
return {
fetchAssets: (...args) => {
dispatch(fetchAssets.apply(this, args));
},
updateAssetState: (...args) => dispatch(updateAssetState.apply(this, args))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Stories);
const lang = new I18n(translations);
@@ -1,13 +0,0 @@
fragment metrics on Asset {
id
title
url
author
created_at
commentCount
action_summaries {
type: __typename
actionCount
actionableItemCount
}
}
@@ -1,30 +0,0 @@
fragment commentView on Comment {
id
body
created_at
status
user {
id
name: username
status
}
asset {
id
title
}
action_summaries {
count
... on FlagActionSummary {
reason
}
}
actions {
... on FlagAction {
reason
message
user {
username
}
}
}
}
+68
View File
@@ -0,0 +1,68 @@
import {add} from 'coral-framework/services/graphqlRegistry';
import update from 'immutability-helper';
const queues = ['all', 'premod', 'flagged', 'accepted', 'rejected'];
const extension = {
mutations: {
SetUserStatus: () => ({
refetchQueries: ['CoralAdmin_Community'],
}),
RejectUsername: () => ({
refetchQueries: ['CoralAdmin_Community'],
}),
SetCommentStatus: ({variables: {commentId, status}}) => ({
updateQueries: {
CoralAdmin_Moderation: (prev) => {
const comment = queues.reduce((comment, queue) => {
return comment ? comment : prev[queue].nodes.find((c) => c.id === commentId);
}, null);
let acceptedNodes = prev.accepted.nodes;
let acceptedCount = prev.acceptedCount;
let rejectedNodes = prev.rejected.nodes;
let rejectedCount = prev.rejectedCount;
if (status !== comment.status) {
if (status === 'ACCEPTED') {
comment.status = 'ACCEPTED';
acceptedCount++;
acceptedNodes = [comment, ...acceptedNodes];
}
else if (status === 'REJECTED') {
comment.status = 'REJECTED';
rejectedCount++;
rejectedNodes = [comment, ...rejectedNodes];
}
}
const premodNodes = prev.premod.nodes.filter((c) => c.id !== commentId);
const flaggedNodes = prev.flagged.nodes.filter((c) => c.id !== commentId);
const premodCount = premodNodes.length < prev.premod.nodes.length ? prev.premodCount - 1 : prev.premodCount;
const flaggedCount = flaggedNodes.length < prev.flagged.nodes.length ? prev.flaggedCount - 1 : prev.flaggedCount;
if (status === 'REJECTED') {
acceptedNodes = prev.accepted.nodes.filter((c) => c.id !== commentId);
acceptedCount = acceptedNodes.length < prev.accepted.nodes.length ? prev.acceptedCount - 1 : prev.acceptedCount;
}
else if (status === 'ACCEPTED') {
rejectedNodes = prev.rejected.nodes.filter((c) => c.id !== commentId);
rejectedCount = rejectedNodes.length < prev.rejected.nodes.length ? prev.rejectedCount - 1 : prev.rejectedCount;
}
return update(prev, {
premodCount: {$set: Math.max(0, premodCount)},
flaggedCount: {$set: Math.max(0, flaggedCount)},
acceptedCount: {$set: Math.max(0, acceptedCount)},
rejectedCount: {$set: Math.max(0, rejectedCount)},
premod: {nodes: {$set: premodNodes}},
flagged: {nodes: {$set: flaggedNodes}},
accepted: {nodes: {$set: acceptedNodes}},
rejected: {nodes: {$set: rejectedNodes}},
});
}
}
}),
},
};
add(extension);
@@ -1,107 +0,0 @@
import {graphql} from 'react-apollo';
import SET_USER_STATUS from './setUserStatus.graphql';
import SET_COMMENT_STATUS from './setCommentStatus.graphql';
import SUSPEND_USER from './suspendUser.graphql';
export const banUser = graphql(SET_USER_STATUS, {
props: ({mutate}) => ({
banUser: ({userId}) => {
return mutate({
variables: {
userId,
status: 'BANNED'
},
refetchQueries: ['Users']
});
}}),
});
export const setUserStatus = graphql(SET_USER_STATUS, {
props: ({mutate}) => ({
approveUser: ({userId}) => {
return mutate({
variables: {
userId,
status: 'APPROVED'
},
refetchQueries: ['Users']
});
}
})
});
export const suspendUser = graphql(SUSPEND_USER, {
props: ({mutate}) => ({
suspendUser: ({userId, message}) => {
return mutate({
variables: {
userId,
message
},
refetchQueries: ['Users']
});
}
})
});
export const setCommentStatus = graphql(SET_COMMENT_STATUS, {
props: ({mutate}) => ({
acceptComment: ({commentId}) => {
return mutate({
variables: {
commentId,
status: 'ACCEPTED'
},
updateQueries: {
ModQueue: (oldData) => {
const premod = oldData.premod.filter(c => c.id !== commentId);
const flagged = oldData.flagged.filter(c => c.id !== commentId);
const rejected = oldData.rejected.filter(c => c.id !== commentId);
const premodCount = premod.length < oldData.premod.length ? oldData.premodCount - 1 : oldData.premodCount;
const flaggedCount = flagged.length < oldData.flagged.length ? oldData.flaggedCount - 1 : oldData.flaggedCount;
const rejectedCount = rejected.length < oldData.rejected.length ? oldData.rejectedCount - 1 : oldData.rejectedCount;
return {
...oldData,
premodCount,
flaggedCount,
rejectedCount,
premod,
flagged,
rejected,
};
}
}
});
},
rejectComment: ({commentId}) => {
return mutate({
variables: {
commentId,
status: 'REJECTED'
},
updateQueries: {
ModQueue: (oldData) => {
const comment = oldData.premod.concat(oldData.flagged).filter(c => c.id === commentId)[0];
const rejected = [comment].concat(oldData.rejected);
const premod = oldData.premod.filter(c => c.id !== commentId);
const flagged = oldData.flagged.filter(c => c.id !== commentId);
const premodCount = premod.length < oldData.premod.length ? oldData.premodCount - 1 : oldData.premodCount;
const flaggedCount = flagged.length < oldData.flagged.length ? oldData.flaggedCount - 1 : oldData.flaggedCount;
const rejectedCount = oldData.rejectedCount + 1;
return {
...oldData,
premodCount,
flaggedCount,
rejectedCount,
premod,
flagged,
rejected
};
}
}
});
}
})
});
@@ -1,7 +0,0 @@
mutation setCommentStatus($commentId: ID!, $status: COMMENT_STATUS!){
setCommentStatus(id: $commentId, status: $status) {
errors {
translation_key
}
}
}
@@ -1,7 +0,0 @@
mutation setUserStatus($userId: ID!, $status: USER_STATUS!) {
setUserStatus(id: $userId, status: $status) {
errors {
translation_key
}
}
}
@@ -1,7 +0,0 @@
mutation suspendUser($userId: ID!, $message: String) {
suspendUser(id: $userId, message: $message) {
errors {
translation_key
}
}
}
@@ -1,6 +0,0 @@
query Assets {
assets {
id
title
}
}
@@ -1,92 +0,0 @@
import {graphql} from 'react-apollo';
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';
export const modQueueQuery = graphql(MOD_QUEUE_QUERY, {
options: ({params: {id = null}}) => {
return {
variables: {
asset_id: id,
sort: 'REVERSE_CHRONOLOGICAL'
}
};
},
props: ({ownProps: {params: {id = null}}, data}) => ({
data,
modQueueResort: modQueueResort(id, data.fetchMore),
loadMore: loadMore(data.fetchMore)
})
});
export const getMetrics = graphql(METRICS, {
options: ({settings: {dashboardWindowStart, dashboardWindowEnd}}) => {
return {
variables: {
from: dashboardWindowStart,
to: dashboardWindowEnd
}
};
}
});
export const loadMore = (fetchMore) => ({limit, cursor, sort, tab, asset_id}) => {
let statuses;
switch(tab) {
case 'all':
statuses = null;
break;
case 'premod':
statuses = ['PREMOD'];
break;
case 'flagged':
statuses = ['NONE', 'PREMOD'];
break;
case 'rejected':
statuses = ['REJECTED'];
break;
}
return fetchMore({
query: MOD_QUEUE_LOAD_MORE,
variables: {
limit,
cursor,
sort,
statuses,
asset_id
},
updateQuery: (oldData, {fetchMoreResult:{comments}}) => {
return {
...oldData,
[tab]: [
...oldData[tab],
...comments
]
};
}
});
};
export const modUserFlaggedQuery = graphql(MOD_USER_FLAGGED_QUERY, {
options: ({params: {action_type = 'FLAG'}}) => {
return {
variables: {
action_type: action_type
}
};
}
});
export const modQueueResort = (id, fetchMore) => (sort) => {
return fetchMore({
query: MOD_QUEUE_QUERY,
variables: {
asset_id: id,
sort
},
updateQuery: (oldData, {fetchMoreResult:{data}}) => data
});
};
@@ -1,13 +0,0 @@
#import "../fragments/commentView.graphql"
query LoadMoreModQueue($limit: Int = 10, $cursor: Date, $sort: SORT_ORDER, $asset_id: ID, $statuses:[COMMENT_STATUS!]) {
comments(query: {limit: $limit, cursor: $cursor, asset_id: $asset_id, statuses: $statuses, sort: $sort}) {
...commentView
action_summaries {
count
... on FlagActionSummary {
reason
}
}
}
}
@@ -1,10 +0,0 @@
#import "../fragments/assetMetricsView.graphql"
query Metrics ($from: Date!, $to: Date!) {
assetsByFlag: assetMetrics(from: $from, to: $to, sort: FLAG) {
...metrics
}
assetsByActivity: assetMetrics(from: $from, to: $to, sort: ACTIVITY) {
...metrics
}
}
@@ -1,54 +0,0 @@
#import "../fragments/commentView.graphql"
query ModQueue ($asset_id: ID, $sort: SORT_ORDER) {
all: comments(query: {
statuses: [NONE, PREMOD, ACCEPTED, REJECTED],
asset_id: $asset_id,
sort: $sort
}) {
...commentView
}
premod: comments(query: {
statuses: [PREMOD],
asset_id: $asset_id,
sort: $sort
}) {
...commentView
}
flagged: comments(query: {
action_type: FLAG,
asset_id: $asset_id,
statuses: [NONE, PREMOD],
sort: $sort
}) {
...commentView
}
rejected: comments(query: {
statuses: [REJECTED],
asset_id: $asset_id,
sort: $sort
}) {
...commentView
}
assets: assets {
id
title
url
}
allCount: commentCount(query: {
asset_id: $asset_id
})
premodCount: commentCount(query: {
statuses: [PREMOD],
asset_id: $asset_id
})
rejectedCount: commentCount(query: {
statuses: [REJECTED],
asset_id: $asset_id
})
flaggedCount: commentCount(query: {
action_type: FLAG,
asset_id: $asset_id,
statuses: [NONE, PREMOD]
})
}
@@ -1,26 +0,0 @@
query Users ($action_type: ACTION_TYPE) {
users (query:{action_type: $action_type}){
id
username
status
roles
actions{
id
created_at
... on FlagAction {
reason
message
user {
id
username
}
}
}
action_summaries {
count
... on FlagActionSummary {
reason
}
}
}
}
+5
View File
@@ -8,6 +8,11 @@ import store from './services/store';
import App from './components/App';
import 'react-mdl/extra/material.js';
import './graphql';
import {loadPluginsTranslations, injectPluginsReducers} from 'coral-framework/helpers/plugins';
loadPluginsTranslations();
injectPluginsReducers();
render(
<ApolloProvider client={client} store={store}>
+1 -5
View File
@@ -4,7 +4,6 @@ import * as actions from '../constants/auth';
const initialState = Map({
loggedIn: false,
user: null,
isAdmin: false,
loginError: null,
loginMaxExceeded: false,
passwordRequestSuccess: null
@@ -24,12 +23,9 @@ export default function auth (state = initialState, action) {
return state
.set('loggedIn', true)
.set('loadingUser', false)
.set('isAdmin', action.isAdmin)
.set('user', action.user);
case actions.LOGOUT_SUCCESS:
case actions.LOGOUT:
return initialState;
case actions.LOGIN_REQUEST:
return state.set('loginError', null);
case actions.LOGIN_SUCCESS:
return state.set('loginMaxExceeded', false).set('loginError', null);
case actions.LOGIN_FAILURE:
+4 -4
View File
@@ -53,17 +53,17 @@ export default function community (state = initialState, action) {
}
case SET_ROLE : {
const commenters = state.get('accounts');
const idx = commenters.findIndex(el => el.id === action.id);
const idx = commenters.findIndex((el) => el.id === action.id);
commenters[idx].roles[0] = action.role;
return state.set('accounts', commenters.map(id => id));
return state.set('accounts', commenters.map((id) => id));
}
case SET_COMMENTER_STATUS: {
const commenters = state.get('accounts');
const idx = commenters.findIndex(el => el.id === action.id);
const idx = commenters.findIndex((el) => el.id === action.id);
commenters[idx].status = action.status;
return state.set('accounts', commenters.map(id => id));
return state.set('accounts', commenters.map((id) => id));
}
case SORT_UPDATE :
+1 -1
View File
@@ -13,5 +13,5 @@ export default {
community,
moderation,
install,
config
config,
};
+52 -5
View File
@@ -1,28 +1,57 @@
import {Map} from 'immutable';
import {fromJS, Map, Set} from 'immutable';
import * as actions from '../constants/moderation';
const initialState = Map({
const initialState = fromJS({
singleView: false,
modalOpen: false,
user: Map({}),
user: {},
commentId: null,
commentStatus: null,
userDetailId: null,
userDetailActiveTab: 'all',
userDetailStatuses: ['NONE', 'ACCEPTED', 'REJECTED', 'PREMOD'],
userDetailSelectedIds: new Set(),
banDialog: false,
shortcutsNoteVisible: window.localStorage.getItem('coral:shortcutsNote') || 'show'
shortcutsNoteVisible: window.localStorage.getItem('coral:shortcutsNote') || 'show',
sortOrder: 'REVERSE_CHRONOLOGICAL',
suspendUserDialog: {
show: false,
userId: null,
username: '',
commentId: null,
commentStatus: '',
},
});
export default function moderation (state = initialState, action) {
switch (action.type) {
case actions.HIDE_BANUSER_DIALOG:
return state
.set('banDialog', false);
.set('banDialog', false)
.set('commentStatus', null);
case actions.SHOW_BANUSER_DIALOG:
return state
.merge({
user: Map(action.user),
commentId: action.commentId,
commentStatus: action.commentStatus,
showRejectedNote: action.showRejectedNote,
banDialog: true
});
case actions.SHOW_SUSPEND_USER_DIALOG:
return state
.mergeDeep({
suspendUserDialog: {
show: true,
userId: action.userId,
username: action.username,
commentId: action.commentId,
commentStatus: action.commentStatus,
}
});
case actions.HIDE_SUSPEND_USER_DIALOG:
return state
.setIn(['suspendUserDialog', 'show'], false);
case actions.SET_ACTIVE_TAB:
return state
.set('activeTab', action.activeTab);
@@ -35,6 +64,24 @@ export default function moderation (state = initialState, action) {
case actions.HIDE_SHORTCUTS_NOTE:
return state
.set('shortcutsNoteVisible', 'hide');
case actions.VIEW_USER_DETAIL:
return state.set('userDetailId', action.userId);
case actions.HIDE_USER_DETAIL:
return state
.set('userDetailId', null)
.update('userDetailSelectedIds', (set) => set.clear());
case actions.CLEAR_USER_DETAIL_SELECTIONS:
return state.update('userDetailSelectedIds', (set) => set.clear());
case actions.CHANGE_USER_DETAIL_STATUSES:
return state
.set('userDetailActiveTab', action.tab)
.set('userDetailStatuses', action.statuses);
case actions.SELECT_USER_DETAIL_COMMENT:
return state.update('userDetailSelectedIds', (set) => set.add(action.id));
case actions.UNSELECT_USER_DETAIL_COMMENT:
return state.update('userDetailSelectedIds', (set) => set.delete(action.id));
case actions.SET_SORT_ORDER:
return state.set('sortOrder', action.order);
default :
return state;
}
@@ -1,8 +1,10 @@
import React from 'react';
import styles from '../Community.css';
import BanUserButton from '../../../components/BanUserButton';
import styles from './Community.css';
import BanUserButton from './BanUserButton';
import {Button} from 'coral-ui';
import {menuActionsMap} from '../../../containers/ModerationQueue/helpers/moderationQueueActionsMap';
import {menuActionsMap} from '../../Moderation/helpers/moderationQueueActionsMap';
import t from 'coral-framework/services/i18n';
const ActionButton = ({type = '', user, ...props}) => {
if (type === 'BAN') {
@@ -17,7 +19,7 @@ const ActionButton = ({type = '', user, ...props}) => {
onClick={() => {
type === 'APPROVE' ? props.approveUser({userId: user.id}) : props.showSuspendUserDialog({user: user});
}}
>{menuActionsMap[type].text}</Button>
>{t(`modqueue.${menuActionsMap[type].text}`)}</Button>
);
};
@@ -2,9 +2,7 @@ import React, {PropTypes} from 'react';
import {Button, Icon} from 'coral-ui';
import styles from './BanUserButton.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const BanUserButton = ({user, ...props}) => (
<div className={styles.ban}>
@@ -14,7 +12,7 @@ const BanUserButton = ({user, ...props}) => (
onClick={props.onClick}
raised>
<Icon name='not_interested' />
{lang.t('comment.ban_user')}
{t('comment.ban_user')}
</Button>
</div>
);
@@ -4,10 +4,7 @@ import styles from './BanUserDialog.css';
import Button from 'coral-ui/components/Button';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const BanUserDialog = ({open, handleClose, handleBanUser, user}) => (
<Dialog
@@ -16,19 +13,19 @@ const BanUserDialog = ({open, handleClose, handleBanUser, user}) => (
open={open}
onClose={handleClose}
onCancel={handleClose}
title={lang.t('community.ban_user')}>
title={t('community.ban_user')}>
<span className={styles.close} onClick={handleClose}>×</span>
<div>
<div className={styles.header}>
<h2>{lang.t('community.ban_user')}</h2>
<h2>{t('community.ban_user')}</h2>
</div>
<div className={styles.separator}>
<h3>{lang.t('community.are_you_sure', user.username)}</h3>
<i>{lang.t('community.note')}</i>
<h3>{t('community.are_you_sure', user.username)}</h3>
<i>{t('community.note')}</i>
</div>
<div className={styles.buttons}>
<Button cStyle="cancel" className={styles.cancel} onClick={handleClose} raised>
{lang.t('community.cancel')}
{t('community.cancel')}
</Button>
<Button
cStyle="black" className={styles.ban}
@@ -38,7 +35,7 @@ const BanUserDialog = ({open, handleClose, handleBanUser, user}) => (
});
}}
raised>
{lang.t('community.yes_ban_user')}
{t('community.yes_ban_user')}
</Button>
</div>
</div>
@@ -1,55 +1,26 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {compose} from 'react-apollo';
import {modUserFlaggedQuery} from 'coral-admin/src/graphql/queries';
import {banUser, setUserStatus, suspendUser} from 'coral-admin/src/graphql/mutations';
import {
fetchAccounts,
updateSorting,
newPage,
showBanUserDialog,
hideBanUserDialog,
showSuspendUserDialog,
hideSuspendUserDialog
} from '../../actions/community';
import CommunityMenu from './components/CommunityMenu';
import BanUserDialog from './components/BanUserDialog';
import SuspendUserDialog from './components/SuspendUserDialog';
import CommunityMenu from './CommunityMenu';
import BanUserDialog from './BanUserDialog';
import SuspendUserDialog from './SuspendUserDialog';
import People from './People';
import FlaggedAccounts from './FlaggedAccounts';
class CommunityContainer extends Component {
export default class Community extends Component {
constructor(props) {
super(props);
state = {
searchValue: '',
timer: null
};
this.state = {
searchValue: '',
timer: null
};
this.onKeyDownHandler = this.onKeyDownHandler.bind(this);
this.onSearchChange = this.onSearchChange.bind(this);
this.onHeaderClickHandler = this.onHeaderClickHandler.bind(this);
this.onNewPageHandler = this.onNewPageHandler.bind(this);
}
componentWillMount() {
this.props.fetchAccounts({});
}
onKeyDownHandler(e) {
onKeyDownHandler = (e) => {
if (e.key === 'Enter') {
e.preventDefault();
this.search();
}
}
onSearchChange(e) {
onSearchChange = (e) => {
const value = e.target.value;
this.setState((prevState) => {
prevState.searchValue = value;
@@ -62,6 +33,16 @@ class CommunityContainer extends Component {
});
}
onHeaderClickHandler = (sort) => {
this.props.updateSorting(sort);
this.search();
}
onNewPageHandler = (page) => {
this.props.newPage(page);
this.search({page});
}
search(query = {}) {
const {community} = this.props;
@@ -71,21 +52,10 @@ class CommunityContainer extends Component {
asc: community.ascPeople,
...query
});
}
onHeaderClickHandler(sort) {
this.props.dispatch(updateSorting(sort));
this.search();
}
onNewPageHandler(page) {
this.props.dispatch(newPage(page));
this.search({page});
}
getTabContent(searchValue, props) {
const {community, data} = props;
const {community, root: {users}} = props;
const activeTab = props.route.path === ':id' ? 'flagged' : props.route.path;
if (activeTab === 'people') {
@@ -108,12 +78,10 @@ class CommunityContainer extends Component {
return (
<div>
<FlaggedAccounts
commenters={data.users}
isFetching={data.loading}
error={data.error}
commenters={users}
showBanUserDialog={props.showBanUserDialog}
approveUser={props.approveUser}
suspendUser={props.suspendUser}
rejectUsername={props.rejectUsername}
showSuspendUserDialog={props.showSuspendUserDialog}
/>
<BanUserDialog
@@ -126,7 +94,7 @@ class CommunityContainer extends Component {
open={community.suspendDialog}
handleClose={props.hideSuspendUserDialog}
user={community.user}
suspendUser={props.suspendUser}
rejectUsername={props.rejectUsername}
/>
</div>
);
@@ -134,7 +102,6 @@ class CommunityContainer extends Component {
render() {
const {searchValue} = this.state;
const tab = this.getTabContent(searchValue, this.props);
return (
@@ -148,22 +115,3 @@ class CommunityContainer extends Component {
}
}
const mapStateToProps = state => ({
community: state.community.toJS()
});
const mapDispatchToProps = dispatch => ({
fetchAccounts: query => dispatch(fetchAccounts(query)),
showBanUserDialog: (user) => dispatch(showBanUserDialog(user)),
hideBanUserDialog: () => dispatch(hideBanUserDialog(false)),
showSuspendUserDialog: (user) => dispatch(showSuspendUserDialog(user)),
hideSuspendUserDialog: () => dispatch(hideSuspendUserDialog())
});
export default compose(
connect(mapStateToProps, mapDispatchToProps),
modUserFlaggedQuery,
banUser,
setUserStatus,
suspendUser
)(CommunityContainer);
@@ -1,6 +1,6 @@
import React from 'react';
const CommunityLayout = props => (
const CommunityLayout = (props) => (
<div>
{props.children}
</div>
@@ -1,14 +1,9 @@
import React from 'react';
import styles from './styles.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
import t from 'coral-framework/services/i18n';
import {Link} from 'react-router';
const lang = new I18n(translations);
const CommunityMenu = () => {
const flaggedPath = '/admin/community/flagged';
const peoplePath = '/admin/community/people';
@@ -17,10 +12,10 @@ const CommunityMenu = () => {
<div className={`mdl-tabs__tab-bar ${styles.tabBar}`}>
<div>
<Link to={flaggedPath} className={`mdl-tabs__tab ${styles.tab}`} activeClassName={styles.active}>
{lang.t('community.flaggedaccounts')}
{t('community.flaggedaccounts')}
</Link>
<Link to={peoplePath} className={`mdl-tabs__tab ${styles.tab}`} activeClassName={styles.active}>
{lang.t('community.people')}
{t('community.people')}
</Link>
</div>
</div>
@@ -1,25 +1,19 @@
import React from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
import styles from './Community.css';
import Loading from './Loading';
import EmptyCard from 'coral-admin/src/components/EmptyCard';
import User from './components/User';
import User from './User';
const FlaggedAccounts = ({...props}) => {
const {commenters, isFetching} = props;
const hasResults = !isFetching && commenters && !!commenters.length;
const {commenters} = props;
const hasResults = commenters && !!commenters.length;
// if (commenter.status === 'PENDING' && commenter.actions.length > 0) {
return (
<div className={styles.container}>
<div className={styles.mainFlaggedContent}>
{ isFetching && <Loading /> }
{
hasResults
? commenters.map((commenter, index) => {
@@ -34,7 +28,7 @@ const FlaggedAccounts = ({...props}) => {
suspendUser={props.suspendUser}
/>;
})
: <EmptyCard>{lang.t('community.no-flagged-accounts')}</EmptyCard>
: <EmptyCard>{t('community.no_flagged_accounts')}</EmptyCard>
}
</div>
</div>
@@ -1,36 +1,32 @@
import React from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
import styles from './Community.css';
import Table from './Table';
import Loading from './Loading';
import Table from '../containers/Table';
import {Pager, Icon} from 'coral-ui';
import EmptyCard from '../../components/EmptyCard';
const lang = new I18n(translations);
import EmptyCard from '../../../components/EmptyCard';
import t from 'coral-framework/services/i18n';
const tableHeaders = [
{
title: lang.t('community.username_and_email'),
title: t('community.username_and_email'),
field: 'username'
},
{
title: lang.t('community.account_creation_date'),
title: t('community.account_creation_date'),
field: 'created_at'
},
{
title: lang.t('community.status'),
title: t('community.status'),
field: 'status'
},
{
title: lang.t('community.newsroom_role'),
title: t('community.newsroom_role'),
field: 'role'
}
];
const People = ({isFetching, commenters, searchValue, onSearchChange, ...props}) => {
const hasResults = !isFetching && !!commenters.length;
const People = ({commenters, searchValue, onSearchChange, ...props}) => {
const hasResults = !!commenters.length;
return (
<div className={styles.container}>
<div className={styles.leftColumn}>
@@ -42,12 +38,11 @@ const People = ({isFetching, commenters, searchValue, onSearchChange, ...props})
className={styles.searchBoxInput}
value={searchValue}
onChange={onSearchChange}
placeholder={lang.t('streams.search')}
placeholder={t('streams.search')}
/>
</div>
</div>
<div className={styles.mainContent}>
{ isFetching && <Loading /> }
{
hasResults
? <Table
@@ -55,7 +50,7 @@ const People = ({isFetching, commenters, searchValue, onSearchChange, ...props})
commenters={commenters}
onHeaderClickHandler={props.onHeaderClickHandler}
/>
: <EmptyCard>{lang.t('community.no-results')}</EmptyCard>
: <EmptyCard>{t('community.no_results')}</EmptyCard>
}
<Pager
totalPages={props.totalPages}
@@ -3,23 +3,20 @@ import React, {Component, PropTypes} from 'react';
import {Dialog, Button} from 'coral-ui';
import styles from './SuspendUserDialog.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const stages = [
{
title: 'suspenduser.title_0',
description: 'suspenduser.description_0',
title: 'suspenduser.title_reject',
description: 'suspenduser.description_reject',
options: {
'j': 'suspenduser.no_cancel',
'k': 'suspenduser.yes_suspend'
}
},
{
title: 'suspenduser.title_1',
description: 'suspenduser.description_1',
title: 'suspenduser.title_notify',
description: 'suspenduser.description_notify',
options: {
'j': 'bandialog.cancel',
'k': 'suspenduser.send'
@@ -34,11 +31,11 @@ class SuspendUserDialog extends Component {
static propTypes = {
stage: PropTypes.number,
handleClose: PropTypes.func.isRequired,
suspendUser: PropTypes.func.isRequired
rejectUsername: PropTypes.func.isRequired
}
componentDidMount() {
this.setState({email: lang.t('suspenduser.email'), about: lang.t('suspenduser.username')});
this.setState({email: t('suspenduser.email_message_reject'), about: t('suspenduser.username')});
}
/*
@@ -46,13 +43,13 @@ class SuspendUserDialog extends Component {
* handles the possible actions for that dialog.
*/
onActionClick = (stage, menuOption) => () => {
const {suspendUser, user} = this.props;
const {rejectUsername, user} = this.props;
const {stage} = this.state;
const cancel = this.props.handleClose;
const next = () => this.setState({stage: stage + 1});
const suspend = () => {
suspendUser({userId: user.user.id, message: this.state.email})
rejectUsername({id: user.user.id, message: this.state.email})
.then(() => {
this.props.handleClose();
});
@@ -79,18 +76,18 @@ class SuspendUserDialog extends Component {
open={open}
onClose={handleClose}
onCancel={handleClose}
title={lang.t('suspenduser.title')}>
title={t('suspenduser.suspend_user')}>
<div className={styles.title}>
{lang.t(stages[stage].title, lang.t('suspenduser.username'))}
{t(stages[stage].title, t('suspenduser.username'))}
</div>
<div className={styles.container}>
<div className={styles.description}>
{lang.t(stages[stage].description, lang.t('suspenduser.username'))}
{t(stages[stage].description, t('suspenduser.username'))}
</div>
{
stage === 1 &&
<div className={styles.writeContainer}>
<div className={styles.emailMessage}>{lang.t('suspenduser.write_message')}</div>
<div className={styles.emailMessage}>{t('suspenduser.write_message')}</div>
<div className={styles.emailContainer}>
<textarea
rows={5}
@@ -103,7 +100,7 @@ class SuspendUserDialog extends Component {
<div className={styles.modalButtons}>
{Object.keys(stages[stage].options).map((key, i) => (
<Button key={i} onClick={this.onActionClick(stage, i)}>
{lang.t(stages[stage].options[key], lang.t('suspenduser.username'))}
{t(stages[stage].options[key], t('suspenduser.username'))}
</Button>
))}
</div>
@@ -0,0 +1,54 @@
import React from 'react';
import {SelectField, Option} from 'react-mdl-selectfield';
import styles from '../components/Community.css';
import t from 'coral-framework/services/i18n';
export default ({headers, commenters, onHeaderClickHandler, onRoleChange, onCommenterStatusChange}) => (
<table className={`mdl-data-table ${styles.dataTable}`}>
<thead>
<tr>
{headers.map((header, i) =>(
<th
key={i}
className="mdl-data-table__cell--non-numeric"
onClick={() => onHeaderClickHandler({field: header.field})}>
{header.title}
</th>
))}
</tr>
</thead>
<tbody>
{commenters.map((row, i)=> (
<tr key={i}>
<td className="mdl-data-table__cell--non-numeric">
{row.username}
<span className={styles.email}>{row.profiles.map(({id}) => id)}</span>
</td>
<td className="mdl-data-table__cell--non-numeric">
{row.created_at}
</td>
<td className="mdl-data-table__cell--non-numeric">
<SelectField label={'Select me'} value={row.status || ''}
className={styles.selectField}
label={t('community.status')}
onChange={(status) => onCommenterStatusChange(row.id, status)}>
<Option value={'ACTIVE'}>{t('community.active')}</Option>
<Option value={'BANNED'}>{t('community.banned')}</Option>
</SelectField>
</td>
<td className="mdl-data-table__cell--non-numeric">
<SelectField label={'Select me'} value={row.roles[0] || ''}
className={styles.selectField}
label={t('community.role')}
onChange={(role) => onRoleChange(row.id, role)}>
<Option value={''}>.</Option>
<Option value={'STAFF'}>{t('community.staff')}</Option>
<Option value={'MODERATOR'}>{t('community.moderator')}</Option>
<Option value={'ADMIN'}>{t('community.admin')}</Option>
</SelectField>
</td>
</tr>
))}
</tbody>
</table>
);
@@ -1,15 +1,20 @@
import React from 'react';
import styles from '../Community.css';
import styles from './Community.css';
import ActionButton from './ActionButton';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../../translations.json';
import t from 'coral-framework/services/i18n';
const lang = new I18n(translations);
const shortReasons = {
'This comment is offensive': t('community.offensive'),
'This looks like an ad/marketing': t('community.spam_ads'),
'This user is impersonating': t('community.impersonating'),
'I don\'t like this username': t('community.dont_like_username'),
'Other': t('community.other')
};
// Render a single user for the list
const User = props => {
const User = (props) => {
const {user, modActionButtons} = props;
let userStatus = user.status;
@@ -35,21 +40,21 @@ const User = props => {
<div className={styles.itemBody}>
<div className={styles.body}>
<div className={styles.flaggedByCount}>
<i className="material-icons">flag</i><span className={styles.flaggedByLabel}>{lang.t('community.flags')}({ user.actions.length })</span>:
<i className="material-icons">flag</i><span className={styles.flaggedByLabel}>{t('community.flags')}({ user.actions.length })</span>:
{ user.action_summaries.map(
(action, i ) => {
(action, i) => {
return <span className={styles.flaggedBy} key={i}>
{lang.t(`community.${action.reason}`)} ({action.count})
{shortReasons[action.reason]} ({action.count})
</span>;
}
)}
</div>
<div className={styles.flaggedReasons}>
{ user.action_summaries.map(
(action_sum, i ) => {
(action_sum, i) => {
return <div key={i}>
<span className={styles.flaggedByLabel}>
{lang.t(`community.${action_sum.reason}`)} ({action_sum.count})
{shortReasons[action_sum.reason]} ({action_sum.count})
</span>
{user.actions.map(
@@ -0,0 +1,107 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {compose, gql} from 'react-apollo';
import withQuery from 'coral-framework/hocs/withQuery';
import {Spinner} from 'coral-ui';
import {withSetUserStatus, withRejectUsername} from 'coral-framework/graphql/mutations';
import {
fetchAccounts,
updateSorting,
newPage,
showBanUserDialog,
hideBanUserDialog,
showSuspendUserDialog,
hideSuspendUserDialog
} from '../../../actions/community';
import Community from '../components/Community';
class CommunityContainer extends Component {
componentWillMount() {
this.props.fetchAccounts({});
}
approveUser = ({userId}) => {
return this.props.setUserStatus({userId, status: 'APPROVED'});
}
banUser = ({userId}) => {
return this.props.setUserStatus({userId, status: 'BANNED'});
}
render() {
if (this.props.data.error) {
return <div>{this.props.data.error.message}</div>;
}
if (!('users' in this.props.root)) {
return <div><Spinner/></div>;
}
return (
<Community {...this.props} approveUser={this.approveUser} banUser={this.banUser}/>
);
}
}
export const withCommunityQuery = withQuery(gql`
query CoralAdmin_Community($action_type: ACTION_TYPE) {
users(query:{action_type: $action_type}){
id
username
status
roles
actions{
id
created_at
... on FlagAction {
reason
message
user {
id
username
}
}
}
action_summaries {
count
... on FlagActionSummary {
reason
}
}
}
}
`, {
options: ({params: {action_type = 'FLAG'}}) => {
return {
variables: {
action_type: action_type
}
};
}
});
const mapStateToProps = (state) => ({
community: state.community.toJS()
});
const mapDispatchToProps = (dispatch) =>
bindActionCreators({
fetchAccounts,
showBanUserDialog,
hideBanUserDialog,
showSuspendUserDialog,
hideSuspendUserDialog,
updateSorting,
newPage,
}, dispatch);
export default compose(
connect(mapStateToProps, mapDispatchToProps),
withCommunityQuery,
withSetUserStatus,
withRejectUsername,
)(CommunityContainer);
@@ -0,0 +1,37 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {compose} from 'react-apollo';
import {setRole, setCommenterStatus} from '../../../actions/community';
import Table from '../components/Table';
class TableContainer extends Component {
constructor (props) {
super(props);
}
render () {
return <Table
{...this.props}
onRoleChange={this.props.setRole}
onCommenterStatusChange={this.props.setCommenterStatus}
commenters={this.props.commenters}
/>;
}
}
const mapStateToProps = (state) => ({
commenters: state.community.get('accounts'),
});
const mapDispatchToProps = (dispatch) =>
bindActionCreators({
setCommenterStatus,
setRole,
}, dispatch);
export default compose(
connect(mapStateToProps, mapDispatchToProps),
)(TableContainer);
@@ -0,0 +1,2 @@
export {default as Community} from './containers/Community';
export {default as CommunityLayout} from './components/CommunityLayout';
@@ -96,24 +96,27 @@
}
}
.charCountTexfield {
width: 4em;
padding: 0px;
.inlineTextfield {
border-color: #ccc;
border-style: solid;
border-width: 0px 0px 1px 0px;
font-size: 14px;
text-align: center;
font-size: inherit;
}
.inlineTextfield:focus {
outline: none;
}
.charCountTexfield, .editCommentTimeframeTextfield {
width: 4em;
padding: 0px;
}
.charCountTexfieldEnabled {
border-color: #00796b;
}
.charCountTexfield:focus {
outline: none;
}
.changedSave {
background-color: #00796B;
color: white;
@@ -1,60 +1,43 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {
fetchSettings,
updateSettings,
saveSettingsToServer,
updateWordlist,
updateDomainlist
} from '../../actions/settings';
import {Button, List, Item, Card, Spinner} from 'coral-ui';
import styles from './Configure.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
import StreamSettings from './StreamSettings';
import ModerationSettings from './ModerationSettings';
import TechSettings from './TechSettings';
import t from 'coral-framework/services/i18n';
import {can} from 'coral-framework/services/perms';
class Configure extends Component {
constructor (props) {
super(props);
export default class Configure extends Component {
this.state = {
activeSection: 'stream',
changed: false,
errors: {}
};
this.changeSection = this.changeSection.bind(this);
}
componentWillMount = () => {
this.props.dispatch(fetchSettings());
}
state = {
activeSection: 'stream',
changed: false,
errors: {}
};
saveSettings = () => {
this.props.dispatch(saveSettingsToServer());
this.props.saveSettingsToServer();
this.setState({changed: false});
}
changeSection(activeSection) {
changeSection = (activeSection) => {
this.setState({activeSection});
}
onChangeWordlist = (listName, list) => {
this.setState({changed: true});
this.props.dispatch(updateWordlist(listName, list));
this.props.updateWordlist(listName, list);
}
onChangeDomainlist = (listName, list) => {
this.setState({changed: true});
this.props.dispatch(updateDomainlist(listName, list));
this.props.updateDomainlist(listName, list);
}
onSettingUpdate = (setting) => {
this.setState({changed: true});
this.props.dispatch(updateSettings(setting));
this.props.updateSettings(setting);
}
// Sets an arbitrary error string and a boolean state.
@@ -105,11 +88,11 @@ class Configure extends Component {
getPageTitle (section) {
switch(section) {
case 'stream':
return lang.t('configure.stream-settings');
return t('configure.stream_settings');
case 'moderation':
return lang.t('configure.moderation-settings');
return t('configure.moderation_settings');
case 'tech':
return lang.t('configure.tech-settings');
return t('configure.tech_settings');
default:
return '';
}
@@ -118,6 +101,11 @@ class Configure extends Component {
render () {
const {activeSection} = this.state;
const section = this.getSection(activeSection);
const {auth: {user}} = this.props;
if (!can(user, 'UPDATE_CONFIG')) {
return <p>You must be an administrator to access config settings. Please find the nearest Admin and ask them to level you up!</p>;
}
const showSave = Object.keys(this.state.errors).reduce(
(bool, error) => this.state.errors[error] ? false : bool, this.state.changed);
@@ -127,13 +115,13 @@ class Configure extends Component {
<div className={styles.leftColumn}>
<List onChange={this.changeSection} activeItem={activeSection}>
<Item itemId='stream' icon='speaker_notes'>
{lang.t('configure.stream-settings')}
{t('configure.stream_settings')}
</Item>
<Item itemId='moderation' icon='thumbs_up_down'>
{lang.t('configure.moderation-settings')}
{t('configure.moderation_settings')}
</Item>
<Item itemId='tech' icon='code'>
{lang.t('configure.tech-settings')}
{t('configure.tech_settings')}
</Item>
</List>
<div className={styles.saveBox}>
@@ -146,7 +134,7 @@ class Configure extends Component {
icon='check'
full
>
{lang.t('configure.save-changes')}
{t('configure.save_changes')}
</Button>
:
<Button
@@ -155,7 +143,7 @@ class Configure extends Component {
icon='check'
full
>
{lang.t('configure.save-changes')}
{t('configure.save_changes')}
</Button>
}
</div>
@@ -170,10 +158,3 @@ class Configure extends Component {
);
}
}
const mapStateToProps = state => ({
settings: state.settings.toJS()
});
export default connect(mapStateToProps)(Configure);
const lang = new I18n(translations);
@@ -2,24 +2,21 @@ import React from 'react';
import {Card} from 'coral-ui';
import styles from './Configure.css';
import TagsInput from 'react-tagsinput';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const Domainlist = ({domains, onChangeDomainlist}) => {
return (
<Card id={styles.domainlist} className={styles.configSetting}>
<div className={styles.wrapper}>
<div className={styles.settingsHeader}>{lang.t('configure.domain-list-title')}</div>
<p className={styles.domainlistDesc}>{lang.t('configure.domain-list-text')}</p>
<div className={styles.settingsHeader}>{t('configure.domain_list_title')}</div>
<p className={styles.domainlistDesc}>{t('configure.domain_list_text')}</p>
<div className={styles.wrapper}>
<TagsInput
value={domains}
inputProps={{placeholder: 'URL'}}
addOnPaste={true}
pasteSplit={data => data.split(',').map(d => d.trim())}
onChange={tags => onChangeDomainlist('whitelist', tags)}
pasteSplit={(data) => data.split(',').map((d) => d.trim())}
onChange={(tags) => onChangeDomainlist('whitelist', tags)}
/>
</div>
</div>
@@ -1,6 +1,5 @@
import React, {Component} from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
import t from 'coral-framework/services/i18n';
import styles from './Configure.css';
import {Button, Card} from 'coral-ui';
@@ -30,7 +29,7 @@ class EmbedLink extends Component {
location.protocol,
'//',
location.hostname,
location.port ? (`:${ window.location.port}`) : ''
location.port ? (`:${window.location.port}`) : ''
].join('');
const coralJsUrl = [talkBaseUrl, '/embed.js'].join('');
const nonce = String(Math.random()).slice(2);
@@ -47,11 +46,11 @@ class EmbedLink extends Component {
<Card shadow="2" className={styles.configSetting}>
<div className={styles.wrapper}>
<div className={styles.settingsHeader}>Embed Comment Stream</div>
<p>{lang.t('configure.copy-and-paste')}</p>
<p>{t('configure.copy_and_paste')}</p>
<textarea rows={5} type='text' className={styles.embedInput} value={embedText} readOnly={true}/>
<div className={styles.actions}>
<Button raised className={styles.copyButton} onClick={this.copyToClipBoard} cStyle="black">
{lang.t('embedlink.copy')}
{t('embedlink.copy')}
</Button>
<div className={styles.copiedText}>
{this.state.copied && 'Copied!'}
@@ -64,5 +63,3 @@ class EmbedLink extends Component {
}
export default EmbedLink;
const lang = new I18n(translations);
@@ -3,9 +3,7 @@ import styles from './Configure.css';
import {Card} from 'coral-ui';
import {Checkbox} from 'react-mdl';
import Wordlist from './Wordlist';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const updateModeration = (updateSettings, mod) => () => {
const moderation = mod === 'PRE' ? 'POST' : 'PRE';
@@ -36,9 +34,9 @@ const ModerationSettings = ({settings, updateSettings, onChangeWordlist}) => {
checked={settings.requireEmailConfirmation} />
</div>
<div className={styles.content}>
<div className={styles.settingsHeader}>{lang.t('configure.require-email-verification')}</div>
<div className={styles.settingsHeader}>{t('configure.require_email_verification')}</div>
<p className={settings.requireEmailConfirmation ? '' : styles.disabledSettingText}>
{lang.t('configure.require-email-verification-text')}
{t('configure.require_email_verification_text')}
</p>
</div>
</Card>
@@ -49,9 +47,9 @@ const ModerationSettings = ({settings, updateSettings, onChangeWordlist}) => {
checked={settings.moderation === 'PRE'} />
</div>
<div className={styles.content}>
<div className={styles.settingsHeader}>{lang.t('configure.enable-pre-moderation')}</div>
<div className={styles.settingsHeader}>{t('configure.enable_pre_moderation')}</div>
<p className={settings.moderation === 'PRE' ? '' : styles.disabledSettingText}>
{lang.t('configure.enable-pre-moderation-text')}
{t('configure.enable_pre_moderation_text')}
</p>
</div>
</Card>
@@ -62,9 +60,9 @@ const ModerationSettings = ({settings, updateSettings, onChangeWordlist}) => {
checked={settings.premodLinksEnable} />
</div>
<div className={styles.content}>
<div className={styles.settingsHeader}>{lang.t('configure.enable-premod-links')}</div>
<div className={styles.settingsHeader}>{t('configure.enable_premod_links')}</div>
<p>
{lang.t('configure.enable-premod-links-text')}
{t('configure.enable_premod_links_text')}
</p>
</div>
</Card>
@@ -1,7 +1,6 @@
import React from 'react';
import {SelectField, Option} from 'react-mdl-selectfield';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
import t from 'coral-framework/services/i18n';
import styles from './Configure.css';
import {Checkbox, Textfield} from 'react-mdl';
import {Card, Icon, TextArea} from 'coral-ui';
@@ -62,6 +61,13 @@ const updateClosedTimeout = (updateSettings, ts, isMeasure) => (event) => {
}
};
const updateEditCommentWindowLength = (updateSettings) => (e) => {
const value = e.target.value;
const valueAsNumber = parseFloat(value);
const milliseconds = (!isNaN(valueAsNumber)) && (valueAsNumber * 1000);
updateSettings({editCommentWindowLength: milliseconds || value});
};
const StreamSettings = ({updateSettings, settingsError, settings, errors}) => {
// just putting this here for shorthand below
@@ -77,23 +83,23 @@ const StreamSettings = ({updateSettings, settingsError, settings, errors}) => {
checked={settings.charCountEnable} />
</div>
<div className={styles.content}>
<div className={styles.settingsHeader}>{lang.t('configure.comment-count-header')}</div>
<div className={styles.settingsHeader}>{t('configure.comment_count_header')}</div>
<p className={settings.charCountEnable ? '' : styles.disabledSettingText}>
<span>{lang.t('configure.comment-count-text-pre')}</span>
<span>{t('configure.comment_count_text_pre')}</span>
<input type='text'
className={`${styles.charCountTexfield} ${settings.charCountEnable && styles.charCountTexfieldEnabled}`}
className={`${styles.inlineTextfield} ${styles.charCountTexfield} ${settings.charCountEnable && styles.charCountTexfieldEnabled}`}
htmlFor='charCount'
onChange={updateCharCount(updateSettings, settingsError)}
value={settings.charCount}
disabled={settings.charCountEnable ? '' : 'disabled'}
/>
<span>{lang.t('configure.comment-count-text-post')}</span>
<span>{t('configure.comment_count_text_post')}</span>
{
errors.charCount &&
<span className={styles.settingsError}>
<br/>
<Icon name="error_outline"/>
{lang.t('configure.comment-count-error')}
{t('configure.comment_count_error')}
</span>
}
</p>
@@ -107,10 +113,10 @@ const StreamSettings = ({updateSettings, settingsError, settings, errors}) => {
</div>
<div className={styles.content}>
<div className={styles.settingsHeader}>
{lang.t('configure.include-comment-stream')}
{t('configure.include_comment_stream')}
</div>
<p className={settings.infoBoxEnable ? '' : styles.disabledSettingText}>
{lang.t('configure.include-comment-stream-desc')}
{t('configure.include_comment_stream_desc')}
</p>
<div className={`${styles.configSettingInfoBox} ${settings.infoBoxEnable ? null : styles.hidden}`} >
<MarkdownEditor
@@ -123,8 +129,8 @@ const StreamSettings = ({updateSettings, settingsError, settings, errors}) => {
</Card>
<Card className={`${styles.configSetting} ${styles.configSettingInfoBox}`}>
<div className={styles.wrapper}>
<div className={styles.settingsHeader}>{lang.t('configure.closed-stream-settings')}</div>
<p>{lang.t('configure.closed-comments-desc')}</p>
<div className={styles.settingsHeader}>{t('configure.closed_stream_settings')}</div>
<p>{t('configure.closed_comments_desc')}</p>
<div>
<TextArea className={styles.descriptionBox}
onChange={updateClosedMessage(updateSettings)}
@@ -133,6 +139,25 @@ const StreamSettings = ({updateSettings, settingsError, settings, errors}) => {
</div>
</div>
</Card>
{/* Edit Comment Timeframe */}
<Card className={styles.configSetting}>
<div className={styles.settingsHeader}>{t('configure.edit_comment_timeframe_heading')}</div>
<p>
{t('configure.edit_comment_timeframe_text_pre')}
&nbsp;
<input
className={`${styles.inlineTextfield} ${styles.editCommentTimeframeTextfield}`}
type="number"
min="0"
onChange={updateEditCommentWindowLength(updateSettings)}
placeholder="30"
defaultValue={(settings.editCommentWindowLength / 1000) /* saved as ms, rendered as seconds */}
pattern='[0-9]+([\.][0-9]*)?'
/>
&nbsp;
{t('configure.edit_comment_timeframe_text_post')}
</p>
</Card>
<Card className={`${styles.configSetting} ${styles.configSettingInfoBox}`}>
<div className={styles.action}>
<Checkbox
@@ -140,7 +165,7 @@ const StreamSettings = ({updateSettings, settingsError, settings, errors}) => {
checked={settings.autoCloseStream} />
</div>
<div className={styles.content}>
{lang.t('configure.close-after')}
{t('configure.close_after')}
<br />
<Textfield
type='number'
@@ -148,15 +173,15 @@ const StreamSettings = ({updateSettings, settingsError, settings, errors}) => {
style={{width: 50}}
onChange={updateClosedTimeout(updateSettings, settings.closedTimeout)}
value={getTimeoutAmount(settings.closedTimeout)}
label={lang.t('configure.closed-comments-label')} />
label={t('configure.closed_comments_label')} />
<div className={styles.configTimeoutSelect}>
<SelectField
label="comments closed time window"
value={getTimeoutMeasure(settings.closedTimeout)}
onChange={updateClosedTimeout(updateSettings, settings.closedTimeout, true)}>
<Option value={'hours'}>{lang.t('configure.hours')}</Option>
<Option value={'days'}>{lang.t('configure.days')}</Option>
<Option value={'weeks'}>{lang.t('configure.weeks')}</Option>
<Option value={'hours'}>{t('configure.hours')}</Option>
<Option value={'days'}>{t('configure.days')}</Option>
<Option value={'weeks'}>{t('configure.weeks')}</Option>
</SelectField>
</div>
</div>
@@ -170,7 +195,7 @@ export default StreamSettings;
// To see if we are talking about weeks, days or hours
// We talk the remainder of the division and see if it's 0
const getTimeoutMeasure = ts => {
const getTimeoutMeasure = (ts) => {
if (ts % TIMESTAMPS['weeks'] === 0) {
return 'weeks';
} else if (ts % TIMESTAMPS['days'] === 0) {
@@ -182,6 +207,4 @@ const getTimeoutMeasure = ts => {
// Dividing the amount by it's measure (hours, days, weeks) we
// obtain the amount of time
const getTimeoutAmount = ts => ts / TIMESTAMPS[getTimeoutMeasure(ts)];
const lang = new I18n(translations);
const getTimeoutAmount = (ts) => ts / TIMESTAMPS[getTimeoutMeasure(ts)];
@@ -3,9 +3,7 @@ import {Card} from 'coral-ui';
import Domainlist from './Domainlist';
import EmbedLink from './EmbedLink';
import styles from './Configure.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const updateCustomCssUrl = (updateSettings) => (event) => {
const customCssUrl = event.target.value;
@@ -21,8 +19,8 @@ const TechSettings = ({settings, onChangeDomainlist, updateSettings}) => {
<EmbedLink />
<Card className={styles.configSetting}>
<div className={styles.wrapper}>
<div className={styles.settingsHeader}>{lang.t('configure.custom-css-url')}</div>
<p>{lang.t('configure.custom-css-url-desc')}</p>
<div className={styles.settingsHeader}>{t('configure.custom_css_url')}</div>
<p>{t('configure.custom_css_url_desc')}</p>
<input
className={styles.customCSSInput}
value={settings.customCssUrl}
@@ -1,6 +1,5 @@
import React from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
import t from 'coral-framework/services/i18n';
import TagsInput from 'react-tagsinput';
import styles from './Configure.css';
import {Card} from 'coral-ui';
@@ -8,33 +7,31 @@ import {Card} from 'coral-ui';
const Wordlist = ({suspectWords, bannedWords, onChangeWordlist}) => (
<div>
<Card id={styles.bannedWordlist} className={styles.configSetting}>
<div className={styles.settingsHeader}>{lang.t('configure.banned-words-title')}</div>
<p className={styles.wordlistDesc}>{lang.t('configure.banned-word-text')}</p>
<div className={styles.settingsHeader}>{t('configure.banned_words_title')}</div>
<p className={styles.wordlistDesc}>{t('configure.banned_word_text')}</p>
<div className={styles.wrapper}>
<TagsInput
value={bannedWords}
inputProps={{placeholder: 'word or phrase'}}
addOnPaste={true}
pasteSplit={data => data.split(',').map(d => d.trim())}
onChange={tags => onChangeWordlist('banned', tags)}
pasteSplit={(data) => data.split(',').map((d) => d.trim())}
onChange={(tags) => onChangeWordlist('banned', tags)}
/>
</div>
</Card>
<Card id={styles.suspectWordlist} className={styles.configSetting}>
<div className={styles.settingsHeader}>{lang.t('configure.suspect-words-title')}</div>
<p className={styles.wordlistDesc}>{lang.t('configure.suspect-word-text')}</p>
<div className={styles.settingsHeader}>{t('configure.suspect_word_title')}</div>
<p className={styles.wordlistDesc}>{t('configure.suspect_word_text')}</p>
<div className={styles.wrapper}>
<TagsInput
value={suspectWords}
inputProps={{placeholder: 'word or phrase'}}
addOnPaste={true}
pasteSplit={data => data.split(',').map(d => d.trim())}
onChange={tags => onChangeWordlist('suspect', tags)} />
pasteSplit={(data) => data.split(',').map((d) => d.trim())}
onChange={(tags) => onChangeWordlist('suspect', tags)} />
</div>
</Card>
</div>
);
export default Wordlist;
const lang = new I18n(translations);

Some files were not shown because too many files have changed in this diff Show More