Compare commits

...
354 Commits
Author SHA1 Message Date
Wyatt Johnson abdb4cbe3e Merge pull request #980 from coralproject/version-bump
Update package.json
2017-09-20 16:27:33 -06:00
Wyatt Johnson 20380cd62f Update package.json 2017-09-20 16:23:07 -06:00
Wyatt Johnson 4c8894d6e9 Merge pull request #978 from coralproject/fix-userdetail-all-tab
Fix empty user detail all tab
2017-09-20 12:48:46 -06:00
Chi Vinh Le dd5d06aa95 Request status=null 2017-09-21 01:43:04 +07:00
Wyatt Johnson 525da57419 Merge pull request #971 from coralproject/new-flags
Flags: Implement Labels, bugfixes and improvements
2017-09-19 17:17:50 -06:00
Wyatt Johnson 4913eda974 Merge branch 'master' into new-flags 2017-09-19 17:12:56 -06:00
Wyatt Johnson cee247f065 Merge pull request #965 from coralproject/flagged-count
Count for Flagged Usernames
2017-09-19 17:12:41 -06:00
Chi Vinh Le 961111c3f7 Allow priviledged user to query for all statuses 2017-09-20 04:36:58 +07:00
Chi Vinh Le 2d96163b76 Disallow querying for all comments unpriviledgly 2017-09-20 04:35:14 +07:00
Chi Vinh Le c3e24a0451 Apply suggenstions 2017-09-20 04:30:29 +07:00
Chi Vinh Le 42954fb84a Return all actions in CreateCommentResponse 2017-09-20 04:17:15 +07:00
Chi Vinh Le 5f7c4f82e7 Return flags when creating comment, restrict access to actions in comment resolver 2017-09-20 02:50:43 +07:00
Chi Vinh Le b482976c58 Allow querying for all statuses 2017-09-20 02:39:31 +07:00
Chi Vinh Le 6e89b8c1aa Merge branch 'missing-comments' into new-flags 2017-09-19 23:53:46 +07:00
Chi Vinh Le e046a9652d Fix SYSTEM_WITHHELD comments missing in all queue and user detail 2017-09-19 23:52:25 +07:00
Belen Curcio 7a74d5ee83 missing prop 2017-09-19 13:26:04 -03:00
Belen Curcio b9086244e2 More proptypes 2017-09-19 13:24:36 -03:00
Chi Vinh Le 7a4aae93b4 Introduce adminCommentLabels and implement Toxic comment label 2017-09-19 23:14:34 +07:00
Belen Curcio a5350c44ae Adding PropTypes 2017-09-19 13:14:20 -03:00
Belen Curcio a211f94a91 Adding status to the FE Query 2017-09-19 13:11:23 -03:00
Belen Curcio bccad5585e Adding statuses 2017-09-19 13:10:35 -03:00
Belen Curcio b3cb99925d Adding PropTypes 2017-09-19 13:10:14 -03:00
Belen Curcio a96d8c2b3c Copy, removing log, and adding PropTypes 2017-09-19 12:45:47 -03:00
Chi Vinh Le b0219948a0 Added core labels 2017-09-19 22:29:51 +07:00
Chi Vinh Le 563a6d23dd First pass adding labels 2017-09-19 21:43:58 +07:00
Belen Curcio bc5d348c98 Merge branch 'flagged-count' of github.com:coralproject/talk into flagged-count 2017-09-19 11:43:31 -03:00
Belen Curcio 818ad07eac lint fixes 2017-09-19 11:43:10 -03:00
Belén Curcio b8f6ab9237 Merge branch 'master' into flagged-count 2017-09-19 11:15:11 -03:00
Belen Curcio f1f9868028 Cleaning console.logs 2017-09-19 11:13:06 -03:00
Chi Vinh Le b5deac7b48 Bugfixes and show different notification for toxic comments
Bugfixes:
- Toxic comment flag was not added
- GraphQL warnings for missing fields
2017-09-19 19:20:38 +07:00
Kim Gardner ae430245ec Merge pull request #970 from coralproject/default-in-stream-mod
Make in-stream moderation a default plugin
2017-09-19 11:47:25 +01:00
Kim Gardner ebe7ccfd10 Make in-stream moderation a default plugin 2017-09-19 11:09:22 +01:00
Kim Gardner f00e8dc335 Merge branch 'master' into flagged-count 2017-09-19 09:44:33 +01:00
Kim Gardner 262213a520 Merge pull request #968 from coralproject/all-comments-translation
Replace hard-coded string on all comments tab with translation
2017-09-19 09:41:03 +01:00
Kim Gardner 00f98520f7 Merge branch 'master' into flagged-count 2017-09-19 09:12:15 +01:00
Kim Gardner 0dfcbc9927 Merge branch 'master' into all-comments-translation 2017-09-19 09:11:44 +01:00
Kim Gardner a68e1c9c0b Merge pull request #969 from coralproject/helmet-config
Expose Helmet configuration
2017-09-19 09:11:14 +01:00
Belen Curcio 75635aff2b Merge branch 'flagged-count' of github.com:coralproject/talk into flagged-count 2017-09-18 15:52:06 -03:00
Belen Curcio ab2e036047 withFragments and parent withQuery added 2017-09-18 15:49:23 -03:00
Wyatt Johnson 52c1989780 Expose Helmet configuration
- Fixes #962
2017-09-18 11:57:57 -06:00
Kiwi abd458ab82 Merge branch 'master' into all-comments-translation 2017-09-18 19:48:09 +02:00
Chi Vinh Le 41afe9fae7 Replace hard-coded string on all comments tab with translation 2017-09-19 00:41:38 +07:00
Kim Gardner e6fa0a6d12 Merge pull request #950 from coralproject/fix-notify-bugs
Fix error notification bugs
2017-09-18 18:38:09 +01:00
Belén Curcio a0fb6030ca Merge branch 'master' into fix-notify-bugs 2017-09-18 14:27:21 -03:00
Kim Gardner c95d0e45f8 Merge pull request #952 from coralproject/instream-ban
In-Stream Ban
2017-09-18 18:26:59 +01:00
Belén Curcio 7144f171ef Merge branch 'master' into fix-notify-bugs 2017-09-18 14:20:33 -03:00
Kim Gardner 23e1b56c6e Merge branch 'master' into instream-ban 2017-09-18 18:19:53 +01:00
Wyatt Johnson 9b999c6249 Merge pull request #967 from coralproject/fix-safari-rendering-issues
Fix safari rendering issues
2017-09-18 11:19:32 -06:00
Kiwi 7a81a125f5 Merge branch 'master' into fix-safari-rendering-issues 2017-09-18 19:14:07 +02:00
Belén Curcio 79cdd65e30 Merge branch 'master' into flagged-count 2017-09-18 14:12:23 -03:00
Chi Vinh Le ed22bc34fc Add a comment 2017-09-19 00:11:49 +07:00
Belen Curcio d7ea88c367 matching master 2017-09-18 14:10:44 -03:00
Belen Curcio afec9932f0 Merge branch 'master' of github.com:coralproject/talk into instream-ban 2017-09-18 14:08:41 -03:00
Chi Vinh Le 2c297d7c2f Promote modqueue comment into own layer to fix safari issues 2017-09-19 00:08:09 +07:00
Kim Gardner 2814070808 Merge pull request #955 from coralproject/static-url
Added support for changing the static url
2017-09-18 18:02:40 +01:00
Kim Gardner 6ed6726daf Merge branch 'master' into static-url 2017-09-18 17:57:49 +01:00
Kim Gardner 21936ae467 Merge pull request #963 from coralproject/react-linting-rules
Linting pass
2017-09-18 17:57:17 +01:00
Kim Gardner 613a7f7073 Merge branch 'master' into static-url 2017-09-18 17:56:38 +01:00
Kim Gardner 9258347886 Merge branch 'master' into instream-ban 2017-09-18 17:56:15 +01:00
Belén Curcio 959193f8b5 Merge branch 'master' into flagged-count 2017-09-18 13:19:41 -03:00
Wyatt Johnson 212c6cd0ce Merge branch 'master' into react-linting-rules 2017-09-18 10:02:49 -06:00
Wyatt Johnson 5f3931f34b Merge pull request #966 from coralproject/toxic-comment-group-id
Turn toxic comment group_id into a constant
2017-09-18 09:49:22 -06:00
Belen Curcio aa3327945e Styles and copy 2017-09-18 12:42:21 -03:00
Chi Vinh Le c8dc5d4cd9 Turn toxic comment group_id into a constant 2017-09-18 22:39:30 +07:00
Wyatt Johnson 11c46439a2 corrected view error 2017-09-18 09:19:52 -06:00
Belen Curcio a07d661655 Adding CountBadge and flaggedUsernamesCount 2017-09-18 11:53:52 -03:00
Belen Curcio 24391de61d userCount 2017-09-18 11:06:31 -03:00
Chi Vinh Le 33822ff6c0 More linting error fixes 2017-09-18 20:38:32 +07:00
Belen Curcio 5d153e764d Linting 2017-09-18 10:30:39 -03:00
Belen Curcio 597d67f5d2 Actions renamed 2017-09-18 10:28:02 -03:00
Belen Curcio 100dd519ee Replacing excludeIf 2017-09-18 10:12:28 -03:00
Belen Curcio eb03d62e51 Merge branch 'instream-ban' of github.com:coralproject/talk into instream-ban 2017-09-18 10:05:12 -03:00
Belen Curcio 8bfc7e942c Renaming 2017-09-18 10:04:39 -03:00
Chi Vinh Le 1a349eb0cd Turn on prop-types linter 2017-09-18 19:03:07 +07:00
Chi Vinh Le f19b333537 Fix some linter warnings 2017-09-18 18:56:52 +07:00
Kim Gardner c6c2d545f8 Merge branch 'master' into static-url 2017-09-18 12:55:28 +01:00
Kim Gardner ebe9945492 Merge branch 'master' into instream-ban 2017-09-18 12:54:54 +01:00
Kim Gardner c6403b2da3 Merge branch 'master' into fix-notify-bugs 2017-09-18 12:54:46 +01:00
Wyatt Johnson cd100a23cb Merge pull request #932 from pdehaan/eslint-react
Add react/recommended ESLint rules
2017-09-15 17:29:28 -06:00
Wyatt Johnson 25761f9e61 Merge branch 'master' into eslint-react 2017-09-15 17:22:51 -06:00
Wyatt Johnson 1a76a83806 Merge pull request #959 from coralproject/view-context-no-tombstone
Don't show tombstone during "view context"
2017-09-15 17:20:29 -06:00
Wyatt Johnson 55ebd1df8e Merge branch 'master' into view-context-no-tombstone 2017-09-15 17:16:07 -06:00
Wyatt Johnson c427691bef Merge pull request #958 from coralproject/detect-n-display-stream-errors
Detect and display stream errors
2017-09-15 17:15:34 -06:00
Wyatt Johnson 93afd793cb Merge branch 'master' into detect-n-display-stream-errors 2017-09-15 17:10:46 -06:00
Wyatt Johnson 35232cf015 Merge pull request #957 from coralproject/fix-config
Fix config parsing bug
2017-09-15 16:56:24 -06:00
Wyatt Johnson f864ebf2e3 Merge branch 'master' into fix-config 2017-09-15 15:56:46 -06:00
Wyatt Johnson a9cc78b61d Merge pull request #943 from coralproject/story/150848457
Added support for deep comment counts
2017-09-15 15:55:35 -06:00
Wyatt Johnson 2c3a52b48c Merge branch 'master' into story/150848457 2017-09-15 15:49:30 -06:00
Wyatt Johnson 0b1a75726c Merge pull request #956 from coralproject/story/150636425
Status SYSTEM_WITHHELD
2017-09-15 15:49:11 -06:00
Wyatt Johnson 384c126d9e added docs 2017-09-15 15:29:20 -06:00
Wyatt Johnson f97094177a revamped configuration for moderation phases 2017-09-15 14:23:18 -06:00
Kiwi 4739f86739 Merge branch 'master' into eslint-react 2017-09-15 20:43:49 +02:00
Chi Vinh Le f386909748 Don't show tombstone during "view context" 2017-09-16 01:36:15 +07:00
Chi Vinh Le aa4f781d25 Better error detection 2017-09-16 01:30:26 +07:00
Chi Vinh Le 4567b4565f Detect and display stream errors 2017-09-16 01:19:59 +07:00
Chi Vinh Le 3133922100 Fix config parsing bug 2017-09-16 01:02:19 +07:00
Kiwi e9bd5e4476 Merge branch 'master' into story/150848457 2017-09-15 19:53:00 +02:00
Wyatt Johnson f2e06d6d27 Merge branch 'master' into story/150636425 2017-09-15 09:57:57 -06:00
Chi Vinh Le e31cdebc12 Make it appear in reported queue 2017-09-15 22:52:19 +07:00
Wyatt Johnson e03e7de82f Merge branch 'master' into static-url 2017-09-15 09:46:05 -06:00
Wyatt Johnson c7b755d2ff Merge pull request #954 from coralproject/url-fix
Fixed embed url link
2017-09-15 08:40:55 -06:00
Chi Vinh Le dc7013187d Merge branch 'master' into story/150636425 2017-09-15 19:11:31 +07:00
Belen Curcio 20c4148301 Close and styling 2017-09-14 17:37:47 -03:00
Belen Curcio ba24af015c Merge branch 'instream-ban' of github.com:coralproject/talk into instream-ban 2017-09-14 17:37:31 -03:00
Wyatt Johnson 94456674df fixed embed url link 2017-09-14 14:32:16 -06:00
Belen Curcio 5231c2d627 Removing perms mods 2017-09-14 17:28:54 -03:00
Wyatt Johnson f74e8dda16 added support for changing the static url 2017-09-14 14:27:45 -06:00
Wyatt Johnson 825d53afcd Merge branch 'master' into eslint-react 2017-09-14 13:28:53 -06:00
Wyatt Johnson 029877080d Merge branch 'master' into fix-notify-bugs 2017-09-14 13:28:34 -06:00
Wyatt Johnson 83f10a4863 Merge branch 'master' into story/150848457 2017-09-14 13:27:53 -06:00
Wyatt Johnson d820d2d2c3 moved support for deepReplyCount to seperate field 2017-09-14 13:08:01 -06:00
Belén Curcio a6443f2bcc Merge branch 'master' into instream-ban 2017-09-14 13:05:58 -03:00
Kim Gardner 7ace5b369a Merge pull request #951 from coralproject/update-readme
Update README
2017-09-14 16:49:40 +01:00
Kim Gardner cf66c10262 Update README 2017-09-14 16:45:19 +01:00
Kiwi 99296ebe69 Merge branch 'master' into fix-notify-bugs 2017-09-14 17:25:50 +02:00
Chi Vinh Le 7600ce8d26 Fix error notification bugs 2017-09-14 22:22:16 +07:00
Kim Gardner 26256b979e Merge branch 'master' into story/150848457 2017-09-14 16:20:20 +01:00
Kim Gardner 0113f02994 Merge pull request #944 from coralproject/new-regexp-highlighter
Better wordlist service and highlighter
2017-09-14 16:20:06 +01:00
Wyatt Johnson b3eb3361bb Merge branch 'master' into new-regexp-highlighter 2017-09-14 08:47:40 -06:00
Wyatt Johnson fce65e616d Merge pull request #949 from coralproject/fix-moderator-rest-permission
Allow Moderator to have read access on assets and settings
2017-09-14 08:47:28 -06:00
Wyatt Johnson 6a4a0b7f6b Merge branch 'master' into eslint-react 2017-09-14 08:33:42 -06:00
Chi Vinh Le c41ab58109 Allow Moderator to have read access on assets and settings 2017-09-14 21:11:40 +07:00
Belen Curcio 837a586234 Ban User confirmation box 2017-09-14 09:26:33 -03:00
Belen Curcio 2facde3894 Adding dialog 2017-09-14 09:14:15 -03:00
Chi Vinh Le 76a6a0e82b Remove natural package 2017-09-14 18:10:24 +07:00
Chi Vinh Le bea25f2a11 Merge branch 'new-regexp-highlighter' of ssh://github.com/coralproject/talk into new-regexp-highlighter 2017-09-14 17:40:01 +07:00
Chi Vinh Le ad361413c7 Reimplement wordlist on server using same regexp solution 2017-09-14 17:36:04 +07:00
Kim Gardner cf61d9e2ca Merge branch 'master' into story/150848457 2017-09-14 10:07:04 +01:00
Kim Gardner 77ef9ff111 Merge branch 'master' into new-regexp-highlighter 2017-09-14 10:06:43 +01:00
Kim Gardner c8cc5e6a34 Merge pull request #948 from coralproject/docs-update
Documentation Update
2017-09-14 09:16:17 +01:00
Belen Curcio bdd5e47427 Icon, translations 2017-09-13 17:38:04 -03:00
Wyatt Johnson 1574e08197 fixes #947 2017-09-13 12:02:20 -06:00
Chi Vinh Le abc651c55d Add some optimizations 2017-09-14 00:50:01 +07:00
Chi Vinh Le fa335564ed Generate RegExp from phrases 2017-09-14 00:10:29 +07:00
Belen Curcio 0ae2919def Perms and excludeIf 2017-09-13 13:42:32 -03:00
Belen Curcio 838a3bad2e Ban In-Stream 2017-09-13 13:21:27 -03:00
Chi Vinh Le 6487072be1 Merge branch 'new-regexp-highlighter' of ssh://github.com/coralproject/talk into new-regexp-highlighter 2017-09-13 22:23:41 +07:00
Chi Vinh Le a16f101a12 Match phrases not just words 2017-09-13 22:20:32 +07:00
Kim Gardner 647502d701 Merge branch 'master' into new-regexp-highlighter 2017-09-13 15:11:35 +01:00
Kim Gardner d728065fe5 Merge branch 'master' into story/150848457 2017-09-13 15:11:30 +01:00
Kim Gardner 18b8a18f1d Merge pull request #946 from coralproject/typo-fix-en-yml
Fix typo
2017-09-13 15:05:20 +01:00
Kim Gardner 1089807086 Fix typo 2017-09-13 15:00:00 +01:00
Kim Gardner 0c1c64fdf9 Merge branch 'master' into eslint-react 2017-09-13 13:19:35 +01:00
Kim Gardner 90a649db9b Merge branch 'master' into story/150848457 2017-09-13 13:18:56 +01:00
Kim Gardner 17ec666d97 Merge branch 'master' into new-regexp-highlighter 2017-09-13 13:18:47 +01:00
Kim Gardner cda86a67ab Merge pull request #942 from coralproject/instream-updates
In-Stream Moderation Updates
2017-09-13 13:18:28 +01:00
Kiwi 32d72129e5 Merge branch 'master' into instream-updates 2017-09-13 14:11:35 +02:00
Kim Gardner 2905ffb5cb Merge branch 'master' into new-regexp-highlighter 2017-09-13 12:43:29 +01:00
Kim Gardner 433b0d310e Merge branch 'master' into story/150848457 2017-09-13 12:43:16 +01:00
Kim Gardner 08848057a5 Merge pull request #941 from coralproject/stable-keys
Provide stable keys for slot elements
2017-09-13 12:43:02 +01:00
Kim Gardner 7f517ed4fb Merge branch 'master' into stable-keys 2017-09-13 12:35:12 +01:00
Kim Gardner c364b3e307 Merge pull request #945 from coralproject/fix-edit-animation
Fix edit animation
2017-09-13 12:34:42 +01:00
Kim Gardner 008df99100 Merge branch 'master' into story/150848457 2017-09-13 11:29:20 +01:00
Belen Curcio bfdfd98135 Linting 2017-09-12 15:11:01 -03:00
Belen Curcio 64be131047 Final 2017-09-12 15:09:11 -03:00
Belen Curcio 7115d4c31f Missing async 2017-09-12 15:02:29 -03:00
Belen Curcio a944cd2608 Correct branch 2017-09-12 15:01:15 -03:00
Belen Curcio 0e7d74559f Notify errors 2017-09-12 14:08:19 -03:00
Belen Curcio 297b905163 Hiding after action 2017-09-12 13:42:49 -03:00
Belen Curcio 9c08b586ec Hiding after action 2017-09-12 13:40:26 -03:00
Belen Curcio dbeca830a2 Closing after featuring and unfeaturing 2017-09-12 13:30:15 -03:00
Belen Curcio 0042767fad No approve button for Approved comments 2017-09-12 13:12:35 -03:00
Wyatt Johnson 110a0093af Merge branch 'master' into eslint-react 2017-09-12 10:00:11 -06:00
Belen Curcio 6bac6ee5c5 Removed old code 2017-09-12 12:59:48 -03:00
Belen Curcio aa364e1abe Renaming Fragment and variable name 2017-09-12 12:58:25 -03:00
Belen Curcio 6e88cc94e0 Merge branch 'reject-instream' of github.com:coralproject/talk into reject-instream 2017-09-12 12:56:07 -03:00
Chi Vinh Le 7976aace00 Typo 2017-09-12 22:46:24 +07:00
Kiwi 1261e4e25c Merge branch 'master' into instream-updates 2017-09-12 17:20:08 +02:00
Chi Vinh Le 2a655331fc Use same tlds list on server 2017-09-12 21:46:03 +07:00
Chi Vinh Le 98b95cab86 Reintroduce linkify 2017-09-12 21:31:59 +07:00
Chi Vinh Le d8ca9dfb07 Fix edit animation 2017-09-12 20:58:33 +07:00
Chi Vinh Le ee3cee2a50 Typo 2017-09-12 20:55:31 +07:00
Chi Vinh Le 65a6c408a7 Add some docs 2017-09-12 20:54:30 +07:00
Chi Vinh Le d18a9a057b Implement simple regexp based highlighter 2017-09-12 20:47:05 +07:00
Kiwi b27e3e0a7f Merge branch 'master' into stable-keys 2017-09-12 11:11:08 +02:00
Kiwi f2804f2394 Merge pull request #930 from coralproject/fix-graphql-warnings
Fix graphql warnings
2017-09-12 11:10:44 +02:00
Chi Vinh Le d1c30ab982 Remove talkUuid and use element key instead 2017-09-12 15:57:40 +07:00
Wyatt Johnson ca411a3227 added support for deep comment counts 2017-09-11 18:01:01 -06:00
Belen Curcio 5e4a48f4cc Updates 2017-09-11 15:38:42 -03:00
Belen Curcio c93b53c25b pdates 2017-09-11 15:11:22 -03:00
Belen Curcio 51f6c0738d Containers 2017-09-11 15:02:01 -03:00
Wyatt Johnson 49f09b87a0 Added new SYSTEM_WITHHELD comment status 2017-09-11 11:09:21 -06:00
Belen Curcio 06c45faeb0 Read/Write Fragments to update the cache 2017-09-11 13:57:24 -03:00
Kiwi 70eee3d4b2 Merge branch 'master' into stable-keys 2017-09-11 18:51:18 +02:00
Chi Vinh Le ecd4267ea9 Remove getSlotComponents completely 2017-09-11 23:46:16 +07:00
Chi Vinh Le 4f0e8d9e47 Provide stable keys for slot elements 2017-09-11 23:43:00 +07:00
Wyatt Johnson 1c630835c1 Merge branch 'master' into eslint-react 2017-09-11 09:07:31 -06:00
Kiwi a9c4c12824 Merge branch 'master' into fix-graphql-warnings 2017-09-11 16:49:10 +02:00
Belen Curcio a22ee3fefe Removing can since thats already checked 2017-09-11 11:44:01 -03:00
Belen Curcio 1e9cc82b17 Using redux to handle the tooltip state 2017-09-11 11:31:59 -03:00
Belen Curcio 65085fea65 No need to handle errors here 2017-09-11 11:02:02 -03:00
Belen Curcio 908b3c20b4 Adding FeaturedButton (we already have Button with Coral-UI) 2017-09-11 10:59:16 -03:00
Belen Curcio 59e21cccba Container for Button 2017-09-11 10:51:27 -03:00
Kim Gardner ab1f1dee3e Merge pull request #936 from coralproject/remember-sort
Init, Introspection service, pymStorage, and talk-plugin-remember-sort
2017-09-11 12:05:41 +01:00
Kim Gardner 04ad649f01 Merge branch 'master' into remember-sort 2017-09-11 12:00:18 +01:00
Kim Gardner 18e36af50a Merge pull request #940 from bocoup/improve-docs
improve docker compose getting started docs
2017-09-11 11:59:40 +01:00
Kim Gardner 8f1ce9cef6 Merge branch 'master' into remember-sort 2017-09-11 11:53:07 +01:00
Kim Gardner e47cb9732e Merge branch 'master' into fix-graphql-warnings 2017-09-11 11:49:45 +01:00
Kim Gardner 5159ecc64e Merge branch 'master' into eslint-react 2017-09-11 11:49:24 +01:00
Kim Gardner 851c5fbfbc Merge branch 'master' into improve-docs 2017-09-11 11:48:35 +01:00
Kim Gardner 0bc9ede8bc Merge pull request #938 from coralproject/story/150381206
Comment Status Fixes
2017-09-11 11:46:45 +01:00
Kim Gardner d8d758255d Merge branch 'master' into story/150381206 2017-09-11 11:39:38 +01:00
Kim Gardner c1e52ba494 Merge pull request #937 from coralproject/reject-instream
In-Stream Moderation - Accept, Reject and Feature!
2017-09-11 11:39:11 +01:00
Kiwi b7e501f7a3 Merge branch 'master' into story/150381206 2017-09-11 10:37:08 +02:00
Boaz Sender ee41cc690c add link to new location for config vars, and include min needed docker env vars in example 2017-09-09 18:05:08 -04:00
Kim Gardner 965b8f9bda Merge branch 'master' into reject-instream 2017-09-09 14:31:54 +01:00
Kim Gardner 823c570539 Merge pull request #939 from coralproject/losowsky-patch-1
Fixed broken link on docs homepage
2017-09-09 14:31:26 +01:00
Andrew Losowsky 221db29539 Fixed broken link on docs homepage
also changed the phones detail so that we don't have to keep updating it with new phones
2017-09-08 21:10:14 -05:00
Wyatt Johnson 9af21b4226 test fixes 2017-09-08 16:23:31 -06:00
Belen Curcio 7f85ceb566 Featuring from Featured Tab 2017-09-08 18:55:11 -03:00
Wyatt Johnson d20bd20005 linting 2017-09-08 15:46:04 -06:00
Wyatt Johnson ce3e29813b implemented status switch when mismatched 2017-09-08 15:41:43 -06:00
Belen Curcio 1f6da44b25 Merge branch 'reject-instream' of github.com:coralproject/talk into reject-instream 2017-09-08 18:07:24 -03:00
Belen Curcio 0ea951f3d9 wrong translation 2017-09-08 17:50:30 -03:00
Belén Curcio b75539fb57 Merge branch 'master' into reject-instream 2017-09-08 17:47:09 -03:00
Belen Curcio 72530e7501 Linting and Indenting 2017-09-08 17:17:03 -03:00
Belen Curcio 790c20e7ac Indent 2017-09-08 17:14:15 -03:00
Belen Curcio 2cbd59b4b5 Featured comments error in permalink view, handling permaview moderation and handling replies moderation 2017-09-08 17:05:20 -03:00
Kiwi d88919e27b Merge branch 'master' into remember-sort 2017-09-08 19:29:08 +02:00
Kiwi 7ea22c84ee Merge pull request #935 from coralproject/kill-the-zombies
Kill the zombies
2017-09-08 19:28:35 +02:00
Kiwi be86a6f3dc Merge branch 'master' into remember-sort 2017-09-08 19:28:26 +02:00
Chi Vinh Le 4046b6e0a6 Remove zombie files 2017-09-09 00:20:18 +07:00
Chi Vinh Le 6b74877d01 Implement and use pymStorage 2017-09-09 00:15:19 +07:00
Chi Vinh Le 9f33a77745 Implement and use pymStorage 2017-09-09 00:11:15 +07:00
Belen Curcio f33c31c70e Merge branch 'master' of github.com:coralproject/talk into reject-instream 2017-09-08 13:49:54 -03:00
Belen Curcio e28f1caaef Styles 2017-09-08 13:33:53 -03:00
Belen Curcio fefacf039f Featured comments should have ACCEPTED status 2017-09-08 13:25:23 -03:00
Belen Curcio 6494669262 Working for permalink 2017-09-08 13:15:17 -03:00
Peter deHaan 4971ba4722 Add react/recommended ESLint rules 2017-09-08 09:02:54 -07:00
Kim Gardner a9626ad12c Merge branch 'master' into fix-graphql-warnings 2017-09-08 14:37:17 +01:00
Belen Curcio fd71acf7e0 With Featured Comments :) 2017-09-08 09:06:33 -03:00
Belen Curcio 05d643d3c3 Styling 2017-09-08 08:35:57 -03:00
Chi Vinh Le 244a4b108d Correctly detect subsequent change 2017-09-08 18:16:49 +07:00
Kim Gardner 1221c6043f Merge pull request #931 from coralproject/prop-types
PropTypes
2017-09-08 12:09:53 +01:00
Chi Vinh Le 0cfd8afce7 Merge branch 'master' into remember-sort
Conflicts:
	.eslintignore
	.gitignore
2017-09-08 17:56:18 +07:00
Chi Vinh Le c8d1da5715 Remember sort plugin 2017-09-08 17:54:02 +07:00
Chi Vinh Le e5bd8e2a3b No need to check for loading config anymore 2017-09-08 17:47:02 +07:00
Chi Vinh Le 7051c76b40 Init step for plugins and bootstrap, introspection service 2017-09-08 17:37:27 +07:00
Kim Gardner 76fd261141 Merge branch 'master' into prop-types 2017-09-08 10:56:35 +01:00
Kim Gardner f2ecfa0a0d Merge branch 'master' into fix-graphql-warnings 2017-09-08 10:56:33 +01:00
Kim Gardner 5e295fc337 Merge pull request #803 from coralproject/feature/talk-plugin-toxic-comments
Toxic Comments Plugin
2017-09-08 10:51:14 +01:00
Kim Gardner 299c6f1ffd Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-09-08 10:16:40 +01:00
Kim Gardner 42e15bd630 Merge branch 'master' into prop-types 2017-09-08 09:37:24 +01:00
Kim Gardner d16066a981 Merge branch 'master' into fix-graphql-warnings 2017-09-08 09:33:59 +01:00
Kim Gardner 51077b689d Merge pull request #926 from coralproject/private-npm
Marking Talk as a Private Repo
2017-09-08 09:33:38 +01:00
Wyatt Johnson f69703a8ba fixed missing 2017-09-08 00:47:08 -06:00
Wyatt Johnson 2e350c2244 Merge branch 'master' into prop-types 2017-09-08 00:44:09 -06:00
Wyatt Johnson b43a57328c Merge branch 'master' into private-npm 2017-09-08 00:40:22 -06:00
Wyatt Johnson d5fcdd6a76 Merge branch 'master' into fix-graphql-warnings 2017-09-08 00:40:15 -06:00
Kim Gardner 589189023a Merge pull request #928 from coralproject/fix-linting
Fix linting
2017-09-08 06:53:08 +01:00
Chi Vinh Le 9c5821f6a2 Fix graphql warnings 2017-09-08 12:06:43 +07:00
Wyatt Johnson 671c1d7449 Merge pull request #927 from pdehaan/issue-923
Tweak ESLint config to check .js files
2017-09-07 14:04:29 -06:00
Wyatt Johnson 22cea681a7 Merge branch 'fix-linting' into issue-923 2017-09-07 14:03:21 -06:00
Wyatt Johnson 56bd3f23c7 fixed broken query 2017-09-07 13:53:37 -06:00
Wyatt Johnson 2b91bcffda fixes #923 2017-09-07 13:49:22 -06:00
Peter deHaan 2b6a5bfe6e Tweak ESLint config to check .js files 2017-09-07 12:46:52 -07:00
Wyatt Johnson d57c4b253a fixes #924 2017-09-07 13:25:15 -06:00
Belen Curcio 462fcb6b94 Approve actions and styles 2017-09-07 15:02:38 -03:00
Belen Curcio 8e96ef4692 Approve 2017-09-07 14:33:53 -03:00
Wyatt Johnson 94b9c4b2df Merge pull request #921 from coralproject/change-websocket-uri
Change Websocket URI
2017-09-07 11:21:54 -06:00
Wyatt Johnson 96e37ac725 moved config loading to bootstrap 2017-09-07 10:58:58 -06:00
Kiwi bd7f81fb35 Merge branch 'master' into change-websocket-uri 2017-09-07 18:36:21 +02:00
Kiwi 53372ca1e8 Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-09-07 18:22:04 +02:00
Kim Gardner 856ae456f4 Merge pull request #920 from coralproject/bump-version
Bump version to 3.5.0
2017-09-07 17:18:06 +01:00
Belen Curcio f6b02a52fe Cache and Tombstoning rejected comment working 2017-09-07 13:08:52 -03:00
Kim Gardner aa52063fa4 Merge branch 'master' into bump-version 2017-09-07 16:55:10 +01:00
Kim Gardner b72bba96fb Merge branch 'master' into change-websocket-uri 2017-09-07 16:54:59 +01:00
Belen Curcio 32d9dc6646 Permissions to moderate comments 2017-09-07 11:27:12 -03:00
Belen Curcio a31a63e1c8 Working Tooltip 2017-09-07 10:12:49 -03:00
Chi Vinh Le f82a0c80bf Handle timeout and failure of perspective api 2017-09-07 19:37:45 +07:00
Belen Curcio 7b59323b26 Moderation Actions 2017-09-07 08:05:39 -03:00
Chi Vinh Le f1c5d479ad Merge branch 'master' into feature/talk-plugin-toxic-comments
Conflicts:
	graph/resolvers/root_mutation.js
	graph/typeDefs.graphql
2017-09-07 16:59:46 +07:00
Chi Vinh Le d8a956d09c Remove dependency on wrapResponse 2017-09-07 16:04:01 +07:00
Chi Vinh Le a78be6874b Remove response helpers 2017-09-07 15:49:51 +07:00
Chi Vinh Le c95c20c9ad Don't put in default plugins 2017-09-07 15:41:00 +07:00
Chi Vinh Le 43b7326db4 Cleanup and apply pr suggestions 2017-09-07 15:38:39 +07:00
Chi Vinh Le b1b3db51a6 Typo 2017-09-07 03:59:15 +07:00
Chi Vinh Le 41cd5b320f Refactor & cleanup toxic-comments plugin 2017-09-07 03:50:49 +07:00
Chi Vinh Le 9b0caa42cd Put toxic comment into premod and add flag 2017-09-06 22:58:52 +07:00
Kim Gardner aeb8852588 Merge pull request #922 from coralproject/story-search
Fixed old story search query
2017-09-06 16:39:00 +01:00
Chi Vinh Le b3fe3afd4c Add todo 2017-09-06 22:20:19 +07:00
Wyatt Johnson e96e9c0d5c Fixed old story search query 2017-09-06 09:18:22 -06:00
Chi Vinh Le a11f149c5a Refactor 2017-09-06 22:15:57 +07:00
Chi Vinh Le a6b517b3dd Remove unused code 2017-09-06 22:14:58 +07:00
Chi Vinh Le 6f82fd76f5 First draft of toxic-comments 2017-09-06 22:11:48 +07:00
Wyatt Johnson 4a9b24f096 added more docs related to cookies 2017-09-05 14:08:43 -06:00
Wyatt Johnson 48875294c8 initial support for changing the uri 2017-09-05 13:57:35 -06:00
Belen Curcio 12be487783 excludeIf no featured tags 2017-09-05 16:19:46 -03:00
Kim Gardner 5953ef1695 Merge pull request #919 from coralproject/staff-badge-bug
Missing permission for staff members
2017-09-05 17:36:08 +01:00
Kim Gardner 17ae62c66b Bump version to 3.5.0 2017-09-05 17:28:23 +01:00
Wyatt Johnson bb66d7220b Merge branch 'master' into staff-badge-bug 2017-09-05 10:26:11 -06:00
Belen Curcio 0cf7d19d4d Missing permission for staff members 2017-09-05 13:20:36 -03:00
Kim Gardner 24a8712159 Merge pull request #918 from coralproject/graph-typo
Graph Typo
2017-09-05 16:58:44 +01:00
Wyatt Johnson 7b27feee96 fixed typo 2017-09-05 09:45:31 -06:00
Kim Gardner 0b1e95e66d Merge pull request #894 from coralproject/asset-graph-api
Added graph API for assets
2017-09-05 16:20:21 +01:00
Wyatt Johnson 997a336483 Merge branch 'master' into asset-graph-api 2017-09-05 08:56:49 -06:00
Kim Gardner 51a4f0e02e Merge pull request #899 from coralproject/settings-graph-api
Added graph API for settings
2017-09-05 13:23:51 +01:00
Kim Gardner 869bf10c96 Merge branch 'master' into asset-graph-api 2017-09-05 11:57:08 +01:00
Kim Gardner 0375e7e039 Merge branch 'master' into settings-graph-api 2017-09-05 11:56:57 +01:00
Kim Gardner 9b29261f3d Merge pull request #917 from coralproject/fix-offtopic-checkbox
OffTopic checkbox should follow state
2017-09-05 11:56:33 +01:00
Kiwi fea5f75aa6 Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-09-05 12:56:27 +02:00
Chi Vinh Le 345d183bc4 OffTopic checkbox should follow state 2017-09-05 17:21:11 +07:00
Kim Gardner 52490375e4 Merge branch 'master' into asset-graph-api 2017-09-04 11:34:03 +01:00
Kim Gardner 53871cb2c6 Merge branch 'master' into settings-graph-api 2017-09-04 11:33:59 +01:00
Wyatt Johnson 9a549a2b63 fixed some bugs from review 2017-09-01 11:21:30 -06:00
Wyatt Johnson 4dbcc65126 Merge branch 'master' into asset-graph-api 2017-08-31 11:57:50 -06:00
Wyatt Johnson 10693f3e5c Merge branch 'master' into settings-graph-api 2017-08-31 11:50:06 -06:00
Wyatt Johnson dfd77dbf63 updated based on cvle's feedback 2017-08-31 11:48:38 -06:00
Wyatt Johnson 7b71511cae removed ! 2017-08-31 10:37:52 -06:00
Wyatt Johnson f260e41274 Merge branch 'master' into asset-graph-api 2017-08-31 08:59:51 -06:00
Kiwi 2631d9338a Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-08-31 12:31:44 +02:00
Kim Gardner 94bb223f0e Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-08-31 08:51:53 +01:00
Kim Gardner 0486d2926d Merge branch 'master' into asset-graph-api 2017-08-31 08:51:29 +01:00
Kim Gardner cb655f15b3 Merge branch 'master' into settings-graph-api 2017-08-31 08:51:16 +01:00
Wyatt Johnson 2eb0637e61 Merge branch 'master' into settings-graph-api 2017-08-30 16:25:51 -06:00
Wyatt Johnson 079a20f13e Merge branch 'master' into asset-graph-api 2017-08-30 16:11:27 -06:00
Wyatt Johnson f0dcef7b37 finished connection, improved graph 2017-08-30 14:23:47 -06:00
Kim Gardner a2fdc11451 Fix merge conflict 2017-08-30 16:23:17 +01:00
Kim Gardner 6b15c335b5 Merge branch 'master' into settings-graph-api 2017-08-30 12:36:09 +01:00
Kim Gardner c246caa520 Merge branch 'master' into asset-graph-api 2017-08-30 12:36:03 +01:00
Wyatt Johnson 8ca32c5808 added missing fields 2017-08-29 13:54:14 -06:00
Wyatt Johnson 5a48705d49 Merge branch 'master' into settings-graph-api 2017-08-29 13:44:20 -06:00
Wyatt Johnson 173c257126 Added Graph API for Settings 2017-08-29 13:43:48 -06:00
Kiwi 9e65f1b00d Merge branch 'master' into asset-graph-api 2017-08-29 21:04:30 +02:00
Kim Gardner bf7dfefcdf Merge branch 'master' into asset-graph-api 2017-08-29 18:52:17 +01:00
Kiwi d4c9749133 Merge branch 'master' into asset-graph-api 2017-08-29 12:59:26 +02:00
Wyatt Johnson 90a8a87eaf Added graph API for assets 2017-08-28 18:57:32 -06:00
Wyatt Johnson deb69d4e8c fixed prop-types deprecation 2017-08-28 12:03:20 -06:00
Kim Gardner f528fb4345 Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-08-21 15:43:28 +01:00
Kim Gardner df79530982 Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-08-21 12:03:06 +01:00
Kim Gardner 1a1e3d2d4a Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-08-21 09:36:54 +01:00
Kim Gardner 7517679c5e Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-08-18 13:11:14 +01:00
Kim Gardner c6d7b714a1 Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-08-18 09:35:33 +01:00
Kim Gardner d12d0cfe4f Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-08-17 10:04:51 +01:00
Kim Gardner 2c6447cd07 Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-08-16 10:38:36 +01:00
Kim Gardner ce63113c5d Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-08-15 11:28:00 +01:00
Kim Gardner 3636bb71c4 Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-08-09 11:38:33 +01:00
Kim Gardner 788950fed2 Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-08-04 07:04:52 -04:00
Kim Gardner 4086fe8684 Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-08-03 09:31:05 -04:00
Kim Gardner 6e6d999c9b Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-08-02 12:48:44 -04:00
Kim Gardner c2f866a077 Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-07-31 19:22:57 -04:00
Kim Gardner 0d037c3acb Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-07-31 18:44:05 -04:00
Jeff Nelson 88f06744b4 unignore 2017-07-31 11:59:15 -04:00
Jeff Nelson 2c1cd50828 turn router method from get to post 2017-07-31 11:59:15 -04:00
Jeff Nelson 8c4612a4dd remove unused import 2017-07-31 11:59:15 -04:00
Jeff Nelson 4b13ccc5c1 enforce API key 2017-07-31 11:59:15 -04:00
Jeff Nelson b62ab9bff0 pass comment to presubmit hooks 2017-07-31 11:59:15 -04:00
Belén Curcio 3740dd98e8 Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-07-28 13:22:29 -03:00
Kim Gardner 4db1cf2656 Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-07-28 10:58:34 -04:00
Belén Curcio eb44c55e05 Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-07-28 10:02:03 -03:00
Kim Gardner 75da26ff7a Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-07-27 13:02:53 -04:00
Kim Gardner 93d0a265b5 Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-07-27 11:05:17 -04:00
Kim Gardner 494d52ca36 Merge branch 'master' into feature/talk-plugin-toxic-comments 2017-07-26 11:39:31 -04:00
Jeff Nelson c67f92eb44 add toxic comments plugin to main api 2017-07-25 12:08:36 -04:00
266 changed files with 4709 additions and 1601 deletions
+4
View File
@@ -22,5 +22,9 @@ plugins/*
!plugins/talk-plugin-author-menu
!plugins/talk-plugin-member-since
!plugins/talk-plugin-ignore-user
!plugins/talk-plugin-moderation-actions
!plugins/talk-plugin-toxic-comments
!plugins/talk-plugin-remember-sort
!plugins/talk-plugin-deep-reply-count
node_modules
+73 -73
View File
@@ -1,75 +1,75 @@
{
"env": {
"es6": true,
"node": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 2017
},
"plugins": [
"promise",
"json"
],
"rules": {
"indent": ["error",
2
],
"no-console": "off",
"linebreak-style": ["error", "unix"],
"quotes": ["error", "single"],
"semi": ["error", "always"],
"no-template-curly-in-string": "warn",
"no-unsafe-negation": "warn",
"array-callback-return": "warn",
"arrow-parens": ["warn", "always"],
"template-curly-spacing": "warn",
"eqeqeq": ["error", "smart"],
"no-eval": "error",
"no-global-assign": "error",
"no-implied-eval": "error",
"lines-around-comment": ["warn", {"beforeLineComment": true}],
"spaced-comment": ["warn", "always", { "line": { "exceptions": ["-", "="] } }],
"no-script-url": "error",
"no-throw-literal": "error",
"yoda": "warn",
"no-path-concat": "error",
"eol-last": "warn",
"no-nested-ternary": "warn",
"no-tabs": "error",
"no-unneeded-ternary": "warn",
"object-curly-spacing": "warn",
"space-infix-ops": ["error"],
"space-in-parens": ["error", "never"],
"space-unary-ops": ["error", {
"words": true,
"nonwords": false
}],
"no-const-assign": "error",
"no-duplicate-imports": "error",
"prefer-template": "warn",
"comma-spacing": ["error", {
"after": true
}],
"no-var": "error",
"no-lonely-if": "error",
"curly": "error",
"no-unused-vars": ["error", {
"argsIgnorePattern": "^_|next",
"varsIgnorePattern": "^_"
}],
"no-multiple-empty-lines": ["error", {
"max": 1
}],
"newline-per-chained-call": ["error", {
"ignoreChainWithDepth": 2
}],
"promise/no-return-wrap": "error",
"promise/param-names": "error",
"promise/catch-or-return": "error",
"promise/no-native": "off",
"promise/no-nesting": "warn",
"promise/no-promise-in-callback": "warn",
"promise/no-callback-in-promise": "warn"
}
"env": {
"es6": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"parserOptions": {
"ecmaVersion": 2017
},
"plugins": [
"json",
"promise",
"react"
],
"rules": {
"promise/no-return-wrap": "error",
"promise/param-names": "error",
"promise/catch-or-return": "warn",
"promise/no-native": "off",
"promise/no-nesting": "warn",
"promise/no-promise-in-callback": "warn",
"promise/no-callback-in-promise": "warn",
"react/display-name": "off",
// We'll keeping using this, as we'll switch over to Preact and we don't
// need to worry about deprecation.
"react/no-find-dom-node": "off",
// TODO: Use default after fixing the errors.
"react/prop-types": "warn",
"array-callback-return": "warn",
"arrow-parens": ["warn", "always"],
"comma-spacing": ["error", {"after": true}],
"curly": "error",
"eol-last": "warn",
"eqeqeq": ["error", "smart"],
"indent": ["error", 2],
"linebreak-style": ["error", "unix"],
"lines-around-comment": ["warn", {"beforeLineComment": true}],
"newline-per-chained-call": ["error", {"ignoreChainWithDepth": 2}],
"no-console": "off",
"no-const-assign": "error",
"no-duplicate-imports": "error",
"no-eval": "error",
"no-global-assign": "error",
"no-implied-eval": "error",
"no-lonely-if": "error",
"no-multiple-empty-lines": ["error", {"max": 1}],
"no-nested-ternary": "warn",
"no-path-concat": "error",
"no-script-url": "error",
"no-tabs": "error",
"no-template-curly-in-string": "warn",
"no-throw-literal": "error",
"no-unneeded-ternary": "warn",
"no-unsafe-negation": "warn",
"no-unused-vars": ["error", {"argsIgnorePattern": "^_|next", "varsIgnorePattern": "^_"}],
"no-var": "error",
"object-curly-spacing": "warn",
"prefer-template": "warn",
"quotes": ["error", "single"],
"semi": ["error", "always"],
"space-in-parens": ["error", "never"],
"space-infix-ops": ["error"],
"space-unary-ops": ["error", {"words": true, "nonwords": false}],
"spaced-comment": ["warn", "always", {"line": {"exceptions": ["-", "="]}}],
"template-curly-spacing": "warn",
"yoda": "warn"
}
}
+5
View File
@@ -29,6 +29,7 @@ plugins/*
!plugins/talk-plugin-comment-content
!plugins/talk-plugin-permalink
!plugins/talk-plugin-featured-comments
!plugins/talk-plugin-toxic-comments
!plugins/talk-plugin-sort-newest
!plugins/talk-plugin-sort-oldest
!plugins/talk-plugin-sort-most-replied
@@ -38,5 +39,9 @@ plugins/*
!plugins/talk-plugin-author-menu
!plugins/talk-plugin-member-since
!plugins/talk-plugin-ignore-user
!plugins/talk-plugin-moderation-actions
!plugins/talk-plugin-toxic-comments
!plugins/talk-plugin-remember-sort
!plugins/talk-plugin-deep-reply-count
**/node_modules/*
+6 -3
View File
@@ -6,11 +6,14 @@ Online comments are broken. Our open-source Talk tool rethinks how moderation, c
Third party licenses are available via the `/client/3rdpartylicenses.txt`
endpoint when the server is running with built assets.
## Important Links
## Try Talk!
- Developer Documentation & Setup Guides: https://coralproject.github.io/talk/
- Developer Documentation & Setup Guides: https://coralproject.github.io/talk/ (includes Installation Guide, Quickstart, Plugin Guide, API Docs, and more)
## Roadmap and Release Schedule
- Talk Roadmap: https://www.pivotaltracker.com/n/projects/1863625
- Pivotal Tracker Backlog & Release Schedule: https://www.pivotaltracker.com/n/projects/1863625
## Learn More about Coral
+11 -3
View File
@@ -2,10 +2,17 @@ const express = require('express');
const bodyParser = require('body-parser');
const morgan = require('morgan');
const path = require('path');
const merge = require('lodash/merge');
const helmet = require('helmet');
const compression = require('compression');
const cookieParser = require('cookie-parser');
const {BASE_URL, BASE_PATH, MOUNT_PATH} = require('./url');
const {
BASE_URL,
BASE_PATH,
MOUNT_PATH,
STATIC_URL,
HELMET_CONFIGURATION,
} = require('./url');
const routes = require('./routes');
const debug = require('debug')('talk:app');
@@ -26,9 +33,9 @@ app.set('trust proxy', 1);
// Enable a suite of security good practices through helmet. We disable
// frameguard to allow crossdomain injection of the embed.
app.use(helmet({
app.use(helmet(merge(HELMET_CONFIGURATION, {
frameguard: false,
}));
})));
// Compress the responses if appropriate.
app.use(compression());
@@ -55,6 +62,7 @@ app.set('view engine', 'ejs');
app.locals.BASE_URL = BASE_URL;
app.locals.BASE_PATH = BASE_PATH;
app.locals.MOUNT_PATH = MOUNT_PATH;
app.locals.STATIC_URL = STATIC_URL;
debug(`mounting routes on the ${MOUNT_PATH} path`);
+1 -1
View File
@@ -1,6 +1,6 @@
import React from 'react';
import {Router, Route, IndexRedirect, IndexRoute} from 'react-router';
import PropTypes from 'prop-types';
import {Router, Route, IndexRedirect, IndexRoute} from 'react-router';
import Configure from 'routes/Configure';
import Dashboard from 'routes/Dashboard';
+13 -13
View File
@@ -128,18 +128,18 @@ 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});
export const checkInstall = (next) => (dispatch, _, {rest}) => {
export const checkInstall = (next) => async (dispatch, _, {rest}) => {
dispatch(checkInstallRequest());
rest('/setup')
.then(({installed}) => {
dispatch(checkInstallSuccess(installed));
if (installed) {
next();
}
})
.catch((error) => {
console.error(error);
const errorMessage = error.translation_key ? t(`error.${error.translation_key}`) : error.toString();
dispatch(checkInstallFailure(errorMessage));
});
try {
const {installed} = await rest('/setup');
dispatch(checkInstallSuccess(installed));
if (installed) {
next();
}
} catch (error) {
console.error(error);
const errorMessage = error.translation_key ? t(`error.${error.translation_key}`) : error.toString();
dispatch(checkInstallFailure(errorMessage));
}
};
+2 -4
View File
@@ -4,10 +4,8 @@ export const viewUserDetail = (userId) => ({type: actions.VIEW_USER_DETAIL, user
export const hideUserDetail = () => ({type: actions.HIDE_USER_DETAIL});
export const changeUserDetailStatuses = (tab) => {
let statuses;
if (tab === 'all') {
statuses = ['NONE', 'ACCEPTED', 'REJECTED', 'PREMOD'];
} else if (tab === 'rejected') {
let statuses = null;
if (tab === 'rejected') {
statuses = ['REJECTED'];
}
return {type: actions.CHANGE_USER_DETAIL_STATUSES, tab, statuses};
@@ -1,4 +1,6 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import styles from './ModerationList.css';
import {Button} from 'coral-ui';
import {menuActionsMap} from '../utils/moderationQueueActionsMap';
@@ -26,7 +28,11 @@ const ActionButton = ({type = '', active, ...props}) => {
};
ActionButton.propTypes = {
active: PropTypes.bool
active: PropTypes.bool,
type: PropTypes.oneOf(['APPROVE', 'REJECT']),
minimal: PropTypes.bool,
acceptComment: PropTypes.func,
rejectComment: PropTypes.func,
};
export default ActionButton;
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Button, Icon} from 'coral-ui';
import {Menu} from 'react-mdl';
import cn from 'classnames';
@@ -57,6 +58,7 @@ class ActionsMenu extends React.Component {
ActionsMenu.propTypes = {
icon: PropTypes.string,
children: PropTypes.node,
};
export default ActionsMenu;
@@ -1,9 +1,14 @@
import React from 'react';
import cn from 'classnames';
import {MenuItem} from 'react-mdl';
import PropTypes from 'prop-types';
import styles from './ActionsMenu.css';
const ActionsMenuItem = (props) =>
<MenuItem className={cn(styles.menuItem, props.className)} {...props} />;
ActionsMenuItem.propTypes = {
className: PropTypes.string,
};
export default ActionsMenuItem;
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import Layout from 'coral-admin/src/components/ui/Layout';
import styles from './NotFound.css';
import {Button, TextField, Alert, Success} from 'coral-ui';
@@ -104,7 +105,9 @@ AdminLogin.propTypes = {
handleLogin: PropTypes.func.isRequired,
passwordRequestSuccess: PropTypes.string,
loginError: PropTypes.string,
recaptchaPublic: PropTypes.string
recaptchaPublic: PropTypes.string,
requestPasswordReset: PropTypes.func,
errorMessage: PropTypes.string,
};
export default AdminLogin;
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Dialog} from 'coral-ui';
import styles from './BanUserDialog.css';
@@ -1,3 +1,7 @@
.root {
position: relative;
}
.bodyLeave {
position: absolute;
width: 100%;
@@ -2,11 +2,13 @@ import React from 'react';
import {murmur3} from 'murmurhash-js';
import {CSSTransitionGroup} from 'react-transition-group';
import styles from './CommentAnimatedEdit.css';
import PropTypes from 'prop-types';
export default ({children, body}) => {
const CommentBodyHighlighter = ({children, body}) => {
return (
<CSSTransitionGroup
component={'div'}
className={styles.root}
transitionName={{
enter: styles.bodyEnter,
enterActive: styles.bodyEnterActive,
@@ -22,3 +24,10 @@ export default ({children, body}) => {
</CSSTransitionGroup>
);
};
CommentBodyHighlighter.propTypes = {
children: PropTypes.node,
body: PropTypes.string,
};
export default CommentBodyHighlighter;
@@ -1,25 +1,78 @@
import React from 'react';
import Highlighter from 'react-highlight-words';
import Linkify from 'react-linkify';
const linkify = new Linkify();
import {matchLinks} from '../utils';
import memoize from 'lodash/memoize';
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
// generate a regulare expression that catches the `phrases`.
function generateRegExp(phrases) {
const inner = phrases
.map((phrase) =>
phrase.split(/\s+/)
.map((word) => escapeRegExp(word))
.join('[\\s"?!.]+')
).join('|');
return new RegExp(`(^|[^\\w])(${inner})(?=[^\\w]|$)`, 'iu');
}
// Generate a regular expression detecting `suspectWords` and `bannedWords` phrases.
function getPhrasesRegexp(suspectWords, bannedWords) {
return generateRegExp([...suspectWords, ...bannedWords]);
}
// Memoized version as arguments rarely change.
const getPhrasesRegexpMemoized = memoize(getPhrasesRegexp);
// markPhrases looks for `supsectWords` and `bannedWords` inside `body` and highlights them by returning
// an array of React Elements.
function markPhrases(body, suspectWords, bannedWords, keyPrefix) {
const regexp = getPhrasesRegexpMemoized(suspectWords, bannedWords);
const tokens = body.split(regexp);
return tokens.map((token, i) =>
i % 3 === 2
? <mark key={`${keyPrefix}_${i}`}>{token}</mark>
: token
);
}
// markLinks looks for links inside `body` and highlights them by returning
// an array of React Elements.
function markLinks(body) {
const matches = matchLinks(body);
const content = [];
let index = 0;
if (matches) {
matches
.forEach((match, i) => {
content.push(body.substring(index, match.index));
content.push(<mark key={i}>{match.text}</mark>);
index = match.lastIndex;
});
}
content.push(body.substring(index));
return content;
}
export default ({suspectWords, bannedWords, body, ...rest}) => {
const links = linkify.getMatches(body);
const linkText = links ? links.map((link) => link.raw) : [];
// First highlight links.
const content = markLinks(body)
.map((element, index) => {
const searchWords = [
...suspectWords,
...bannedWords,
...linkText
];
// Keep highlighted links.
if (typeof element !== 'string') {
return element;
}
// Highlight suspect and banned phrase inside this part of text.
return markPhrases(element, suspectWords, bannedWords, index);
});
return (
<Highlighter
{...rest}
autoEscape={true}
searchWords={searchWords}
textToHighlight={body}
/>
<div {...rest}>
{content}
</div>
);
};
@@ -1,4 +0,0 @@
.textareaContainer {
width: 100%;
}
@@ -1,35 +0,0 @@
import React from 'react';
import styles from './CommentBox.css';
import {Button} from 'react-mdl';
// Renders a comment box for creating a new comment
export default class CommentBox extends React.Component {
constructor (props) {
super(props);
this.state = {name: '', body: ''};
this.onSubmit = this.onSubmit.bind(this);
}
onSubmit () {
const {name, body} = this.state;
this.props.onSubmit({name, body});
this.setState({body: '', name: ''});
}
render (props, {name, body}) {
return (
<div>
<div class={`${styles.textareaContainer} mdl-textfield mdl-js-textfield`}>
<input type='text' value={name} onInput={this.linkState('name')} class='mdl-textfield__input' id='name' />
<label class='mdl-textfield__label' for='name'>Your name</label>
</div>
<div class={`${styles.textareaContainer} mdl-textfield mdl-js-textfield`}>
<textarea value={body} onInput={this.linkState('body')} class='mdl-textfield__input' type='text' rows='5' id='comment' />
<label class='mdl-textfield__label' for='comment'>Write your comment</label>
</div>
<Button onClick={this.onSubmit} raised>Post</Button>
</div>
);
}
}
@@ -0,0 +1,27 @@
.root {
display: flex;
justify-content: flex-end;
}
.coreLabels {
> *:not(:last-child) {
margin-right: 3px;
}
}
.slot {
&:not(:empty) {
padding-left: 3px;
}
> *:not(:last-child) {
margin-right: 3px;
}
}
.replyLabel {
background-color: #3D73D5;
}
.premodLabel {
background-color: #063B9A;
}
@@ -0,0 +1,45 @@
import React from 'react';
import PropTypes from 'prop-types';
import Label from 'coral-ui/components/Label';
import Slot from 'coral-framework/components/Slot';
import FlagLabel from 'coral-ui/components/FlagLabel';
import cn from 'classnames';
import styles from './CommentLabels.css';
function isUserFlagged(actions) {
return actions.some((action) => action.__typename === 'FlagAction' && action.user);
}
function hasSuspectedWords(actions) {
return actions.some((action) => action.__typename === 'FlagAction' && action.reason === 'Matched suspect word filter');
}
function hasHistoryFlag(actions) {
return actions.some((action) => action.__typename === 'FlagAction' && action.reason === 'TRUST');
}
const CommentLabels = ({comment, comment: {className, status, actions, hasParent}}) => {
return (
<div className={cn(className, styles.root)}>
<div className={styles.coreLabels}>
{hasParent && <Label iconName="reply" className={styles.replyLabel}>reply</Label>}
{status === 'PREMOD' && <Label iconName="query_builder" className={styles.premodLabel}>Pre-Mod</Label>}
{isUserFlagged(actions) && <FlagLabel iconName="person">User</FlagLabel>}
{hasSuspectedWords(actions) && <FlagLabel iconName="sms_failed">Suspect</FlagLabel>}
{hasHistoryFlag(actions) && <FlagLabel iconName="sentiment_very_dissatisfied">History</FlagLabel>}
</div>
<Slot className={styles.slot} fill="adminCommentLabels" queryData={{comment}} />
</div>
);
};
CommentLabels.propTypes = {
comment: PropTypes.shape({
className: PropTypes.string,
status: PropTypes.string,
actions: PropTypes.array,
hasParent: PropTypes.bool,
}),
};
export default CommentLabels;
@@ -1,30 +0,0 @@
.commentType {
display: inline-block;
color: white;
background: grey;
box-sizing: border-box;
padding: 2px 5px;
font-size: 12px;
height: 24px;
letter-spacing: 0.4px;
line-height: 22px;
> i {
font-size: 14px;
vertical-align: text-top;
margin: 0;
margin-right: 4px;
}
&.premod {
background: #063B9A;
}
&.flagged {
background: #d03235;
}
&.no-type {
display: none;
}
}
@@ -1,31 +0,0 @@
import React, {PropTypes} from 'react';
import styles from './CommentType.css';
import {Icon} from 'coral-ui';
import cn from 'classnames';
const CommentType = (props) => {
const typeData = getTypeData(props.type);
return (
<span className={cn(styles.commentType, styles[typeData.className], props.className)}>
<Icon name={typeData.icon}/>{typeData.text}
</span>
);
};
const getTypeData = (type) => {
switch (type) {
case 'premod':
return {icon: 'query_builder', text: 'Pre-Mod', className: 'premod'};
case 'flagged':
return {icon: 'flag', text: 'Flagged', className: 'flagged'};
default:
return {icon: 'flag', className: 'no-type'};
}
};
CommentType.propTypes = {
type: PropTypes.string.isRequired
};
export default CommentType;
@@ -5,7 +5,7 @@
vertical-align: middle;
padding: 1px 5px;
border-radius: 2px;
margin-left: 2px;
margin-left: 5px;
line-height: 18px;
box-sizing: border-box;
height: 18px;
@@ -1,9 +1,10 @@
import React, {PropTypes} from 'react';
import styles from './CommentCount.css';
import React from 'react';
import PropTypes from 'prop-types';
import styles from './CountBadge.css';
import t from 'coral-framework/services/i18n';
const CommentCount = ({count}) => {
const CountBadge = ({count}) => {
let number = count;
// shorten large counts to abbreviations
@@ -20,8 +21,8 @@ const CommentCount = ({count}) => {
);
};
CommentCount.propTypes = {
CountBadge.propTypes = {
count: PropTypes.number.isRequired
};
export default CommentCount;
export default CountBadge;
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Card} from 'coral-ui';
const EmptyCard = (props) => (
+2 -1
View File
@@ -1,4 +1,5 @@
import React, {Component, PropTypes} from 'react';
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {Icon} from 'coral-ui';
import styles from './FlagBox.css';
import t from 'coral-framework/services/i18n';
@@ -1,9 +1,8 @@
import React from 'react';
import Linkify from 'react-linkify';
const linkify = new Linkify();
import {matchLinks} from '../utils';
export default ({text, children}) => {
const hasLinks = !!linkify.getMatches(text);
const hasLinks = !!matchLinks(text);
if (!hasLinks) {
return null;
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Button} from 'coral-ui';
import styles from './LoadMore.css';
import cn from 'classnames';
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import Modal from 'components/Modal';
import styles from './ModerationKeysModal.css';
import t from 'coral-framework/services/i18n';
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import styles from './ModerationList.css';
import key from 'keymaster';
import Hammer from 'hammerjs';
@@ -1,11 +0,0 @@
import React from 'react';
import {Badge} from 'coral-ui';
import t from 'coral-framework/services/i18n';
const ReplyBadge = () => (
<Badge icon="reply">
{t('modqueue.reply')}
</Badge>
);
export default ReplyBadge;
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Dialog} from 'coral-ui';
import {RadioGroup, Radio} from 'react-mdl';
import styles from './SuspendUserDialog.css';
@@ -28,16 +28,26 @@ export default class UserDetail extends React.Component {
bulkReject: PropTypes.func.isRequired,
}
rejectThenReload = (info) => {
this.props.rejectComment(info).then(() => {
rejectThenReload = async (info) => {
try {
await this.props.rejectComment(info);
this.props.data.refetch();
});
} catch (err) {
// TODO: handle error.
console.error(err);
}
}
acceptThenReload = (info) => {
this.props.acceptComment(info).then(() => {
acceptThenReload = async (info) => {
try {
await this.props.acceptComment(info);
this.props.data.refetch();
});
} catch (err) {
// TODO: handle error.
console.error(err);
}
}
showAll = () => {
@@ -133,7 +143,7 @@ export default class UserDetail extends React.Component {
<Slot
fill="userProfile"
data={this.props.data}
queryData={root, user}
queryData={{root, user}}
/>
<hr/>
@@ -173,7 +183,6 @@ export default class UserDetail extends React.Component {
key={comment.id}
user={user}
comment={comment}
selected={false}
suspectWords={suspectWords}
bannedWords={bannedWords}
actions={actionsMap[status]}
@@ -55,7 +55,7 @@
position: relative;
}
.badgeBar {
.labels {
position: absolute;
right: 0px;
}
@@ -1,18 +1,17 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Link} from 'react-router';
import {Icon} from 'coral-ui';
import FlagBox from './FlagBox';
import ReplyBadge from './ReplyBadge';
import styles from './UserDetailComment.css';
import CommentType from './CommentType';
import {getActionSummary} from 'coral-framework/utils';
import ActionButton from 'coral-admin/src/components/ActionButton';
import CommentBodyHighlighter from 'coral-admin/src/components/CommentBodyHighlighter';
import IfHasLink from 'coral-admin/src/components/IfHasLink';
import cn from 'classnames';
import {getCommentType} from 'coral-admin/src/utils/comment';
import CommentAnimatedEdit from './CommentAnimatedEdit';
import CommentLabels from '../containers/CommentLabels';
import t, {timeago} from 'coral-framework/services/i18n';
@@ -34,7 +33,6 @@ class UserDetailComment extends React.Component {
const flagActionSummaries = getActionSummary('FlagActionSummary', comment);
const flagActions = comment.actions && comment.actions.filter((a) => a.__typename === 'FlagAction');
const commentType = getCommentType(comment);
return (
<li
@@ -58,9 +56,8 @@ class UserDetailComment extends React.Component {
: null
}
<div className={styles.badgeBar}>
{comment.hasParent && <ReplyBadge/>}
<CommentType type={commentType}/>
<div className={styles.labels}>
<CommentLabels comment={comment} />
</div>
</div>
<div className={styles.story}>
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Navigation, Drawer} from 'react-mdl';
import {IndexLink, Link} from 'react-router';
import styles from './Drawer.css';
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Navigation, Header, IconButton, MenuItem, Menu} from 'react-mdl';
import {Link, IndexLink} from 'react-router';
import styles from './Header.css';
@@ -72,12 +73,12 @@ const CoralHeader = ({
<Menu target="menu-settings" align="right">
<MenuItem onClick={() => showShortcuts(true)}>{t('configure.shortcuts')}</MenuItem>
<MenuItem>
<a href="https://github.com/coralproject/talk/releases" target="_blank">
<a href="https://github.com/coralproject/talk/releases" target="_blank" rel="noopener noreferrer">
View latest version
</a>
</MenuItem>
<MenuItem>
<a href="https://coralproject.net/contribute.html#other-ideas-and-bug-reports" target="_blank">
<a href="https://coralproject.net/contribute.html#other-ideas-and-bug-reports" target="_blank" rel="noopener noreferrer">
Report a bug or give feedback
</a>
</MenuItem>
@@ -87,8 +88,8 @@ const CoralHeader = ({
</Menu>
</div>
</li>
<li>
{`v${process.env.VERSION}`}
<li>
{`v${process.env.VERSION}`}
</li>
</ul>
</div>
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Layout as LayoutMDL} from 'react-mdl';
import Header from './Header';
import Drawer from './Drawer';
@@ -6,15 +6,22 @@ import {hideBanUserDialog} from '../actions/banUserDialog';
import {withSetUserStatus, withSetCommentStatus} from 'coral-framework/graphql/mutations';
import {compose} from 'react-apollo';
import t from 'coral-framework/services/i18n';
import {getErrorMessages} from 'coral-framework/utils';
import {notify} from 'coral-framework/actions/notification';
class BanUserDialogContainer extends Component {
banUser = async () => {
const {userId, commentId, commentStatus, setUserStatus, setCommentStatus, hideBanUserDialog} = this.props;
await setUserStatus({userId, status: 'BANNED'});
hideBanUserDialog();
if (commentId && commentStatus && commentStatus !== 'REJECTED') {
await setCommentStatus({commentId, status: 'REJECTED'});
const {userId, commentId, commentStatus, setUserStatus, setCommentStatus, hideBanUserDialog, notify} = this.props;
try {
await setUserStatus({userId, status: 'BANNED'});
hideBanUserDialog();
if (commentId && commentStatus && commentStatus !== 'REJECTED') {
await setCommentStatus({commentId, status: 'REJECTED'});
}
}
catch(err) {
notify('error', getErrorMessages(err));
}
}
@@ -50,6 +57,7 @@ const mapStateToProps = ({banUserDialog: {open, userId, username, commentId, com
const mapDispatchToProps = (dispatch) => ({
...bindActionCreators({
hideBanUserDialog,
notify,
}, dispatch),
});
@@ -0,0 +1,27 @@
import {gql} from 'react-apollo';
import CommentLabels from '../components/CommentLabels';
import withFragments from 'coral-framework/hocs/withFragments';
import {getSlotFragmentSpreads} from 'coral-framework/utils';
const slots = [
'adminCommentLabels',
];
export default withFragments({
comment: gql`
fragment CoralAdmin_CommentLabels_comment on Comment {
hasParent
status
actions {
__typename
... on FlagAction {
reason
}
user {
id
}
}
${getSlotFragmentSpreads(slots, 'comment')}
}
`
})(CommentLabels);
@@ -17,21 +17,13 @@ class SuspendUserDialogContainer extends Component {
const {userId, username, commentStatus, commentId, hideSuspendUserDialog, setCommentStatus, suspendUser, notify} = this.props;
hideSuspendUserDialog();
try {
const result = await suspendUser({id: userId, message, until});
if (result.data.suspendUser.errors) {
throw result.data.suspendUser.errors;
}
await suspendUser({id: userId, message, until});
notify(
'success',
t('suspenduser.notify_suspend_until', username, timeago(until)),
);
if (commentId && commentStatus && commentStatus !== 'REJECTED') {
return setCommentStatus({commentId, status: 'REJECTED'})
.then((result) => {
if (result.data.setCommentStatus.errors) {
throw result.data.setCommentStatus.errors;
}
});
await setCommentStatus({commentId, status: 'REJECTED'});
}
}
catch(err) {
@@ -36,14 +36,19 @@ class UserDetailContainer extends React.Component {
isLoadingMore = false;
// status can be 'ACCEPTED' or 'REJECTED'
bulkSetCommentStatus = (status) => {
bulkSetCommentStatus = async (status) => {
const changes = this.props.selectedCommentIds.map((commentId) => {
return this.props.setCommentStatus({commentId, status});
});
Promise.all(changes).then(() => {
try {
await Promise.all(changes);
this.props.clearUserDetailSelections(); // un-select everything
});
} catch (err) {
// TODO: handle error.
console.error(err);
}
}
bulkReject = () => {
@@ -1,6 +1,8 @@
import {gql} from 'react-apollo';
import UserDetailComment from '../components/UserDetailComment';
import withFragments from 'coral-framework/hocs/withFragments';
import {getDefinitionName} from 'coral-framework/utils';
import CommentLabels from './CommentLabels';
export default withFragments({
comment: gql`
@@ -35,6 +37,8 @@ export default withFragments({
editing {
edited
}
...${getDefinitionName(CommentLabels.fragments.comment)}
}
${CommentLabels.fragments.comment}
`
})(UserDetailComment);
+14 -14
View File
@@ -12,23 +12,23 @@ import {toast} from 'react-toastify';
import {createNotificationService} from './services/notification';
import {hideShortcutsNote} from './actions/moderation';
function hidrateStore({store, storage}) {
smoothscroll.polyfill();
function init({store, storage}) {
if (storage && storage.getItem('coral:shortcutsNote') === 'hide') {
store.dispatch(hideShortcutsNote());
}
}
smoothscroll.polyfill();
async function main() {
const notification = createNotificationService(toast);
const context = await createContext({reducers, graphqlExtension, pluginsConfig, notification, init});
render(
<TalkProvider {...context}>
<App />
</TalkProvider>
, document.querySelector('#root')
);
}
const notification = createNotificationService(toast);
const context = createContext({reducers, graphqlExtension, pluginsConfig, notification});
// hidrate Store with external data.
hidrateStore(context);
render(
<TalkProvider {...context}>
<App />
</TalkProvider>
, document.querySelector('#root')
);
main();
@@ -3,7 +3,7 @@ import * as actions from '../constants/userDetail';
const initialState = {
userId: null,
activeTab: 'all',
statuses: ['NONE', 'ACCEPTED', 'REJECTED', 'PREMOD'],
statuses: null,
selectedCommentIds: [],
};
@@ -4,6 +4,7 @@ import CommunityMenu from './CommunityMenu';
import People from './People';
import FlaggedAccounts from '../containers/FlaggedAccounts';
import RejectUsernameDialog from './RejectUsernameDialog';
import PropTypes from 'prop-types';
export default class Community extends Component {
@@ -76,7 +77,10 @@ export default class Community extends Component {
return (
<div>
<FlaggedAccounts />
<FlaggedAccounts
data={this.props.data}
root={this.props.root}
/>
<RejectUsernameDialog
open={community.rejectUsernameDialog}
handleClose={props.hideRejectUsernameDialog}
@@ -90,15 +94,25 @@ export default class Community extends Component {
render() {
const {searchValue} = this.state;
const tab = this.getTabContent(searchValue, this.props);
const {root: {flaggedUsernamesCount}} = this.props;
return (
<div>
<CommunityMenu />
<div>
{ tab }
</div>
<CommunityMenu flaggedUsernamesCount={flaggedUsernamesCount} />
<div>{tab}</div>
</div>
);
}
}
Community.propTypes = {
community: PropTypes.object,
fetchAccounts: PropTypes.func,
hideRejectUsernameDialog: PropTypes.func,
updateSorting: PropTypes.func,
newPage: PropTypes.func,
route: PropTypes.object,
rejectUsername: PropTypes.func,
data: PropTypes.object,
root: PropTypes.object
};
@@ -1,18 +1,21 @@
import React from 'react';
import styles from './CommunityMenu.css';
import t from 'coral-framework/services/i18n';
import {Link} from 'react-router';
import PropTypes from 'prop-types';
import CountBadge from '../../../components/CountBadge';
const CommunityMenu = () => {
const CommunityMenu = ({flaggedUsernamesCount = 0}) => {
const flaggedPath = '/admin/community/flagged';
const peoplePath = '/admin/community/people';
return (
<div className='mdl-tabs'>
<div className={`mdl-tabs__tab-bar ${styles.tabBar}`}>
<div>
<Link to={flaggedPath} className={`mdl-tabs__tab ${styles.tab}`} activeClassName={styles.active}>
{t('community.flaggedaccounts')}
<CountBadge count={flaggedUsernamesCount} />
</Link>
<Link to={peoplePath} className={`mdl-tabs__tab ${styles.tab}`} activeClassName={styles.active}>
{t('community.people')}
@@ -23,4 +26,8 @@ const CommunityMenu = () => {
);
};
CommunityMenu.propTypes = {
flaggedUsernamesCount: PropTypes.number,
};
export default CommunityMenu;
@@ -85,7 +85,7 @@ class User extends React.Component {
<span className={styles.flaggedByLabel}>
{t('community.flags')}({ user.actions.length })
</span>:
{ user.action_summaries.map(
{ user.action_summaries.map(
(action, i) => {
return <span className={styles.flaggedBy} key={i}>
{shortReasons[action.reason]} ({action.count})
@@ -1,4 +1,5 @@
import React, {Component, PropTypes} from 'react';
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {Dialog, Button} from 'coral-ui';
import styles from './RejectUsernameDialog.css';
@@ -48,11 +49,15 @@ class RejectUsernameDialog extends Component {
const cancel = this.props.handleClose;
const next = () => this.setState({stage: stage + 1});
const suspend = () => {
rejectUsername({id: user.user.id, message: this.state.email})
.then(() => {
this.props.handleClose();
});
const suspend = async () => {
try {
await rejectUsername({id: user.user.id, message: this.state.email});
this.props.handleClose();
} catch (err) {
// TODO: handle error.
console.error(err);
}
};
const suspendModalActions = [
@@ -28,7 +28,8 @@ export default ({headers, commenters, onHeaderClickHandler, onRoleChange, onComm
{row.created_at}
</td>
<td className="mdl-data-table__cell--non-numeric">
<SelectField label={'Select me'} value={row.status || ''}
<SelectField
value={row.status || ''}
className={styles.selectField}
label={t('community.status')}
onChange={(status) => onCommenterStatusChange(row.id, status)}>
@@ -37,7 +38,8 @@ export default ({headers, commenters, onHeaderClickHandler, onRoleChange, onComm
</SelectField>
</td>
<td className="mdl-data-table__cell--non-numeric">
<SelectField label={'Select me'} value={row.roles[0] || ''}
<SelectField
value={row.roles[0] || ''}
className={styles.selectField}
label={t('community.role')}
onChange={(role) => onRoleChange(row.id, role)}>
@@ -1,9 +1,16 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {compose} from 'react-apollo';
import {compose, gql} from 'react-apollo';
import withQuery from 'coral-framework/hocs/withQuery';
import PropTypes from 'prop-types';
import FlaggedAccounts from '../containers/FlaggedAccounts';
import FlaggedUser from '../containers/FlaggedUser';
import {withSetUserStatus, withRejectUsername} from 'coral-framework/graphql/mutations';
import {getDefinitionName} from 'coral-framework/utils';
import {
fetchAccounts,
updateSorting,
@@ -20,15 +27,57 @@ class CommunityContainer extends Component {
}
render() {
return (
<Community {...this.props} />
);
return <Community
fetchAccounts={this.props.fetchAccounts}
community={this.props.community}
hideRejectUsernameDialog={this.props.hideRejectUsernameDialog}
updateSorting={this.props.updateSorting}
newPage={this.props.newPage}
route={this.props.route}
rejectUsername={this.props.rejectUsername}
data={this.props.data}
root={this.props.root}
/>;
}
}
const mapStateToProps = (state) => ({
community: state.community,
});
CommunityContainer.propTypes = {
community: PropTypes.object,
fetchAccounts: PropTypes.func,
hideRejectUsernameDialog: PropTypes.func,
updateSorting: PropTypes.func,
newPage: PropTypes.func,
route: PropTypes.object,
rejectUsername: PropTypes.func,
data: PropTypes.object,
root: PropTypes.object
};
const withData = withQuery(gql`
query TalkAdmin_FlaggedUsernamesCount {
flaggedUsernamesCount: userCount(query: {
action_type: FLAG,
statuses: [PENDING]
})
...${getDefinitionName(FlaggedAccounts.fragments.root)}
...${getDefinitionName(FlaggedUser.fragments.root)}
me {
...${getDefinitionName(FlaggedUser.fragments.me)}
__typename
}
}
${FlaggedAccounts.fragments.root}
${FlaggedUser.fragments.root}
${FlaggedUser.fragments.me}
`, {
options: {
fetchPolicy: 'network-only',
},
});
const mapDispatchToProps = (dispatch) =>
bindActionCreators({
fetchAccounts,
@@ -41,4 +90,5 @@ export default compose(
connect(mapStateToProps, mapDispatchToProps),
withSetUserStatus,
withRejectUsername,
withData,
)(CommunityContainer);
@@ -2,8 +2,9 @@ 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 {withFragments} from 'plugin-api/beta/client/hocs';
import {Spinner} from 'coral-ui';
import PropTypes from 'prop-types';
import {withSetUserStatus} from 'coral-framework/graphql/mutations';
import {showBanUserDialog} from 'actions/banUserDialog';
@@ -24,7 +25,10 @@ class FlaggedAccountsContainer extends Component {
}
approveUser = ({userId}) => {
return this.props.setUserStatus({userId, status: 'APPROVED'});
return this.props.setUserStatus({
userId,
status: 'APPROVED'
});
}
loadMore = () => {
@@ -74,6 +78,16 @@ class FlaggedAccountsContainer extends Component {
}
}
FlaggedAccountsContainer.propTypes = {
showBanUserDialog: PropTypes.func,
showSuspendUserDialog: PropTypes.func,
showRejectUsernameDialog: PropTypes.func,
viewUserDetail: PropTypes.func,
setUserStatus: PropTypes.func,
data: PropTypes.object,
root: PropTypes.object
};
const LOAD_MORE_QUERY = gql`
query TalkAdmin_LoadMoreFlaggedAccounts($limit: Int, $cursor: Cursor) {
users(query:{action_type: FLAG, statuses: [PENDING], limit: $limit, cursor: $cursor}){
@@ -88,31 +102,6 @@ const LOAD_MORE_QUERY = gql`
${FlaggedUser.fragments.user}
`;
export const withFlaggedAccountsyQuery = withQuery(gql`
query TalkAdmin_FlaggedAccounts {
...${getDefinitionName(FlaggedUser.fragments.root)}
users(query:{action_type: FLAG, statuses: [PENDING], limit: 10}){
hasNextPage
endCursor
nodes {
__typename
...${getDefinitionName(FlaggedUser.fragments.user)}
}
}
me {
__typename
...${getDefinitionName(FlaggedUser.fragments.me)}
}
}
${FlaggedUser.fragments.root}
${FlaggedUser.fragments.user}
${FlaggedUser.fragments.me}
`, {
options: {
fetchPolicy: 'network-only',
},
});
const mapDispatchToProps = (dispatch) =>
bindActionCreators({
showBanUserDialog,
@@ -123,6 +112,23 @@ const mapDispatchToProps = (dispatch) =>
export default compose(
connect(null, mapDispatchToProps),
withFlaggedAccountsyQuery,
withSetUserStatus,
withFragments({
root: gql`
fragment TalkAdminCommunity_FlaggedAccounts_root on RootQuery {
users(query:{action_type: FLAG, statuses: [PENDING], limit: 10}){
hasNextPage
endCursor
nodes {
__typename
...${getDefinitionName(FlaggedUser.fragments.user)}
}
}
me {
id
}
}
${FlaggedUser.fragments.user}
`,
}),
)(FlaggedAccountsContainer);
@@ -1,6 +1,6 @@
import React, {Component} from 'react';
import t from 'coral-framework/services/i18n';
import {join} from 'path';
import join from 'url-join';
import styles from './Configure.css';
import {Button, Card} from 'coral-ui';
import {BASE_URL} from 'coral-framework/constants/url';
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import styles from './Configure.css';
import {Card} from 'coral-ui';
import {Checkbox} from 'react-mdl';
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Card} from 'coral-ui';
import Domainlist from './Domainlist';
import EmbedLink from './EmbedLink';
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Link} from 'react-router';
import styles from './Widget.css';
import t from 'coral-framework/services/i18n';
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import styles from './Dashboard.css';
import {Icon} from 'coral-ui';
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Link} from 'react-router';
import styles from './Widget.css';
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Link} from 'react-router';
import styles from './Widget.css';
import t from 'coral-framework/services/i18n';
@@ -1,4 +1,5 @@
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {compose} from 'react-apollo';
@@ -31,7 +32,7 @@ class InstallContainer extends Component {
}
InstallContainer.contextTypes = {
router: React.PropTypes.object
router: PropTypes.object
};
const mapStateToProps = (state) => ({
@@ -1,11 +1,11 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Link} from 'react-router';
import {Icon} from 'coral-ui';
import ReplyBadge from 'coral-admin/src/components/ReplyBadge';
import FlagBox from 'coral-admin/src/components/FlagBox';
import styles from './styles.css';
import CommentType from 'coral-admin/src/components/CommentType';
import CommentLabels from 'coral-admin/src/components/CommentLabels';
import CommentAnimatedEdit from 'coral-admin/src/components/CommentAnimatedEdit';
import Slot from 'coral-framework/components/Slot';
import {getActionSummary} from 'coral-framework/utils';
@@ -15,7 +15,6 @@ import ActionsMenuItem from 'coral-admin/src/components/ActionsMenuItem';
import CommentBodyHighlighter from 'coral-admin/src/components/CommentBodyHighlighter';
import IfHasLink from 'coral-admin/src/components/IfHasLink';
import cn from 'classnames';
import {getCommentType} from 'coral-admin/src/utils/comment';
import t, {timeago} from 'coral-framework/services/i18n';
@@ -65,7 +64,6 @@ class Comment extends React.Component {
const flagActionSummaries = getActionSummary('FlagActionSummary', comment);
const flagActions = comment.actions && comment.actions.filter((a) => a.__typename === 'FlagAction');
const commentType = getCommentType(comment);
const selectionStateCSS = selected ? 'mdl-shadow--16dp' : 'mdl-shadow--2dp';
@@ -108,8 +106,9 @@ class Comment extends React.Component {
</ActionsMenu>
}
<div className={styles.adminCommentInfoBar}>
{comment.hasParent && <ReplyBadge/>}
<CommentType type={commentType} className={styles.commentType}/>
<CommentLabels
comment={comment}
/>
<Slot
fill="adminCommentInfoBar"
data={data}
@@ -126,7 +125,7 @@ class Comment extends React.Component {
</div>
<CommentAnimatedEdit body={comment.body}>
<div className={styles.itemBody}>
<p className={styles.body}>
<div className={styles.body}>
<CommentBodyHighlighter
suspectWords={suspectWords}
bannedWords={bannedWords}
@@ -140,7 +139,7 @@ class Comment extends React.Component {
>
<Icon name="open_in_new" /> {t('comment.view_context')}
</a>
</p>
</div>
<Slot
fill="adminCommentContent"
data={data}
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Icon} from 'coral-ui';
import styles from './styles.css';
import t from 'coral-framework/services/i18n';
@@ -1,5 +1,6 @@
import React, {PropTypes} from 'react';
import CommentCount from './CommentCount';
import React from 'react';
import PropTypes from 'prop-types';
import CountBadge from '../../../components/CountBadge';
import styles from './styles.css';
import {SelectField, Option} from 'react-mdl-selectfield';
import {Icon} from 'coral-ui';
@@ -27,7 +28,7 @@ const ModerationMenu = ({
to={getModPath(queue.key, asset.id)}
className={cn('mdl-tabs__tab', styles.tab, {[styles.active]: activeTab === queue.key})}
activeClassName={styles.active}>
<Icon name={queue.icon} className={styles.tabIcon} /> {queue.name} <CommentCount count={queue.count} />
<Icon name={queue.icon} className={styles.tabIcon} /> {queue.name} <CountBadge count={queue.count} />
</Link>
)}
</div>
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import Comment from '../containers/Comment';
import styles from './styles.css';
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import styles from './StorySearch.css';
const formatDate = (date) => {
@@ -8,7 +8,7 @@ const StorySearch = (props) => {
const {
root: {
assets = []
assets,
},
data: {loading}
} = props;
@@ -62,7 +62,7 @@ const StorySearch = (props) => {
{
loading
? <Spinner />
: assets.map((story, i) => {
: assets.nodes.map((story, i) => {
const storyOpen = story.closedAt === null || new Date(story.closedAt) > new Date();
return <Story
@@ -77,7 +77,7 @@ const StorySearch = (props) => {
})
}
{assets.length === 0 && <div className={styles.noResults}>No results</div>}
{assets.nodes.length === 0 && <div className={styles.noResults}>No results</div>}
</div>
</div>
</div>
@@ -186,6 +186,14 @@ span {
padding: 10px 0;
min-height: 0;
/*
Fix rendering issues in Safari by promoting this
into its own layer.
https://www.pivotaltracker.com/story/show/151142211
*/
transform: translateZ(0);
.container {
padding: 0 14px;
}
@@ -1,7 +1,8 @@
import {gql} from 'react-apollo';
import Comment from '../components/Comment';
import CommentLabels from '../../../containers/CommentLabels';
import withFragments from 'coral-framework/hocs/withFragments';
import {getSlotFragmentSpreads} from 'coral-framework/utils';
import {getSlotFragmentSpreads, getDefinitionName} from 'coral-framework/utils';
const slots = [
'adminCommentInfoBar',
@@ -58,6 +59,8 @@ export default withFragments({
}
hasParent
${getSlotFragmentSpreads(slots, 'comment')}
...${getDefinitionName(CommentLabels.fragments.comment)}
}
${CommentLabels.fragments.comment}
`
})(Comment);
@@ -170,7 +170,8 @@ class ModerationContainer extends Component {
cursor: this.props.root[tab].endCursor,
sortOrder: this.props.data.variables.sortOrder,
asset_id: this.props.data.variables.asset_id,
statuses: this.props.queueConfig[tab].statuses,
statuses: this.props.queueConfig[tab].statuses || null,
tags: this.props.queueConfig[tab].tags || null,
action_type: this.props.queueConfig[tab].action_type,
};
return this.props.data.fetchMore({
@@ -214,7 +215,7 @@ class ModerationContainer extends Component {
return <Spinner />;
}
const premodEnabled = assetId ? isPremod(asset.settings.moderation) :
const premodEnabled = assetId ? isPremod(asset.settings.moderation) :
isPremod(settings.moderation);
const currentQueueConfig = Object.assign({}, this.props.queueConfig);
@@ -293,8 +294,8 @@ const COMMENT_REJECTED_SUBSCRIPTION = gql`
`;
const LOAD_MORE_QUERY = gql`
query CoralAdmin_Moderation_LoadMore($limit: Int = 10, $cursor: Cursor, $sortOrder: SORT_ORDER, $asset_id: ID, $statuses:[COMMENT_STATUS!], $action_type: ACTION_TYPE) {
comments(query: {limit: $limit, cursor: $cursor, asset_id: $asset_id, statuses: $statuses, sortOrder: $sortOrder, action_type: $action_type}) {
query CoralAdmin_Moderation_LoadMore($limit: Int = 10, $cursor: Cursor, $sortOrder: SORT_ORDER, $asset_id: ID, $tags:[String!], $statuses:[COMMENT_STATUS!], $action_type: ACTION_TYPE) {
comments(query: {limit: $limit, cursor: $cursor, asset_id: $asset_id, statuses: $statuses, sortOrder: $sortOrder, action_type: $action_type, tags: $tags}) {
nodes {
...${getDefinitionName(Comment.fragments.comment)}
}
@@ -319,10 +320,10 @@ const commentConnectionFragment = gql`
`;
const withModQueueQuery = withQuery(({queueConfig}) => gql`
query CoralAdmin_Moderation($asset_id: ID, $sortOrder: SORT_ORDER, $allAssets: Boolean!) {
query CoralAdmin_Moderation($asset_id: ID, $sortOrder: SORT_ORDER, $allAssets: Boolean!, $nullStatuses: [COMMENT_STATUS!]) {
${Object.keys(queueConfig).map((queue) => `
${queue}: comments(query: {
${queueConfig[queue].statuses ? `statuses: [${queueConfig[queue].statuses.join(', ')}],` : ''}
statuses: ${queueConfig[queue].statuses ? `[${queueConfig[queue].statuses.join(', ')}],` : '$nullStatuses'}
${queueConfig[queue].tags ? `tags: ["${queueConfig[queue].tags.join('", "')}"],` : ''}
${queueConfig[queue].action_type ? `action_type: ${queueConfig[queue].action_type}` : ''}
asset_id: $asset_id,
@@ -333,7 +334,7 @@ const withModQueueQuery = withQuery(({queueConfig}) => gql`
`)}
${Object.keys(queueConfig).map((queue) => `
${queue}Count: commentCount(query: {
${queueConfig[queue].statuses ? `statuses: [${queueConfig[queue].statuses.join(', ')}],` : ''}
statuses: ${queueConfig[queue].statuses ? `[${queueConfig[queue].statuses.join(', ')}],` : '$nullStatuses'}
${queueConfig[queue].tags ? `tags: ["${queueConfig[queue].tags.join('", "')}"],` : ''}
${queueConfig[queue].action_type ? `action_type: ${queueConfig[queue].action_type}` : ''}
asset_id: $asset_id,
@@ -361,6 +362,7 @@ const withModQueueQuery = withQuery(({queueConfig}) => gql`
asset_id: id,
sortOrder: props.moderation.sortOrder,
allAssets: id === null,
nullStatuses: null,
},
fetchPolicy: 'network-only'
};
@@ -89,12 +89,14 @@ class StorySearchContainer extends React.Component {
export const withAssetSearchQuery = withQuery(gql`
query SearchStories($value: String = "") {
assets(query: {value: $value, limit: 10}) {
id
title
url
created_at
closedAt
author
nodes {
id
title
url
created_at
closedAt
author
}
}
}
`, {
@@ -13,7 +13,7 @@ export default {
},
reported: {
action_type: 'FLAG',
statuses: ['NONE', 'PREMOD'],
statuses: ['NONE', 'PREMOD', 'SYSTEM_WITHHELD'],
icon: 'flag',
name: t('modqueue.reported'),
},
@@ -28,7 +28,6 @@ export default {
name: t('modqueue.rejected'),
},
all: {
statuses: ['NONE', 'PREMOD', 'ACCEPTED', 'REJECTED'],
icon: 'question_answer',
name: t('modqueue.all'),
},
@@ -50,17 +50,22 @@ export default class Stories extends Component {
return `${d.getMonth() + 1}/${d.getDate()}/${d.getFullYear()}`;
}
onStatusClick = (closeStream, id, statusMenuOpen) => () => {
onStatusClick = (closeStream, id, statusMenuOpen) => async () => {
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);
});
try {
await this.props.updateAssetState(id, closeStream ? Date.now() : null);
const {search, sort, filter, page} = this.state;
this.props.fetchAssets(page, limit, search, sort, filter);
} catch (err) {
// TODO: handle error.
console.error(err);
}
} else {
this.setState((prev) => {
prev.statusMenus[id] = true;
@@ -0,0 +1,8 @@
import LinkifyIt from 'linkify-it';
import tlds from 'tlds';
export function createLinkify() {
const linkify = new LinkifyIt();
linkify.tlds(tlds);
return linkify;
}
-9
View File
@@ -1,9 +0,0 @@
export function getCommentType(comment) {
let commentType = '';
if (comment.status === 'PREMOD') {
commentType = 'premod';
} else if (comment.actions && comment.actions.some((a) => a.__typename === 'FlagAction')) {
commentType = 'flagged';
}
return commentType;
}
+10
View File
@@ -1,4 +1,14 @@
import LinkifyIt from 'linkify-it';
import tlds from 'tlds';
const linkify = new LinkifyIt();
linkify.tlds(tlds);
export function matchLinks(text) {
return linkify.match(text);
}
export const isPremod = (mod) => mod === 'PRE';
export const getModPath = (type = 'all', assetId) =>
assetId ? `/admin/moderate/${type}/${assetId}` : `/admin/moderate/${type}`;
@@ -1,4 +1,5 @@
import React, {PureComponent, PropTypes} from 'react';
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import marked from 'marked';
const renderer = new marked.Renderer();
@@ -18,7 +18,7 @@ import {getEditableUntilDate} from './util';
import {findCommentWithId} from '../graphql/utils';
import CommentContent from './CommentContent';
import Slot from 'coral-framework/components/Slot';
import IgnoredCommentTombstone from './IgnoredCommentTombstone';
import CommentTombstone from './CommentTombstone';
import InactiveCommentLabel from './InactiveCommentLabel';
import {EditableCommentContent} from './EditableCommentContent';
import {getActionSummary, iPerformedThisAction, forEachError, isCommentActive, getShallowChanges} from 'coral-framework/utils';
@@ -209,6 +209,10 @@ export default class Comment extends React.Component {
}
}
commentIsRejected(comment) {
return comment.status === 'REJECTED';
}
commentIsIgnored(comment) {
const me = this.props.root.me;
return (
@@ -338,8 +342,12 @@ export default class Comment extends React.Component {
commentClassNames = []
} = this.props;
if (!highlighted && this.commentIsRejected(comment)) {
return <CommentTombstone action='reject' />;
}
if (this.commentIsIgnored(comment)) {
return <IgnoredCommentTombstone />;
return <CommentTombstone action='ignore' />;
}
const view = this.getVisibileReplies();
@@ -2,8 +2,21 @@ import React from 'react';
import t from 'coral-framework/services/i18n';
// Render in place of a Comment when the author of the comment is ignored
class IgnoredCommentTombstone extends React.Component {
// Render in place of a Comment when the author of the comment is <action>
class CommentTombstone extends React.Component {
getCopy() {
const {action} = this.props;
switch (action) {
case 'ignore':
return t('framework.comment_is_ignored');
case 'reject':
return t('framework.comment_is_rejected');
default :
return t('framework.comment_is_hidden');
}
}
render() {
return (
<div>
@@ -14,11 +27,11 @@ class IgnoredCommentTombstone extends React.Component {
padding: '1em',
color: '#3E4F71',
}}>
{t('framework.comment_is_ignored')}
{this.getCopy()}
</p>
</div>
);
}
}
export default IgnoredCommentTombstone;
export default CommentTombstone;
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import t from 'coral-framework/services/i18n';
/**
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {notifyForNewCommentStatus} from 'talk-plugin-commentbox/CommentBox';
import {CommentForm} from 'talk-plugin-commentbox/CommentForm';
import styles from './Comment.css';
@@ -38,10 +39,10 @@ export class EditableCommentContent extends React.Component {
maxCharCount: PropTypes.number,
// edit a comment, passed {{ body }}
editComment: React.PropTypes.func,
editComment: PropTypes.func,
// called when editing should be stopped
stopEditing: React.PropTypes.func,
stopEditing: PropTypes.func,
}
constructor(props) {
@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import Stream from '../containers/Stream';
import Slot from 'coral-framework/components/Slot';
import {can} from 'coral-framework/services/perms';
@@ -90,8 +91,8 @@ export default class Embed extends React.Component {
}
Embed.propTypes = {
data: React.PropTypes.shape({
loading: React.PropTypes.bool,
error: React.PropTypes.object
data: PropTypes.shape({
loading: PropTypes.bool,
error: PropTypes.object
}).isRequired
};
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import styles from './Comment.css';
import {Button} from 'coral-ui';
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import t from 'coral-framework/services/i18n';
import styles from './InactiveCommentLabel.css';
import {Icon} from 'coral-ui';
@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Button} from 'coral-ui';
import t from 'coral-framework/services/i18n';
@@ -160,7 +160,7 @@ class Stream extends React.Component {
loading={loading}
appendTabs={
<Tab tabId={'all'} key='all'>
All Comments <TabCount active={activeStreamTab === 'all'} sub>{totalCommentCount}</TabCount>
{t('stream.all_comments')} <TabCount active={activeStreamTab === 'all'} sub>{totalCommentCount}</TabCount>
</Tab>
}
appendTabPanes={
@@ -201,7 +201,7 @@ class Stream extends React.Component {
data,
root,
appendItemArray,
root: {asset, asset: {comment: highlightedComment, comments}},
root: {asset, asset: {comment: highlightedComment}},
postComment,
notify,
updateItem,
@@ -222,9 +222,8 @@ class Stream extends React.Component {
const slotProps = {data};
const slotQueryData = {root, asset};
if (!highlightedComment && !comments) {
console.error('Talk: No comments came back from the graph given that query. Please, check the query params.');
return <StreamError />;
if (highlightedComment === null) {
return <StreamError>{t('stream.comment_not_found')}</StreamError>;
}
return (
@@ -308,7 +307,7 @@ Stream.propTypes = {
postComment: PropTypes.func.isRequired,
// edit a comment, passed (id, asset_id, { body })
editComment: React.PropTypes.func
editComment: PropTypes.func
};
export default Stream;
@@ -1,9 +1,8 @@
import React from 'react';
import styles from './StreamError.css';
import t from 'coral-framework/services/i18n';
export const StreamError = () => (
export const StreamError = ({children}) => (
<div className={styles.streamError}>
{t('common.error')}
{children}
</div>
);
@@ -15,8 +15,8 @@ class StreamTabPanel extends React.Component {
{loading
? <div className={styles.spinnerContainer}><Spinner /></div>
: <TabContent activeTab={activeTab} sub={sub}>
{tabPanes}
</TabContent>
{tabPanes}
</TabContent>
}
</div>
);
@@ -1,4 +1,5 @@
import React, {Component, PropTypes} from 'react';
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import t from 'coral-framework/services/i18n';
import styles from './SuspendAccount.css';
import {Button} from 'coral-ui';
@@ -92,12 +92,6 @@ const singleCommentFragment = gql`
const withCommentFragments = withFragments({
root: gql`
fragment CoralEmbedStream_Comment_root on RootQuery {
me {
ignoredUsers {
id
}
}
__typename
me {
ignoredUsers {
id
@@ -215,6 +215,6 @@ const mapDispatchToProps = (dispatch) =>
export default compose(
connect(mapStateToProps, mapDispatchToProps),
branch((props) => !props.auth.checkedInitialLogin && props.config, renderComponent(Spinner)),
branch((props) => !props.auth.checkedInitialLogin, renderComponent(Spinner)),
withEmbedQuery,
)(EmbedContainer);
@@ -51,7 +51,7 @@ class StreamContainer extends React.Component {
return prev;
}
if (['PREMOD', 'REJECTED'].includes(commentEdited.status)) {
if (['PREMOD', 'REJECTED', 'SYSTEM_WITHHELD'].includes(commentEdited.status)) {
return removeCommentFromEmbedQuery(prev, commentEdited.id);
}
},
@@ -178,7 +178,7 @@ class StreamContainer extends React.Component {
render() {
if (!this.props.root.asset
|| !this.props.root.asset.comment
|| this.props.root.asset.comment === undefined
&& !this.props.root.asset.comments
) {
return <Spinner />;
@@ -302,7 +302,7 @@ const fragments = {
questionBoxEnable
questionBoxContent
questionBoxIcon
closeTimeout
closedTimeout
closedMessage
charCountEnable
charCount
@@ -26,9 +26,9 @@ class StreamTabPanelContainer extends React.Component {
// it does not result in a change of slot children.
const changes = getShallowChanges(this.props, next);
if (changes.length === 1 && changes[0] === 'reduxState') {
const prevUuid = this.getSlotComponents(this.props.tabSlot, this.props).map((cmp) => cmp.talkUuid);
const nextUuid = this.getSlotComponents(next.tabSlot, next).map((cmp) => cmp.talkUuid);
return !isEqual(prevUuid, nextUuid);
const prevKeys = this.getSlotElements(this.props.tabSlot, this.props).map((el) => el.key);
const nextKeys = this.getSlotElements(next.tabSlot, next).map((el) => el.key);
return !isEqual(prevKeys, nextKeys);
}
// Prevent Slot from rerendering when no props has shallowly changed.
@@ -37,42 +37,33 @@ class StreamTabPanelContainer extends React.Component {
fallbackAllTab(props = this.props) {
if (props.activeTab !== props.fallbackTab) {
const slotPlugins = this.getSlotComponents(props.tabSlot, props).map((c) => c.talkPluginName);
const slotPlugins = this.getSlotElements(props.tabSlot, props).map((el) => el.type.talkPluginName);
if (slotPlugins.indexOf(props.activeTab) === -1) {
props.setActiveTab(props.fallbackTab);
}
}
}
getSlotComponents(slot, props = this.props) {
getSlotElements(slot, props = this.props) {
const {plugins} = this.context;
return plugins.getSlotComponents(slot, props.reduxState, props.slotProps, props.queryData);
return plugins.getSlotElements(slot, props.reduxState, props.slotProps, props.queryData);
}
getPluginTabElements(props = this.props) {
const {plugins} = this.context;
return this.getSlotComponents(props.tabSlot).map((PluginComponent) => {
const pluginProps = plugins.getSlotComponentProps(PluginComponent, props.reduxState, props.slotProps, props.queryData);
return this.getSlotElements(props.tabSlot).map((el) => {
return (
<Tab tabId={PluginComponent.talkPluginName} key={PluginComponent.talkPluginName}>
<PluginComponent
{...pluginProps}
active={this.props.activeTab === PluginComponent.talkPluginName}
/>
<Tab tabId={el.type.talkPluginName} key={el.type.talkPluginName}>
{React.cloneElement(el, {active: this.props.activeTab === el.type.talkPluginName})}
</Tab>
);
});
}
getPluginTabPaneElements(props = this.props) {
const {plugins} = this.context;
return this.getSlotComponents(props.tabPaneSlot).map((PluginComponent) => {
const pluginProps = plugins.getSlotComponentProps(PluginComponent, props.reduxState, props.slotProps, props.queryData);
return this.getSlotElements(props.tabPaneSlot).map((el) => {
return (
<TabPane tabId={PluginComponent.talkPluginName} key={PluginComponent.talkPluginName}>
<PluginComponent
{...pluginProps}
/>
<TabPane tabId={el.type.talkPluginName} key={el.type.talkPluginName}>
{el}
</TabPane>
);
});
+12 -3
View File
@@ -64,6 +64,13 @@ export default {
hasNextPage
}
}
actions {
__typename
... on FlagAction {
reason
message
}
}
}
fragment CoralEmbedStream_CreateCommentResponse_Comment on Comment {
@@ -109,12 +116,14 @@ export default {
},
mutations: {
PostComment: ({
variables: {comment: {asset_id, body, parent_id, tags = []}},
variables: {input: {asset_id, body, parent_id, tags = []}},
state: {auth},
}) => ({
optimisticResponse: {
createComment: {
__typename: 'CreateCommentResponse',
errors: null,
actions: [],
comment: {
__typename: 'Comment',
user: {
@@ -166,7 +175,7 @@ export default {
},
updateQueries: {
CoralEmbedStream_Embed: (prev, {mutationResult: {data: {createComment: {comment}}}}) => {
if (prev.asset.settings.moderation === 'PRE' || comment.status === 'PREMOD' || comment.status === 'REJECTED') {
if (prev.asset.settings.moderation === 'PRE' || comment.status === 'PREMOD' || comment.status === 'REJECTED' || comment.status === 'SYSTEM_WITHHELD') {
return prev;
}
return insertCommentIntoEmbedQuery(prev, comment);
@@ -185,7 +194,7 @@ export default {
EditComment: () => ({
updateQueries: {
CoralEmbedStream_Embed: (prev, {mutationResult: {data: {editComment: {comment}}}}) => {
if (!['PREMOD', 'REJECTED'].includes(comment.status)) {
if (!['PREMOD', 'REJECTED', 'SYSTEM_WITHHELD'].includes(comment.status)) {
return null;
}
return removeCommentFromEmbedQuery(prev, comment.id);
+35 -32
View File
@@ -10,11 +10,6 @@ import reducers from './reducers';
import TalkProvider from 'coral-framework/components/TalkProvider';
import pluginsConfig from 'pluginsConfig';
const context = createContext({reducers, graphqlExtension, pluginsConfig});
// TODO: move init code into `bootstrap` service after auth has been refactored.
const {store, pym} = context;
function inIframe() {
try {
return window.self !== window.top;
@@ -23,37 +18,45 @@ function inIframe() {
}
}
function init(config = {}) {
store.dispatch(addExternalConfig(config));
store.dispatch(checkLogin());
}
// TODO: move init code into `bootstrap` service after auth has been refactored.
function preInit({store, pym}) {
// Don't run this in the popup.
if (!window.opener) {
if (inIframe()) {
// TODO: This is popup specific code and needs to be refactored.
if (!inIframe()) {
store.dispatch(addExternalConfig({}));
store.dispatch(checkLogin());
return;
}
pym.onMessage('login', (token) => {
if (token) {
store.dispatch(handleAuthToken(token));
}
store.dispatch(checkLogin());
});
pym.onMessage('logout', () => {
store.dispatch(logout());
});
return new Promise((resolve) => {
pym.sendMessage('getConfig');
pym.onMessage('config', (config) => {
init(JSON.parse(config));
});
pym.onMessage('login', (token) => {
if (token) {
store.dispatch(handleAuthToken(token));
}
store.dispatch(addExternalConfig(JSON.parse(config)));
store.dispatch(checkLogin());
resolve();
});
pym.onMessage('logout', () => {
store.dispatch(logout());
});
} else {
init();
}
});
}
render(
<TalkProvider {...context}>
<AppRouter />
</TalkProvider>
, document.querySelector('#talk-embed-stream-container')
);
async function main() {
const context = await createContext({reducers, graphqlExtension, pluginsConfig, preInit});
render(
<TalkProvider {...context}>
<AppRouter />
</TalkProvider>
, document.querySelector('#talk-embed-stream-container')
);
}
main();
+4
View File
@@ -3,6 +3,7 @@ import pym from 'pym.js';
import EventEmitter from 'eventemitter2';
import {buildUrl} from 'coral-framework/utils/url';
import Snackbar from './Snackbar';
import {createStorage, connectStorageToPym} from 'coral-framework/services/storage';
const NOTIFICATION_OFFSET = 200;
@@ -134,6 +135,9 @@ export default class Stream {
// If the user clicks outside the embed, then tell the embed.
document.addEventListener('click', this.handleClick.bind(this), true);
// Listens to storage requests on pym and relay it to local storage.
connectStorageToPym(createStorage(), this.pym);
}
login(token) {
+1 -1
View File
@@ -83,7 +83,7 @@ Talk.render = (el, opts) => {
console.warn(
'This page does not include a canonical link tag. Talk has inferred this asset_url from the window object. Query params have been stripped, which may cause a single thread to be present across multiple pages.'
);
if (!window.location.origin) {
window.location.origin = `${window.location.protocol}//${window.location.hostname}${window.location.port ? `:${window.location.port}` : ''}`;
}
@@ -1,4 +1,5 @@
import React, {PureComponent, PropTypes} from 'react';
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import marked from 'marked';
const renderer = new marked.Renderer();
@@ -1,4 +1,5 @@
import React, {Component, PropTypes} from 'react';
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import SimpleMDE from 'simplemde';
import cn from 'classnames';
import noop from 'lodash/noop';
+3 -3
View File
@@ -20,9 +20,9 @@ class Slot extends React.Component {
// it does not result in a change of slot children.
const changes = getShallowChanges(this.props, next);
if (changes.length === 1 && changes[0] === 'reduxState') {
const prevChildrenUuid = this.getChildren(this.props).map((child) => child.type.talkUuid);
const nextChildrenUuid = this.getChildren(next).map((child) => child.type.talkUuid);
return !isEqual(prevChildrenUuid, nextChildrenUuid);
const prevChildrenKeys = this.getChildren(this.props).map((child) => child.key);
const nextChildrenKeys = this.getChildren(next).map((child) => child.key);
return !isEqual(prevChildrenKeys, nextChildrenKeys);
}
// Prevent Slot from rerendering when no props has shallowly changed.
@@ -6,6 +6,7 @@ export default {
'SetCommentStatusResponse',
'SuspendUserResponse',
'RejectUsernameResponse',
'CreateCommentResponse',
'SetUserStatusResponse',
'CreateFlagResponse',
'EditCommentResponse',

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