From 76b125f042dd4da55c997b10c206712a8072055b Mon Sep 17 00:00:00 2001 From: IAmSamHankins Date: Fri, 4 Aug 2017 13:42:19 -0400 Subject: [PATCH 01/25] adjustments to comment queue counters --- .../src/routes/Moderation/components/CommentCount.css | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client/coral-admin/src/routes/Moderation/components/CommentCount.css b/client/coral-admin/src/routes/Moderation/components/CommentCount.css index 4d24d5702..998133d07 100644 --- a/client/coral-admin/src/routes/Moderation/components/CommentCount.css +++ b/client/coral-admin/src/routes/Moderation/components/CommentCount.css @@ -1,16 +1,16 @@ .count { display: inline-block; - background: #989797; + background: #616161; margin: 2px; vertical-align: middle; - padding: 1px 7px; + padding: 1px 5px; border-radius: 2px; margin-left: 2px; - line-height: 20px; + line-height: 18px; box-sizing: border-box; - height: 21px; + height: 18px; right: 0; - margin-top: -2px; + margin-top: 0px; font-size: 12px; color: white; } From 11b2bc265a0e1469383b0613a0a4b3066bf32820 Mon Sep 17 00:00:00 2001 From: IAmSamHankins Date: Fri, 4 Aug 2017 13:50:14 -0400 Subject: [PATCH 02/25] comment tag/marker updates for size --- client/coral-admin/src/components/CommentType.css | 5 +++-- .../client/components/ModTag.css | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/client/coral-admin/src/components/CommentType.css b/client/coral-admin/src/components/CommentType.css index b5dbc229b..61a65f89a 100644 --- a/client/coral-admin/src/components/CommentType.css +++ b/client/coral-admin/src/components/CommentType.css @@ -3,10 +3,11 @@ color: white; background: grey; box-sizing: border-box; - padding: 2px 8px; + padding: 0px 5px; border-radius: 2px; font-size: 12px; - height: 28px; + height: 24px; + letter-spacing: 0.4px; > i { font-size: 14px; diff --git a/plugins/talk-plugin-featured-comments/client/components/ModTag.css b/plugins/talk-plugin-featured-comments/client/components/ModTag.css index c8ba1b6ba..683c16570 100644 --- a/plugins/talk-plugin-featured-comments/client/components/ModTag.css +++ b/plugins/talk-plugin-featured-comments/client/components/ModTag.css @@ -4,13 +4,14 @@ color: #696969; background-color: white; box-sizing: border-box; - padding: 2px 8px; + padding: 0px 5px; border-radius: 2px; font-size: 12px; - height: 28px; + height: 24px; transition: background-color .2s cubic-bezier(.4,0,.2,1), color .2s cubic-bezier(.4,0,.2,1), border-color .2s cubic-bezier(.4,0,.2,1); margin: 2px 0px; letter-spacing: 0.4px; + } .tag:hover { @@ -39,4 +40,3 @@ font-size: 15px; vertical-align: text-bottom; } - \ No newline at end of file From ddadd6c5d32bd17c1741e95c8e01e4f54a3c9d68 Mon Sep 17 00:00:00 2001 From: IAmSamHankins Date: Mon, 7 Aug 2017 10:26:42 -0500 Subject: [PATCH 03/25] adjustments/fixes to approved rejected widths --- client/coral-admin/src/components/CommentType.css | 3 ++- client/coral-admin/src/components/ModerationList.css | 1 - client/coral-ui/components/Button.css | 7 ++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/client/coral-admin/src/components/CommentType.css b/client/coral-admin/src/components/CommentType.css index 61a65f89a..e4851275e 100644 --- a/client/coral-admin/src/components/CommentType.css +++ b/client/coral-admin/src/components/CommentType.css @@ -8,7 +8,8 @@ font-size: 12px; height: 24px; letter-spacing: 0.4px; - + margin-bottom: 1px; + > i { font-size: 14px; vertical-align: text-top; diff --git a/client/coral-admin/src/components/ModerationList.css b/client/coral-admin/src/components/ModerationList.css index 89e43e02a..4ac894290 100644 --- a/client/coral-admin/src/components/ModerationList.css +++ b/client/coral-admin/src/components/ModerationList.css @@ -186,7 +186,6 @@ .actionButton { transform: scale(.8); margin: 0; - width: 140px; } .minimal { diff --git a/client/coral-ui/components/Button.css b/client/coral-ui/components/Button.css index 7bd1d4379..1b7efb205 100644 --- a/client/coral-ui/components/Button.css +++ b/client/coral-ui/components/Button.css @@ -27,9 +27,10 @@ } .icon { - margin-right: 13px; + margin-right: 5px; font-size: 18px; vertical-align: middle; + margin-top: -3px; } .type--black { @@ -143,7 +144,7 @@ border-radius: 3px; text-transform: capitalize; box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.03), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.09); - width: 128px; + width: 129px; &:hover { box-shadow: none; @@ -166,7 +167,7 @@ border-radius: 3px; text-transform: capitalize; box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.03), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.09); - width: 128px; + width: 129px; &:hover { color: white; From 27216cbfdbc7c8208516c3cc720a2df8e9cf66da Mon Sep 17 00:00:00 2001 From: IAmSamHankins Date: Mon, 7 Aug 2017 10:32:21 -0500 Subject: [PATCH 04/25] hierarchy for asset search title --- .../coral-admin/src/routes/Moderation/components/styles.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/coral-admin/src/routes/Moderation/components/styles.css b/client/coral-admin/src/routes/Moderation/components/styles.css index ccc762641..b821d9429 100644 --- a/client/coral-admin/src/routes/Moderation/components/styles.css +++ b/client/coral-admin/src/routes/Moderation/components/styles.css @@ -111,7 +111,7 @@ span { color: white; text-transform: capitalize; font-weight: 400; - font-size: 15px; + font-size: 20px; letter-spacing: 1px; transition: background-color 200ms; opacity: 1; @@ -490,7 +490,7 @@ span { .searchTrigger { position: relative; - top: .3em; + top: .2em; } .adminCommentInfoBar { @@ -499,4 +499,4 @@ span { right: 0px; top: 0px; text-align: right; -} \ No newline at end of file +} From 53cac48e3b365bc9e4066b5b8e9163ecd7307e75 Mon Sep 17 00:00:00 2001 From: IAmSamHankins Date: Mon, 7 Aug 2017 11:53:39 -0500 Subject: [PATCH 05/25] resizing of the comment component --- client/coral-admin/src/routes/Moderation/components/styles.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-admin/src/routes/Moderation/components/styles.css b/client/coral-admin/src/routes/Moderation/components/styles.css index b821d9429..cccf85f78 100644 --- a/client/coral-admin/src/routes/Moderation/components/styles.css +++ b/client/coral-admin/src/routes/Moderation/components/styles.css @@ -173,7 +173,7 @@ span { border-bottom: 1px solid #e0e0e0; font-size: 18px; width: 100%; - max-width: 700px; + max-width: 650px; min-width: 400px; margin: 0 auto; position: relative; From c08d040d1d1969979eb1f2c8617a7f51df1fd567 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 8 Aug 2017 15:37:45 +1000 Subject: [PATCH 06/25] Added whitelist question to cli-setup --- bin/cli-setup | 37 ++++++++++++++++---- package.json | 2 +- yarn.lock | 96 ++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 111 insertions(+), 24 deletions(-) diff --git a/bin/cli-setup b/bin/cli-setup index 9ecdecc95..f95fca8d4 100755 --- a/bin/cli-setup +++ b/bin/cli-setup @@ -94,7 +94,7 @@ const performSetup = async () => { name: 'requireEmailConfirmation', default: settings.requireEmailConfirmation, message: 'Should emails always be confirmed' - } + }, ]); // Update the settings that were changed. @@ -104,6 +104,31 @@ const performSetup = async () => { } }); + answers = await inquirer.prompt([ + { + type: 'confirm', + name: 'inputWhitelistedDomains', + default: true, + message: 'Would you like to specify a whitelisted domain' + }, + { + type: 'input', + name: 'whitelistedDomain', + message: 'Whitelisted Domain', + validate: (input) => { + if (input && input.length > 0) { + return true; + } + + return 'Whitelisted Domain cannot be empty.'; + } + } + ]); + + if (answers.inputWhitelistedDomains) { + settings.domains.whitelist = [answers.whitelistedDomain]; + } + console.log('\nWe\'ll ask you some questions about your first admin user.\n'); let user = await inquirer.prompt([ @@ -147,7 +172,11 @@ const performSetup = async () => { name: 'confirmPassword', message: 'Confirm Password', type: 'password', - filter: (confirmPassword) => { + filter: (confirmPassword, {password}) => { + if (password !== confirmPassword) { + return Promise.reject(new Error('Passwords do not match')); + } + return UsersService .isValidPassword(confirmPassword) .catch((err) => { @@ -157,10 +186,6 @@ const performSetup = async () => { }, ]); - if (user.password !== user.confirmPassword) { - return Promise.reject(new Error('Passwords do not match')); - } - let {user: newUser} = await SetupService.setup({ settings: settings.toObject(), user: { diff --git a/package.json b/package.json index 476e7eda5..8e83f17a9 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "graphql-tools": "^0.10.1", "helmet": "^3.5.0", "immutability-helper": "^2.2.0", - "inquirer": "^3.0.6", + "inquirer": "^3.2.1", "joi": "^10.4.1", "jsonwebtoken": "^7.3.0", "jwt-decode": "^2.2.0", diff --git a/yarn.lock b/yarn.lock index 255dc7415..a5d73a756 100644 --- a/yarn.lock +++ b/yarn.lock @@ -162,6 +162,10 @@ ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" +ansi-escapes@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-2.0.0.tgz#5bae52be424878dd9783e8910e3fc2922e83c81b" + ansi-regex@^1.0.0, ansi-regex@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-1.1.1.tgz#41c847194646375e6a1a5d10c3ca054ef9fc980d" @@ -170,10 +174,20 @@ ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" +ansi-styles@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" + dependencies: + color-convert "^1.9.0" + any-promise@^0.1.0, any-promise@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-0.1.0.tgz#830b680aa7e56f33451d4b049f3bd8044498ee27" @@ -1498,6 +1512,14 @@ chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" +chalk@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e" + dependencies: + ansi-styles "^3.1.0" + escape-string-regexp "^1.0.5" + supports-color "^4.0.0" + change-emitter@^0.1.2: version "0.1.6" resolved "https://registry.yarnpkg.com/change-emitter/-/change-emitter-0.1.6.tgz#e8b2fe3d7f1ab7d69a32199aff91ea6931409515" @@ -1727,7 +1749,7 @@ codemirror@*: version "5.25.2" resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.25.2.tgz#8c77677ca9c9248d757d3a07ed1e89a8404850b7" -color-convert@^1.3.0: +color-convert@^1.3.0, color-convert@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" dependencies: @@ -3053,10 +3075,12 @@ extend@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/extend/-/extend-1.3.0.tgz#d1516fb0ff5624d2ebf9123ea1dac5a1994004f8" -external-editor@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.1.tgz#4c597c6c88fa6410e41dbbaa7b1be2336aa31095" +external-editor@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.4.tgz#1ed9199da9cbfe2ef2f7a31b2fde8b0d12368972" dependencies: + iconv-lite "^0.4.17" + jschardet "^1.4.2" tmp "^0.0.31" extglob@^0.3.1: @@ -3757,6 +3781,10 @@ has-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -3972,6 +4000,10 @@ iconv-lite@0.4.15, iconv-lite@^0.4.5, iconv-lite@~0.4.13: version "0.4.15" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" +iconv-lite@^0.4.17: + version "0.4.18" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2" + icss-replace-symbols@1.0.2, icss-replace-symbols@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.0.2.tgz#cb0b6054eb3af6edc9ab1d62d01933e2d4c8bfa5" @@ -4103,22 +4135,23 @@ inquirer@0.8.2: rx "^2.4.3" through "^2.3.6" -inquirer@^3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.0.6.tgz#e04aaa9d05b7a3cb9b0f407d04375f0447190347" +inquirer@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.2.1.tgz#06ceb0f540f45ca548c17d6840959878265fa175" dependencies: - ansi-escapes "^1.1.0" - chalk "^1.0.0" + ansi-escapes "^2.0.0" + chalk "^2.0.0" cli-cursor "^2.1.0" cli-width "^2.0.0" - external-editor "^2.0.1" + external-editor "^2.0.4" figures "^2.0.0" lodash "^4.3.0" mute-stream "0.0.7" run-async "^2.2.0" - rx "^4.1.0" - string-width "^2.0.0" - strip-ansi "^3.0.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" through "^2.3.6" interpret@^1.0.0: @@ -4560,6 +4593,10 @@ jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" +jschardet@^1.4.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.5.1.tgz#c519f629f86b3a5bedba58a88d311309eec097f9" + jsdom@^7.0.2: version "7.2.2" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-7.2.2.tgz#40b402770c2bda23469096bee91ab675e3b1fc6e" @@ -7434,6 +7471,16 @@ run-async@^2.2.0: dependencies: is-promise "^2.1.0" +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + rx-lite@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" @@ -7442,10 +7489,6 @@ rx@^2.4.3: version "2.5.3" resolved "https://registry.yarnpkg.com/rx/-/rx-2.5.3.tgz#21adc7d80f02002af50dae97fd9dbf248755f566" -rx@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" - safe-buffer@^5.0.1, safe-buffer@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" @@ -7833,6 +7876,13 @@ string-width@^2.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^3.0.0" +string-width@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + string.prototype.codepointat@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.0.tgz#6b26e9bd3afcaa7be3b4269b526de1b82000ac78" @@ -7871,6 +7921,12 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -7961,6 +8017,12 @@ supports-color@^3.1.2, supports-color@^3.2.3: dependencies: has-flag "^1.0.0" +supports-color@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.2.1.tgz#65a4bb2631e90e02420dba5554c375a4754bb836" + dependencies: + has-flag "^2.0.0" + svgo@^0.7.0: version "0.7.2" resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" From e16dd14e47630354601175a4cedcb0c7fd84528d Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 8 Aug 2017 23:33:07 +1000 Subject: [PATCH 07/25] fix bug with impl --- bin/cli-setup | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/cli-setup b/bin/cli-setup index f95fca8d4..2e5c1e5b8 100755 --- a/bin/cli-setup +++ b/bin/cli-setup @@ -115,6 +115,7 @@ const performSetup = async () => { type: 'input', name: 'whitelistedDomain', message: 'Whitelisted Domain', + when: ({inputWhitelistedDomains}) => inputWhitelistedDomains, validate: (input) => { if (input && input.length > 0) { return true; From c62e7328c5801466315a5c632f90566b5ed8a2fa Mon Sep 17 00:00:00 2001 From: IAmSamHankins Date: Wed, 9 Aug 2017 10:15:52 -0500 Subject: [PATCH 08/25] adjustments to top navigation and logo --- client/coral-admin/src/components/FlagBox.css | 2 +- client/coral-admin/src/components/ui/Logo.css | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/client/coral-admin/src/components/FlagBox.css b/client/coral-admin/src/components/FlagBox.css index 402a88045..232803203 100644 --- a/client/coral-admin/src/components/FlagBox.css +++ b/client/coral-admin/src/components/FlagBox.css @@ -1,6 +1,6 @@ .flagBox { border-top: 1px solid rgba(66, 66, 66, 0.12); - + margin-top: 10px; .container { padding: 0 14px; } diff --git a/client/coral-admin/src/components/ui/Logo.css b/client/coral-admin/src/components/ui/Logo.css index af2758bcb..62a223683 100644 --- a/client/coral-admin/src/components/ui/Logo.css +++ b/client/coral-admin/src/components/ui/Logo.css @@ -10,16 +10,18 @@ .logo span { display: inline-block; margin-left: 10px; - font-size: 18px; + font-size: 26px; vertical-align: middle; font-weight: 500; + color: white; } .logo { - background: #E5E5E5; + background: #696969; height: 100%; width: 128px; z-index: 10; + border-right: 1px #757575 solid; } .base { From ca422f0109ec25508efb4d9b64975dfef25dd1b7 Mon Sep 17 00:00:00 2001 From: IAmSamHankins Date: Wed, 9 Aug 2017 10:23:03 -0500 Subject: [PATCH 09/25] mod queue nav styling adjust --- .../coral-admin/src/routes/Moderation/components/styles.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/coral-admin/src/routes/Moderation/components/styles.css b/client/coral-admin/src/routes/Moderation/components/styles.css index cccf85f78..d1d1ae697 100644 --- a/client/coral-admin/src/routes/Moderation/components/styles.css +++ b/client/coral-admin/src/routes/Moderation/components/styles.css @@ -18,7 +18,7 @@ .tab { flex: 1; - color: #C0C0C0; + color: #BDBDBD; text-transform: capitalize; font-weight: 100; font-size: 14px; @@ -29,7 +29,7 @@ margin-right: 20px; &:hover { color: white; - border-bottom: solid 2px #F36451; + /*border-bottom: solid 2px #F36451;*/ box-sizing: border-box; } } From b9243938bdfab47376caf9061fc8508188a70ef0 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 10 Aug 2017 10:33:45 +1000 Subject: [PATCH 10/25] Added support for changing the singing cookie name --- config.js | 19 +++++++++++++++++++ docs/_docs/02-01-configuration.md | 12 ++++++++++-- services/passport.js | 13 +++++++------ 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/config.js b/config.js index 4472af26e..4a3609dc8 100644 --- a/config.js +++ b/config.js @@ -7,6 +7,8 @@ // entrypoint for the entire applications configuration. require('env-rewrite').rewrite(); +const uniq = require('lodash/uniq'); + //============================================================================== // CONFIG INITIALIZATION //============================================================================== @@ -31,6 +33,13 @@ const CONFIG = { // token. JWT_COOKIE_NAME: process.env.TALK_JWT_COOKIE_NAME || 'authorization', + // JWT_SIGNING_COOKIE_NAME will be the cookie set when cookies are issued. + // This defaults to the TALK_JWT_COOKIE_NAME value. + JWT_SIGNING_COOKIE_NAME: process.env.TALK_JWT_SIGNING_COOKIE_NAME || process.env.TALK_JWT_COOKIE_NAME || 'authorization', + + // JWT_COOKIE_NAMES declares the many cookie names used for verification. + JWT_COOKIE_NAMES: process.env.TALK_JWT_COOKIE_NAMES || null, + // JWT_CLEAR_COOKIE_LOGOUT specifies whether the named cookie should be // cleared when the user is logged out. JWT_CLEAR_COOKIE_LOGOUT: process.env.TALK_JWT_CLEAR_COOKIE_LOGOUT ? process.env.TALK_JWT_CLEAR_COOKIE_LOGOUT !== 'FALSE' : true, @@ -165,6 +174,16 @@ if (CONFIG.JWT_DISABLE_ISSUER) { CONFIG.JWT_ISSUER = undefined; } +// Parse and handle cookie names. +if (CONFIG.JWT_COOKIE_NAMES) { + CONFIG.JWT_COOKIE_NAMES = CONFIG.JWT_COOKIE_NAMES.split(','); +} else { + CONFIG.JWT_COOKIE_NAMES = []; +} + +// Add in the default cookie names and strip duplicates. +CONFIG.JWT_COOKIE_NAMES = uniq(CONFIG.JWT_COOKIE_NAMES.concat([CONFIG.JWT_COOKIE_NAME, CONFIG.JWT_SIGNING_COOKIE_NAME])); + //------------------------------------------------------------------------------ // External database url's //------------------------------------------------------------------------------ diff --git a/docs/_docs/02-01-configuration.md b/docs/_docs/02-01-configuration.md index 74bd8972e..b02376c24 100644 --- a/docs/_docs/02-01-configuration.md +++ b/docs/_docs/02-01-configuration.md @@ -87,8 +87,16 @@ on the contents of those variables.** These are advanced settings for fine tuning the auth integration, and is not needed in most situations. -- `TALK_JWT_COOKIE_NAME` (_optional_) - the name of the cookie to extract the - JWT from (Default `authorization`) +- `TALK_JWT_COOKIE_NAME` (_optional_) - the default cookie name to check for a + valid JWT token to use for verifying a user. (Default `authorization`) +- `TALK_JWT_SIGNING_COOKIE_NAME` (_optional_) - the default cookie name that is + use to set a cookie containing a JWT that was issued by Talk. + (Default `process.env.TALK_JWT_COOKIE_NAME`) +- `TALK_JWT_COOKIE_NAMES` (_optional_) - the different cookie names to check for + a JWT token in, seperated by `,`. By default, we always use the + `process.env.TALK_JWT_COOKIE_NAME` and `process.env.TALK_JWT_SIGNING_COOKIE_NAME` + for this value. Any additional cookie names specified here will be appended to + the list of cookie names to inspect. - `TALK_JWT_CLEAR_COOKIE_LOGOUT` (_optional_) - when `FALSE`, Talk will not clear the cookie with name `TALK_JWT_COOKIE_NAME` when logging out (Default `TRUE`) diff --git a/services/passport.js b/services/passport.js index 409bb2279..31a8ecba1 100644 --- a/services/passport.js +++ b/services/passport.js @@ -23,7 +23,8 @@ const { JWT_ALG, RECAPTCHA_SECRET, RECAPTCHA_ENABLED, - JWT_COOKIE_NAME, + JWT_SIGNING_COOKIE_NAME, + JWT_COOKIE_NAMES, JWT_CLEAR_COOKIE_LOGOUT, JWT_USER_ID_CLAIM, } = require('../config'); @@ -53,7 +54,7 @@ const GenerateToken = (user) => { const SetTokenForSafari = (req, res, token) => { const browser = bowser._detect(req.headers['user-agent']); if (browser.ios || browser.safari) { - res.cookie(JWT_COOKIE_NAME, token, { + res.cookie(JWT_SIGNING_COOKIE_NAME, token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', expires: new Date(Date.now() + ms(JWT_EXPIRY)) @@ -169,7 +170,7 @@ const HandleLogout = (req, res, next) => { // Only clear the cookie on logout if enabled. if (JWT_CLEAR_COOKIE_LOGOUT) { - res.clearCookie(JWT_COOKIE_NAME); + res.clearCookie(JWT_SIGNING_COOKIE_NAME); } res.status(204).end(); @@ -209,11 +210,11 @@ const CheckBlacklisted = async (jwt) => { const JwtStrategy = require('passport-jwt').Strategy; const ExtractJwt = require('passport-jwt').ExtractJwt; -let cookieExtractor = function(req) { +let cookieExtractor = (cookieName) => (req) => { let token = null; if (req && req.cookies) { - token = req.cookies[JWT_COOKIE_NAME]; + token = req.cookies[cookieName]; } return token; @@ -237,7 +238,7 @@ passport.use(new JwtStrategy({ // Prepare the extractor from the header. jwtFromRequest: ExtractJwt.fromExtractors([ - cookieExtractor, + ...JWT_COOKIE_NAMES.map(cookieExtractor), ExtractJwt.fromUrlQueryParameter('access_token'), ExtractJwt.fromAuthHeaderWithScheme('Bearer') ]), From 6d70a7b20e048166578b5313530cf0ed91719208 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 10 Aug 2017 10:46:11 +1000 Subject: [PATCH 11/25] improved code around cookie handling, added to docs --- docs/_docs/02-01-configuration.md | 8 ++++++++ services/passport.js | 18 ++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/docs/_docs/02-01-configuration.md b/docs/_docs/02-01-configuration.md index b02376c24..18a483723 100644 --- a/docs/_docs/02-01-configuration.md +++ b/docs/_docs/02-01-configuration.md @@ -123,6 +123,14 @@ will be used: } ``` +When our passport middleware checks for JWT tokens, it searches in the following +order: + +1. Custom cookies named from the list in `TALK_JWT_COOKIE_NAMES`. +2. Default cookies named `TALK_JWT_COOKIE_NAME` then `TALK_JWT_SIGNING_COOKIE_NAME`. +3. Query parameter `?access_token={TOKEN}`. +4. Header: `Authorization: Bearer {TOKEN}`. + ### Email - `TALK_SMTP_EMAIL` (*required for email*) - the address to send emails from diff --git a/services/passport.js b/services/passport.js index 31a8ecba1..14a2134ce 100644 --- a/services/passport.js +++ b/services/passport.js @@ -210,14 +210,20 @@ const CheckBlacklisted = async (jwt) => { const JwtStrategy = require('passport-jwt').Strategy; const ExtractJwt = require('passport-jwt').ExtractJwt; -let cookieExtractor = (cookieName) => (req) => { - let token = null; - +let cookieExtractor = (req) => { if (req && req.cookies) { - token = req.cookies[cookieName]; + + // Walk over all the cookie names in JWT_COOKIE_NAMES. + for (const cookieName of JWT_COOKIE_NAMES) { + + // Check to see if that cookie is set. + if (cookieName in req.cookies && req.cookies[cookieName] !== null && req.cookies[cookieName].length > 0) { + return req.cookies[cookieName]; + } + } } - return token; + return null; }; // Override the JwtVerifier method on the JwtStrategy so we can pack the @@ -238,7 +244,7 @@ passport.use(new JwtStrategy({ // Prepare the extractor from the header. jwtFromRequest: ExtractJwt.fromExtractors([ - ...JWT_COOKIE_NAMES.map(cookieExtractor), + cookieExtractor, ExtractJwt.fromUrlQueryParameter('access_token'), ExtractJwt.fromAuthHeaderWithScheme('Bearer') ]), From 0013c366860981a076a4ee3f08405456fc8f317a Mon Sep 17 00:00:00 2001 From: Kim Gardner Date: Thu, 10 Aug 2017 11:20:45 +0100 Subject: [PATCH 12/25] Update version number to 3.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 476e7eda5..087044a4c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "talk", - "version": "3.0.0", + "version": "3.1.0", "description": "A better commenting experience from Mozilla, The New York Times, and the Washington Post. https://coralproject.net", "main": "app.js", "scripts": { From 83ded4bda960420ecb9ea676e547f44addf4951e Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Thu, 10 Aug 2017 18:37:14 +0700 Subject: [PATCH 13/25] Refactor into queueConfig --- client/coral-admin/src/AppRouter.js | 24 +- .../Moderation/components/Moderation.js | 41 +--- .../Moderation/components/ModerationMenu.js | 67 +----- .../Moderation/containers/Moderation.js | 226 ++++++------------ .../utils.js => routes/Moderation/graphql.js} | 57 ++--- .../src/routes/Moderation/queueConfig.js | 35 +++ .../client/containers/ModSubscription.js | 25 +- 7 files changed, 170 insertions(+), 305 deletions(-) rename client/coral-admin/src/{graphql/utils.js => routes/Moderation/graphql.js} (74%) create mode 100644 client/coral-admin/src/routes/Moderation/queueConfig.js diff --git a/client/coral-admin/src/AppRouter.js b/client/coral-admin/src/AppRouter.js index 4b3ea0f0b..9772ebf17 100644 --- a/client/coral-admin/src/AppRouter.js +++ b/client/coral-admin/src/AppRouter.js @@ -37,27 +37,11 @@ const routes = ( - - - - - - - - - - - - - - - - - - - - + + + + diff --git a/client/coral-admin/src/routes/Moderation/components/Moderation.js b/client/coral-admin/src/routes/Moderation/components/Moderation.js index ce0c31e33..f50ff9c50 100644 --- a/client/coral-admin/src/routes/Moderation/components/Moderation.js +++ b/client/coral-admin/src/routes/Moderation/components/Moderation.js @@ -101,33 +101,19 @@ export default class Moderation extends Component { } render () { - const {root, data, moderation, settings, viewUserDetail, hideUserDetail, activeTab, getModPath, premodEnabled, ...props} = this.props; - const assetId = this.props.params.id; + const {root, data, moderation, settings, viewUserDetail, hideUserDetail, activeTab, getModPath, queueConfig, handleCommentChange, ...props} = this.props; const {asset} = root; + const assetId = asset && asset.id; const comments = root[activeTab]; - let activeTabCount; - switch(activeTab) { - case 'all': - activeTabCount = root.allCount; - break; - case 'new': - activeTabCount = root.newCount; - break; - case 'approved': - activeTabCount = root.approvedCount; - break; - case 'premod': - activeTabCount = root.premodCount; - break; - case 'reported': - activeTabCount = root.reportedCount; - break; - case 'rejected': - activeTabCount = root.rejectedCount; - break; - } + const activeTabCount = root[`${activeTab}Count`]; + const menuItems = Object.keys(queueConfig).map((queue) => ({ + key: queue, + name: queueConfig[queue].name, + icon: queueConfig[queue].icon, + count: root[`${queue}Count`] + })); return (
@@ -139,16 +125,10 @@ export default class Moderation extends Component { />
diff --git a/client/coral-admin/src/routes/Moderation/components/ModerationMenu.js b/client/coral-admin/src/routes/Moderation/components/ModerationMenu.js index 62bbd4d2e..7b427ac54 100644 --- a/client/coral-admin/src/routes/Moderation/components/ModerationMenu.js +++ b/client/coral-admin/src/routes/Moderation/components/ModerationMenu.js @@ -9,16 +9,10 @@ import cn from 'classnames'; import t from 'coral-framework/services/i18n'; const ModerationMenu = ({ - asset = {}, - allCount, - approvedCount, - premodCount, - newCount, - rejectedCount, - reportedCount, + asset = {}, + items, selectSort, sort, - premodEnabled, getModPath, activeTab }) => { @@ -27,49 +21,15 @@ const ModerationMenu = ({
- - { - premodEnabled ? ( - - {t('modqueue.premod')} - - ) : ( - - {t('modqueue.new')} - - ) - } - - - {t('modqueue.reported')} - - - {t('modqueue.approved')} - - - {t('modqueue.rejected')} - - - {t('modqueue.all')} - + {items.map((queue) => + + {queue.name} + + )}
{ + return handleCommentChange(root, comment, this.props.data.variables.sort, notify, queueConfig, this.activeTab); + }; + get activeTab() { - const {root: {asset, settings}, router, route} = this.props; + const {root: {asset, settings}} = this.props; + const id = getAssetId(this.props); + const tab = getTab(this.props); // Grab premod from asset or from settings - const premod = !router.params.id ? settings.moderation : asset.settings.moderation; + const premod = !id ? settings.moderation : asset.settings.moderation; const queue = isPremod(premod) ? 'premod' : 'new'; - const activeTab = route.path && route.path !== ':id' ? route.path : queue; + const activeTab = tab ? tab : queue; return activeTab; } @@ -57,15 +78,10 @@ class ModerationContainer extends Component { variables, updateQuery: (prev, {subscriptionData: {data: {commentAccepted: comment}}}) => { const user = comment.status_history[comment.status_history.length - 1].assigned_by; - const sort = this.props.moderation.sortOrder; const notify = this.props.auth.user.id === user.id - ? {} - : { - activeQueue: this.activeTab, - text: t('modqueue.notify_accepted', user.username, prepareNotificationText(comment.body)), - anyQueue: false, - }; - return handleCommentChange(prev, comment, sort, notify); + ? '' + : t('modqueue.notify_accepted', user.username, prepareNotificationText(comment.body)); + return this.handleCommentChange(prev, comment, notify); }, }); @@ -74,15 +90,10 @@ class ModerationContainer extends Component { variables, updateQuery: (prev, {subscriptionData: {data: {commentRejected: comment}}}) => { const user = comment.status_history[comment.status_history.length - 1].assigned_by; - const sort = this.props.moderation.sortOrder; const notify = this.props.auth.user.id === user.id - ? {} - : { - activeQueue: this.activeTab, - text: t('modqueue.notify_rejected', user.username, prepareNotificationText(comment.body)), - anyQueue: false, - }; - return handleCommentChange(prev, comment, sort, notify); + ? '' + : t('modqueue.notify_rejected', user.username, prepareNotificationText(comment.body)); + return this.handleCommentChange(prev, comment, notify); }, }); @@ -90,13 +101,8 @@ class ModerationContainer extends Component { document: COMMENT_EDITED_SUBSCRIPTION, variables, updateQuery: (prev, {subscriptionData: {data: {commentEdited: comment}}}) => { - const sort = this.props.moderation.sortOrder; - const notify = { - activeQueue: this.activeTab, - text: t('modqueue.notify_edited', comment.user.username, prepareNotificationText(comment.body)), - anyQueue: false, - }; - return handleCommentChange(prev, comment, sort, notify); + const notify = t('modqueue.notify_edited', comment.user.username, prepareNotificationText(comment.body)); + return this.handleCommentChange(prev, comment, notify); }, }); @@ -105,13 +111,8 @@ class ModerationContainer extends Component { variables, updateQuery: (prev, {subscriptionData: {data: {commentFlagged: comment}}}) => { const user = comment.actions[comment.actions.length - 1].user; - const sort = this.props.moderation.sortOrder; - const notify = { - activeQueue: this.activeTab, - text: t('modqueue.notify_flagged', user.username, prepareNotificationText(comment.body)), - anyQueue: true, - }; - return handleCommentChange(prev, comment, sort, notify); + const notify = t('modqueue.notify_flagged', user.username, prepareNotificationText(comment.body)); + return this.handleCommentChange(prev, comment, notify); }, }); @@ -160,28 +161,9 @@ class ModerationContainer extends Component { cursor: this.props.root[tab].endCursor, sort: this.props.data.variables.sort, asset_id: this.props.data.variables.asset_id, + statuses: queueConfig[tab].statuses, + action_type: queueConfig[tab].action_type, }; - switch(tab) { - case 'all': - variables.statuses = null; - break; - case 'new': - variables.statuses = ['NONE', 'PREMOD']; - break; - case 'approved': - variables.statuses = ['ACCEPTED']; - break; - case 'premod': - variables.statuses = ['PREMOD']; - break; - case 'reported': - variables.statuses = ['NONE', 'PREMOD']; - variables.action_type = 'FLAG'; - break; - case 'rejected': - variables.statuses = ['REJECTED']; - break; - } return this.props.data.fetchMore({ query: LOAD_MORE_QUERY, variables, @@ -199,7 +181,8 @@ class ModerationContainer extends Component { }; render () { - const {root, root: {asset, settings}, data, params: {id: assetId}} = this.props; + const {root, root: {asset, settings}, data} = this.props; + const assetId = getAssetId(this.props); if (data.error) { return
Error
; @@ -222,6 +205,14 @@ class ModerationContainer extends Component { return ; } + const premodEnabled = assetId ? isPremod(asset.settings.moderation) : isPremod(settings.moderation); + const currentQueueConfig = Object.assign({}, queueConfig); + if (premodEnabled) { + delete currentQueueConfig.new; + } else { + delete currentQueueConfig.premod; + } + return ; } } @@ -314,49 +306,25 @@ const commentConnectionFragment = gql` const withModQueueQuery = withQuery(gql` query CoralAdmin_Moderation($asset_id: ID, $sort: SORT_ORDER, $allAssets: Boolean!) { - all: comments(query: { - statuses: [NONE, PREMOD, ACCEPTED, REJECTED], - asset_id: $asset_id, - sort: $sort - }) { - ...CoralAdmin_Moderation_CommentConnection - } - new: comments(query: { - statuses: [NONE, PREMOD], - asset_id: $asset_id, - sort: $sort - }) { - ...CoralAdmin_Moderation_CommentConnection - } - approved: comments(query: { - statuses: [ACCEPTED], - asset_id: $asset_id, - sort: $sort - }) { - ...CoralAdmin_Moderation_CommentConnection - } - premod: comments(query: { - statuses: [PREMOD], + ${Object.keys(queueConfig).map((queue) => ` + ${queue}: comments(query: { + ${queueConfig[queue].statuses ? `statuses: [${queueConfig[queue].statuses.join(', ')}],` : ''} + ${queueConfig[queue].tags ? `tags: ["${queueConfig[queue].tags.join('", "')}"],` : ''} + ${queueConfig[queue].action_type ? `action_type: ${queueConfig[queue].action_type}` : ''} asset_id: $asset_id, sort: $sort - }) { - ...CoralAdmin_Moderation_CommentConnection - } - reported: comments(query: { - action_type: FLAG, + }) { + ...CoralAdmin_Moderation_CommentConnection + } + `)} + ${Object.keys(queueConfig).map((queue) => ` + ${queue}Count: commentCount(query: { + ${queueConfig[queue].statuses ? `statuses: [${queueConfig[queue].statuses.join(', ')}],` : ''} + ${queueConfig[queue].tags ? `tags: ["${queueConfig[queue].tags.join('", "')}"],` : ''} + ${queueConfig[queue].action_type ? `action_type: ${queueConfig[queue].action_type}` : ''} asset_id: $asset_id, - statuses: [NONE, PREMOD], - sort: $sort - }) { - ...CoralAdmin_Moderation_CommentConnection - } - rejected: comments(query: { - statuses: [REJECTED], - asset_id: $asset_id, - sort: $sort - }) { - ...CoralAdmin_Moderation_CommentConnection - } + }) + `)} asset(id: $asset_id) @skip(if: $allAssets) { id title @@ -365,30 +333,6 @@ const withModQueueQuery = withQuery(gql` moderation } } - allCount: commentCount(query: { - asset_id: $asset_id - }) - newCount: commentCount(query: { - statuses: [NONE, PREMOD], - asset_id: $asset_id - }) - approvedCount: commentCount(query: { - statuses: [ACCEPTED], - asset_id: $asset_id - }) - premodCount: commentCount(query: { - statuses: [PREMOD], - asset_id: $asset_id - }) - rejectedCount: commentCount(query: { - statuses: [REJECTED], - asset_id: $asset_id - }) - reportedCount: commentCount(query: { - action_type: FLAG, - asset_id: $asset_id, - statuses: [NONE, PREMOD] - }) settings { organizationName moderation @@ -396,11 +340,12 @@ const withModQueueQuery = withQuery(gql` } ${commentConnectionFragment} `, { - options: ({params: {id = null}, moderation: {sortOrder}}) => { + options: (props) => { + const id = getAssetId(props); return { variables: { asset_id: id, - sort: sortOrder, + sort: props.moderation.sortOrder, allAssets: id === null } }; @@ -409,33 +354,18 @@ const withModQueueQuery = withQuery(gql` const withQueueCountPolling = withQuery(gql` query CoralAdmin_ModerationCountPoll($asset_id: ID) { - allCount: commentCount(query: { - asset_id: $asset_id - }) - newCount: commentCount(query: { - statuses: [NONE, PREMOD], - asset_id: $asset_id - }) - approvedCount: commentCount(query: { - statuses: [ACCEPTED], - asset_id: $asset_id - }) - premodCount: commentCount(query: { - statuses: [PREMOD], - asset_id: $asset_id - }) - rejectedCount: commentCount(query: { - statuses: [REJECTED], - asset_id: $asset_id - }) - reportedCount: commentCount(query: { - action_type: FLAG, - asset_id: $asset_id, - statuses: [NONE, PREMOD] - }) + ${Object.keys(queueConfig).map((queue) => ` + ${queue}Count: commentCount(query: { + ${queueConfig[queue].statuses ? `statuses: [${queueConfig[queue].statuses.join(', ')}],` : ''} + ${queueConfig[queue].tags ? `tags: ["${queueConfig[queue].tags.join('", "')}"],` : ''} + ${queueConfig[queue].action_type ? `action_type: ${queueConfig[queue].action_type}` : ''} + asset_id: $asset_id, + }) + `)} } `, { - options: ({params: {id = null}}) => { + options: (props) => { + const id = getAssetId(props); return { pollInterval: 5000, variables: { diff --git a/client/coral-admin/src/graphql/utils.js b/client/coral-admin/src/routes/Moderation/graphql.js similarity index 74% rename from client/coral-admin/src/graphql/utils.js rename to client/coral-admin/src/routes/Moderation/graphql.js index f729cc0ea..0d4991f72 100644 --- a/client/coral-admin/src/graphql/utils.js +++ b/client/coral-admin/src/routes/Moderation/graphql.js @@ -1,7 +1,6 @@ import update from 'immutability-helper'; import * as notification from 'coral-admin/src/services/notification'; -const queues = ['all', 'premod', 'reported', 'approved', 'rejected', 'new']; const limit = 10; const ascending = (a, b) => { @@ -67,32 +66,24 @@ function addCommentToQueue(root, queue, comment, sort) { /** * getCommentQueues determines in which queues a comment should be placed. */ -function getCommentQueues(comment) { - const queues = ['all']; - const isFlagged = comment.actions && comment.actions.some((a) => a.__typename === 'FlagAction'); - - switch(comment.status) { - case 'ACCEPTED': - queues.push('approved'); - break; - case 'REJECTED': - queues.push('rejected'); - break; - case 'PREMOD': - queues.push('premod'); - queues.push('new'); - if (isFlagged) { - queues.push('reported'); +function getCommentQueues(comment, queueConfig) { + const queues = []; + Object.keys(queueConfig).forEach((key) => { + const {action_type, statuses, tags} = queueConfig[key]; + let addToQueues = false; + if (statuses && statuses.indexOf(comment.status) >= 0) { + addToQueues = true; } - break; - case 'NONE': - queues.push('new'); - if (isFlagged) { - queues.push('reported'); + if (tags && comment.tags && comment.tags.some((tagLink) => tags.indexOf(tagLink.tag.name) >= 0)) { + addToQueues = true; } - break; - } - + if (action_type && comment.actions && comment.actions.some((a) => a.__typename.toLowerCase() === `${action_type}action`)) { + addToQueues = true; + } + if (addToQueues) { + queues.push(key); + } + }); return queues; } @@ -106,42 +97,42 @@ function getCommentQueues(comment) { * @param {string} notify.text notification text to show * @param {bool} notify.anyQueue if true show the notification when the comment is shown * in the current active queue besides the 'all' queue. + * @param {Object} queueConfig queue configuration * @return {Object} next state of the store */ -export function handleCommentChange(root, comment, sort, notify) { +export function handleCommentChange(root, comment, sort, notify, queueConfig, activeQueue) { let next = root; - const nextQueues = getCommentQueues(comment); + const nextQueues = getCommentQueues(comment, queueConfig); let notificationShown = false; const showNotificationOnce = () => { if (notificationShown) { return; } - notification.info(notify.text); + notification.info(notify); notificationShown = true; }; - queues.forEach((queue) => { + Object.keys(queueConfig).forEach((queue) => { if (nextQueues.indexOf(queue) >= 0) { if (!queueHasComment(next, queue, comment.id)) { next = addCommentToQueue(next, queue, comment, sort); - if (notify && notify.activeQueue === queue && shouldCommentBeAdded(next, queue, comment, sort)) { + if (notify && activeQueue === queue && shouldCommentBeAdded(next, queue, comment, sort)) { showNotificationOnce(comment); } } } else if(queueHasComment(next, queue, comment.id)){ next = removeCommentFromQueue(next, queue, comment.id); - if (notify && notify.activeQueue === queue) { + if (notify && activeQueue === queue) { showNotificationOnce(comment); } } if ( notify - && (queue === 'all' || notify.anyQueue) && queueHasComment(next, queue, comment.id) - && notify.activeQueue === queue + && activeQueue === queue ) { showNotificationOnce(comment); } diff --git a/client/coral-admin/src/routes/Moderation/queueConfig.js b/client/coral-admin/src/routes/Moderation/queueConfig.js new file mode 100644 index 000000000..5385b5e23 --- /dev/null +++ b/client/coral-admin/src/routes/Moderation/queueConfig.js @@ -0,0 +1,35 @@ +import t from 'coral-framework/services/i18n'; + +export default { + premod: { + statuses: ['PREMOD'], + icon: 'access_time', + name: t('modqueue.premod'), + }, + new: { + statuses: ['NONE', 'PREMOD'], + icon: 'question_answer', + name: t('modqueue.new'), + }, + reported: { + action_type: 'FLAG', + statuses: ['NONE', 'PREMOD'], + icon: 'flag', + name: t('modqueue.reported'), + }, + approved: { + statuses: ['ACCEPTED'], + icon: 'check', + name: t('modqueue.approved'), + }, + rejected: { + statuses: ['REJECTED'], + icon: 'close', + name: t('modqueue.rejected'), + }, + all: { + statuses: ['NONE', 'PREMOD', 'ACCEPTED', 'REJECTED'], + icon: 'question_answer', + name: t('modqueue.all'), + } +}; diff --git a/plugins/talk-plugin-featured-comments/client/containers/ModSubscription.js b/plugins/talk-plugin-featured-comments/client/containers/ModSubscription.js index 647c7ecfd..85e0d8fe2 100644 --- a/plugins/talk-plugin-featured-comments/client/containers/ModSubscription.js +++ b/plugins/talk-plugin-featured-comments/client/containers/ModSubscription.js @@ -2,7 +2,6 @@ import React from 'react'; import {gql} from 'react-apollo'; import {connect} from 'react-redux'; import Comment from 'coral-admin/src/routes/Moderation/containers/Comment'; -import {handleCommentChange} from 'coral-admin/src/graphql/utils'; import {getDefinitionName} from 'coral-framework/utils'; import truncate from 'lodash/truncate'; import t from 'coral-framework/services/i18n'; @@ -22,20 +21,14 @@ class ModSubscription extends React.Component { assetId: this.props.data.variables.asset_id, }, updateQuery: (prev, {subscriptionData: {data: {commentFeatured: {user, comment}}}}) => { - const sort = this.props.data.variables.sort; - const text = this.props.user.id === user.id - ? {} + const notify = this.props.user.id === user.id + ? '' : t( 'talk-plugin-featured-comments.notify_featured', user.username, prepareNotificationText(comment.body), ); - const notify = { - activeQueue: this.props.activeTab, - text, - anyQueue: true, - }; - return handleCommentChange(prev, comment, sort, notify); + return this.props.handleCommentChange(prev, comment, notify); }, }, { @@ -44,20 +37,14 @@ class ModSubscription extends React.Component { assetId: this.props.data.variables.asset_id, }, updateQuery: (prev, {subscriptionData: {data: {commentUnfeatured: {user, comment}}}}) => { - const sort = this.props.data.variables.sort; - const text = this.props.user.id === user.id - ? {} + const notify = this.props.user.id === user.id + ? '' : t( 'talk-plugin-featured-comments.notify_unfeatured', user.username, prepareNotificationText(comment.body), ); - const notify = { - activeQueue: this.props.activeTab, - text, - anyQueue: true, - }; - return handleCommentChange(prev, comment, sort, notify); + return this.props.handleCommentChange(prev, comment, notify); } }, ]; From 6956b4cd3102112ee3eff9b1d8400d8c260754c7 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Thu, 10 Aug 2017 18:39:02 +0700 Subject: [PATCH 14/25] Remove Tag should keep remaining tags --- services/tags.js | 4 ++-- test/server/services/tags.js | 42 ++++++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/services/tags.js b/services/tags.js index fbe6b58ec..b0d0c4b96 100644 --- a/services/tags.js +++ b/services/tags.js @@ -205,8 +205,8 @@ class TagsService { return updateModel(item_type, query, { $pull: { tags: { - name: link.tag.name - } + 'tag.name': link.tag.name, + }, } }); } diff --git a/test/server/services/tags.js b/test/server/services/tags.js index 7cdad829e..1080563f0 100644 --- a/test/server/services/tags.js +++ b/test/server/services/tags.js @@ -27,7 +27,7 @@ describe('services.TagsService', () => { const id = comment.id; const name = 'BEST'; const assigned_by = user.id; - + await TagsService.add(id, 'COMMENTS', { tag: { name @@ -45,7 +45,7 @@ describe('services.TagsService', () => { const id = comment.id; const name = 'BEST'; const assigned_by = user.id; - + await TagsService.add(id, 'COMMENTS', { tag: { name @@ -103,5 +103,43 @@ describe('services.TagsService', () => { expect(tags.length).to.equal(0); } }); + it('removes a tag out of 2', async () => { + const id = comment.id; + const name = 'BEST'; + const assigned_by = user.id; + + await TagsService.add(id, 'COMMENTS', { + tag: { + name: 'ANOTHER' + }, + assigned_by + }); + + await TagsService.add(id, 'COMMENTS', { + tag: { + name + }, + assigned_by + }); + + { + const {tags} = await CommentsService.findById(id); + expect(tags.length).to.equal(2); + } + + // ok now to remove it + await TagsService.remove(id, 'COMMENTS', { + tag: { + name + }, + assigned_by + }); + + { + const {tags} = await CommentsService.findById(id); + expect(tags.length).to.equal(1); + expect(tags[0].tag.name).to.equal('ANOTHER'); + } + }); }); }); From 6794827a7730a44d58315ebd0aa51bc2adfbd334 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Thu, 10 Aug 2017 20:23:31 +0700 Subject: [PATCH 15/25] Support adding modqueues from plugins --- client/coral-admin/src/routes/Moderation/queueConfig.js | 4 +++- client/coral-framework/helpers/plugins.js | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/client/coral-admin/src/routes/Moderation/queueConfig.js b/client/coral-admin/src/routes/Moderation/queueConfig.js index 5385b5e23..b9e9e5320 100644 --- a/client/coral-admin/src/routes/Moderation/queueConfig.js +++ b/client/coral-admin/src/routes/Moderation/queueConfig.js @@ -1,4 +1,5 @@ import t from 'coral-framework/services/i18n'; +import {getModQueueConfigs} from 'coral-framework/helpers/plugins'; export default { premod: { @@ -31,5 +32,6 @@ export default { statuses: ['NONE', 'PREMOD', 'ACCEPTED', 'REJECTED'], icon: 'question_answer', name: t('modqueue.all'), - } + }, + ...getModQueueConfigs(), }; diff --git a/client/coral-framework/helpers/plugins.js b/client/coral-framework/helpers/plugins.js index 5e5a8c0c0..b2ca78142 100644 --- a/client/coral-framework/helpers/plugins.js +++ b/client/coral-framework/helpers/plugins.js @@ -3,6 +3,7 @@ import uniq from 'lodash/uniq'; import pick from 'lodash/pick'; import merge from 'lodash/merge'; import flattenDeep from 'lodash/flattenDeep'; +import isEmpty from 'lodash/isEmpty'; import flatten from 'lodash/flatten'; import {loadTranslations} from 'coral-framework/services/i18n'; import {injectReducers} from 'coral-framework/services/store'; @@ -64,7 +65,13 @@ export function getSlotFragments(slot, part) { export function getGraphQLExtensions() { return plugins .map((o) => pick(o.module, ['mutations', 'queries', 'fragments'])) - .filter((o) => o); + .filter((o) => !isEmpty(o)); +} + +export function getModQueueConfigs() { + return merge(...plugins + .map((o) => o.module.modQueues) + .filter((o) => o)); } function getTranslations() { From ada5e6f747c7740967f6488e11fbb6cf555479b4 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 11 Aug 2017 19:53:08 +0700 Subject: [PATCH 16/25] Update apollo and fix warnings --- .../coral-embed-stream/src/graphql/index.js | 10 ++- package.json | 4 +- yarn.lock | 84 +++++++++++-------- 3 files changed, 57 insertions(+), 41 deletions(-) diff --git a/client/coral-embed-stream/src/graphql/index.js b/client/coral-embed-stream/src/graphql/index.js index f52cc4e7d..2c39235a2 100644 --- a/client/coral-embed-stream/src/graphql/index.js +++ b/client/coral-embed-stream/src/graphql/index.js @@ -152,8 +152,6 @@ const extension = { }, created_at: new Date().toISOString(), body, - parent_id, - asset_id, action_summaries: [], tags: tags.map((tag) => ({ tag: { @@ -169,8 +167,14 @@ const extension = { })), status: 'NONE', replyCount: 0, + asset: { + __typename: 'Asset', + id: asset_id, + title: '', + url: '', + }, parent: parent_id - ? {id: parent_id} + ? {__typename: 'Comment', id: parent_id} : null, replies: { __typename: 'CommentConnection', diff --git a/package.json b/package.json index bb0a724ac..ebe1138f6 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "passport-local": "^1.0.0", "prop-types": "^15.5.10", "query-strings": "^0.0.1", - "react-apollo": "^1.1.0", + "react-apollo": "^1.4.12", "react-input-autosize": "^1.1.4", "react-recaptcha": "^2.2.6", "react-toastify": "^1.5.0", @@ -136,7 +136,7 @@ "yamljs": "^0.2.10" }, "devDependencies": { - "apollo-client": "^1.0.4", + "apollo-client": "^1.9.1", "autoprefixer": "^6.5.2", "babel-cli": "^6.24.0", "babel-core": "^6.24.0", diff --git a/yarn.lock b/yarn.lock index a5d73a756..9c1ac35e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,10 +9,6 @@ git-url-parse "^6.0.2" shelljs "^0.7.0" -"@types/async@^2.0.31": - version "2.0.40" - resolved "https://registry.yarnpkg.com/@types/async/-/async-2.0.40.tgz#ac02de68e66c004a61b7cb16df8b1db3a254cca9" - "@types/express-serve-static-core@*": version "4.0.44" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.0.44.tgz#a1c3bd5d80e93c72fba91a03f5412c47f21d4ae7" @@ -26,18 +22,18 @@ "@types/express-serve-static-core" "*" "@types/serve-static" "*" +"@types/graphql@0.10.2": + version "0.10.2" + resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.10.2.tgz#d7c79acbaa17453b6681c80c34b38fcb10c4c08c" + "@types/graphql@^0.8.5", "@types/graphql@^0.8.6": version "0.8.6" resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.8.6.tgz#b34fb880493ba835b0c067024ee70130d6f9bb68" -"@types/graphql@^0.9.0", "@types/graphql@^0.9.1": +"@types/graphql@^0.9.1": version "0.9.1" resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.9.1.tgz#b04ebe84bc997cc60dbea2ed4d0d4342c737f99d" -"@types/isomorphic-fetch@0.0.33": - version "0.0.33" - resolved "https://registry.yarnpkg.com/@types/isomorphic-fetch/-/isomorphic-fetch-0.0.33.tgz#3ea1b86f8b73e6a7430d01d4dbd5b1f63fd72718" - "@types/mime@*": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-0.0.29.tgz#fbcfd330573b912ef59eeee14602bface630754b" @@ -203,20 +199,27 @@ anymatch@^1.3.0: arrify "^1.0.0" micromatch "^2.1.5" -apollo-client@^1.0.2, apollo-client@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-1.0.4.tgz#af75db8cdd27e08a835ddfb39807849e178540f9" +apollo-client@^1.4.0, apollo-client@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-1.9.1.tgz#9e6a383605572c755038cf5d7fdac9382bcdc040" dependencies: - graphql "^0.9.3" + apollo-link-core "^0.5.0" + graphql "^0.10.0" graphql-anywhere "^3.0.1" graphql-tag "^2.0.0" redux "^3.4.0" symbol-observable "^1.0.2" whatwg-fetch "^2.0.0" optionalDependencies: - "@types/async" "^2.0.31" - "@types/graphql" "^0.9.0" - "@types/isomorphic-fetch" "0.0.33" + "@types/graphql" "0.10.2" + +apollo-link-core@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/apollo-link-core/-/apollo-link-core-0.5.0.tgz#dc87da1aaa63b029321ae70938dc26257f5ab8c6" + dependencies: + graphql "^0.10.3" + graphql-tag "^2.4.2" + zen-observable-ts "^0.4.0" app-module-path@^2.2.0: version "2.2.0" @@ -3711,6 +3714,10 @@ graphql-tag@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.0.0.tgz#f3efe3b4d64f33bfe8479ae06a461c9d72f2a6fe" +graphql-tag@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.4.2.tgz#6a63297d8522d03a2b72d26f1b239aab343840cd" + graphql-tools@^0.10.1: version "0.10.1" resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-0.10.1.tgz#274aa338d50b1c0b3ed6936eafd8ed3a19ed1828" @@ -3721,13 +3728,19 @@ graphql-tools@^0.10.1: optionalDependencies: "@types/graphql" "^0.8.5" +graphql@^0.10.0, graphql@^0.10.3: + version "0.10.5" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.10.5.tgz#c9be17ca2bdfdbd134077ffd9bbaa48b8becd298" + dependencies: + iterall "^1.1.0" + graphql@^0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.7.2.tgz#cc894a32823399b8a0cb012b9e9ecad35cd00f72" dependencies: iterall "1.0.2" -graphql@^0.9.1, graphql@^0.9.3: +graphql@^0.9.1: version "0.9.3" resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.9.3.tgz#71fc0fa331bffb9c20678485861cfb370803118e" dependencies: @@ -3876,6 +3889,10 @@ hoist-non-react-statics@^1.0.0, hoist-non-react-statics@^1.0.3, hoist-non-react- version "1.2.0" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" +hoist-non-react-statics@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.2.2.tgz#c0eca5a7d5a28c5ada3107eb763b01da6bfa81fb" + home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -3996,11 +4013,11 @@ iconv-lite@0.4.13: version "0.4.13" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" -iconv-lite@0.4.15, iconv-lite@^0.4.5, iconv-lite@~0.4.13: +iconv-lite@0.4.15: version "0.4.15" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" -iconv-lite@^0.4.17: +iconv-lite@^0.4.17, iconv-lite@^0.4.5, iconv-lite@~0.4.13: version "0.4.18" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2" @@ -4531,7 +4548,7 @@ iterall@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.0.3.tgz#e0b31958f835013c323ff0b10943829ac69aa4b7" -iterall@^1.1.1: +iterall@^1.1.0, iterall@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.1.1.tgz#f7f0af11e9a04ec6426260f5019d9fcca4d50214" @@ -6912,14 +6929,14 @@ react-addons-test-utils@^15.4.2: fbjs "^0.8.4" object-assign "^4.1.0" -react-apollo@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/react-apollo/-/react-apollo-1.1.1.tgz#136a6be6e0ed7bfa5292e67073e1829fe12e1e17" +react-apollo@^1.4.12: + version "1.4.12" + resolved "https://registry.yarnpkg.com/react-apollo/-/react-apollo-1.4.12.tgz#0cacbdd335acec4c1079feb48047df1c43f77bdf" dependencies: - apollo-client "^1.0.2" + apollo-client "^1.4.0" graphql-anywhere "^3.0.0" graphql-tag "^2.0.0" - hoist-non-react-statics "^1.2.0" + hoist-non-react-statics "^2.2.0" invariant "^2.2.1" lodash.flatten "^4.2.0" lodash.isequal "^4.1.1" @@ -6927,10 +6944,8 @@ react-apollo@^1.1.0: lodash.pick "^4.4.0" object-assign "^4.0.1" prop-types "^15.5.8" - optionalDependencies: - react-dom "0.14.x || 15.* || ^15.0.0" -"react-dom@0.14.x || 15.* || ^15.0.0", react-dom@^15.3.1, react-dom@^15.4.2: +react-dom@^15.3.1, react-dom@^15.4.2: version "15.5.4" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.5.4.tgz#ba0c28786fd52ed7e4f2135fe0288d462aef93da" dependencies: @@ -7869,14 +7884,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^3.0.0" - -string-width@^2.1.0: +string-width@^2.0.0, string-width@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: @@ -8816,3 +8824,7 @@ yauzl@^2.5.0: dependencies: buffer-crc32 "~0.2.3" fd-slicer "~1.0.1" + +zen-observable-ts@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.4.0.tgz#a74bc9fe59747948a577bd513d438e70fcfae7e2" From 17bc396b06fea740c11d28177031f500d770570d Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 11 Aug 2017 20:55:23 +0700 Subject: [PATCH 17/25] Fix Ignored User in permalink --- client/coral-embed-stream/style/default.css | 2 +- client/coral-framework/hocs/withMutation.js | 4 ++-- client/coral-framework/hocs/withQuery.js | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/client/coral-embed-stream/style/default.css b/client/coral-embed-stream/style/default.css index 802cd2e5b..6ba376096 100644 --- a/client/coral-embed-stream/style/default.css +++ b/client/coral-embed-stream/style/default.css @@ -13,7 +13,7 @@ body { width: 100%; font-size: 14px; margin: 0px; - padding: 0px 0px 50px 0px; + padding: 0px 0px 100px 0px; height: auto !important; } diff --git a/client/coral-framework/hocs/withMutation.js b/client/coral-framework/hocs/withMutation.js index c9108c0fe..7e2c3d09d 100644 --- a/client/coral-framework/hocs/withMutation.js +++ b/client/coral-framework/hocs/withMutation.js @@ -92,13 +92,13 @@ export default (document, config = {}) => (WrappedComponent) => { // Do not run updates when we have mutation errors. return prev; } - return map[key](prev, result); + return map[key](prev, result) || prev; }; } else { const existing = res[key]; res[key] = (prev, result) => { const next = existing(prev, result); - return map[key](next, result); + return map[key](next, result) || next; }; } }); diff --git a/client/coral-framework/hocs/withQuery.js b/client/coral-framework/hocs/withQuery.js index adb67b7b3..82c9c29d4 100644 --- a/client/coral-framework/hocs/withQuery.js +++ b/client/coral-framework/hocs/withQuery.js @@ -128,8 +128,10 @@ export default (document, config = {}) => (WrappedComponent) => { const reducer = withSkipOnErrors( reducerCallbacks.reduce( - (a, b) => (prev, ...rest) => - b(a(prev, ...rest), ...rest), + (a, b) => (prev, ...rest) => { + const next = a(prev, ...rest); + return b(next, ...rest) || next; + } )); return { From 45cf72256beab523c779e54fc547a2f4a13115a5 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 11 Aug 2017 21:11:59 +0700 Subject: [PATCH 18/25] Fix dashboard links --- .../src/routes/Dashboard/components/ActivityWidget.js | 6 +++--- .../src/routes/Dashboard/components/FlagWidget.js | 6 +++--- .../src/routes/Dashboard/components/LikeWidget.js | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/client/coral-admin/src/routes/Dashboard/components/ActivityWidget.js b/client/coral-admin/src/routes/Dashboard/components/ActivityWidget.js index 5f974971c..d92b2bd14 100644 --- a/client/coral-admin/src/routes/Dashboard/components/ActivityWidget.js +++ b/client/coral-admin/src/routes/Dashboard/components/ActivityWidget.js @@ -17,11 +17,11 @@ const ActivityWidget = ({assets}) => { ? assets.map((asset) => { return (
- Moderate + Moderate

{asset.commentCount}

- +

{asset.title}

- +

{asset.author} — Published: {new Date(asset.created_at).toLocaleDateString()}

); diff --git a/client/coral-admin/src/routes/Dashboard/components/FlagWidget.js b/client/coral-admin/src/routes/Dashboard/components/FlagWidget.js index ef0974fbd..ef4a6857e 100644 --- a/client/coral-admin/src/routes/Dashboard/components/FlagWidget.js +++ b/client/coral-admin/src/routes/Dashboard/components/FlagWidget.js @@ -24,11 +24,11 @@ const FlagWidget = ({assets}) => { return (
- Moderate + Moderate

{flagSummary ? flagSummary.actionCount : 0}

- +

{asset.title}

- +

{asset.author} — Published: {new Date(asset.created_at).toLocaleDateString()}

); diff --git a/client/coral-admin/src/routes/Dashboard/components/LikeWidget.js b/client/coral-admin/src/routes/Dashboard/components/LikeWidget.js index 2188e38dd..a61f888bf 100644 --- a/client/coral-admin/src/routes/Dashboard/components/LikeWidget.js +++ b/client/coral-admin/src/routes/Dashboard/components/LikeWidget.js @@ -19,11 +19,11 @@ const LikeWidget = ({assets}) => { const likeSummary = asset.action_summaries.find((s) => s.type === 'LikeAssetActionSummary'); return (
- Moderate + Moderate

{likeSummary ? likeSummary.actionCount : 0}

- +

{asset.title}

- +

{asset.author} — Published: {new Date(asset.created_at).toLocaleDateString()}

); From 7360a43898878f3ce7314841c8daf7ee60c7c24f Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 11 Aug 2017 22:50:12 +0700 Subject: [PATCH 19/25] Remove immutable from embed stream --- .../containers/ConfigureStreamContainer.js | 2 +- .../src/containers/Embed.js | 2 +- .../src/containers/Stream.js | 5 +- .../coral-embed-stream/src/graphql/index.js | 6 +- client/coral-framework/actions/asset.js | 4 +- client/coral-framework/actions/auth.js | 27 +- client/coral-framework/actions/user.js | 21 -- client/coral-framework/constants/assets.js | 3 - client/coral-framework/constants/user.js | 10 - client/coral-framework/reducers/asset.js | 19 +- client/coral-framework/reducers/auth.js | 281 +++++++++++------- client/coral-framework/reducers/index.js | 2 - client/coral-framework/reducers/user.js | 43 --- .../containers/ProfileContainer.js | 11 +- plugin-api/beta/client/hocs/withReaction.js | 2 +- plugin-api/beta/client/hocs/withTags.js | 2 +- .../client/components/ChangeUsername.js | 2 +- .../client/components/SignInButton.js | 2 +- .../client/components/SignInContainer.js | 2 +- .../client/components/UserBox.js | 4 +- 20 files changed, 236 insertions(+), 214 deletions(-) delete mode 100644 client/coral-framework/actions/user.js delete mode 100644 client/coral-framework/constants/assets.js delete mode 100644 client/coral-framework/constants/user.js delete mode 100644 client/coral-framework/reducers/user.js diff --git a/client/coral-configure/containers/ConfigureStreamContainer.js b/client/coral-configure/containers/ConfigureStreamContainer.js index e7b937030..8489c809f 100644 --- a/client/coral-configure/containers/ConfigureStreamContainer.js +++ b/client/coral-configure/containers/ConfigureStreamContainer.js @@ -119,7 +119,7 @@ class ConfigureStreamContainer extends Component { } const mapStateToProps = (state) => ({ - asset: state.asset.toJS() + asset: state.asset }); const mapDispatchToProps = (dispatch) => ({ diff --git a/client/coral-embed-stream/src/containers/Embed.js b/client/coral-embed-stream/src/containers/Embed.js index 06646a6c2..e21a683d1 100644 --- a/client/coral-embed-stream/src/containers/Embed.js +++ b/client/coral-embed-stream/src/containers/Embed.js @@ -170,7 +170,7 @@ export const withEmbedQuery = withQuery(EMBED_QUERY, { }); const mapStateToProps = (state) => ({ - auth: state.auth.toJS(), + auth: state.auth, commentId: state.stream.commentId, assetId: state.stream.assetId, assetUrl: state.stream.assetUrl, diff --git a/client/coral-embed-stream/src/containers/Stream.js b/client/coral-embed-stream/src/containers/Stream.js index 73676713c..451b115a9 100644 --- a/client/coral-embed-stream/src/containers/Stream.js +++ b/client/coral-embed-stream/src/containers/Stream.js @@ -10,7 +10,6 @@ import { import * as authActions from 'coral-framework/actions/auth'; import * as notificationActions from 'coral-framework/actions/notification'; -import {editName} from 'coral-framework/actions/user'; import {setActiveReplyBox, setActiveTab, viewAllComments} from '../actions/stream'; import Stream from '../components/Stream'; import Comment from './Comment'; @@ -26,7 +25,7 @@ import { } from '../graphql/utils'; import omit from 'lodash/omit'; -const {showSignInDialog} = authActions; +const {showSignInDialog, editName} = authActions; const {addNotification} = notificationActions; class StreamContainer extends React.Component { @@ -298,7 +297,7 @@ const fragments = { }; const mapStateToProps = (state) => ({ - auth: state.auth.toJS(), + auth: state.auth, refetching: state.embed.refetching, commentCountCache: state.stream.commentCountCache, activeReplyBox: state.stream.activeReplyBox, diff --git a/client/coral-embed-stream/src/graphql/index.js b/client/coral-embed-stream/src/graphql/index.js index f52cc4e7d..4cd4a5d23 100644 --- a/client/coral-embed-stream/src/graphql/index.js +++ b/client/coral-embed-stream/src/graphql/index.js @@ -147,8 +147,8 @@ const extension = { __typename: 'Comment', user: { __typename: 'User', - id: auth.toJS().user.id, - username: auth.toJS().user.username + id: auth.user.id, + username: auth.user.username }, created_at: new Date().toISOString(), body, @@ -162,7 +162,7 @@ const extension = { __typename: 'Tag' }, assigned_by: { - id: auth.toJS().user.id, + id: auth.user.id, __typename: 'User' }, __typename: 'TagLink' diff --git a/client/coral-framework/actions/asset.js b/client/coral-framework/actions/asset.js index 24739ddde..aab3caf3a 100644 --- a/client/coral-framework/actions/asset.js +++ b/client/coral-framework/actions/asset.js @@ -13,7 +13,7 @@ const updateAssetSettingsSuccess = (settings) => ({type: actions.UPDATE_ASSET_SE const updateAssetSettingsFailure = (error) => ({type: actions.UPDATE_ASSET_SETTINGS_FAILURE, error}); export const updateConfiguration = (newConfig) => (dispatch, getState) => { - const assetId = getState().asset.toJS().id; + const assetId = getState().asset.id; dispatch(updateAssetSettingsRequest()); coralApi(`/assets/${assetId}/settings`, {method: 'PUT', body: newConfig}) .then(() => { @@ -27,7 +27,7 @@ export const updateConfiguration = (newConfig) => (dispatch, getState) => { }; export const updateOpenStream = (closedBody) => (dispatch, getState) => { - const assetId = getState().asset.toJS().id; + const assetId = getState().asset.id; dispatch(fetchAssetRequest()); coralApi(`/assets/${assetId}/status`, {method: 'PUT', body: closedBody}) .then(() => { diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index f4cf5217e..7c6d3bf89 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -4,6 +4,7 @@ import * as actions from '../constants/auth'; import * as Storage from '../helpers/storage'; import coralApi, {base} from '../helpers/request'; import pym from '../services/pym'; +import {addNotification} from '../actions/notification'; import {resetWebsocket} from 'coral-framework/services/client'; import t from 'coral-framework/services/i18n'; @@ -220,7 +221,7 @@ const signUpSuccess = (user) => ({type: actions.FETCH_SIGNUP_SUCCESS, user}); const signUpFailure = (error) => ({type: actions.FETCH_SIGNUP_FAILURE, error}); export const fetchSignUp = (formData) => (dispatch, getState) => { - const redirectUri = getState().auth.toJS().redirectUri; + const redirectUri = getState().auth.redirectUri; dispatch(signUpRequest()); coralApi('/users', { @@ -257,7 +258,7 @@ const forgotPasswordFailure = (error) => ({ export const fetchForgotPassword = (email) => (dispatch, getState) => { dispatch(forgotPasswordRequest(email)); - const redirectUri = getState().auth.toJS().redirectUri; + const redirectUri = getState().auth.redirectUri; coralApi('/account/password/reset', { method: 'POST', body: {email, loc: redirectUri} @@ -351,7 +352,7 @@ const verifyEmailFailure = () => ({ }); export const requestConfirmEmail = (email) => (dispatch, getState) => { - const redirectUri = getState().auth.toJS().redirectUri; + const redirectUri = getState().auth.redirectUri; dispatch(verifyEmailRequest()); return coralApi('/users/resend-verify', { method: 'POST', @@ -378,3 +379,23 @@ export const setRedirectUri = (uri) => ({ type: actions.SET_REDIRECT_URI, uri, }); + +//============================================================================== +// Edit Username +//============================================================================== + +const editUsernameFailure = (error) => ({type: actions.EDIT_USERNAME_FAILURE, error}); +const editUsernameSuccess = () => ({type: actions.EDIT_USERNAME_SUCCESS}); + +export const editName = (username) => (dispatch) => { + return coralApi('/account/username', {method: 'PUT', body: {username}}) + .then(() => { + dispatch(editUsernameSuccess()); + dispatch(addNotification('success', t('framework.success_name_update'))); + }) + .catch((error) => { + console.error(error); + const errorMessage = error.translation_key ? t(`error.${error.translation_key}`) : error.toString(); + dispatch(editUsernameFailure(errorMessage)); + }); +}; diff --git a/client/coral-framework/actions/user.js b/client/coral-framework/actions/user.js deleted file mode 100644 index a6ad45d4a..000000000 --- a/client/coral-framework/actions/user.js +++ /dev/null @@ -1,21 +0,0 @@ -import {addNotification} from '../actions/notification'; -import coralApi from '../helpers/request'; -import * as actions from '../constants/auth'; - -import t from 'coral-framework/services/i18n'; - -const editUsernameFailure = (error) => ({type: actions.EDIT_USERNAME_FAILURE, error}); -const editUsernameSuccess = () => ({type: actions.EDIT_USERNAME_SUCCESS}); - -export const editName = (username) => (dispatch) => { - return coralApi('/account/username', {method: 'PUT', body: {username}}) - .then(() => { - dispatch(editUsernameSuccess()); - dispatch(addNotification('success', t('framework.success_name_update'))); - }) - .catch((error) => { - console.error(error); - const errorMessage = error.translation_key ? t(`error.${error.translation_key}`) : error.toString(); - dispatch(editUsernameFailure(errorMessage)); - }); -}; diff --git a/client/coral-framework/constants/assets.js b/client/coral-framework/constants/assets.js deleted file mode 100644 index 3883ee835..000000000 --- a/client/coral-framework/constants/assets.js +++ /dev/null @@ -1,3 +0,0 @@ -export const MULTIPLE_ASSETS_REQUEST = 'MULTIPLE_ASSETS_REQUEST'; -export const MULTIPLE_ASSETS_SUCCESS = 'MULTIPLE_ASSETS_SUCCESS'; -export const MULTIPLE_ASSSETS_FAILURE = 'MULTIPLE_ASSSETS_FAILURE'; diff --git a/client/coral-framework/constants/user.js b/client/coral-framework/constants/user.js deleted file mode 100644 index 1557a42c9..000000000 --- a/client/coral-framework/constants/user.js +++ /dev/null @@ -1,10 +0,0 @@ -export const EDIT_NAME_REQUEST = 'EDIT_NAME_REQUEST'; -export const EDIT_NAME_SUCCESS = 'EDIT_NAME_SUCCESS'; -export const EDIT_NAME_FAILURE = 'EDIT_NAME_FAILURE'; -export const COMMENTS_BY_USER_REQUEST = 'COMMENTS_BY_USER_REQUEST'; -export const COMMENTS_BY_USER_SUCCESS = 'COMMENTS_BY_USER_SUCCESS'; -export const COMMENTS_BY_USER_FAILURE = 'COMMENTS_BY_USER_FAILURE'; -export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS'; -export const UPDATE_USERNAME = 'UPDATE_USERNAME'; -export const IGNORE_USER_SUCCESS = 'IGNORE_USER_SUCCESS'; -export const STOP_IGNORING_USER_SUCCESS = 'STOP_IGNORING_USER_SUCCESS'; diff --git a/client/coral-framework/reducers/asset.js b/client/coral-framework/reducers/asset.js index f9d0a55e3..b9837eddd 100644 --- a/client/coral-framework/reducers/asset.js +++ b/client/coral-framework/reducers/asset.js @@ -1,24 +1,27 @@ -import {Map} from 'immutable'; import * as actions from '../constants/asset'; -const initialState = Map({ +const initialState = { closedAt: null, settings: null, title: null, url: null, - features: Map({}), + features: {}, status: 'open', moderation: null -}); +}; export default function asset (state = initialState, action) { switch (action.type) { case actions.FETCH_ASSET_SUCCESS: - return state - .merge(action.asset); + return { + ...state, + ...action.asset, + }; case actions.UPDATE_ASSET_SETTINGS_SUCCESS: - return state - .setIn(['settings'], action.settings); + return { + ...state, + settings: action.settings, + }; default: return state; } diff --git a/client/coral-framework/reducers/auth.js b/client/coral-framework/reducers/auth.js index 5481b7a5e..1e18ddffa 100644 --- a/client/coral-framework/reducers/auth.js +++ b/client/coral-framework/reducers/auth.js @@ -1,8 +1,7 @@ -import {Map, fromJS} from 'immutable'; import * as actions from '../constants/auth'; import pym from 'coral-framework/services/pym'; -const initialState = Map({ +const initialState = { isLoading: false, loggedIn: false, user: null, @@ -21,27 +20,34 @@ const initialState = Map({ fromSignUp: false, requireEmailConfirmation: false, redirectUri: pym.parentUrl || location.href, -}); +}; const purge = (user) => { - const {settings, profiles, ...userData} = user; // eslint-disable-line - return fromJS(userData); + const {settings, ...userData} = user; // eslint-disable-line + return userData; }; export default function auth (state = initialState, action) { switch (action.type) { case actions.FOCUS_SIGNIN_DIALOG: - return state - .set('signInDialogFocus', true); + return { + ...state, + signInDialogFocus: true, + }; case actions.BLUR_SIGNIN_DIALOG: - return state - .set('signInDialogFocus', false); - case actions.SHOW_SIGNIN_DIALOG : - return state - .set('showSignInDialog', true) - .set('signInDialogFocus', true); + return { + ...state, + signInDialogFocus: false, + }; + case actions.SHOW_SIGNIN_DIALOG: + return { + ...state, + showSignInDialog: true, + signInDialogFocus: true, + }; case actions.HIDE_SIGNIN_DIALOG : - return state.merge(Map({ + return { + ...state, isLoading: false, showSignInDialog: false, signInDialogFocus: false, @@ -53,125 +59,198 @@ export default function auth (state = initialState, action) { emailVerificationSuccess: false, emailVerificationLoading: false, successSignUp: false - })); - case actions.SHOW_CREATEUSERNAME_DIALOG : - return state - .set('showCreateUsernameDialog', true); - case actions.HIDE_CREATEUSERNAME_DIALOG : - return state.merge(Map({ - showCreateUsernameDialog: false - })); - case actions.CREATE_USERNAME_SUCCESS : - return state.merge(Map({ + }; + case actions.SHOW_CREATEUSERNAME_DIALOG: + return { + ...state, + showCreateUsernameDialog: true, + }; + case actions.HIDE_CREATEUSERNAME_DIALOG: + return { + ...state, showCreateUsernameDialog: false, - error: '' - })); - case actions.CREATE_USERNAME_FAILURE : - return state - .set('error', action.error); - case actions.CHANGE_VIEW : - return state - .set('error', '') - .set('view', action.view); + }; + case actions.CREATE_USERNAME_SUCCESS: + return { + ...state, + showCreateUsernameDialog: false, + error: '', + }; + case actions.CREATE_USERNAME_FAILURE: + return { + ...state, + error: action.error, + }; + case actions.CHANGE_VIEW: + return { + ...state, + error: action.error, + view: action.view, + }; case actions.CLEAN_STATE: return initialState; case actions.FETCH_SIGNIN_REQUEST: - return state - .set('isLoading', true); + return { + ...state, + isLoading: true, + }; case actions.CHECK_LOGIN_FAILURE: - return state - .set('checkedInitialLogin', true) - .set('loggedIn', false) - .set('user', null); + return { + ...state, + checkedInitialLogin: true, + loggedIn: false, + user: null, + }; case actions.CHECK_LOGIN_SUCCESS: - return state - .set('checkedInitialLogin', true) - .set('loggedIn', true) - .set('user', purge(action.user)); + return { + ...state, + checkedInitialLogin: true, + loggedIn: true, + user: purge(action.user), + }; case actions.FETCH_SIGNIN_SUCCESS: - return state - .set('loggedIn', true) - .set('user', purge(action.user)); + return { + ...state, + loggedIn: true, + user: purge(action.user), + }; case actions.FETCH_SIGNIN_FAILURE: - return state - .set('isLoading', false) - .set('error', action.error) - .set('user', null); + return { + ...state, + isLoading: false, + error: action.error, + user: null, + }; case actions.FETCH_SIGNUP_FACEBOOK_REQUEST: - return state - .set('fromSignUp', true); + return { + ...state, + fromSignUp: true, + }; case actions.FETCH_SIGNIN_FACEBOOK_REQUEST: - return state - .set('fromSignUp', false); + return { + ...state, + fromSignUp: false, + }; case actions.FETCH_SIGNIN_FACEBOOK_SUCCESS: - return state - .set('user', purge(action.user)) - .set('loggedIn', true); + return { + ...state, + loggedIn: true, + user: purge(action.user), + }; case actions.FETCH_SIGNIN_FACEBOOK_FAILURE: - return state - .set('error', action.error) - .set('user', null); + return { + ...state, + error: action.error, + user: null, + }; case actions.FETCH_SIGNUP_REQUEST: - return state - .set('isLoading', true); + return { + ...state, + isLoading: true, + }; case actions.FETCH_SIGNUP_FAILURE: - return state - .set('error', action.error) - .set('isLoading', false); + return { + ...state, + error: action.error, + isLoading: false, + }; case actions.FETCH_SIGNUP_SUCCESS: - return state - .set('isLoading', false) - .set('successSignUp', true); + return { + ...state, + isLoading: false, + successSignUp: true, + }; case actions.LOGOUT: - return state - .set('user', null) - .set('isLoading', false) - .set('loggedIn', false); + return { + ...state, + user: null, + isLoading: false, + loggedIn: false, + }; case actions.INVALID_FORM: - return state - .set('error', action.error); + return { + ...state, + error: action.error, + }; case actions.VALID_FORM: - return state - .set('error', ''); + return { + ...state, + error: '', + }; case actions.FETCH_FORGOT_PASSWORD_SUCCESS: - return state - .set('passwordRequestFailure', null) - .set('passwordRequestSuccess', 'If you have a registered account, a password reset link was sent to that email'); + return { + ...state, + passwordRequestFailure: null, + passwordRequestSuccess: 'If you have a registered account, a password reset link was sent to that email', + }; case actions.FETCH_FORGOT_PASSWORD_FAILURE: - return state - .set('passwordRequestFailure', 'There was an error sending your password reset email. Please try again soon!') - .set('passwordRequestSuccess', null); + return { + ...state, + passwordRequestFailure: 'There was an error sending your password reset email. Please try again soon!', + passwordRequestSuccess: null, + }; case actions.UPDATE_USERNAME: - return state - .setIn(['user', 'username'], action.username); + return { + ...state, + user: { + ...state.user, + username: action.username, + } + }; case actions.VERIFY_EMAIL_FAILURE: - return state - .set('emailVerificationFailure', true) - .set('emailVerificationLoading', false); + return { + ...state, + emailVerificationFailure: true, + emailVerificationLoading: false, + }; case actions.VERIFY_EMAIL_REQUEST: - return state.set('emailVerificationLoading', true); + return { + ...state, + emailVerificationLoading: true, + }; case actions.VERIFY_EMAIL_SUCCESS: - return state - .set('emailVerificationSuccess', true) - .set('emailVerificationLoading', false); + return { + ...state, + emailVerificationSuccess: true, + emailVerificationLoading: false, + }; case actions.SET_REQUIRE_EMAIL_VERIFICATION: - return state - .set('requireEmailConfirmation', action.required); + return { + ...state, + requireEmailConfirmation: action.required, + }; case actions.SET_REDIRECT_URI: - return state - .set('redirectUri', action.uri); + return { + ...state, + redirectUri: action.uri, + }; case 'APOLLO_SUBSCRIPTION_RESULT': if (action.operationName === 'UserBanned' && state.getIn(['user', 'id']) === action.variables.user_id) { - return state - .mergeIn(['user'], action.result.data.userBanned); + return { + ...state, + user: { + ...state.user, + ...action.result.data.userBanned, + }, + }; } if (action.operationName === 'UserSuspended' && state.getIn(['user', 'id']) === action.variables.user_id) { - return state - .mergeIn(['user'], action.result.data.userSuspended); + return { + ...state, + user: { + ...state.user, + ...action.result.data.userSuspended, + }, + }; } if (action.operationName === 'UsernameRejected' && state.getIn(['user', 'id']) === action.variables.user_id) { - return state - .mergeIn(['user'], action.result.data.usernameRejected); + return { + ...state, + user: { + ...state.user, + ...action.result.data.usernameRejected, + }, + }; } return state; default : diff --git a/client/coral-framework/reducers/index.js b/client/coral-framework/reducers/index.js index f1ac580dc..6b9b730ca 100644 --- a/client/coral-framework/reducers/index.js +++ b/client/coral-framework/reducers/index.js @@ -1,11 +1,9 @@ import auth from './auth'; -import user from './user'; import asset from './asset'; import {reducer as commentBox} from '../../talk-plugin-commentbox'; export default { auth, - user, asset, commentBox, }; diff --git a/client/coral-framework/reducers/user.js b/client/coral-framework/reducers/user.js deleted file mode 100644 index bc40cf3ae..000000000 --- a/client/coral-framework/reducers/user.js +++ /dev/null @@ -1,43 +0,0 @@ -import {Map} from 'immutable'; -import * as authActions from '../constants/auth'; -import * as actions from '../constants/user'; -import * as assetActions from '../constants/assets'; - -const initialState = Map({ - username: '', - profiles: [], - settings: {}, - myComments: [], - myAssets: [], // the assets from which myComments (above) originated -}); - -const purge = (user) => { - const {_id, created_at, updated_at, __v, roles, ...userData} = user; // eslint-disable-line - return userData; -}; - -export default function user (state = initialState, action) { - switch (action.type) { - case authActions.CHECK_LOGIN_SUCCESS: - return state.merge(Map(purge(action.user))); - case authActions.CHECK_LOGIN_FAILURE: - return initialState; - case authActions.FETCH_SIGNIN_SUCCESS: - return state.merge(Map(purge(action.user))); - case authActions.FETCH_SIGNIN_FAILURE: - return initialState; - case authActions.FETCH_SIGNIN_FACEBOOK_SUCCESS: - return state.merge(Map(purge(action.user))); - case authActions.FETCH_SIGNIN_FACEBOOK_FAILURE: - return initialState; - case actions.SAVE_BIO_SUCCESS: - return state.set('settings', action.settings); - case actions.COMMENTS_BY_USER_SUCCESS: - return state.set('myComments', action.comments); - case assetActions.MULTIPLE_ASSETS_SUCCESS: - return state.set('myAssets', action.assets); - case actions.LOGOUT_SUCCESS: - return initialState; - } - return state; -} diff --git a/client/coral-settings/containers/ProfileContainer.js b/client/coral-settings/containers/ProfileContainer.js index 0090847f7..e33c0b6cd 100644 --- a/client/coral-settings/containers/ProfileContainer.js +++ b/client/coral-settings/containers/ProfileContainer.js @@ -51,7 +51,7 @@ class ProfileContainer extends Component { }; render() { - const {auth, asset, showSignInDialog, stopIgnoringUser} = this.props; + const {auth, auth: {user}, asset, showSignInDialog, stopIgnoringUser} = this.props; const {me} = this.props.root; const loading = [1, 2, 4].indexOf(this.props.data.networkStatus) >= 0; @@ -63,14 +63,14 @@ class ProfileContainer extends Component { return ; } - const localProfile = this.props.user.profiles.find( + const localProfile = user.profiles.find( (p) => p.provider === 'local' ); const emailAddress = localProfile && localProfile.id; return (
-

{this.props.user.username}

+

{user.username}

{emailAddress ?

{emailAddress}

: null} {me.ignoredUsers && me.ignoredUsers.length @@ -138,9 +138,8 @@ const withProfileQuery = withQuery( `); const mapStateToProps = (state) => ({ - user: state.user.toJS(), - asset: state.asset.toJS(), - auth: state.auth.toJS() + asset: state.asset, + auth: state.auth }); const mapDispatchToProps = (dispatch) => diff --git a/plugin-api/beta/client/hocs/withReaction.js b/plugin-api/beta/client/hocs/withReaction.js index 7f43cc5b2..22c30d639 100644 --- a/plugin-api/beta/client/hocs/withReaction.js +++ b/plugin-api/beta/client/hocs/withReaction.js @@ -363,7 +363,7 @@ export default (reaction) => (WrappedComponent) => { ); const mapStateToProps = (state) => ({ - user: state.auth.toJS().user, + user: state.auth.user, }); const mapDispatchToProps = (dispatch) => diff --git a/plugin-api/beta/client/hocs/withTags.js b/plugin-api/beta/client/hocs/withTags.js index e9b5bdff0..b0a74f4d7 100644 --- a/plugin-api/beta/client/hocs/withTags.js +++ b/plugin-api/beta/client/hocs/withTags.js @@ -84,7 +84,7 @@ export default (tag) => (WrappedComponent) => { } const mapStateToProps = (state) => ({ - user: state.auth.toJS().user, + user: state.auth.user, }); const mapDispatchToProps = (dispatch) => diff --git a/plugins/talk-plugin-auth/client/components/ChangeUsername.js b/plugins/talk-plugin-auth/client/components/ChangeUsername.js index ed3c5ace0..c1ad081b1 100644 --- a/plugins/talk-plugin-auth/client/components/ChangeUsername.js +++ b/plugins/talk-plugin-auth/client/components/ChangeUsername.js @@ -122,7 +122,7 @@ class ChangeUsernameContainer extends React.Component { } const mapStateToProps = ({auth}) => ({ - auth: auth.toJS() + auth: auth }); const mapDispatchToProps = (dispatch) => diff --git a/plugins/talk-plugin-auth/client/components/SignInButton.js b/plugins/talk-plugin-auth/client/components/SignInButton.js index 0adb300a7..9c8a04b11 100644 --- a/plugins/talk-plugin-auth/client/components/SignInButton.js +++ b/plugins/talk-plugin-auth/client/components/SignInButton.js @@ -16,7 +16,7 @@ const SignInButton = ({loggedIn, showSignInDialog}) => ( ); const mapStateToProps = ({auth}) => ({ - loggedIn: auth.toJS().loggedIn + loggedIn: auth.loggedIn }); const mapDispatchToProps = (dispatch) => diff --git a/plugins/talk-plugin-auth/client/components/SignInContainer.js b/plugins/talk-plugin-auth/client/components/SignInContainer.js index 6950f4124..188651186 100644 --- a/plugins/talk-plugin-auth/client/components/SignInContainer.js +++ b/plugins/talk-plugin-auth/client/components/SignInContainer.js @@ -176,7 +176,7 @@ class SignInContainer extends React.Component { } const mapStateToProps = (state) => ({ - auth: state.auth.toJS() + auth: state.auth }); const mapDispatchToProps = (dispatch) => diff --git a/plugins/talk-plugin-auth/client/components/UserBox.js b/plugins/talk-plugin-auth/client/components/UserBox.js index 5b79b664a..61540d3c5 100644 --- a/plugins/talk-plugin-auth/client/components/UserBox.js +++ b/plugins/talk-plugin-auth/client/components/UserBox.js @@ -22,8 +22,8 @@ const UserBox = ({loggedIn, user, logout, onShowProfile}) => ( ); const mapStateToProps = ({auth}) => ({ - loggedIn: auth.toJS().loggedIn, - user: auth.toJS().user + loggedIn: auth.loggedIn, + user: auth.user }); const mapDispatchToProps = (dispatch) => From 2e8863285dc9f108222d2df66c1255246bb48712 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 14 Aug 2017 16:49:00 +0700 Subject: [PATCH 20/25] Rm immutable-js from admin --- client/coral-admin/src/actions/assets.js | 2 +- client/coral-admin/src/actions/install.js | 6 +- client/coral-admin/src/actions/settings.js | 2 +- client/coral-admin/src/containers/Layout.js | 6 +- .../coral-admin/src/containers/UserDetail.js | 4 +- client/coral-admin/src/reducers/assets.js | 51 ++++--- client/coral-admin/src/reducers/auth.js | 60 +++++--- client/coral-admin/src/reducers/community.js | 101 ++++++++------ client/coral-admin/src/reducers/config.js | 13 +- client/coral-admin/src/reducers/install.js | 131 +++++++++++------- client/coral-admin/src/reducers/moderation.js | 45 ++++-- client/coral-admin/src/reducers/settings.js | 81 ++++++----- .../routes/Community/containers/Community.js | 4 +- .../src/routes/Community/containers/Table.js | 2 +- .../routes/Configure/containers/Configure.js | 4 +- .../routes/Dashboard/containers/Dashboard.js | 4 +- .../src/routes/Install/containers/Install.js | 2 +- .../Moderation/containers/Moderation.js | 6 +- .../src/routes/Stories/containers/Stories.js | 2 +- .../client/containers/ModSubscription.js | 2 +- 20 files changed, 316 insertions(+), 212 deletions(-) diff --git a/client/coral-admin/src/actions/assets.js b/client/coral-admin/src/actions/assets.js index 75bd2477d..b9ebe0ada 100644 --- a/client/coral-admin/src/actions/assets.js +++ b/client/coral-admin/src/actions/assets.js @@ -35,7 +35,7 @@ export const fetchAssets = (skip = '', limit = '', search = '', sort = '', filte // Update an asset state // Get comments to fill each of the three lists on the mod queue export const updateAssetState = (id, closedAt) => (dispatch) => { - dispatch({type: UPDATE_ASSET_STATE_REQUEST}); + dispatch({type: UPDATE_ASSET_STATE_REQUEST, id, closedAt}); return coralApi(`/assets/${id}/status`, {method: 'PUT', body: {closedAt}}) .then(() => dispatch({type: UPDATE_ASSET_STATE_SUCCESS})) .catch((error) => { diff --git a/client/coral-admin/src/actions/install.js b/client/coral-admin/src/actions/install.js index 33cefab63..6393c58dd 100644 --- a/client/coral-admin/src/actions/install.js +++ b/client/coral-admin/src/actions/install.js @@ -93,21 +93,21 @@ const validation = (formData, dispatch, next) => { }; export const submitSettings = () => (dispatch, getState) => { - const settingsFormData = getState().install.toJS().data.settings; + const settingsFormData = getState().install.data.settings; validation(settingsFormData, dispatch, function() { dispatch(nextStep()); }); }; export const submitUser = () => (dispatch, getState) => { - const userFormData = getState().install.toJS().data.user; + const userFormData = getState().install.data.user; validation(userFormData, dispatch, function() { dispatch(nextStep()); }); }; export const finishInstall = () => (dispatch, getState) => { - const data = getState().install.toJS().data; + const data = getState().install.data; dispatch(installRequest()); return coralApi('/setup', {method: 'POST', body: data}) .then(() => { diff --git a/client/coral-admin/src/actions/settings.js b/client/coral-admin/src/actions/settings.js index ba8b917ea..ca9062b9e 100644 --- a/client/coral-admin/src/actions/settings.js +++ b/client/coral-admin/src/actions/settings.js @@ -42,7 +42,7 @@ export const updateDomainlist = (listName, list) => { }; export const saveSettingsToServer = () => (dispatch, getState) => { - let settings = getState().settings.toJS(); + let settings = getState().settings; if (settings.charCount) { settings.charCount = parseInt(settings.charCount); } diff --git a/client/coral-admin/src/containers/Layout.js b/client/coral-admin/src/containers/Layout.js index 8b119fb72..ae022f2ef 100644 --- a/client/coral-admin/src/containers/Layout.js +++ b/client/coral-admin/src/containers/Layout.js @@ -74,10 +74,8 @@ class LayoutContainer extends Component { } const mapStateToProps = (state) => ({ - auth: state.auth.toJS(), - TALK_RECAPTCHA_PUBLIC: state.config - .get('data') - .get('TALK_RECAPTCHA_PUBLIC', null) + auth: state.auth, + TALK_RECAPTCHA_PUBLIC: state.config.data.TALK_RECAPTCHA_PUBLIC, }); const mapDispatchToProps = (dispatch) => ({ diff --git a/client/coral-admin/src/containers/UserDetail.js b/client/coral-admin/src/containers/UserDetail.js index e59629a85..2ae6e4c9c 100644 --- a/client/coral-admin/src/containers/UserDetail.js +++ b/client/coral-admin/src/containers/UserDetail.js @@ -169,8 +169,8 @@ const mapStateToProps = (state) => ({ selectedCommentIds: state.userDetail.selectedCommentIds, statuses: state.userDetail.statuses, activeTab: state.userDetail.activeTab, - bannedWords: state.settings.toJS().wordlist.banned, - suspectWords: state.settings.toJS().wordlist.suspect, + bannedWords: state.settings.wordlist.banned, + suspectWords: state.settings.wordlist.suspect, }); const mapDispatchToProps = (dispatch) => ({ diff --git a/client/coral-admin/src/reducers/assets.js b/client/coral-admin/src/reducers/assets.js index 03f0be9bb..bb8751973 100644 --- a/client/coral-admin/src/reducers/assets.js +++ b/client/coral-admin/src/reducers/assets.js @@ -1,35 +1,40 @@ -import {Map, List, fromJS} from 'immutable'; import * as actions from '../constants/assets'; +import update from 'immutability-helper'; -const initialState = Map({ - byId: Map(), - ids: List(), - assets: List() -}); +const initialState = { + byId: {}, + ids: [], + assets: [] +}; export default function assets (state = initialState, action) { switch (action.type) { - case actions.FETCH_ASSETS_SUCCESS: - return replaceAssets(action, state); + case actions.FETCH_ASSETS_SUCCESS: { + const assets = action.assets.reduce((prev, curr) => { + prev[curr.id] = curr; + return prev; + }, {}); + + return update(state, { + byId: {$set: assets}, + count: {$set: action.count}, + ids: {$set: Object.keys(assets)}, + }); + } case actions.UPDATE_ASSET_STATE_REQUEST: - return state - .setIn(['byId', action.id, 'closedAt'], action.closedAt); + return update(state, { + byId: { + [action.id]: { + closedAt: {$set: action.closedAt}, + }, + }, + }); case actions.UPDATE_ASSETS: - return state - .set('assets', List(action.assets)); + return update(state, { + assets: {$set: action.assets}, + }); default: return state; } } -const replaceAssets = (action, state) => { - const assets = fromJS(action.assets.reduce((prev, curr) => { - prev[curr.id] = curr; - return prev; - }, {})); - - return state - .set('byId', assets) - .set('count', action.count) - .set('ids', List(assets.keys())); -}; diff --git a/client/coral-admin/src/reducers/auth.js b/client/coral-admin/src/reducers/auth.js index a60d73cec..a9c7f520e 100644 --- a/client/coral-admin/src/reducers/auth.js +++ b/client/coral-admin/src/reducers/auth.js @@ -1,43 +1,63 @@ -import {Map} from 'immutable'; import * as actions from '../constants/auth'; -const initialState = Map({ +const initialState = { loggedIn: false, user: null, loginError: null, loginMaxExceeded: false, passwordRequestSuccess: null -}); +}; export default function auth (state = initialState, action) { switch (action.type) { case actions.CHECK_LOGIN_REQUEST: - return state - .set('loadingUser', true); + return { + ...state, + loadingUser: true, + }; case actions.CHECK_LOGIN_FAILURE: - return state - .set('loggedIn', false) - .set('loadingUser', false) - .set('user', null); + return { + ...state, + loggedIn: false, + loadingUser: false, + user: null, + }; case actions.CHECK_LOGIN_SUCCESS: - return state - .set('loggedIn', true) - .set('loadingUser', false) - .set('user', action.user); + return { + ...state, + loggedIn: true, + loadingUser: false, + user: action.user, + }; case actions.LOGOUT: return initialState; case actions.LOGIN_SUCCESS: - return state.set('loginMaxExceeded', false).set('loginError', null); + return { + ...state, + loginMaxExceeded: false, + loginError: null, + }; case actions.LOGIN_FAILURE: - return state.set('loginError', action.message); + return { + ...state, + loginError: action.message, + }; case actions.FETCH_FORGOT_PASSWORD_REQUEST: - return state.set('passwordRequestSuccess', null); + return { + ...state, + passwordRequestSuccess: null, + }; case actions.FETCH_FORGOT_PASSWORD_SUCCESS: - return state.set('passwordRequestSuccess', 'If you have a registered account, a password reset link was sent to that email.'); + return { + ...state, + passwordRequestSuccess: 'If you have a registered account, a password reset link was sent to that email.', + }; case actions.LOGIN_MAXIMUM_EXCEEDED: - return state - .set('loginMaxExceeded', true) - .set('loginError', action.message); + return { + ...state, + loginMaxExceeded: true, + loginError: action.message, + }; default : return state; } diff --git a/client/coral-admin/src/reducers/community.js b/client/coral-admin/src/reducers/community.js index 3fba504f8..9f724c8d6 100644 --- a/client/coral-admin/src/reducers/community.js +++ b/client/coral-admin/src/reducers/community.js @@ -1,5 +1,3 @@ -import {Map} from 'immutable'; - import { FETCH_COMMENTERS_REQUEST, FETCH_COMMENTERS_FAILURE, @@ -13,8 +11,8 @@ import { HIDE_REJECT_USERNAME_DIALOG } from '../constants/community'; -const initialState = Map({ - community: Map(), +const initialState = { + community: {}, isFetchingPeople: false, errorPeople: '', accounts: [], @@ -22,72 +20,87 @@ const initialState = Map({ ascPeople: false, totalPagesPeople: 0, pagePeople: 0, - user: Map({}), + user: {}, banDialog: false, rejectUsernameDialog: false -}); +}; export default function community (state = initialState, action) { switch (action.type) { case FETCH_COMMENTERS_REQUEST : - return state - .set('isFetchingPeople', true); + return { + ...state, + isFetchingPeople: true, + }; case FETCH_COMMENTERS_FAILURE : - return state - .set('isFetchingPeople', false) - .set('errorPeople', action.error); - + return { + ...state, + isFetchingPeople: false, + errorPeople: action.error, + }; case FETCH_COMMENTERS_SUCCESS : { const {accounts, type, page, count, limit, totalPages, ...rest} = action; // eslint-disable-line - return state - .merge({ - isFetchingPeople: false, - errorPeople: '', - pagePeople: page, - countPeople: count, - limitPeople: limit, - totalPagesPeople: totalPages, - ...rest - }) - .set('accounts', accounts); // Sets to normal array + return { + ...state, + isFetchingPeople: false, + errorPeople: '', + pagePeople: page, + countPeople: count, + limitPeople: limit, + totalPagesPeople: totalPages, + ...rest, + accounts, // Sets to normal array + }; } case SET_ROLE : { - const commenters = state.get('accounts'); + const commenters = state.accounts; const idx = commenters.findIndex((el) => el.id === action.id); commenters[idx].roles[0] = action.role; - return state.set('accounts', commenters.map((id) => id)); + return { + ...state, + accounts: commenters.map((id) => id), + }; } case SET_COMMENTER_STATUS: { - const commenters = state.get('accounts'); + const commenters = state.accounts; const idx = commenters.findIndex((el) => el.id === action.id); commenters[idx].status = action.status; - return state.set('accounts', commenters.map((id) => id)); + return { + ...state, + accounts: commenters.map((id) => id), + }; } case SORT_UPDATE : - return state - .set('fieldPeople', action.sort.field) - .set('ascPeople', !state.get('ascPeople')); + return { + ...state, + fieldPeople: action.sort.field, + ascPeople: !state.ascPeople, + }; case HIDE_BANUSER_DIALOG: - return state - .set('banDialog', false); + return { + ...state, + banDialog: false, + }; case SHOW_BANUSER_DIALOG: - return state - .merge({ - user: Map(action.user), - banDialog: true - }); + return { + ...state, + user: action.user, + banDialog: true, + }; case HIDE_REJECT_USERNAME_DIALOG: - return state - .set('rejectUsernameDialog', false); + return { + ...state, + rejectUsernameDialog: false, + }; case SHOW_REJECT_USERNAME_DIALOG: - return state - .merge({ - user: Map(action.user), - rejectUsernameDialog: true - }); + return { + ...state, + user: action.user, + rejectUsernameDialog: true + }; default : return state; } diff --git a/client/coral-admin/src/reducers/config.js b/client/coral-admin/src/reducers/config.js index a5d11d6eb..310a198ed 100644 --- a/client/coral-admin/src/reducers/config.js +++ b/client/coral-admin/src/reducers/config.js @@ -1,15 +1,16 @@ -import {Map} from 'immutable'; - import * as actions from '../actions/config'; -const initialState = Map({ - data: Map({}) -}); +const initialState = { + data: {} +}; export default function config (state = initialState, action) { switch (action.type) { case actions.CONFIG_UPDATED: - return state.set('data', Map(action.data)); + return { + ...state, + data: action.data, + }; default: return state; } diff --git a/client/coral-admin/src/reducers/install.js b/client/coral-admin/src/reducers/install.js index 1f0f079ff..c6e85c69f 100644 --- a/client/coral-admin/src/reducers/install.js +++ b/client/coral-admin/src/reducers/install.js @@ -1,30 +1,29 @@ -import {Map, List} from 'immutable'; - import * as actions from '../constants/install'; +import update from 'immutability-helper'; -const initialState = Map({ +const initialState = { isLoading: false, - data: Map({ - settings: Map({ + data: { + settings: { organizationName: '', - domains: Map({ - whitelist: List() - }) - }), - user: Map({ + domains: { + whitelist: [], + } + }, + user: { username: '', email: '', password: '', confirmPassword: '' - }) - }), - errors: Map({ + } + }, + errors: { organizationName: '', username: '', email: '', password: '', confirmPassword: '' - }), + }, showErrors: false, hasError: false, error: null, @@ -44,57 +43,91 @@ const initialState = Map({ installRequest: null, installRequestError: null, alreadyInstalled: false -}); +}; export default function install (state = initialState, action) { switch (action.type) { case actions.NEXT_STEP: - return state - .set('step', state.get('step') + 1); + return { + ...state, + step: state.step + 1, + }; case actions.PREVIOUS_STEP: - return state - .set('step', state.get('step') - 1); + return { + ...state, + step: state.step - 1, + }; case actions.GO_TO_STEP: - return state - .set('step', action.step); + return { + ...state, + step: action.step, + }; case actions.UPDATE_PERMITTED_DOMAINS_SETTINGS: - return state - .setIn(['data', 'settings', 'domains', 'whitelist'], action.value); + return update(state, { + data: { + settings: { + domains: { + whitelist: {$set: action.value}, + }, + }, + }, + }); case actions.UPDATE_FORMDATA_SETTINGS: - return state - .setIn(['data', 'settings', action.name], action.value); + return update(state, { + data: { + settings: { + [action.name]: {$set: action.value}, + }, + }, + }); case actions.UPDATE_FORMDATA_USER: - return state - .setIn(['data', 'user', action.name], action.value); + return update(state, { + data: { + user: { + [action.name]: {$set: action.value}, + }, + }, + }); case actions.HAS_ERROR: - return state - .merge({ - hasError: true, - showErrors: true - }); + return { + ...state, + hasError: true, + showErrors: true, + }; case actions.ADD_ERROR: - return state - .setIn(['errors', action.name], action.error); + return update(state, { + errors: { + [action.name]: {$set: action.error}, + }, + }); case actions.CLEAR_ERRORS: - return state - .set('errors', Map()); + return { + ...state, + errors: {}, + }; case actions.INSTALL_REQUEST: - return state - .set('isLoading', true); + return { + ...state, + isLoading: true, + }; case actions.INSTALL_SUCCESS: - return state - .set('isLoading', false) - .set('installRequest', 'SUCCESS'); + return { + ...state, + isLoading: false, + installRequest: 'SUCCESS', + }; case actions.INSTALL_FAILURE: - return state - .merge({ - isLoading: false, - installRequest: 'FAILURE', - installRequestError: action.error - }); + return { + ...state, + isLoading: false, + installRequest: 'FAILURE', + installRequestError: action.error + }; case actions.CHECK_INSTALL_SUCCESS: - return state - .set('alreadyInstalled', action.installed); + return { + ...state, + alreadyInstalled: action.installed, + }; default : return state; } diff --git a/client/coral-admin/src/reducers/moderation.js b/client/coral-admin/src/reducers/moderation.js index a0cba1f5f..e0a608488 100644 --- a/client/coral-admin/src/reducers/moderation.js +++ b/client/coral-admin/src/reducers/moderation.js @@ -1,37 +1,54 @@ -import {fromJS} from 'immutable'; import * as actions from '../constants/moderation'; -const initialState = fromJS({ +const initialState = { singleView: false, modalOpen: false, storySearchVisible: false, storySearchString: '', shortcutsNoteVisible: window.localStorage.getItem('coral:shortcutsNote') || 'show', sortOrder: 'REVERSE_CHRONOLOGICAL', -}); +}; export default function moderation (state = initialState, action) { switch (action.type) { case actions.MODERATION_CLEAR_STATE: return initialState; case actions.TOGGLE_MODAL: - return state - .set('modalOpen', action.open); + return { + ...state, + modalOpen: action.open, + }; case actions.SINGLE_VIEW: - return state - .set('singleView', !state.get('singleView')); + return { + ...state, + singleView: !state.singleView, + }; case actions.HIDE_SHORTCUTS_NOTE: - return state - .set('shortcutsNoteVisible', 'hide'); + return { + ...state, + shortcutsNoteVisible: 'hide', + }; case actions.SHOW_STORY_SEARCH: - return state.set('storySearchVisible', true); + return { + ...state, + storySearchVisible: true, + }; case actions.HIDE_STORY_SEARCH: - return state.set('storySearchVisible', false); + return { + ...state, + storySearchVisible: false, + }; case actions.STORY_SEARCH_CHANGE_VALUE: - return state.set('storySearchString', action.value); + return { + ...state, + storySearchString: action.value, + }; case actions.SET_SORT_ORDER: - return state.set('sortOrder', action.order); - default : + return { + ...state, + sortOrder: action.order, + }; + default: return state; } } diff --git a/client/coral-admin/src/reducers/settings.js b/client/coral-admin/src/reducers/settings.js index 67907b327..6e29ba719 100644 --- a/client/coral-admin/src/reducers/settings.js +++ b/client/coral-admin/src/reducers/settings.js @@ -1,5 +1,5 @@ -import {Map, List} from 'immutable'; import * as actions from '../actions/settings'; +import update from 'immutability-helper'; // this is initialized here because // currently you have to reload the dashboard to get new stats @@ -10,63 +10,80 @@ const DASHBOARD_WINDOW_MINUTES = 5; let then = new Date(); then.setMinutes(then.getMinutes() - DASHBOARD_WINDOW_MINUTES); -const initialState = Map({ - wordlist: Map({ - banned: List(), - suspect: List() - }), +const initialState = { + wordlist: { + banned: [], + suspect: [] + }, dashboardWindowStart: then.toISOString(), dashboardWindowEnd: new Date().toISOString(), - domains: Map({ - whitelist: List() - }), + domains: { + whitelist: [] + }, saveSettingsError: null, fetchSettingsError: null, fetchingSettings: false -}); +}; export default function settings (state = initialState, action) { switch (action.type) { case actions.SETTINGS_LOADING: - return state - .set('fetchingSettings', true) - .set('fetchSettingsError', null); + return { + ...state, + fetchingSettings: true, + fetchSettingsError: null, + }; case actions.SETTINGS_RECEIVED: - return state.merge({ + return { + ...state, fetchingSettings: false, fetchSettingsError: null, ...action.settings - }); + }; case actions.SETTINGS_FETCH_ERROR: - return state - .set('fetchingSettings', false) - .set('fetchSettingsError', action.error); + return { + ...state, + fetchingSettings: false, + fetchSettingsError: action.error, + }; case actions.SETTINGS_UPDATED: - return state.merge({ + return { + ...state, fetchingSettings: false, fetchSettingsError: null, ...action.settings - }); + }; case actions.SAVE_SETTINGS_LOADING: - return state - .set('fetchingSettings', true) - .set('saveSettingsError', null); + return { + ...state, + fetchingSettings: true, + saveSettingsError: null, + }; case actions.SAVE_SETTINGS_SUCCESS: - return state.merge({ + return { + ...state, fetchingSettings: false, fetchSettingsError: null, ...action.settings - }); + }; case actions.SAVE_SETTINGS_FAILED: - return state - .set('fetchingSettings', false) - .set('fetchSettingsError', action.error); + return { + ...state, + fetchingSettings: false, + fetchSettingsError: action.error, + }; case actions.WORDLIST_UPDATED: - return state - .setIn(['wordlist', action.listName], action.list); + return update(state, { + wordList: { + [action.listName]: {$set: action.list}, + } + }); case actions.DOMAINLIST_UPDATED: - return state - .setIn(['domains', action.listName], action.list); + return update(state, { + domains: { + [action.listName]: {$set: action.list}, + } + }); default: return state; } diff --git a/client/coral-admin/src/routes/Community/containers/Community.js b/client/coral-admin/src/routes/Community/containers/Community.js index a9a164ac9..b04fc0281 100644 --- a/client/coral-admin/src/routes/Community/containers/Community.js +++ b/client/coral-admin/src/routes/Community/containers/Community.js @@ -87,8 +87,8 @@ export const withCommunityQuery = withQuery(gql` }); const mapStateToProps = (state) => ({ - community: state.community.toJS(), - currentUser: state.auth.toJS().user, + community: state.community, + currentUser: state.auth.user, }); const mapDispatchToProps = (dispatch) => diff --git a/client/coral-admin/src/routes/Community/containers/Table.js b/client/coral-admin/src/routes/Community/containers/Table.js index 8bd5395e4..5d4e4914f 100644 --- a/client/coral-admin/src/routes/Community/containers/Table.js +++ b/client/coral-admin/src/routes/Community/containers/Table.js @@ -23,7 +23,7 @@ class TableContainer extends Component { } const mapStateToProps = (state) => ({ - commenters: state.community.get('accounts'), + commenters: state.community.accounts, }); const mapDispatchToProps = (dispatch) => diff --git a/client/coral-admin/src/routes/Configure/containers/Configure.js b/client/coral-admin/src/routes/Configure/containers/Configure.js index c68b39e0c..aff1e57b2 100644 --- a/client/coral-admin/src/routes/Configure/containers/Configure.js +++ b/client/coral-admin/src/routes/Configure/containers/Configure.js @@ -23,8 +23,8 @@ class ConfigureContainer extends Component { } const mapStateToProps = (state) => ({ - auth: state.auth.toJS(), - settings: state.settings.toJS() + auth: state.auth, + settings: state.settings }); const mapDispatchToProps = (dispatch) => diff --git a/client/coral-admin/src/routes/Dashboard/containers/Dashboard.js b/client/coral-admin/src/routes/Dashboard/containers/Dashboard.js index ea1fb2b6c..74faedcf7 100644 --- a/client/coral-admin/src/routes/Dashboard/containers/Dashboard.js +++ b/client/coral-admin/src/routes/Dashboard/containers/Dashboard.js @@ -54,8 +54,8 @@ export const witDashboardQuery = withQuery(gql` const mapStateToProps = (state) => { return { - settings: state.settings.toJS(), - moderation: state.moderation.toJS() + settings: state.settings, + moderation: state.moderation }; }; diff --git a/client/coral-admin/src/routes/Install/containers/Install.js b/client/coral-admin/src/routes/Install/containers/Install.js index 5dcb35705..442127e47 100644 --- a/client/coral-admin/src/routes/Install/containers/Install.js +++ b/client/coral-admin/src/routes/Install/containers/Install.js @@ -35,7 +35,7 @@ InstallContainer.contextTypes = { }; const mapStateToProps = (state) => ({ - install: state.install.toJS() + install: state.install }); const mapDispatchToProps = (dispatch) => diff --git a/client/coral-admin/src/routes/Moderation/containers/Moderation.js b/client/coral-admin/src/routes/Moderation/containers/Moderation.js index d7f62491d..d5ca5c840 100644 --- a/client/coral-admin/src/routes/Moderation/containers/Moderation.js +++ b/client/coral-admin/src/routes/Moderation/containers/Moderation.js @@ -376,9 +376,9 @@ const withQueueCountPolling = withQuery(gql` }); const mapStateToProps = (state) => ({ - moderation: state.moderation.toJS(), - settings: state.settings.toJS(), - auth: state.auth.toJS(), + moderation: state.moderation, + settings: state.settings, + auth: state.auth, }); const mapDispatchToProps = (dispatch) => ({ diff --git a/client/coral-admin/src/routes/Stories/containers/Stories.js b/client/coral-admin/src/routes/Stories/containers/Stories.js index 450efcf74..f645f310c 100644 --- a/client/coral-admin/src/routes/Stories/containers/Stories.js +++ b/client/coral-admin/src/routes/Stories/containers/Stories.js @@ -12,7 +12,7 @@ class StoriesContainer extends Component { } const mapStateToProps = (state) => ({ - assets: state.assets.toJS() + assets: state.assets }); const mapDispatchToProps = (dispatch) => diff --git a/plugins/talk-plugin-featured-comments/client/containers/ModSubscription.js b/plugins/talk-plugin-featured-comments/client/containers/ModSubscription.js index 85e0d8fe2..82f323530 100644 --- a/plugins/talk-plugin-featured-comments/client/containers/ModSubscription.js +++ b/plugins/talk-plugin-featured-comments/client/containers/ModSubscription.js @@ -91,7 +91,7 @@ const COMMENT_UNFEATURED_SUBSCRIPTION = gql` `; const mapStateToProps = (state) => ({ - user: state.auth.toJS().user, + user: state.auth.user, }); export default connect(mapStateToProps, null)(ModSubscription); From cdfef8c9896da81538fe321713c2bd1ee21b63cc Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 14 Aug 2017 16:56:51 +0700 Subject: [PATCH 21/25] Remove immutable --- package.json | 1 - yarn.lock | 17 +++-------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index bb0a724ac..a0a1efe17 100644 --- a/package.json +++ b/package.json @@ -180,7 +180,6 @@ "hammerjs": "^2.0.8", "history": "^3.0.0", "ignore-styles": "^5.0.1", - "immutable": "^3.8.1", "imports-loader": "^0.7.1", "istanbul": "^1.1.0-alpha.1", "jsdom": "^9.8.3", diff --git a/yarn.lock b/yarn.lock index a5d73a756..9244af84f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3996,11 +3996,11 @@ iconv-lite@0.4.13: version "0.4.13" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" -iconv-lite@0.4.15, iconv-lite@^0.4.5, iconv-lite@~0.4.13: +iconv-lite@0.4.15: version "0.4.15" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" -iconv-lite@^0.4.17: +iconv-lite@^0.4.17, iconv-lite@^0.4.5, iconv-lite@~0.4.13: version "0.4.18" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2" @@ -4034,10 +4034,6 @@ immutability-helper@^2.2.0: dependencies: invariant "^2.2.0" -immutable@^3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.1.tgz#200807f11ab0f72710ea485542de088075f68cd2" - imports-loader@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/imports-loader/-/imports-loader-0.7.1.tgz#f204b5f34702a32c1db7d48d89d5e867a0441253" @@ -7869,14 +7865,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^3.0.0" - -string-width@^2.1.0: +string-width@^2.0.0, string-width@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: From 06cf33521fb26ae4e6ba9b6fdf5eb2a858161b8f Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 14 Aug 2017 19:40:52 +0700 Subject: [PATCH 22/25] Remove immutable-js traces from docs --- docs/_docs/03-05-client-architecture.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/docs/_docs/03-05-client-architecture.md b/docs/_docs/03-05-client-architecture.md index 6bb44bfad..6996811c5 100644 --- a/docs/_docs/03-05-client-architecture.md +++ b/docs/_docs/03-05-client-architecture.md @@ -6,7 +6,6 @@ permalink: /docs/architecture/client ## The Stack - [React](#react) - [Redux](#redux) - - [ImmutableJS](#immutablejs) ## The Architecture @@ -96,14 +95,6 @@ We use [Apollo](http://www.apollodata.com/) to handle graph requests and handle ## Redux We use [Redux](http://redux.js.org/) to handle the auth state. - -## ImmutableJS -We use Immutable JS to maintain our state immutable. -We found some really good tradeoffs while building Talk. - -[How to use ImmutableJS and how we use it with Talk](https://facebook.github.io/immutable-js/docs/#/) - - ## Test [How we do testing at Coral with Talk]({{ "/docs/development/tools" | absolute_url }}) From abda77a7e725fe4fa2a304527d51ec21994a7fb3 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 14 Aug 2017 19:55:04 +0700 Subject: [PATCH 23/25] Fix console error in offtopic --- .../talk-plugin-offtopic/client/components/OffTopicFilter.js | 1 - .../talk-plugin-offtopic/client/containers/OffTopicFilter.js | 4 ---- 2 files changed, 5 deletions(-) diff --git a/plugins/talk-plugin-offtopic/client/components/OffTopicFilter.js b/plugins/talk-plugin-offtopic/client/components/OffTopicFilter.js index 171bafeb2..426dea29a 100644 --- a/plugins/talk-plugin-offtopic/client/components/OffTopicFilter.js +++ b/plugins/talk-plugin-offtopic/client/components/OffTopicFilter.js @@ -16,7 +16,6 @@ export default class OffTopicFilter extends React.Component { this.props.removeCommentClassName(idx); this.props.toggleCheckbox(); } - this.props.closeViewingOptions(); } render() { diff --git a/plugins/talk-plugin-offtopic/client/containers/OffTopicFilter.js b/plugins/talk-plugin-offtopic/client/containers/OffTopicFilter.js index 9548b764e..7eab8c526 100644 --- a/plugins/talk-plugin-offtopic/client/containers/OffTopicFilter.js +++ b/plugins/talk-plugin-offtopic/client/containers/OffTopicFilter.js @@ -3,9 +3,6 @@ import {bindActionCreators} from 'redux'; import {toggleCheckbox} from '../actions'; import {commentClassNamesSelector} from 'plugin-api/alpha/client/selectors'; import OffTopicFilter from '../components/OffTopicFilter'; -import { - closeViewingOptions -} from 'plugins/talk-plugin-viewing-options/client/actions'; import { addCommentClassName, removeCommentClassName @@ -20,7 +17,6 @@ const mapDispatchToProps = (dispatch) => bindActionCreators( { toggleCheckbox, - closeViewingOptions, addCommentClassName, removeCommentClassName }, From c52a97338c7ad05e1ea115436bf0d39624619842 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 14 Aug 2017 21:25:48 +0700 Subject: [PATCH 24/25] Fix FakeComment styles --- .../client/components/CreateUsernameDialog.js | 2 +- .../client/components/FakeComment.css | 37 ++++++++++ .../client/components/FakeComment.js | 72 +++++++------------ 3 files changed, 63 insertions(+), 48 deletions(-) create mode 100644 plugins/talk-plugin-auth/client/components/FakeComment.css diff --git a/plugins/talk-plugin-auth/client/components/CreateUsernameDialog.js b/plugins/talk-plugin-auth/client/components/CreateUsernameDialog.js index 12916b4dd..4b0babed6 100644 --- a/plugins/talk-plugin-auth/client/components/CreateUsernameDialog.js +++ b/plugins/talk-plugin-auth/client/components/CreateUsernameDialog.js @@ -32,7 +32,7 @@ const CreateUsernameDialog = ({ className={styles.fakeComment} username={formData.username} created_at={Date.now()} - comment={{body:t('createdisplay.fake_comment_body')}} + body={t('createdisplay.fake_comment_body')} />

{t('createdisplay.if_you_dont_change_your_name')} diff --git a/plugins/talk-plugin-auth/client/components/FakeComment.css b/plugins/talk-plugin-auth/client/components/FakeComment.css new file mode 100644 index 000000000..8b5521aea --- /dev/null +++ b/plugins/talk-plugin-auth/client/components/FakeComment.css @@ -0,0 +1,37 @@ +.root { + border-top: 1px solid rgba(0, 0, 0, 0.1); + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + margin-bottom: 10px; + padding: 8px 0px 10px 0px; + position: relative; +} + +.body { + +} + +.footer { + display: flex; + justify-content: space-between; +} + +.button { + color: #2a2a2a; + margin: 5px 10px 5px 0px; + background: none; + padding: 0px; + border: none; + font-size: inherit; + vertical-align: middle; + + &:hover { + color: #767676; + cursor: pointer; + } +} + +.icon { + font-size: 12px; + padding: 0 2px 0 5px; + vertical-align: middle; +} diff --git a/plugins/talk-plugin-auth/client/components/FakeComment.js b/plugins/talk-plugin-auth/client/components/FakeComment.js index b6b4e7609..eefada587 100644 --- a/plugins/talk-plugin-auth/client/components/FakeComment.js +++ b/plugins/talk-plugin-auth/client/components/FakeComment.js @@ -2,65 +2,43 @@ import React from 'react'; import t from 'coral-framework/services/i18n'; import {ReplyButton} from 'talk-plugin-replies'; import PubDate from 'talk-plugin-pubdate/PubDate'; -import Slot from 'coral-framework/components/Slot'; import AuthorName from 'talk-plugin-author-name/AuthorName'; -import styles from 'coral-embed-stream/src/components/Comment.css'; +import styles from './FakeComment.css'; +import {Icon} from 'plugin-api/beta/client/components/ui'; -export const FakeComment = ({username, created_at, comment}) => ( -

-
- +export const FakeComment = ({username, created_at, body}) => ( +
+ - -
-
- + {}} + parentCommentId={'commentID'} + currentUserId={{}} + />
- {}} - parentCommentId={'commentID'} - currentUserId={{}} - /> -
-
-
- -
-
-
From db37a0b38ef3226ee34be491eb2622e65b0646b0 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 15 Aug 2017 16:43:44 +0700 Subject: [PATCH 25/25] Check existance of featuredComments in query --- plugins/talk-plugin-featured-comments/client/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/talk-plugin-featured-comments/client/index.js b/plugins/talk-plugin-featured-comments/client/index.js index 82cba8b91..ad10f87ca 100644 --- a/plugins/talk-plugin-featured-comments/client/index.js +++ b/plugins/talk-plugin-featured-comments/client/index.js @@ -26,6 +26,9 @@ export default { IgnoreUser: ({variables}) => ({ updateQueries: { CoralEmbedStream_Embed: (previous) => { + if (!previous.asset.featuredComments) { + return previous; + } const ignoredUserId = variables.id; const newNodes = previous.asset.featuredComments.nodes.filter((n) => n.user.id !== ignoredUserId); const removedCount = previous.asset.featuredComments.nodes.length - newNodes.length;