From da2f1fda15d2a90db287ec061efdb08d15486603 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Thu, 24 Mar 2016 17:39:55 +0530 Subject: [PATCH 01/44] FIX: increase read_timeout when downloading avatar --- app/controllers/user_avatars_controller.rb | 2 +- lib/file_helper.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/user_avatars_controller.rb b/app/controllers/user_avatars_controller.rb index 3b57d0578db..a3469105438 100644 --- a/app/controllers/user_avatars_controller.rb +++ b/app/controllers/user_avatars_controller.rb @@ -129,7 +129,7 @@ class UserAvatarsController < ApplicationController unless File.exist? path FileUtils.mkdir_p PROXY_PATH - tmp = FileHelper.download(url, 1.megabyte, filename, true) + tmp = FileHelper.download(url, 1.megabyte, filename, true, 10) FileUtils.mv tmp.path, path end diff --git a/lib/file_helper.rb b/lib/file_helper.rb index 015833bba88..ecf966a5fdd 100644 --- a/lib/file_helper.rb +++ b/lib/file_helper.rb @@ -6,7 +6,7 @@ class FileHelper filename =~ images_regexp end - def self.download(url, max_file_size, tmp_file_name, follow_redirect=false) + def self.download(url, max_file_size, tmp_file_name, follow_redirect=false, read_timeout=5) raise Discourse::InvalidParameters.new(:url) unless url =~ /^https?:\/\// uri = parse_url(url) @@ -14,7 +14,7 @@ class FileHelper tmp = Tempfile.new([tmp_file_name, extension]) File.open(tmp.path, "wb") do |f| - downloaded = uri.open("rb", read_timeout: 5, redirect: follow_redirect, allow_redirections: :all) + downloaded = uri.open("rb", read_timeout: read_timeout, redirect: follow_redirect, allow_redirections: :all) while f.size <= max_file_size && data = downloaded.read(512.kilobytes) f.write(data) end From b270e0142b01ec4e1bca06eec3d1098172ab0327 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 24 Mar 2016 11:12:38 -0400 Subject: [PATCH 02/44] FIX: If site settings are missing don't do anything --- config/initializers/100-logster.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/initializers/100-logster.rb b/config/initializers/100-logster.rb index ada7b9dd08e..5748c30ae07 100644 --- a/config/initializers/100-logster.rb +++ b/config/initializers/100-logster.rb @@ -64,7 +64,7 @@ store.redis_raw_connection = redis.without_namespace severities = [Logger::WARN, Logger::ERROR, Logger::FATAL, Logger::UNKNOWN] RailsMultisite::ConnectionManagement.each_connection do - error_rate_per_minute = SiteSetting.alert_admins_if_errors_per_minute + error_rate_per_minute = SiteSetting.alert_admins_if_errors_per_minute rescue 0 if error_rate_per_minute > 0 store.register_rate_limit_per_minute(severities, error_rate_per_minute) do |rate| @@ -72,7 +72,7 @@ RailsMultisite::ConnectionManagement.each_connection do end end - error_rate_per_hour = SiteSetting.alert_admins_if_errors_per_hour + error_rate_per_hour = SiteSetting.alert_admins_if_errors_per_hour rescue 0 if error_rate_per_hour > 0 store.register_rate_limit_per_hour(severities, error_rate_per_hour) do |rate| From e407ef9d0e595bdd2ff2c11dcd9329ea9f96f6ec Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 24 Mar 2016 11:14:17 -0400 Subject: [PATCH 03/44] FIX: Also support `nil` values for the site settings --- config/initializers/100-logster.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/initializers/100-logster.rb b/config/initializers/100-logster.rb index 5748c30ae07..e237d6aa75e 100644 --- a/config/initializers/100-logster.rb +++ b/config/initializers/100-logster.rb @@ -66,7 +66,7 @@ severities = [Logger::WARN, Logger::ERROR, Logger::FATAL, Logger::UNKNOWN] RailsMultisite::ConnectionManagement.each_connection do error_rate_per_minute = SiteSetting.alert_admins_if_errors_per_minute rescue 0 - if error_rate_per_minute > 0 + if (error_rate_per_minute || 0) > 0 store.register_rate_limit_per_minute(severities, error_rate_per_minute) do |rate| MessageBus.publish("/logs_error_rate_exceeded", { rate: rate, duration: 'minute' }) end @@ -74,7 +74,7 @@ RailsMultisite::ConnectionManagement.each_connection do error_rate_per_hour = SiteSetting.alert_admins_if_errors_per_hour rescue 0 - if error_rate_per_hour > 0 + if (error_rate_per_hour || 0) > 0 store.register_rate_limit_per_hour(severities, error_rate_per_hour) do |rate| MessageBus.publish("/logs_error_rate_exceeded", { rate: rate, duration: 'hour' }) end From 476a5fd43c64542d5157faf1e3e46cedec1771f1 Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Thu, 24 Mar 2016 13:21:57 -0400 Subject: [PATCH 04/44] FIX: unhandled extensions like .php on static routes will show the usual not found page --- config/routes.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index 80a1533d4d3..0e75b73ed9c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -252,15 +252,15 @@ Discourse::Application.routes.draw do end resources :static - post "login" => "static#enter" - get "login" => "static#show", id: "login" - get "password-reset" => "static#show", id: "password_reset" - get "faq" => "static#show", id: "faq" - get "guidelines" => "static#show", id: "guidelines", as: 'guidelines' - get "tos" => "static#show", id: "tos", as: 'tos' - get "privacy" => "static#show", id: "privacy", as: 'privacy' - get "signup" => "static#show", id: "signup" - get "login-preferences" => "static#show", id: "login" + post "login" => "static#enter", constraints: { format: /(json|html)/ } + get "login" => "static#show", id: "login", constraints: { format: /(json|html)/ } + get "password-reset" => "static#show", id: "password_reset", constraints: { format: /(json|html)/ } + get "faq" => "static#show", id: "faq", constraints: { format: /(json|html)/ } + get "guidelines" => "static#show", id: "guidelines", as: 'guidelines', constraints: { format: /(json|html)/ } + get "tos" => "static#show", id: "tos", as: 'tos', constraints: { format: /(json|html)/ } + get "privacy" => "static#show", id: "privacy", as: 'privacy', constraints: { format: /(json|html)/ } + get "signup" => "static#show", id: "signup", constraints: { format: /(json|html)/ } + get "login-preferences" => "static#show", id: "login", constraints: { format: /(json|html)/ } get "users/admin-login" => "users#admin_login" put "users/admin-login" => "users#admin_login" From db15772ab1514e4d6bfa36259aae3ebd5771e331 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 24 Mar 2016 13:05:09 -0400 Subject: [PATCH 05/44] UX: Make user info rendering more consistent --- .../discourse/components/user-info.js.es6 | 23 ++++++++ .../discourse/components/user-small.js.es6 | 15 ----- .../discourse/controllers/badges/show.js.es6 | 12 +--- .../discourse/helpers/format-date.js.es6 | 2 + .../discourse/helpers/inline-date.js.es6 | 6 ++ .../discourse/models/user-badge.js.es6 | 7 +-- .../discourse/routes/badges-show.js.es6 | 8 +-- .../javascripts/discourse/templates/about.hbs | 8 +-- .../discourse/templates/badges/show.hbs | 37 +++---------- .../{user-small.hbs => user-info.hbs} | 7 +++ .../discourse/templates/group/members.hbs | 2 +- .../discourse/templates/mobile/users.hbs | 2 +- .../javascripts/discourse/templates/users.hbs | 2 +- .../stylesheets/common/base/directory.scss | 4 ++ .../stylesheets/common/base/user-badges.scss | 55 ++----------------- app/assets/stylesheets/common/base/user.scss | 27 ++++++++- app/assets/stylesheets/mobile/user.scss | 2 +- config/locales/client.en.yml | 3 +- test/javascripts/acceptance/about-test.js.es6 | 4 +- 19 files changed, 98 insertions(+), 128 deletions(-) create mode 100644 app/assets/javascripts/discourse/components/user-info.js.es6 delete mode 100644 app/assets/javascripts/discourse/components/user-small.js.es6 create mode 100644 app/assets/javascripts/discourse/helpers/inline-date.js.es6 rename app/assets/javascripts/discourse/templates/components/{user-small.hbs => user-info.hbs} (84%) diff --git a/app/assets/javascripts/discourse/components/user-info.js.es6 b/app/assets/javascripts/discourse/components/user-info.js.es6 new file mode 100644 index 00000000000..05dde9fffea --- /dev/null +++ b/app/assets/javascripts/discourse/components/user-info.js.es6 @@ -0,0 +1,23 @@ +import { url } from 'discourse/lib/computed'; +import computed from 'ember-addons/ember-computed-decorators'; + +function normalize(name) { + return name.replace(/[\-\_ \.]/g, '').toLowerCase(); +} + +export default Ember.Component.extend({ + classNameBindings: [':user-info', 'size'], + size: 'small', + userPath: url('user.username', '/users/%@'), + + // TODO: In later ember releases `hasBlock` works without this + hasBlock: Ember.computed.alias('template'), + + @computed('user.name', 'user.username') + name(name, username) { + if (name && normalize(username) !== normalize(name)) { + return name; + } + } + +}); diff --git a/app/assets/javascripts/discourse/components/user-small.js.es6 b/app/assets/javascripts/discourse/components/user-small.js.es6 deleted file mode 100644 index 9dc06993815..00000000000 --- a/app/assets/javascripts/discourse/components/user-small.js.es6 +++ /dev/null @@ -1,15 +0,0 @@ -import { url } from 'discourse/lib/computed'; - -export default Ember.Component.extend({ - classNames: ['user-small'], - - userPath: url('user.username', '/users/%@'), - - name: function() { - const name = this.get('user.name'); - if (name && this.get('user.username') !== name) { - return name; - } - }.property('user.name') - -}); diff --git a/app/assets/javascripts/discourse/controllers/badges/show.js.es6 b/app/assets/javascripts/discourse/controllers/badges/show.js.es6 index ad83dd80319..54be27a6651 100644 --- a/app/assets/javascripts/discourse/controllers/badges/show.js.es6 +++ b/app/assets/javascripts/discourse/controllers/badges/show.js.es6 @@ -6,7 +6,7 @@ export default Ember.Controller.extend({ userBadges: null, needs: ["application"], - user: function(){ + user: function() { if (this.get("username")) { return this.get('userBadges')[0].get('user'); } @@ -37,16 +37,6 @@ export default Ember.Controller.extend({ } }, - layoutClass: function(){ - var user = this.get("user") ? " single-user" : ""; - var ub = this.get("userBadges"); - if(ub && ub[0] && ub[0].post_id){ - return "user-badge-with-posts" + user; - } else { - return "user-badge-no-posts" + user; - } - }.property("userBadges"), - canLoadMore: function() { if (this.get('noMoreBadges')) { return false; } diff --git a/app/assets/javascripts/discourse/helpers/format-date.js.es6 b/app/assets/javascripts/discourse/helpers/format-date.js.es6 index 7c68a517225..1937c441991 100644 --- a/app/assets/javascripts/discourse/helpers/format-date.js.es6 +++ b/app/assets/javascripts/discourse/helpers/format-date.js.es6 @@ -25,3 +25,5 @@ registerUnbound('format-date', function(val, params) { return new Handlebars.SafeString(autoUpdatingRelativeAge(date, {format: format, title: title, leaveAgo: leaveAgo})); } }); + + diff --git a/app/assets/javascripts/discourse/helpers/inline-date.js.es6 b/app/assets/javascripts/discourse/helpers/inline-date.js.es6 new file mode 100644 index 00000000000..874434fd3c9 --- /dev/null +++ b/app/assets/javascripts/discourse/helpers/inline-date.js.es6 @@ -0,0 +1,6 @@ +import { relativeAge } from 'discourse/lib/formatter'; + +export default function(dt, params) { + dt = params.data.view.getStream(dt).value(); + return relativeAge(new Date(dt)); +} diff --git a/app/assets/javascripts/discourse/models/user-badge.js.es6 b/app/assets/javascripts/discourse/models/user-badge.js.es6 index a99c997d631..bc257aafc81 100644 --- a/app/assets/javascripts/discourse/models/user-badge.js.es6 +++ b/app/assets/javascripts/discourse/models/user-badge.js.es6 @@ -6,13 +6,8 @@ const UserBadge = Discourse.Model.extend({ return "/t/-/" + this.get('topic_id') + "/" + this.get('post_number'); } }.property(), // avoid the extra bindings for now - /** - Revoke this badge. - @method revoke - @returns {Promise} a promise that resolves when the badge has been revoked. - **/ - revoke: function() { + revoke() { return Discourse.ajax("/user_badges/" + this.get('id'), { type: "DELETE" }); diff --git a/app/assets/javascripts/discourse/routes/badges-show.js.es6 b/app/assets/javascripts/discourse/routes/badges-show.js.es6 index 74e04c64404..544d6cfdd85 100644 --- a/app/assets/javascripts/discourse/routes/badges-show.js.es6 +++ b/app/assets/javascripts/discourse/routes/badges-show.js.es6 @@ -15,10 +15,7 @@ export default Discourse.Route.extend({ }, serialize(model) { - return { - id: model.get("id"), - slug: model.get("slug") - }; + return model.getProperties('id', 'slug'); }, model(params) { @@ -29,13 +26,12 @@ export default Discourse.Route.extend({ } }, - afterModel(model,transition) { + afterModel(model, transition) { const username = transition.queryParams && transition.queryParams.username; return UserBadge.findByBadgeId(model.get("id"), {username}).then(userBadges => { this.userBadges = userBadges; }); - }, titleToken() { diff --git a/app/assets/javascripts/discourse/templates/about.hbs b/app/assets/javascripts/discourse/templates/about.hbs index ca3f050ffe0..3d8f993ba08 100644 --- a/app/assets/javascripts/discourse/templates/about.hbs +++ b/app/assets/javascripts/discourse/templates/about.hbs @@ -22,8 +22,8 @@

{{i18n 'about.our_admins'}}

- {{#each a in model.admins}} - {{user-small user=a}} + {{#each model.admins as |a|}} + {{user-info user=a}} {{/each}}
@@ -35,8 +35,8 @@

{{i18n 'about.our_moderators'}}

- {{#each m in model.moderators}} - {{user-small user=m}} + {{#each model.moderators as |m|}} + {{user-info user=m}} {{/each}}
diff --git a/app/assets/javascripts/discourse/templates/badges/show.hbs b/app/assets/javascripts/discourse/templates/badges/show.hbs index 865c76f23cf..131d52fef31 100644 --- a/app/assets/javascripts/discourse/templates/badges/show.hbs +++ b/app/assets/javascripts/discourse/templates/badges/show.hbs @@ -14,57 +14,38 @@
{{#unless user}} -
{{i18n 'badges.granted' count=grantCount}}
+
{{i18n 'badges.granted' count=grantCount}}
{{/unless}}
{{i18n 'badges.allow_title'}} {{{view.allowTitle}}}
{{i18n 'badges.multiple_grant'}} {{{view.multipleGrant}}}
- - {{#if user}} {{/if}} {{#if userBadges}} -
- {{#each ub in userBadges}} -
- {{#if user}} - {{format-date ub.granted_at}} - {{else}} - {{#link-to 'user' ub.user classNames="badge-info"}} - {{avatar ub.user imageSize="large"}} -
- {{ub.user.username}} - {{format-date ub.granted_at}} -
- {{/link-to}} - {{/if}} - +
+ {{#each userBadges as |ub|}} + {{#user-info user=ub.user size="medium" class="badge-info" date=ub.granted_at}} +
{{i18n 'badges.granted_on' date=(inline-date ub.granted_at)}}
{{#if ub.post_number}} {{{ub.topic.fancyTitle}}} {{/if}} -
+ {{/user-info}} {{/each}} {{#unless canLoadMore}} {{#if user}} - {{i18n 'badges.more_with_badge'}} + {{log model}} + {{i18n 'badges.others_count' count=model.grant_count}} {{/if}} {{/unless}} -
{{conditional-loading-spinner condition=canLoadMore}} diff --git a/app/assets/javascripts/discourse/templates/components/user-small.hbs b/app/assets/javascripts/discourse/templates/components/user-info.hbs similarity index 84% rename from app/assets/javascripts/discourse/templates/components/user-small.hbs rename to app/assets/javascripts/discourse/templates/components/user-info.hbs index 83edc9c958d..8270000cc2d 100644 --- a/app/assets/javascripts/discourse/templates/components/user-small.hbs +++ b/app/assets/javascripts/discourse/templates/components/user-info.hbs @@ -8,4 +8,11 @@ {{unbound name}}
{{unbound user.title}}
+ + {{#if hasBlock}} +
+ {{yield}} +
+ {{/if}} + diff --git a/app/assets/javascripts/discourse/templates/group/members.hbs b/app/assets/javascripts/discourse/templates/group/members.hbs index ba4715c0d50..2d3c9d80f54 100644 --- a/app/assets/javascripts/discourse/templates/group/members.hbs +++ b/app/assets/javascripts/discourse/templates/group/members.hbs @@ -18,7 +18,7 @@ {{#each model.members as |m|}} - {{user-small user=m}} + {{user-info user=m}} {{#if m.owner}}{{i18n "groups.owner"}}{{/if}} diff --git a/app/assets/javascripts/discourse/templates/mobile/users.hbs b/app/assets/javascripts/discourse/templates/mobile/users.hbs index cea25c3a63a..cb1c3f6c9dc 100644 --- a/app/assets/javascripts/discourse/templates/mobile/users.hbs +++ b/app/assets/javascripts/discourse/templates/mobile/users.hbs @@ -13,7 +13,7 @@ {{#each ic in model itemController="directory-item"}}
{{#with ic.model as |it|}} - {{user-small user=it.user}} + {{user-info user=it.user}} {{user-stat value=it.likes_received label="directory.likes_received" icon="heart"}} {{user-stat value=it.likes_given label="directory.likes_given" icon="heart"}} {{user-stat value=it.topic_count label="directory.topic_count"}} diff --git a/app/assets/javascripts/discourse/templates/users.hbs b/app/assets/javascripts/discourse/templates/users.hbs index bca1399a192..71aad9499ea 100644 --- a/app/assets/javascripts/discourse/templates/users.hbs +++ b/app/assets/javascripts/discourse/templates/users.hbs @@ -28,7 +28,7 @@ {{#each ic in model itemController="directory-item"}} {{#with ic.model as |it|}} - {{user-small user=it.user}} + {{user-info user=it.user}} {{number it.likes_received}} {{number it.likes_given}} {{number it.topic_count}} diff --git a/app/assets/stylesheets/common/base/directory.scss b/app/assets/stylesheets/common/base/directory.scss index ad4004264fc..6af69033aa6 100644 --- a/app/assets/stylesheets/common/base/directory.scss +++ b/app/assets/stylesheets/common/base/directory.scss @@ -1,6 +1,10 @@ .directory { margin-bottom: 100px; + .user-info { + margin-bottom: 0; + } + .period-chooser { float: left; } diff --git a/app/assets/stylesheets/common/base/user-badges.scss b/app/assets/stylesheets/common/base/user-badges.scss index 04b77bc5a4c..ddf9ed6e572 100644 --- a/app/assets/stylesheets/common/base/user-badges.scss +++ b/app/assets/stylesheets/common/base/user-badges.scss @@ -135,66 +135,23 @@ } } } +.user-info.medium.badge-info { + min-height: 80px; - -/* /badges/:id/:slug page styling. */ -.show-badge { - .badge-user { - text-align: center; - width: 100px; - padding: 5px 10px; - margin-bottom: 10px; - display: inline-block; - vertical-align: top; - - .details { - margin: 0 10px; - padding-top: 3px; - color: $primary; - } - - .username { - word-wrap: break-word; - } - - .date { - display: block; - color: lighten($primary, 40%); - font-size: 0.714em; - } - } -} - -.show-badge .user-badge-with-posts .badge-user { - width: 45%; - padding: 0 0 0 4%; - margin-bottom: 20px; - - .badge-info { - width: 100px; - display: block; - float: left; + .granted-on { + color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%)); } .post-link { - width: 250px; display: block; - float: left; - margin-left: 18px; - text-align: left; + margin-top: 0.2em; } } .show-badge .badge-user-info { - margin-left: 2%; .earned { - margin-top: 15px; font-size: 1.3em; - } - .username { - margin-top: 5px; - display: block; - color: dark-light-choose(scale-color($primary, $lightness: 30%), scale-color($secondary, $lightness: 70%)); + margin-bottom: 1em; } } diff --git a/app/assets/stylesheets/common/base/user.scss b/app/assets/stylesheets/common/base/user.scss index 8ec1047f4c5..cba098d5152 100644 --- a/app/assets/stylesheets/common/base/user.scss +++ b/app/assets/stylesheets/common/base/user.scss @@ -92,10 +92,10 @@ margin-bottom: 15px; } -.user-small { +.user-info { display: inline-block; - width: 333px; clear: both; + margin-bottom: 1em; .user-image { float: left; @@ -128,7 +128,30 @@ margin-top: 3px; color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%)); } + } +} +.user-info.small { + width: 333px; +} + +.user-info.medium { + width: 550px; + min-height: 60px; + + .user-image { + width: 55px; + } + .user-detail { + width: 450px; + } + + .username, .name { + display: block; + } + + .name { + margin-left: 0; } } diff --git a/app/assets/stylesheets/mobile/user.scss b/app/assets/stylesheets/mobile/user.scss index 7725172431a..489730fdbde 100644 --- a/app/assets/stylesheets/mobile/user.scss +++ b/app/assets/stylesheets/mobile/user.scss @@ -169,7 +169,7 @@ color: $primary; } } - .user-small { + .user-info { width: 245px; } } diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 6e118b47fdb..347efcb6bd0 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -2855,7 +2855,8 @@ en: earned_n_times: one: "Earned this badge 1 time" other: "Earned this badge %{count} times" - more_with_badge: "Others with this badge" + granted_on: "Granted %{date}" + others_count: "Others with this badge (%{count})" title: Badges allow_title: "can be used as a title" multiple_grant: "can be awarded multiple times" diff --git a/test/javascripts/acceptance/about-test.js.es6 b/test/javascripts/acceptance/about-test.js.es6 index b45675f1aa4..9819ed8cba5 100644 --- a/test/javascripts/acceptance/about-test.js.es6 +++ b/test/javascripts/acceptance/about-test.js.es6 @@ -4,8 +4,8 @@ acceptance("About"); test("viewing", () => { visit("/about"); andThen(() => { - ok(exists('.about.admins .user-small'), 'has admins'); - ok(exists('.about.moderators .user-small'), 'has moderators'); + ok(exists('.about.admins .user-info'), 'has admins'); + ok(exists('.about.moderators .user-info'), 'has moderators'); ok(exists('.about.stats tr td'), 'has stats'); }); }); From e51259ee7b03203580dcf4b2eaeafb6e52d28d41 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 24 Mar 2016 13:50:45 -0400 Subject: [PATCH 06/44] FIX: Broken test --- test/javascripts/acceptance/badges-test.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/javascripts/acceptance/badges-test.js.es6 b/test/javascripts/acceptance/badges-test.js.es6 index abe9205fe0a..ec7d26fdbd4 100644 --- a/test/javascripts/acceptance/badges-test.js.es6 +++ b/test/javascripts/acceptance/badges-test.js.es6 @@ -11,6 +11,6 @@ test("Visit Badge Pages", () => { visit("/badges/9/autobiographer"); andThen(() => { ok(exists('.badges-listing div'), "has the badge in the listing"); - ok(exists('.badge-user'), "has the list of users with that badge"); + ok(exists('.user-info'), "has the list of users with that badge"); }); }); From 2c2a0435256031fe6aeae246b165d6df9c4c3263 Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Thu, 24 Mar 2016 13:00:10 -0700 Subject: [PATCH 07/44] unify badge count info --- .../javascripts/discourse/templates/badges/show.hbs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/app/assets/javascripts/discourse/templates/badges/show.hbs b/app/assets/javascripts/discourse/templates/badges/show.hbs index 131d52fef31..5976649b3e7 100644 --- a/app/assets/javascripts/discourse/templates/badges/show.hbs +++ b/app/assets/javascripts/discourse/templates/badges/show.hbs @@ -13,22 +13,12 @@
- {{#unless user}} -
{{i18n 'badges.granted' count=grantCount}}
- {{/unless}} +
{{i18n 'badges.granted' count=grantCount}}
{{i18n 'badges.allow_title'}} {{{view.allowTitle}}}
{{i18n 'badges.multiple_grant'}} {{{view.multipleGrant}}}
- {{#if user}} - - {{/if}} - {{#if userBadges}}
{{#each userBadges as |ub|}} From d1e1a91cb6084bd998dc2b298efb372716fef61f Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 24 Mar 2016 17:20:17 -0400 Subject: [PATCH 08/44] FIX: Large widths, weird button floating on badge view --- app/assets/javascripts/discourse/templates/badges/show.hbs | 3 ++- app/assets/stylesheets/common/base/user.scss | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/discourse/templates/badges/show.hbs b/app/assets/javascripts/discourse/templates/badges/show.hbs index 5976649b3e7..7f15cc73e13 100644 --- a/app/assets/javascripts/discourse/templates/badges/show.hbs +++ b/app/assets/javascripts/discourse/templates/badges/show.hbs @@ -32,8 +32,9 @@ {{#unless canLoadMore}} {{#if user}} - {{log model}} + {{/if}} {{/unless}}
diff --git a/app/assets/stylesheets/common/base/user.scss b/app/assets/stylesheets/common/base/user.scss index cba098d5152..da721c7ebbf 100644 --- a/app/assets/stylesheets/common/base/user.scss +++ b/app/assets/stylesheets/common/base/user.scss @@ -136,14 +136,14 @@ } .user-info.medium { - width: 550px; + width: 480px; min-height: 60px; .user-image { width: 55px; } .user-detail { - width: 450px; + width: 380px; } .username, .name { From 9bd8ea4633dcca18f139a5bd876a7f02de48cd37 Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Thu, 24 Mar 2016 15:06:31 -0700 Subject: [PATCH 09/44] more long badge descriptions --- config/locales/server.en.yml | 55 +++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 8210d689e67..bdd5b6e6002 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -2770,49 +2770,72 @@ en: read_guidelines: | This badge is granted for reading the community guidelines. Following and sharing these simple guidelines helps build a safe, fun, and sustainable community for everyone. Always remember there's another human being, one very much like yourself, on the other side of that screen. Be nice! reader: | - This badge is granted the first time you read a long topic with more than 100 replies. Reading a conversation closely helps you follow the discussion, understand different viewpoints, and leads to more interesting conversations. The more you read, the better the conversation gets. As we like to say, Reading is Fundamental! :simple_smile: + This badge is granted the first time you read a long topic with more than 100 replies. Reading a conversation closely helps you follow the discussion, understand different viewpoints, and leads to more interesting conversations. The more you read, the better the conversation gets. As we like to say, Reading is Fundamental! :slight_smile: editor: | - This badge is granted the first time you edit one of your posts. While you won't be able to edit your posts forever, editing is always a good idea -- you can improve your posts, fix small mistakes, or add anything you missed when you originally posted. Edit to make your posts even better! + This badge is granted the first time you edit one of your posts. While you won't be able to edit your posts forever, editing is always a good idea — you can improve your posts, fix small mistakes, or add anything you missed when you originally posted. Edit to make your posts even better! first_flag: | - This badge is granted the first time you flag a post. Flagging is how we all help keep this a clean, well lit place for everyone. If you notice any posts that require moderator attention for any reason please don't hesitate to flag. You can also use flag to send personal messages to fellow users if you see an issue with their post. If you see a problem, flag it! - nice_share: | - This badge is granted for sharing a link that was clicked by 25 outside visitors. Thanks for spreading the word about our discussions, and this community. + This badge is granted the first time you flag a post. Flagging is how we all help keep this a clean, well lit place for everyone. If you notice any posts that require moderator attention for any reason please don't hesitate to flag. You can also flag to send personal messages to fellow users if you see an issue with their post. If you see a problem, :flag_black: flag it! welcome: | - This badge is granted when you receive your first like on a post. Congratulations, you've posted something that your fellow community members found interesting, cool, or useful! Now keep going! + This badge is granted when you receive your first like on a post. Congratulations, you've posted something that your fellow community members found interesting, cool, or useful! anniversary: | This badge is granted when you've been a member for a year with at least one post in that year. Thank you for sticking around and contributing to our community. We couldn't do it without you. + nice_share: | + This badge is granted for sharing a link that was clicked by 25 outside visitors. Thanks for spreading the word about our discussions, and this community. good_share: | This badge is granted for sharing a link that was clicked by 300 outside visitors. Good work! You've shown off a great discussion to a bunch of new people and helped this community grow. great_share: | This badge is granted for sharing a link that was clicked by 1000 outside visitors. Wow! You've promoted an interesting discussion to a huge new audience, and helped us grow our community in a big way! nice_topic: | - This badge is granted when your topic gets 10 likes. You started an interesting conversation that the community enjoyed. + This badge is granted when your topic gets 10 likes. Hey, you started an interesting conversation that the community enjoyed! nice_post: | - This badge is granted when your reply gets 10 likes. Your reply made an impression on the community and helped move the conversation forward. + This badge is granted when your reply gets 10 likes. Your reply really made an impression on the community and helped move the conversation forward! good_topic: | - This badge is granted when your topic gets 25 likes. You launched a vibrant conversation that the community really responded to. + This badge is granted when your topic gets 25 likes. You launched a vibrant conversation that the community rallied around and loved! good_post: | - This badge is granted when your reply gets 25 likes. Your reply was exceptional and it made the conversation a whole lot better for everyone. + This badge is granted when your reply gets 25 likes. Your reply was exceptional and made the conversation a whole lot better for everyone! great_topic: | - This badge is granted when your topic gets 50 likes. Wow! You kicked off a fascinating conversation and the community loved the dynamic discussion that resulted. + This badge is granted when your topic gets 50 likes. You kicked off a fascinating conversation and the community enjoyed the dynamic discussion that resulted! great_post: | This badge is granted when your reply gets 50 likes. Wow! Your reply was inspiring, fascinating, hilarious, or insightful and the community loved it. - basic: | - This badge is granted when you reach trust level 1. Thanks for sticking around a little while and reading a few topics to learn what our community is about. Your new user restrictions have been lifted; you've been granted all essential community abilities, such as personal messaging, flagging, wiki editing, and the ability to post multiple images and links. appreciated: | - This badge is granted when you receive at least one like on 20 different posts. The community is enjoying your contributions to the conversations here, so keep them coming! + This badge is granted when you receive at least one like on 20 different posts. The community is enjoying your contributions to the conversations here! + respected: | + This badge is granted when you receive at least 2 likes on 100 different posts. The community is growing to respect your many contributions to the conversations here. + admired: | + This badge is granted when you receive at least 5 likes on 300 different posts. Wow! The community admires your frequent, high quality contributions to the conversations here. out_of_love: | - This badge is granted when you use all 50 of your daily likes. Letting the community know what's great by regularly liking those posts you enjoy and appreciate is the best way to encourage people to create even more great discussions in the future. + This badge is granted when you use all 50 of your daily likes. Remembering to take a moment and like the posts you enjoy and appreciate encourages your fellow community members to create even more great discussions in the future. + higher_love: | + This badge is granted when you use all 50 of your daily likes for 5 days. Thanks for taking the time actively encouraging the best conversations every day! + crazy_in_love: | + This badge is granted when you use all 50 of your daily likes for 20 days. Wow! You're a model of regularly encouraging your fellow community members! promoter: | This badge is granted when you invite someone to join the community via the invite button on your user page, or at the bottom of a topic. Inviting friends who might be interested in specific discussions is an great way to introduce new people to our community, so thanks! + campaigner: | + This badge is granted when you've invited 3 people who subsequently spent enough time on the site to become basic users. A vibrant community needs a regular infusion of newcomers who regularly participate and add new voices to the conversationss. + champion: | + This badge is granted when you've invited 5 people who subsequently spent enough time on the site to become full members. Wow! Thanks for expanding the diversity of our community with new members! thank_you: | - This badge is granted when you have at least 20 liked posts. + This badge is granted when you've received 20 likes on your posts and have given 10 or more likes in return. When someone likes your posts, you find the time to like what other people are posting in return. + gives_back: | + This badge is granted when you've received 100 likes and have given 100 or more likes in return. Thanks for paying it forward, and liking in return! + empathetic: | + This badge is granted when you've received 500 likes and have given 1000 or more likes in return. Wow! You're a model of generosity and mutual love :two_hearts:. + basic: | + This badge is granted when you reach trust level 1. Thanks for sticking around a little while and reading a few topics to learn what our community is about. Your new user restrictions have been lifted; you've been granted all essential community abilities, such as personal messaging, flagging, wiki editing, and the ability to post multiple images and links. member: | This badge is granted when you reach trust level 2. Thanks for participating over a period of weeks to truly join our community. You can now send invitations from your user page or individual topics, create group personal messages, and have a few more likes per day. regular: | This badge is granted when you reach trust level 3. Thanks for being a regular part of our community over a period of months. You're now one of the most active readers, and a reliable contributor that makes our community great. You can now recategorize and rename topics, take advantage of more powerful spam flags, access a private lounge area, and you'll also get lots more likes per day. leader: | This badge is granted when you reach trust level 4. You're a leader in this community as selected by staff, and you set a positive example for the rest of the community in your actions and words here. You have the ability to edit all posts, take common topic moderator actions such as pin, close, unlist, archive, split, and merge, and you have tons of likes per day. + popular_link: | + This badge is granted when a link you shared gets 50 clicks. Thanks for posting a useful link that added interesting context to the conversation! + hot_link: | + This badge is granted when a link you shared gets 300 clicks. Thanks for posting a fascinating link that drove the conversation forward and illuminated the discussion! + famous_link: | + This badge is granted when a link you shared gets 1000 clicks. Wow! You posted a link that significantly improved the conversation by addding essential detail, context, and information. Great work! + admin_login: success: "Email Sent" From f0c022351d6e800eed3ff56c583cadb8be06bbbd Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Thu, 24 Mar 2016 15:47:00 -0700 Subject: [PATCH 10/44] de-line the badge page a bit --- .../stylesheets/common/base/user-badges.scss | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/assets/stylesheets/common/base/user-badges.scss b/app/assets/stylesheets/common/base/user-badges.scss index ddf9ed6e572..4501f733116 100644 --- a/app/assets/stylesheets/common/base/user-badges.scss +++ b/app/assets/stylesheets/common/base/user-badges.scss @@ -66,15 +66,17 @@ /* Badge listing in /badges. */ .badges-listing { + margin: 20px 0; - tr { - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); - td { - padding: 10px 0; - } + + tr.title { + border-bottom: 2px solid dark-light-diff($primary, $secondary, 90%, -60%); + } + + td { + padding: 10px 0; } - border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); width: 90%; padding: 10px; display: table; @@ -94,6 +96,7 @@ .grant-count { font-size: 120%; + font-weight: bold; } .badge, .grant-count { From 92551df979a981f93340645cd386b206790c929e Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Fri, 25 Mar 2016 00:46:36 -0700 Subject: [PATCH 11/44] de-emphasize user page nav a bit from pure black --- app/assets/stylesheets/common/base/user.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/assets/stylesheets/common/base/user.scss b/app/assets/stylesheets/common/base/user.scss index da721c7ebbf..19af88da241 100644 --- a/app/assets/stylesheets/common/base/user.scss +++ b/app/assets/stylesheets/common/base/user.scss @@ -19,6 +19,14 @@ i.fa-heart { color: $love !important; } + .nav-pills { + a { + color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 40%)); + } + i { + color: dark-light-choose(scale-color($primary, $lightness: 55%), scale-color($secondary, $lightness: 55%)); + } + } } .user-field { From 17afdc34cc4e296c0a794db479570c0d9ffda934 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Fri, 25 Mar 2016 17:56:52 +0530 Subject: [PATCH 12/44] UX: user invite email style should be consistent with other user notifications --- app/mailers/user_notifications.rb | 28 ++++++++++---- app/views/email/invite.html.erb | 13 +++++++ config/locales/server.en.yml | 64 ++++++++++++++++--------------- 3 files changed, 68 insertions(+), 37 deletions(-) create mode 100644 app/views/email/invite.html.erb diff --git a/app/mailers/user_notifications.rb b/app/mailers/user_notifications.rb index f549b606c2f..1fa152df21a 100644 --- a/app/mailers/user_notifications.rb +++ b/app/mailers/user_notifications.rb @@ -173,12 +173,14 @@ class UserNotifications < ActionMailer::Base end def user_invited_to_private_message(user, opts) - opts[:use_template_html] = true + opts[:allow_reply_by_email] = false + opts[:use_invite_template] = true notification_email(user, opts) end def user_invited_to_topic(user, opts) - opts[:use_template_html] = true + opts[:allow_reply_by_email] = false + opts[:use_invite_template] = true opts[:show_category_in_subject] = true notification_email(user, opts) end @@ -273,7 +275,7 @@ class UserNotifications < ActionMailer::Base add_re_to_subject: opts[:add_re_to_subject], show_category_in_subject: opts[:show_category_in_subject], notification_type: notification_type, - use_template_html: opts[:use_template_html], + use_invite_template: opts[:use_invite_template], user: user ) end @@ -322,9 +324,21 @@ class UserNotifications < ActionMailer::Base .where('created_at > ?', 1.day.ago) .count) >= (SiteSetting.max_emails_per_day_per_user-1) - topic_excerpt = "" - if opts[:use_template_html] + if opts[:use_invite_template] + if post.topic.private_message? + invite_template = "user_notifications.invited_to_private_message_body" + else + invite_template = "user_notifications.invited_to_topic_body" + end topic_excerpt = post.excerpt.gsub("\n", " ") if post.is_first_post? && post.excerpt + message = I18n.t(invite_template, username: post.username, topic_title: title, topic_excerpt: topic_excerpt, site_title: SiteSetting.title, site_description: SiteSetting.site_description) + html = UserNotificationRenderer.new(Rails.configuration.paths["app/views"]).render( + template: 'email/invite', + format: :html, + locals: { message: PrettyText.cook(message, sanitize: false).html_safe, + classes: RTL.new(user).css_class + } + ) else in_reply_to_post = post.reply_to_post if user.user_option.email_in_reply_to html = UserNotificationRenderer.new(Rails.configuration.paths["app/views"]).render( @@ -337,6 +351,7 @@ class UserNotifications < ActionMailer::Base classes: RTL.new(user).css_class } ) + message = email_post_markdown(post) + (reached_limit ? "\n\n#{I18n.t "user_notifications.reached_limit", count: SiteSetting.max_emails_per_day_per_user}" : ""); end template = "user_notifications.user_#{notification_type}" @@ -348,8 +363,7 @@ class UserNotifications < ActionMailer::Base email_opts = { topic_title: title, - topic_excerpt: topic_excerpt, - message: email_post_markdown(post) + (reached_limit ? "\n\n#{I18n.t "user_notifications.reached_limit", count: SiteSetting.max_emails_per_day_per_user}" : ""), + message: message, url: post.url, post_id: post.id, topic_id: post.topic_id, diff --git a/app/views/email/invite.html.erb b/app/views/email/invite.html.erb new file mode 100644 index 00000000000..f6c1dfccc8c --- /dev/null +++ b/app/views/email/invite.html.erb @@ -0,0 +1,13 @@ +
> + +
%{header_instructions}
+ + <% if message.present? %> +
<%= message %>
+ <% end %> + +
+ + + +
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index bdd5b6e6002..21bdf0fe2df 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -2067,53 +2067,57 @@ en: posted_by: "Posted by %{username} on %{post_date}" + invited_to_private_message_body: | + %{username} invited you to a message + + > **%{topic_title}** + > + > %{topic_excerpt} + + at + + > %{site_title} -- %{site_description} + + invited_to_topic_body: | + %{username} invited you to a discussion + + > **%{topic_title}** + > + > %{topic_excerpt} + + at + + > %{site_title} -- %{site_description} + user_invited_to_private_message_pm: subject_template: "[%{site_name}] %{username} invited you to a message '%{topic_title}'" text_body_template: | + %{header_instructions} - %{username} invited you to a message + %{message} - > **%{topic_title}** - > - > %{topic_excerpt} - - at - - > %{site_title} -- %{site_description} - - Please visit this link to view the message: %{base_url}%{url} + --- + %{respond_instructions} user_invited_to_private_message_pm_staged: subject_template: "[%{site_name}] %{username} invited you to a message '%{topic_title}'" text_body_template: | + %{header_instructions} - %{username} invited you to a message + %{message} - > **%{topic_title}** - > - > %{topic_excerpt} - - at - - > %{site_title} -- %{site_description} - - Please visit this link to view the message: %{base_url}%{url} + --- + %{respond_instructions} user_invited_to_topic: subject_template: "[%{site_name}] %{username} invited you to '%{topic_title}'" text_body_template: | + %{header_instructions} - %{username} invited you to a discussion + %{message} - > **%{topic_title}** - > - > %{topic_excerpt} - - at - - > %{site_title} -- %{site_description} - - Please visit this link to view the message: %{base_url}%{url} + --- + %{respond_instructions} user_replied: subject_template: "[%{site_name}] %{topic_title}" From 9e9c81c30bf6a86ecb7fcc89667b3caa5146a142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Fri, 25 Mar 2016 16:44:08 +0100 Subject: [PATCH 13/44] improve error log when timing out while connecting to mail server --- app/jobs/scheduled/poll_mailbox.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/jobs/scheduled/poll_mailbox.rb b/app/jobs/scheduled/poll_mailbox.rb index 03193837fd9..320b9858830 100644 --- a/app/jobs/scheduled/poll_mailbox.rb +++ b/app/jobs/scheduled/poll_mailbox.rb @@ -96,9 +96,12 @@ module Jobs process_popmail(p) end end + rescue Net::OpenTimeout => e + mark_as_errored! + Discourse.handle_job_exception(e, error_context(@args, "Connecting to '#{SiteSetting.pop3_polling_host}' for polling emails.")) rescue Net::POPAuthenticationError => e mark_as_errored! - Discourse.handle_job_exception(e, error_context(@args, "Signing in to poll incoming email")) + Discourse.handle_job_exception(e, error_context(@args, "Signing in to poll incoming emails.")) end POLL_MAILBOX_ERRORS_KEY ||= "poll_mailbox_errors".freeze From d129c61a4aab6f5c713f5f6b48da1f2ada036f22 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 25 Mar 2016 11:23:31 -0400 Subject: [PATCH 14/44] FIX: Badge loading more was stuck --- .../discourse/controllers/badges/show.js.es6 | 22 ++++++++----------- .../discourse/mixins/load-more.js.es6 | 4 ++-- .../discourse/views/badges-show.js.es6 | 2 +- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/badges/show.js.es6 b/app/assets/javascripts/discourse/controllers/badges/show.js.es6 index 54be27a6651..1af975fcdac 100644 --- a/app/assets/javascripts/discourse/controllers/badges/show.js.es6 +++ b/app/assets/javascripts/discourse/controllers/badges/show.js.es6 @@ -1,4 +1,5 @@ import UserBadge from 'discourse/models/user-badge'; +import computed from 'ember-addons/ember-computed-decorators'; export default Ember.Controller.extend({ queryParams: ['username'], @@ -22,30 +23,25 @@ export default Ember.Controller.extend({ actions: { loadMore() { - const self = this; const userBadges = this.get('userBadges'); UserBadge.findByBadgeId(this.get('model.id'), { offset: userBadges.length, username: this.get('username'), - }).then(function(result) { + }).then(result => { userBadges.pushObjects(result); - if(userBadges.length === 0){ - self.set('noMoreBadges', true); + if (userBadges.length === 0){ + this.set('noMoreBadges', true); } }); } }, - canLoadMore: function() { - if (this.get('noMoreBadges')) { return false; } - - if (this.get('userBadges')) { - return this.get('grantCount') > this.get('userBadges.length'); - } else { - return false; - } - }.property('noMoreBadges', 'model.grant_count', 'userBadges.length'), + @computed('noMoreBadges', 'model.grant_count', 'userBadges.length') + canLoadMore(noMoreBadges, grantCount, userBadgeLength) { + if (noMoreBadges) { return false; } + return grantCount > (userBadgeLength || 0); + }, _showFooter: function() { this.set("controllers.application.showFooter", !this.get("canLoadMore")); diff --git a/app/assets/javascripts/discourse/mixins/load-more.js.es6 b/app/assets/javascripts/discourse/mixins/load-more.js.es6 index 415c43b5e29..c422e1cd633 100644 --- a/app/assets/javascripts/discourse/mixins/load-more.js.es6 +++ b/app/assets/javascripts/discourse/mixins/load-more.js.es6 @@ -2,12 +2,12 @@ import Eyeline from 'discourse/lib/eyeline'; import Scrolling from 'discourse/mixins/scrolling'; import { on } from 'ember-addons/ember-computed-decorators'; -// Provides the ability to load more items for a view which is scrolled to the bottom. +// Provides the ability to load more items for a view which is scrolled to the bottom. export default Ember.Mixin.create(Ember.ViewTargetActionSupport, Scrolling, { scrolled() { const eyeline = this.get('eyeline'); - if (eyeline) { eyeline.update(); } + return eyeline && eyeline.update(); }, loadMoreUnlessFull() { diff --git a/app/assets/javascripts/discourse/views/badges-show.js.es6 b/app/assets/javascripts/discourse/views/badges-show.js.es6 index 9f94ae6a3ad..2aae5f7675a 100644 --- a/app/assets/javascripts/discourse/views/badges-show.js.es6 +++ b/app/assets/javascripts/discourse/views/badges-show.js.es6 @@ -1,7 +1,7 @@ import LoadMore from "discourse/mixins/load-more"; export default Ember.View.extend(LoadMore, { - eyelineSelector: '.badge-user', + eyelineSelector: '.badge-info', tickOrX: function(field){ var icon = this.get('controller.model.' + field) ? "fa-check" : "fa-times"; return ""; From d7b568f98e0be84c14259cfdbda8dbb320f93abe Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 25 Mar 2016 11:37:26 -0400 Subject: [PATCH 15/44] REFACTOR: Remove view from badges-show --- .../controllers/admin-email-incomings.js.es6 | 22 ++-- .../admin/controllers/admin-email-logs.js.es6 | 21 ++-- .../admin/templates/email-received.hbs | 100 ++++++++--------- .../admin/templates/email-rejected.hbs | 102 +++++++++--------- .../admin/templates/email-sent.hbs | 88 +++++++-------- .../admin/templates/email-skipped.hbs | 88 +++++++-------- .../admin/views/admin-email-incomings.js.es6 | 14 --- .../admin/views/admin-email-logs.js.es6 | 14 --- .../admin/views/admin-email-received.js.es6 | 5 - .../admin/views/admin-email-rejected.js.es6 | 5 - .../admin/views/admin-email-sent.js.es6 | 5 - .../admin/views/admin-email-skipped.js.es6 | 5 - .../discourse/components/check-mark.js.es6 | 11 ++ .../discourse/components/load-more.js.es6 | 16 +++ .../discourse/mixins/load-more.js.es6 | 8 ++ .../discourse/templates/badges/show.hbs | 22 ++-- .../discourse/views/badges-show.js.es6 | 11 -- 17 files changed, 272 insertions(+), 265 deletions(-) delete mode 100644 app/assets/javascripts/admin/views/admin-email-incomings.js.es6 delete mode 100644 app/assets/javascripts/admin/views/admin-email-logs.js.es6 delete mode 100644 app/assets/javascripts/admin/views/admin-email-received.js.es6 delete mode 100644 app/assets/javascripts/admin/views/admin-email-rejected.js.es6 delete mode 100644 app/assets/javascripts/admin/views/admin-email-sent.js.es6 delete mode 100644 app/assets/javascripts/admin/views/admin-email-skipped.js.es6 create mode 100644 app/assets/javascripts/discourse/components/check-mark.js.es6 create mode 100644 app/assets/javascripts/discourse/components/load-more.js.es6 delete mode 100644 app/assets/javascripts/discourse/views/badges-show.js.es6 diff --git a/app/assets/javascripts/admin/controllers/admin-email-incomings.js.es6 b/app/assets/javascripts/admin/controllers/admin-email-incomings.js.es6 index deb7f0771c6..a6acd9af78f 100644 --- a/app/assets/javascripts/admin/controllers/admin-email-incomings.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-email-incomings.js.es6 @@ -1,11 +1,21 @@ import IncomingEmail from 'admin/models/incoming-email'; export default Ember.Controller.extend({ - loadMore() { - return IncomingEmail.findAll(this.get("filter"), this.get("model.length")) - .then(incoming => { - if (incoming.length < 50) { this.get("model").set("allLoaded", true); } - this.get("model").addObjects(incoming); - }); + loading: false, + + actions: { + + loadMore() { + if (this.get("loading") || this.get("model.allLoaded")) { return; } + this.set('loading', true); + + IncomingEmail.findAll(this.get("filter"), this.get("model.length")) + .then(incoming => { + if (incoming.length < 50) { this.get("model").set("allLoaded", true); } + this.get("model").addObjects(incoming); + }).finally(() => { + this.set('loading', false); + }); + } } }); diff --git a/app/assets/javascripts/admin/controllers/admin-email-logs.js.es6 b/app/assets/javascripts/admin/controllers/admin-email-logs.js.es6 index 2506a0cd999..44a38dfa324 100644 --- a/app/assets/javascripts/admin/controllers/admin-email-logs.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-email-logs.js.es6 @@ -1,11 +1,20 @@ import EmailLog from 'admin/models/email-log'; export default Ember.Controller.extend({ - loadMore() { - return EmailLog.findAll(this.get("filter"), this.get("model.length")) - .then(logs => { - if (logs.length < 50) { this.get("model").set("allLoaded", true); } - this.get("model").addObjects(logs); - }); + loading: false, + + actions: { + loadMore() { + if (this.get("loading") || this.get("model.allLoaded")) { return; } + + this.set('loading', true); + return EmailLog.findAll(this.get("filter"), this.get("model.length")) + .then(logs => { + if (logs.length < 50) { this.get("model").set("allLoaded", true); } + this.get("model").addObjects(logs); + }).finally(() => { + this.set('loading', false); + }); + } } }); diff --git a/app/assets/javascripts/admin/templates/email-received.hbs b/app/assets/javascripts/admin/templates/email-received.hbs index 95e0cb2dc57..e6e3bcbec96 100644 --- a/app/assets/javascripts/admin/templates/email-received.hbs +++ b/app/assets/javascripts/admin/templates/email-received.hbs @@ -1,55 +1,57 @@ - - - - - - - +{{#load-more selector=".email-list tr" action="loadMore"}} + + + + + + + + + + + + + + + - - - - - - - - - {{#each email in model}} - - - + + + + - - - - {{else}} - - {{/each}} + + + {{else}} + + {{/each}} - + +{{/load-more}} -{{conditional-loading-spinner condition=view.loading}} +{{conditional-loading-spinner condition=loading}} diff --git a/app/assets/javascripts/admin/templates/email-rejected.hbs b/app/assets/javascripts/admin/templates/email-rejected.hbs index 3c5f3cba8eb..664eb728669 100644 --- a/app/assets/javascripts/admin/templates/email-rejected.hbs +++ b/app/assets/javascripts/admin/templates/email-rejected.hbs @@ -1,54 +1,56 @@ - - - - - - - - +{{#load-more selector=".email-list tr" action="loadMore"}} + + + + + + + + + + + + + + + + + - - - - - - - - + {{#each email in model}} + + + + + + + + {{else}} + + {{/each}} - {{#each email in model}} - - - - - - - - {{else}} - - {{/each}} + +{{/load-more}} - - -{{conditional-loading-spinner condition=view.loading}} +{{conditional-loading-spinner condition=loading}} diff --git a/app/assets/javascripts/admin/templates/email-sent.hbs b/app/assets/javascripts/admin/templates/email-sent.hbs index 2f8785c6f59..ca5fb4aaa2a 100644 --- a/app/assets/javascripts/admin/templates/email-sent.hbs +++ b/app/assets/javascripts/admin/templates/email-sent.hbs @@ -1,47 +1,49 @@ - - - - - - - - +{{#load-more selector=".email-list tr" action="loadMore"}} + + + + + + + + + + + + + + + + + - - - - - - - - + {{#each l in model}} + + + + + + + + {{else}} + + {{/each}} - {{#each l in model}} - - - - - - - - {{else}} - - {{/each}} + +{{/load-more}} - - -{{conditional-loading-spinner condition=view.loading}} +{{conditional-loading-spinner condition=loading}} diff --git a/app/assets/javascripts/admin/templates/email-skipped.hbs b/app/assets/javascripts/admin/templates/email-skipped.hbs index 6ef48725668..9c21c428cd9 100644 --- a/app/assets/javascripts/admin/templates/email-skipped.hbs +++ b/app/assets/javascripts/admin/templates/email-skipped.hbs @@ -1,47 +1,49 @@ - - - - - - - - +{{#load-more selector=".email-list tr" action="loadMore"}} + + + + + + + + + + + + + + + + + - - - - - - - - + {{#each l in model}} + + + + + + + + {{else}} + + {{/each}} - {{#each l in model}} - - - - - - - - {{else}} - - {{/each}} + +{{/load-more}} - - -{{conditional-loading-spinner condition=view.loading}} +{{conditional-loading-spinner condition=loading}} diff --git a/app/assets/javascripts/admin/views/admin-email-incomings.js.es6 b/app/assets/javascripts/admin/views/admin-email-incomings.js.es6 deleted file mode 100644 index 6360f857b71..00000000000 --- a/app/assets/javascripts/admin/views/admin-email-incomings.js.es6 +++ /dev/null @@ -1,14 +0,0 @@ -import LoadMore from "discourse/mixins/load-more"; - -export default Ember.View.extend(LoadMore, { - loading: false, - eyelineSelector: ".email-list tr", - - actions: { - loadMore() { - if (this.get("loading") || this.get("model.allLoaded")) { return; } - this.set("loading", true); - return this.get("controller").loadMore().then(() => this.set("loading", false)); - } - } -}); diff --git a/app/assets/javascripts/admin/views/admin-email-logs.js.es6 b/app/assets/javascripts/admin/views/admin-email-logs.js.es6 deleted file mode 100644 index 6360f857b71..00000000000 --- a/app/assets/javascripts/admin/views/admin-email-logs.js.es6 +++ /dev/null @@ -1,14 +0,0 @@ -import LoadMore from "discourse/mixins/load-more"; - -export default Ember.View.extend(LoadMore, { - loading: false, - eyelineSelector: ".email-list tr", - - actions: { - loadMore() { - if (this.get("loading") || this.get("model.allLoaded")) { return; } - this.set("loading", true); - return this.get("controller").loadMore().then(() => this.set("loading", false)); - } - } -}); diff --git a/app/assets/javascripts/admin/views/admin-email-received.js.es6 b/app/assets/javascripts/admin/views/admin-email-received.js.es6 deleted file mode 100644 index da0d8de157c..00000000000 --- a/app/assets/javascripts/admin/views/admin-email-received.js.es6 +++ /dev/null @@ -1,5 +0,0 @@ -import AdminEmailIncomingsView from "admin/views/admin-email-incomings"; - -export default AdminEmailIncomingsView.extend({ - templateName: "admin/templates/email-received" -}); diff --git a/app/assets/javascripts/admin/views/admin-email-rejected.js.es6 b/app/assets/javascripts/admin/views/admin-email-rejected.js.es6 deleted file mode 100644 index b89fe8d46a0..00000000000 --- a/app/assets/javascripts/admin/views/admin-email-rejected.js.es6 +++ /dev/null @@ -1,5 +0,0 @@ -import AdminEmailIncomingsView from "admin/views/admin-email-incomings"; - -export default AdminEmailIncomingsView.extend({ - templateName: "admin/templates/email-rejected" -}); diff --git a/app/assets/javascripts/admin/views/admin-email-sent.js.es6 b/app/assets/javascripts/admin/views/admin-email-sent.js.es6 deleted file mode 100644 index d007a79644f..00000000000 --- a/app/assets/javascripts/admin/views/admin-email-sent.js.es6 +++ /dev/null @@ -1,5 +0,0 @@ -import AdminEmailLogsView from "admin/views/admin-email-logs"; - -export default AdminEmailLogsView.extend({ - templateName: "admin/templates/email-sent" -}); diff --git a/app/assets/javascripts/admin/views/admin-email-skipped.js.es6 b/app/assets/javascripts/admin/views/admin-email-skipped.js.es6 deleted file mode 100644 index e3c44670992..00000000000 --- a/app/assets/javascripts/admin/views/admin-email-skipped.js.es6 +++ /dev/null @@ -1,5 +0,0 @@ -import AdminEmailLogsView from "admin/views/admin-email-logs"; - -export default AdminEmailLogsView.extend({ - templateName: "admin/templates/email-skipped" -}); diff --git a/app/assets/javascripts/discourse/components/check-mark.js.es6 b/app/assets/javascripts/discourse/components/check-mark.js.es6 new file mode 100644 index 00000000000..702af6a15a4 --- /dev/null +++ b/app/assets/javascripts/discourse/components/check-mark.js.es6 @@ -0,0 +1,11 @@ +import computed from 'ember-addons/ember-computed-decorators'; + +export default Ember.Component.extend({ + tagName: 'i', + classNameBindings: [':fa', 'iconClass'], + + @computed('checked') + iconClass(checked) { + return checked ? 'fa-check' : 'fa-times'; + } +}); diff --git a/app/assets/javascripts/discourse/components/load-more.js.es6 b/app/assets/javascripts/discourse/components/load-more.js.es6 new file mode 100644 index 00000000000..4b355a5b0aa --- /dev/null +++ b/app/assets/javascripts/discourse/components/load-more.js.es6 @@ -0,0 +1,16 @@ +import LoadMore from "discourse/mixins/load-more"; + +export default Ember.Component.extend(LoadMore, { + _viaComponent: true, + + init() { + this._super(); + this.set('eyelineSelector', this.get('selector')); + }, + + actions: { + loadMore() { + this.sendAction(); + } + } +}); diff --git a/app/assets/javascripts/discourse/mixins/load-more.js.es6 b/app/assets/javascripts/discourse/mixins/load-more.js.es6 index c422e1cd633..16c8734054d 100644 --- a/app/assets/javascripts/discourse/mixins/load-more.js.es6 +++ b/app/assets/javascripts/discourse/mixins/load-more.js.es6 @@ -5,6 +5,14 @@ import { on } from 'ember-addons/ember-computed-decorators'; // Provides the ability to load more items for a view which is scrolled to the bottom. export default Ember.Mixin.create(Ember.ViewTargetActionSupport, Scrolling, { + init() { + this._super(); + if (!this._viaComponent) { + console.warn('Using `LoadMore` as a view mixin is deprecated. Use `{{load-more}}` instead'); + } + + }, + scrolled() { const eyeline = this.get('eyeline'); return eyeline && eyeline.update(); diff --git a/app/assets/javascripts/discourse/templates/badges/show.hbs b/app/assets/javascripts/discourse/templates/badges/show.hbs index 7f15cc73e13..f762e6dfe62 100644 --- a/app/assets/javascripts/discourse/templates/badges/show.hbs +++ b/app/assets/javascripts/discourse/templates/badges/show.hbs @@ -14,21 +14,25 @@
{{i18n 'badges.granted' count=grantCount}}
-
{{i18n 'badges.allow_title'}} {{{view.allowTitle}}}
{{i18n 'badges.multiple_grant'}} {{{view.multipleGrant}}} +
+ {{i18n 'badges.allow_title'}} {{check-mark checked=model.allow_title}}
+ {{i18n 'badges.multiple_grant'}} {{check-mark checked=model.multiple_grant}}
{{#if userBadges}}
- {{#each userBadges as |ub|}} - {{#user-info user=ub.user size="medium" class="badge-info" date=ub.granted_at}} -
{{i18n 'badges.granted_on' date=(inline-date ub.granted_at)}}
- {{#if ub.post_number}} - {{{ub.topic.fancyTitle}}} - {{/if}} - {{/user-info}} - {{/each}} + {{#load-more selector=".badge-info" action="loadMore"}} + {{#each userBadges as |ub|}} + {{#user-info user=ub.user size="medium" class="badge-info" date=ub.granted_at}} +
{{i18n 'badges.granted_on' date=(inline-date ub.granted_at)}}
+ {{#if ub.post_number}} + {{{ub.topic.fancyTitle}}} + {{/if}} + {{/user-info}} + {{/each}} + {{/load-more}} {{#unless canLoadMore}} {{#if user}} diff --git a/app/assets/javascripts/discourse/views/badges-show.js.es6 b/app/assets/javascripts/discourse/views/badges-show.js.es6 deleted file mode 100644 index 2aae5f7675a..00000000000 --- a/app/assets/javascripts/discourse/views/badges-show.js.es6 +++ /dev/null @@ -1,11 +0,0 @@ -import LoadMore from "discourse/mixins/load-more"; - -export default Ember.View.extend(LoadMore, { - eyelineSelector: '.badge-info', - tickOrX: function(field){ - var icon = this.get('controller.model.' + field) ? "fa-check" : "fa-times"; - return ""; - }, - allowTitle: function() { return this.tickOrX("allow_title"); }.property(), - multipleGrant: function() { return this.tickOrX("multiple_grant"); }.property() -}); From ba10327cc823317b3b530fa1d4e46da81ea2132a Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 25 Mar 2016 12:04:26 -0400 Subject: [PATCH 16/44] FIX: Minor badge page issues --- .../discourse/controllers/badges/show.js.es6 | 38 +++++++++---------- .../discourse/templates/badges/show.hbs | 8 ++-- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/badges/show.js.es6 b/app/assets/javascripts/discourse/controllers/badges/show.js.es6 index 1af975fcdac..1346bf64364 100644 --- a/app/assets/javascripts/discourse/controllers/badges/show.js.es6 +++ b/app/assets/javascripts/discourse/controllers/badges/show.js.es6 @@ -1,5 +1,5 @@ import UserBadge from 'discourse/models/user-badge'; -import computed from 'ember-addons/ember-computed-decorators'; +import { default as computed, observes } from 'ember-addons/ember-computed-decorators'; export default Ember.Controller.extend({ queryParams: ['username'], @@ -7,19 +7,17 @@ export default Ember.Controller.extend({ userBadges: null, needs: ["application"], - user: function() { - if (this.get("username")) { + @computed('username') + user(username) { + if (username) { return this.get('userBadges')[0].get('user'); } - }.property("username"), + }, - grantCount: function() { - if (this.get("username")) { - return this.get('userBadges.grant_count'); - } else { - return this.get('model.grant_count'); - } - }.property('username', 'model', 'userBadges'), + @computed('username', 'model.grant_count', 'userBadges.grant_count') + grantCount(username, modelCount, userCount) { + return username ? userCount : modelCount; + }, actions: { loadMore() { @@ -37,22 +35,20 @@ export default Ember.Controller.extend({ } }, - @computed('noMoreBadges', 'model.grant_count', 'userBadges.length') + @computed('noMoreBadges', 'grantCount', 'userBadges.length') canLoadMore(noMoreBadges, grantCount, userBadgeLength) { if (noMoreBadges) { return false; } return grantCount > (userBadgeLength || 0); }, - _showFooter: function() { + @observes('canLoadMore') + _showFooter() { this.set("controllers.application.showFooter", !this.get("canLoadMore")); - }.observes("canLoadMore"), + }, - longDescription: function(){ - return Discourse.Emoji.unescape(this.get('model.long_description')); - }.property('model.long_description'), - - showLongDescription: function(){ - return this.get('model.long_description'); - }.property('userBadges') + @computed('model.long_description') + longDescription(modelLongDesc) { + return Discourse.Emoji.unescape(modelLongDesc); + } }); diff --git a/app/assets/javascripts/discourse/templates/badges/show.hbs b/app/assets/javascripts/discourse/templates/badges/show.hbs index f762e6dfe62..c60cbb216de 100644 --- a/app/assets/javascripts/discourse/templates/badges/show.hbs +++ b/app/assets/javascripts/discourse/templates/badges/show.hbs @@ -5,10 +5,10 @@ {{model.displayName}} - {{#if showLongDescription}} - + {{#if longDescription}} + {{/if}}
From 2c5eed9a85e6be88e8a0e31052ec4270af097aa7 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 25 Mar 2016 12:11:22 -0400 Subject: [PATCH 17/44] FIX: Basic badge description was missing --- config/locales/server.en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index bdd5b6e6002..fd45ea35b67 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -2821,7 +2821,7 @@ en: This badge is granted when you've received 100 likes and have given 100 or more likes in return. Thanks for paying it forward, and liking in return! empathetic: | This badge is granted when you've received 500 likes and have given 1000 or more likes in return. Wow! You're a model of generosity and mutual love :two_hearts:. - basic: | + basic_user: | This badge is granted when you reach trust level 1. Thanks for sticking around a little while and reading a few topics to learn what our community is about. Your new user restrictions have been lifted; you've been granted all essential community abilities, such as personal messaging, flagging, wiki editing, and the ability to post multiple images and links. member: | This badge is granted when you reach trust level 2. Thanks for participating over a period of weeks to truly join our community. You can now send invitations from your user page or individual topics, create group personal messages, and have a few more likes per day. From 56c13856ddf53d3317c90836b8716f943c63135b Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 25 Mar 2016 12:19:12 -0400 Subject: [PATCH 18/44] Move Editor and First Flag to "Getting Started" category --- db/fixtures/006_badges.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/db/fixtures/006_badges.rb b/db/fixtures/006_badges.rb index 5d594a2f011..5b168778876 100644 --- a/db/fixtures/006_badges.rb +++ b/db/fixtures/006_badges.rb @@ -134,7 +134,8 @@ Badge.seed do |b| b.target_posts = true b.show_posts = false b.query = Badge::Queries::FirstFlag - b.default_badge_grouping_id = BadgeGrouping::Community + b.badge_grouping_id = BadgeGrouping::GettingStarted + b.default_badge_grouping_id = BadgeGrouping::GettingStarted b.trigger = Badge::Trigger::PostAction b.auto_revoke = false b.system = true @@ -228,7 +229,8 @@ Badge.seed do |b| b.badge_type_id = BadgeType::Bronze b.multiple_grant = false b.query = Badge::Queries::Editor - b.default_badge_grouping_id = BadgeGrouping::Community + b.badge_grouping_id = BadgeGrouping::GettingStarted + b.default_badge_grouping_id = BadgeGrouping::GettingStarted b.trigger = Badge::Trigger::PostRevision b.system = true end From 5f54dd908a5c6e940a9013b1b5c0c57325ccd9bd Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 25 Mar 2016 12:21:24 -0400 Subject: [PATCH 19/44] Recategorize link badges --- db/fixtures/006_badges.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/db/fixtures/006_badges.rb b/db/fixtures/006_badges.rb index 5b168778876..bb2e9fba0f9 100644 --- a/db/fixtures/006_badges.rb +++ b/db/fixtures/006_badges.rb @@ -287,7 +287,8 @@ end b.target_posts = true b.show_posts = true b.query = Badge::Queries.linking_badge(count) - b.default_badge_grouping_id = BadgeGrouping::Community + b.badge_grouping_id = BadgeGrouping::Posting + b.default_badge_grouping_id = BadgeGrouping::Posting # don't trigger for now, its too expensive b.trigger = Badge::Trigger::None b.system = true From 207bf1b3397f1ae7b85715362660523bb62ccb23 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 25 Mar 2016 12:54:33 -0400 Subject: [PATCH 20/44] FIX: Broken Javscript test --- app/assets/javascripts/discourse/controllers/badges/show.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/controllers/badges/show.js.es6 b/app/assets/javascripts/discourse/controllers/badges/show.js.es6 index 1346bf64364..52a4c7395c0 100644 --- a/app/assets/javascripts/discourse/controllers/badges/show.js.es6 +++ b/app/assets/javascripts/discourse/controllers/badges/show.js.es6 @@ -48,7 +48,7 @@ export default Ember.Controller.extend({ @computed('model.long_description') longDescription(modelLongDesc) { - return Discourse.Emoji.unescape(modelLongDesc); + return Discourse.Emoji.unescape(modelLongDesc || ''); } }); From 27c793a990f985d2b03ad7cc553435ba4274e9a0 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 25 Mar 2016 15:32:48 -0400 Subject: [PATCH 21/44] UX: Show badges as cards on the badges index and show page --- .../discourse/components/badge-card.js.es6 | 15 ++ .../discourse/components/check-mark.js.es6 | 13 +- .../discourse/controllers/badges/show.js.es6 | 5 - .../javascripts/discourse/models/badge.js.es6 | 7 - .../discourse/templates/badges/index.hbs | 28 ++- .../discourse/templates/badges/show.hbs | 22 +-- .../templates/components/badge-card.hbs | 19 ++ .../stylesheets/common/base/user-badges.scss | 174 +++++++++++++----- app/serializers/badge_index_serializer.rb | 1 + .../javascripts/acceptance/badges-test.js.es6 | 4 +- 10 files changed, 193 insertions(+), 95 deletions(-) create mode 100644 app/assets/javascripts/discourse/components/badge-card.js.es6 create mode 100644 app/assets/javascripts/discourse/templates/components/badge-card.hbs diff --git a/app/assets/javascripts/discourse/components/badge-card.js.es6 b/app/assets/javascripts/discourse/components/badge-card.js.es6 new file mode 100644 index 00000000000..bb694471cb9 --- /dev/null +++ b/app/assets/javascripts/discourse/components/badge-card.js.es6 @@ -0,0 +1,15 @@ +import computed from 'ember-addons/ember-computed-decorators'; + +export default Ember.Component.extend({ + size: 'medium', + classNameBindings: [':badge-card', 'size'], + + @computed('size') + summary(size) { + if (size === 'large') { + return Discourse.Emoji.unescape(this.get('badge.long_description') || ''); + } + return this.get('badge.translatedDescription'); + } + +}); diff --git a/app/assets/javascripts/discourse/components/check-mark.js.es6 b/app/assets/javascripts/discourse/components/check-mark.js.es6 index 702af6a15a4..a934a490a45 100644 --- a/app/assets/javascripts/discourse/components/check-mark.js.es6 +++ b/app/assets/javascripts/discourse/components/check-mark.js.es6 @@ -1,11 +1,16 @@ import computed from 'ember-addons/ember-computed-decorators'; export default Ember.Component.extend({ - tagName: 'i', - classNameBindings: [':fa', 'iconClass'], + tagName: 'span', + classNameBindings: [':check-display', 'status'], @computed('checked') - iconClass(checked) { - return checked ? 'fa-check' : 'fa-times'; + status(checked) { + return checked ? 'status-checked' : 'status-unchecked'; + }, + + render(buffer) { + const icon = this.get('checked') ? 'check' : 'times'; + buffer.push(``); } }); diff --git a/app/assets/javascripts/discourse/controllers/badges/show.js.es6 b/app/assets/javascripts/discourse/controllers/badges/show.js.es6 index 52a4c7395c0..714635f6030 100644 --- a/app/assets/javascripts/discourse/controllers/badges/show.js.es6 +++ b/app/assets/javascripts/discourse/controllers/badges/show.js.es6 @@ -44,11 +44,6 @@ export default Ember.Controller.extend({ @observes('canLoadMore') _showFooter() { this.set("controllers.application.showFooter", !this.get("canLoadMore")); - }, - - @computed('model.long_description') - longDescription(modelLongDesc) { - return Discourse.Emoji.unescape(modelLongDesc || ''); } }); diff --git a/app/assets/javascripts/discourse/models/badge.js.es6 b/app/assets/javascripts/discourse/models/badge.js.es6 index 6e3d852c78d..3181739a223 100644 --- a/app/assets/javascripts/discourse/models/badge.js.es6 +++ b/app/assets/javascripts/discourse/models/badge.js.es6 @@ -33,13 +33,6 @@ const Badge = RestModel.extend({ return I18n.t(i18nKey, {defaultValue: this.get('name')}); }.property('name', 'i18nNameKey'), - /** - The i18n translated description for this badge. Returns the null if no - translation exists. - - @property translatedDescription - @type {String} - **/ translatedDescription: function() { const i18nKey = "badges.badge." + this.get('i18nNameKey') + ".description"; let translation = I18n.t(i18nKey); diff --git a/app/assets/javascripts/discourse/templates/badges/index.hbs b/app/assets/javascripts/discourse/templates/badges/index.hbs index 2d6de7fbda4..093c258ee6d 100644 --- a/app/assets/javascripts/discourse/templates/badges/index.hbs +++ b/app/assets/javascripts/discourse/templates/badges/index.hbs @@ -1,21 +1,17 @@

{{i18n 'badges.title'}}

- - - {{#each bg in badgeGroups}} - - - - {{#each b in bg.badges}} - - - - - - +
+ {{#each bg in badgeGroups}} +
+
+

{{bg.badgeGrouping.displayName}}

+
+ + {{#each bg.badges as |b|}} + {{badge-card badge=b}} {{/each}} - {{/each}} -
-

{{bg.badgeGrouping.displayName}}

{{#if b.has_badge}}{{/if}}{{user-badge badge=b}}{{{b.displayDescriptionHtml}}}{{b.grant_count}}
+
+ {{/each}} +
diff --git a/app/assets/javascripts/discourse/templates/badges/show.hbs b/app/assets/javascripts/discourse/templates/badges/show.hbs index c60cbb216de..83b2c74db81 100644 --- a/app/assets/javascripts/discourse/templates/badges/show.hbs +++ b/app/assets/javascripts/discourse/templates/badges/show.hbs @@ -5,18 +5,16 @@ {{model.displayName}} - {{#if longDescription}} - - {{/if}} - -
-
-
{{i18n 'badges.granted' count=grantCount}}
-
- {{i18n 'badges.allow_title'}} {{check-mark checked=model.allow_title}}
- {{i18n 'badges.multiple_grant'}} {{check-mark checked=model.multiple_grant}} +
+ {{badge-card badge=model size="large"}} +
+
+
+ {{check-mark checked=model.allow_title}} {{i18n 'badges.allow_title'}} +
+
+ {{check-mark checked=model.multiple_grant}} {{i18n 'badges.multiple_grant'}} +
diff --git a/app/assets/javascripts/discourse/templates/components/badge-card.hbs b/app/assets/javascripts/discourse/templates/components/badge-card.hbs new file mode 100644 index 00000000000..6ba8ac189a9 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/components/badge-card.hbs @@ -0,0 +1,19 @@ +{{#link-to 'badges.show' badge}} + {{#if badge.grant_count}} + {{badge.grant_count}} + {{/if}} + {{#if badge.has_badge}} + {{fa-icon "check"}} + {{/if}} +
+
+ {{icon-or-image badge.icon}} +
+
+
+

{{badge.displayName}}

+
{{{summary}}}
+
+
+
+{{/link-to}} diff --git a/app/assets/stylesheets/common/base/user-badges.scss b/app/assets/stylesheets/common/base/user-badges.scss index 4501f733116..c18c6ac3636 100644 --- a/app/assets/stylesheets/common/base/user-badges.scss +++ b/app/assets/stylesheets/common/base/user-badges.scss @@ -32,6 +32,7 @@ } } + /* User badge listing. */ .user-badges-list { text-align: center; @@ -64,55 +65,6 @@ } } -/* Badge listing in /badges. */ -.badges-listing { - - margin: 20px 0; - - tr.title { - border-bottom: 2px solid dark-light-diff($primary, $secondary, 90%, -60%); - } - - td { - padding: 10px 0; - } - - width: 90%; - padding: 10px; - display: table; - color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 60%)); - - .row { - display: table-row; - > div { - display: table-cell; - vertical-align: middle; - } - } - - .user-badge { - font-size: $base-font-size; - } - - .grant-count { - font-size: 120%; - font-weight: bold; - } - - .badge, .grant-count { - white-space: nowrap; - } - - .info { - font-size: 0.9em; - text-align: right; - } - - .description { - } - -} - @media all and (max-width: 750px) { .show-badge .user-badge-with-posts .badge-user a.post-link { width: auto; @@ -202,3 +154,127 @@ margin-bottom: 15px; margin-top: 15px; } + +.badge-card { + position: relative; + display: inline-block; + background-color: dark-light-diff($primary, $secondary, 95%, -65%); + margin-right: 5px; + margin-bottom: 10px; + box-shadow: 1px 1px 3px rgba(0.0, 0.0, 0.0, 0.2); + + .check-display { + position: absolute; + left: 5px; + top: 5px; + } + + .grant-count { + position: absolute; + right: 5px; + top: 5px; + font-weight: bold; + color: dark-light-diff($primary, $secondary, 50%, -65%); + font-size: 1.2em; + } + + .badge-contents { + display: flex; + flex-direction: row; + min-height: 128px; + + .badge-icon { + min-width: 90px; + display: flex; + align-items: center; + justify-content: center; + background-color: dark-light-diff($primary, $secondary, 92%, -60%); + font-size: 3em; + + &.badge-type-gold .fa { + color: #ffd700 !important; + } + + &.badge-type-silver .fa { + color: #c0c0c0 !important; + } + + &.badge-type-bronze .fa { + color: #cd7f32 !important; + } + } + + .badge-info { + display: flex; + align-items: center; + justify-content: center; + padding: 15px; + color: $primary; + + h3 { + margin-bottom: 0.25em; + } + } + } +} + +.badge-card.medium { + width: 360px; +} + +.badge-card.large { + width: 750px; + a { + cursor: default; + } +} + + +.badge-groups { + margin: 20px 0; + color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 60%)); + h3 { + margin-bottom: 1.0em; + } +} + +.badge-grouping { + margin-bottom: 1.5em; +} + +.show-badge-details { + display: flex; + flex-direction: row; + margin-bottom: 2em; + margin-top: 1em; + + .badge-grant-info { + display: flex; + align-items: center; + margin-left: 1em; + } + .grant-info-item { + margin-bottom: 1em; + color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 60%)); + } +} + +.check-display { + display: inline-block; + width: 18px; + border-radius: 10px; + text-align: center; + .fa { + font-size: 0.9em; + color: $secondary; + } +} + +.check-display.status-checked { + background-color: dark-light-diff($primary, $secondary, 40%, -60%); +} + +.check-display.status-unchecked { + background-color: $danger; +} + diff --git a/app/serializers/badge_index_serializer.rb b/app/serializers/badge_index_serializer.rb index 533c71133e5..85c013a4b94 100644 --- a/app/serializers/badge_index_serializer.rb +++ b/app/serializers/badge_index_serializer.rb @@ -9,4 +9,5 @@ class BadgeIndexSerializer < BadgeSerializer def has_badge @options[:user_badges].include?(object.id) end + end diff --git a/test/javascripts/acceptance/badges-test.js.es6 b/test/javascripts/acceptance/badges-test.js.es6 index ec7d26fdbd4..77148f10fce 100644 --- a/test/javascripts/acceptance/badges-test.js.es6 +++ b/test/javascripts/acceptance/badges-test.js.es6 @@ -5,12 +5,12 @@ acceptance("Badges"); test("Visit Badge Pages", () => { visit("/badges"); andThen(() => { - ok(exists('.badges-listing tr'), "has a list of badges"); + ok(exists('.badge-groups .badge-card'), "has a list of badges"); }); visit("/badges/9/autobiographer"); andThen(() => { - ok(exists('.badges-listing div'), "has the badge in the listing"); + ok(exists('.badge-card'), "has the badge in the listing"); ok(exists('.user-info'), "has the list of users with that badge"); }); }); From 64feffbb60a588b4cabcb27230b11e42a13ff30e Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Sat, 26 Mar 2016 00:42:00 +0530 Subject: [PATCH 22/44] FEATURE: site setting for suppressing categories from digest email --- app/models/topic.rb | 4 ++++ config/locales/server.en.yml | 1 + config/site_settings.yml | 3 +++ spec/models/topic_spec.rb | 12 +++++++++++- 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/models/topic.rb b/app/models/topic.rb index a38c2b2e4e7..7150e00ecbd 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -339,6 +339,10 @@ class Topic < ActiveRecord::Base # Remove muted categories muted_category_ids = CategoryUser.where(user_id: user.id, notification_level: CategoryUser.notification_levels[:muted]).pluck(:category_id) + if SiteSetting.digest_suppress_categories.present? + muted_category_ids += SiteSetting.digest_suppress_categories.split("|").map(&:to_i) + muted_category_ids = muted_category_ids.uniq + end if muted_category_ids.present? topics = topics.where("topics.category_id NOT IN (?)", muted_category_ids) end diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index daf57b981da..f4f603f8a70 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1195,6 +1195,7 @@ en: digest_topics: "The maximum number of topics to display in the email digest." digest_min_excerpt_length: "Minimum post excerpt in the email digest, in characters." delete_digest_email_after_days: "Suppress digest emails for users not seen on the site for more than (n) days." + digest_suppress_categories: "Suppress these categories from digest emails." disable_digest_emails: "Disable digest emails for all users." detect_custom_avatars: "Whether or not to check that users have uploaded custom profile pictures." diff --git a/config/site_settings.yml b/config/site_settings.yml index bb593681b84..3a4bc825fc2 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -512,6 +512,9 @@ email: digest_min_excerpt_length: 100 digest_topics: 20 delete_digest_email_after_days: 365 + digest_suppress_categories: + type: category_list + default: '' disable_digest_emails: default: false client: true diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb index e2ae6c0549f..6c071fce293 100644 --- a/spec/models/topic_spec.rb +++ b/spec/models/topic_spec.rb @@ -1296,6 +1296,16 @@ describe Topic do expect(Topic.for_digest(user, 1.year.ago, top_order: true)).to be_blank end + it "doesn't return topics from suppressed categories" do + user = Fabricate(:user) + category = Fabricate(:category) + Fabricate(:topic, category: category) + + SiteSetting.digest_suppress_categories = "#{category.id}" + + expect(Topic.for_digest(user, 1.year.ago, top_order: true)).to be_blank + end + it "doesn't return topics from TL0 users" do new_user = Fabricate(:user, trust_level: 0) Fabricate(:topic, user_id: new_user.id) @@ -1607,7 +1617,7 @@ describe Topic do topic.update_status('closed', true, user) topic.reload - + expect(@topic_status_event_triggered).to eq(true) end end From 83b79a4e1e01b02fa48ef377bfb509473115f6f3 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 25 Mar 2016 16:10:21 -0400 Subject: [PATCH 23/44] UX: Show a user's badges as cards --- .../discourse/components/badge-card.js.es6 | 8 ++++ .../discourse/templates/badges/index.hbs | 4 +- .../templates/components/badge-card.hbs | 32 +++++++-------- .../discourse/templates/user/badges.hbs | 6 ++- .../stylesheets/common/base/user-badges.scss | 39 +------------------ 5 files changed, 31 insertions(+), 58 deletions(-) diff --git a/app/assets/javascripts/discourse/components/badge-card.js.es6 b/app/assets/javascripts/discourse/components/badge-card.js.es6 index bb694471cb9..396577968b3 100644 --- a/app/assets/javascripts/discourse/components/badge-card.js.es6 +++ b/app/assets/javascripts/discourse/components/badge-card.js.es6 @@ -4,6 +4,14 @@ export default Ember.Component.extend({ size: 'medium', classNameBindings: [':badge-card', 'size'], + @computed('count', 'badge.grant_count') + displayCount(count, grantCount) { + const c = parseInt(count || grantCount || 0); + if (count > 1) { + return count; + } + }, + @computed('size') summary(size) { if (size === 'large') { diff --git a/app/assets/javascripts/discourse/templates/badges/index.hbs b/app/assets/javascripts/discourse/templates/badges/index.hbs index 093c258ee6d..3eb249eda99 100644 --- a/app/assets/javascripts/discourse/templates/badges/index.hbs +++ b/app/assets/javascripts/discourse/templates/badges/index.hbs @@ -9,7 +9,9 @@
{{#each bg.badges as |b|}} - {{badge-card badge=b}} + {{#link-to 'badges.show' badge.id badge.slug}} + {{badge-card badge=b}} + {{/link-to}} {{/each}}
{{/each}} diff --git a/app/assets/javascripts/discourse/templates/components/badge-card.hbs b/app/assets/javascripts/discourse/templates/components/badge-card.hbs index 6ba8ac189a9..1ce23006e2f 100644 --- a/app/assets/javascripts/discourse/templates/components/badge-card.hbs +++ b/app/assets/javascripts/discourse/templates/components/badge-card.hbs @@ -1,19 +1,17 @@ -{{#link-to 'badges.show' badge}} - {{#if badge.grant_count}} - {{badge.grant_count}} - {{/if}} - {{#if badge.has_badge}} - {{fa-icon "check"}} - {{/if}} -
-
- {{icon-or-image badge.icon}} -
-
-
-

{{badge.displayName}}

-
{{{summary}}}
-
+{{#if displayCount}} + {{displayCount}} +{{/if}} +{{#if badge.has_badge}} + {{fa-icon "check"}} +{{/if}} +
+
+ {{icon-or-image badge.icon}} +
+
+
+

{{badge.displayName}}

+
{{{summary}}}
-{{/link-to}} +
diff --git a/app/assets/javascripts/discourse/templates/user/badges.hbs b/app/assets/javascripts/discourse/templates/user/badges.hbs index 7cfc318ba1b..1c7c660be00 100644 --- a/app/assets/javascripts/discourse/templates/user/badges.hbs +++ b/app/assets/javascripts/discourse/templates/user/badges.hbs @@ -1,5 +1,7 @@
- {{#each ub in controller}} - {{user-badge badge=ub.badge count=ub.count user=user}} + {{#each controller as |ub|}} + {{#link-to 'badges.show' ub.badge.id ub.badge.slug (query-params username=user.username_lower)}} + {{badge-card badge=ub.badge count=ub.count}} + {{/link-to}} {{/each}}
diff --git a/app/assets/stylesheets/common/base/user-badges.scss b/app/assets/stylesheets/common/base/user-badges.scss index c18c6ac3636..c781f323583 100644 --- a/app/assets/stylesheets/common/base/user-badges.scss +++ b/app/assets/stylesheets/common/base/user-badges.scss @@ -32,39 +32,6 @@ } } - -/* User badge listing. */ -.user-badges-list { - text-align: center; - - .user-badge { - max-width: 80px; - text-align: center; - vertical-align: top; - margin: 10px; - border: none; - - .fa { - display: block; - font-size: 3.571em; - margin-bottom: 5px; - } - - img { - display: block; - margin: auto auto 4px; - width: 55px; - height: 55px; - } - - .count { - display: block; - font-size: 0.8em; - color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%)); - } - } -} - @media all and (max-width: 750px) { .show-badge .user-badge-with-posts .badge-user a.post-link { width: auto; @@ -219,17 +186,13 @@ } .badge-card.medium { - width: 360px; + width: 350px; } .badge-card.large { width: 750px; - a { - cursor: default; - } } - .badge-groups { margin: 20px 0; color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 60%)); From 4cca4f2f5ba8f82ddf656b62c980de95d5b93599 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 25 Mar 2016 16:20:59 -0400 Subject: [PATCH 24/44] FIX: Typo --- app/assets/javascripts/discourse/components/badge-card.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/components/badge-card.js.es6 b/app/assets/javascripts/discourse/components/badge-card.js.es6 index 396577968b3..9e379b32fb7 100644 --- a/app/assets/javascripts/discourse/components/badge-card.js.es6 +++ b/app/assets/javascripts/discourse/components/badge-card.js.es6 @@ -6,7 +6,7 @@ export default Ember.Component.extend({ @computed('count', 'badge.grant_count') displayCount(count, grantCount) { - const c = parseInt(count || grantCount || 0); + const count = parseInt(count || grantCount || 0); if (count > 1) { return count; } From d493702a901d42172b14a355eff585718b58b228 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 25 Mar 2016 16:29:29 -0400 Subject: [PATCH 25/44] FIX: For real this time :'( --- .../javascripts/discourse/components/badge-card.js.es6 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/discourse/components/badge-card.js.es6 b/app/assets/javascripts/discourse/components/badge-card.js.es6 index 9e379b32fb7..72e97bf8e2d 100644 --- a/app/assets/javascripts/discourse/components/badge-card.js.es6 +++ b/app/assets/javascripts/discourse/components/badge-card.js.es6 @@ -6,9 +6,9 @@ export default Ember.Component.extend({ @computed('count', 'badge.grant_count') displayCount(count, grantCount) { - const count = parseInt(count || grantCount || 0); - if (count > 1) { - return count; + const c = parseInt(count || grantCount || 0); + if (c > 1) { + return c; } }, From b4d3973aa1006f959fcfca9014bc479b7af3d81d Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Fri, 25 Mar 2016 14:03:00 -0700 Subject: [PATCH 26/44] add success color to check on badges --- app/assets/stylesheets/common/base/user-badges.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/common/base/user-badges.scss b/app/assets/stylesheets/common/base/user-badges.scss index c781f323583..49eb08b7675 100644 --- a/app/assets/stylesheets/common/base/user-badges.scss +++ b/app/assets/stylesheets/common/base/user-badges.scss @@ -234,7 +234,7 @@ } .check-display.status-checked { - background-color: dark-light-diff($primary, $secondary, 40%, -60%); + background-color: $success; } .check-display.status-unchecked { From 96b765d1e6320b25a95990af8e37df46963fbcec Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 25 Mar 2016 17:34:09 -0400 Subject: [PATCH 27/44] FIX: Broken link --- app/assets/javascripts/discourse/templates/badges/index.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/templates/badges/index.hbs b/app/assets/javascripts/discourse/templates/badges/index.hbs index 3eb249eda99..f82722c2d6f 100644 --- a/app/assets/javascripts/discourse/templates/badges/index.hbs +++ b/app/assets/javascripts/discourse/templates/badges/index.hbs @@ -9,7 +9,7 @@
{{#each bg.badges as |b|}} - {{#link-to 'badges.show' badge.id badge.slug}} + {{#link-to 'badges.show' b.id b.slug}} {{badge-card badge=b}} {{/link-to}} {{/each}} From 483c19199ebb6250a775f71af3bf04a51e9054e9 Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Fri, 25 Mar 2016 16:31:34 -0700 Subject: [PATCH 28/44] slightly shorter badge copy --- config/locales/client.en.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 347efcb6bd0..13bc3f37702 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -2858,8 +2858,8 @@ en: granted_on: "Granted %{date}" others_count: "Others with this badge (%{count})" title: Badges - allow_title: "can be used as a title" - multiple_grant: "can be awarded multiple times" + allow_title: "available title" + multiple_grant: "awarded multiple times" badge_count: one: "1 Badge" other: "%{count} Badges" From 8a8d931688550e8867a56b227a864f4429d8b155 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Sat, 26 Mar 2016 10:25:33 +0800 Subject: [PATCH 29/44] UX: Buttons not positioned within form. --- .../javascripts/discourse/templates/user/preferences.hbs | 2 +- app/assets/stylesheets/mobile/user.scss | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/templates/user/preferences.hbs b/app/assets/javascripts/discourse/templates/user/preferences.hbs index d5e4699834d..6591c9eb824 100644 --- a/app/assets/javascripts/discourse/templates/user/preferences.hbs +++ b/app/assets/javascripts/discourse/templates/user/preferences.hbs @@ -278,7 +278,7 @@ {{plugin-outlet "user-custom-controls"}} -
+
{{partial 'user/preferences/save-button'}}
diff --git a/app/assets/stylesheets/mobile/user.scss b/app/assets/stylesheets/mobile/user.scss index 489730fdbde..b4c841f97c8 100644 --- a/app/assets/stylesheets/mobile/user.scss +++ b/app/assets/stylesheets/mobile/user.scss @@ -56,6 +56,10 @@ } } + .delete-account { + overflow: hidden; + } + .checkbox-label { overflow: auto; display: block; From ef6536453bcb801787644664500071b22fdb4a0d Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Sat, 26 Mar 2016 11:51:11 +0800 Subject: [PATCH 30/44] UX: Logs notice close button not positioned properly. --- .../javascripts/discourse/components/global-notice.js.es6 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/discourse/components/global-notice.js.es6 b/app/assets/javascripts/discourse/components/global-notice.js.es6 index 852f19ecd88..f61798163fb 100644 --- a/app/assets/javascripts/discourse/components/global-notice.js.es6 +++ b/app/assets/javascripts/discourse/components/global-notice.js.es6 @@ -27,9 +27,9 @@ export default Ember.Component.extend(StringBuffer, { if (notices.length > 0) { buffer.push(_.map(notices, n => { - var html = `
${n[0]}`; + var html = `
`; if (n[2]) html += n[2]; - html += '
'; + html += `${n[0]}
`; return html; }).join("")); } From 4648c0ee1938347b9d8b8de895aaff2d60bf6e8b Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Sat, 26 Mar 2016 09:47:05 +0530 Subject: [PATCH 31/44] FIX: description for custom badges were not showing up --- app/assets/javascripts/discourse/components/badge-card.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/components/badge-card.js.es6 b/app/assets/javascripts/discourse/components/badge-card.js.es6 index 72e97bf8e2d..82914733ae4 100644 --- a/app/assets/javascripts/discourse/components/badge-card.js.es6 +++ b/app/assets/javascripts/discourse/components/badge-card.js.es6 @@ -17,7 +17,7 @@ export default Ember.Component.extend({ if (size === 'large') { return Discourse.Emoji.unescape(this.get('badge.long_description') || ''); } - return this.get('badge.translatedDescription'); + return this.get('badge.displayDescriptionHtml'); } }); From 9a5ded48cfc1204742ae97ea5120907f5cc10462 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Sat, 26 Mar 2016 13:28:49 +0800 Subject: [PATCH 32/44] FIX: Return a proper error message when sync sso fails. --- app/controllers/admin/users_controller.rb | 8 +- .../admin/users_controller_spec.rb | 88 +++++++++++-------- 2 files changed, 57 insertions(+), 39 deletions(-) diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index da18abe08dc..b51f6e71a35 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -282,9 +282,13 @@ class Admin::UsersController < Admin::AdminController return render nothing: true, status: 404 unless SiteSetting.enable_sso sso = DiscourseSingleSignOn.parse("sso=#{params[:sso]}&sig=#{params[:sig]}") - user = sso.lookup_or_create_user - render_serialized(user, AdminDetailedUserSerializer, root: false) + begin + user = sso.lookup_or_create_user + render_serialized(user, AdminDetailedUserSerializer, root: false) + rescue ActiveRecord::RecordInvalid => ex + render json: failed_json.merge(message: ex.message), status: 403 + end end def delete_other_accounts_with_same_ip diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index b3de180969c..d49745940b4 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -507,52 +507,66 @@ describe Admin::UsersController do end - it 'can sync up sso' do - log_in(:admin) - SiteSetting.enable_sso = true - SiteSetting.sso_overrides_email = true - SiteSetting.sso_overrides_name = true - SiteSetting.sso_overrides_username = true + context '#sync_sso' do + let(:sso) { SingleSignOn.new } + let(:sso_secret) { "sso secret" } - SiteSetting.sso_secret = "sso secret" + before do + log_in(:admin) - sso = SingleSignOn.new - sso.sso_secret = "sso secret" - sso.name = "Bob The Bob" - sso.username = "bob" - sso.email = "bob@bob.com" - sso.external_id = "1" + SiteSetting.enable_sso = true + SiteSetting.sso_overrides_email = true + SiteSetting.sso_overrides_name = true + SiteSetting.sso_overrides_username = true + SiteSetting.sso_secret = sso_secret + sso.sso_secret = sso_secret + end - user = DiscourseSingleSignOn.parse(sso.payload) - .lookup_or_create_user - sso.name = "Bill" - sso.username = "Hokli$$!!" - sso.email = "bob2@bob.com" + it 'can sync up with the sso' do + sso.name = "Bob The Bob" + sso.username = "bob" + sso.email = "bob@bob.com" + sso.external_id = "1" - xhr :post, :sync_sso, Rack::Utils.parse_query(sso.payload) - expect(response).to be_success + user = DiscourseSingleSignOn.parse(sso.payload) + .lookup_or_create_user - user.reload - expect(user.email).to eq("bob2@bob.com") - expect(user.name).to eq("Bill") - expect(user.username).to eq("Hokli") + sso.name = "Bill" + sso.username = "Hokli$$!!" + sso.email = "bob2@bob.com" - # It can also create new users - sso = SingleSignOn.new - sso.sso_secret = "sso secret" - sso.name = "Dr. Claw" - sso.username = "dr_claw" - sso.email = "dr@claw.com" - sso.external_id = "2" - xhr :post, :sync_sso, Rack::Utils.parse_query(sso.payload) - expect(response).to be_success + xhr :post, :sync_sso, Rack::Utils.parse_query(sso.payload) + expect(response).to be_success - user = User.where(email: 'dr@claw.com').first - expect(user).to be_present - expect(user.ip_address).to be_blank + user.reload + expect(user.email).to eq("bob2@bob.com") + expect(user.name).to eq("Bill") + expect(user.username).to eq("Hokli") + end + it 'should create new users' do + sso.name = "Dr. Claw" + sso.username = "dr_claw" + sso.email = "dr@claw.com" + sso.external_id = "2" + xhr :post, :sync_sso, Rack::Utils.parse_query(sso.payload) + expect(response).to be_success + + user = User.where(email: 'dr@claw.com').first + expect(user).to be_present + expect(user.ip_address).to be_blank + end + + it 'should return the right message if the record is invalid' do + sso.email = "" + sso.name = "" + sso.external_id = "1" + + xhr :post, :sync_sso, Rack::Utils.parse_query(sso.payload) + expect(response.status).to eq(403) + expect(JSON.parse(response.body)["message"]).to include("Email can't be blank") + end end - end From 4f061ee4443341b43047867a817bea104e1dd116 Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Sat, 26 Mar 2016 01:16:53 -0700 Subject: [PATCH 33/44] no width on submit-panel helps small phones --- app/assets/stylesheets/mobile/compose.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/mobile/compose.scss b/app/assets/stylesheets/mobile/compose.scss index d7372c53a31..276dbdd1db5 100644 --- a/app/assets/stylesheets/mobile/compose.scss +++ b/app/assets/stylesheets/mobile/compose.scss @@ -181,7 +181,7 @@ input { bottom: 35px; } .submit-panel { - width: 50%; + // don't specify width; needs to auto-size for smallest phones position: absolute; display: block; bottom: 2px; From b83861325e82941c96b7b8d3b19e3a214b7c68a8 Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Sat, 26 Mar 2016 01:18:16 -0700 Subject: [PATCH 34/44] tighten submit button spacing on mobile too --- app/assets/stylesheets/mobile/compose.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/mobile/compose.scss b/app/assets/stylesheets/mobile/compose.scss index 276dbdd1db5..f272ffe7131 100644 --- a/app/assets/stylesheets/mobile/compose.scss +++ b/app/assets/stylesheets/mobile/compose.scss @@ -184,7 +184,7 @@ input { // don't specify width; needs to auto-size for smallest phones position: absolute; display: block; - bottom: 2px; + bottom: 0; } } .category-input { From 04f68f6277e71d868166907392da7187d7d067e7 Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Sat, 26 Mar 2016 01:30:20 -0700 Subject: [PATCH 35/44] make badges work better on mobile --- app/assets/stylesheets/mobile/user.scss | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/mobile/user.scss b/app/assets/stylesheets/mobile/user.scss index b4c841f97c8..5c347a5ba20 100644 --- a/app/assets/stylesheets/mobile/user.scss +++ b/app/assets/stylesheets/mobile/user.scss @@ -179,12 +179,9 @@ } .user-content { - padding: 10px 8px; background-color: $secondary; - border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); - margin-bottom: 10px; box-sizing: border-box; - margin-top: 20px; + margin-top: 10px; .btn.right { float: right @@ -600,3 +597,13 @@ .notification-buttons { display: inline-block; } + +// mobile fixups for badges + +.badge-card.medium { + width: 300px; +} + +.show-badge-details .badge-grant-info { + display: none; +} From 1b4b361841a90a4b0d85679ee1f0bba648810c17 Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Sat, 26 Mar 2016 01:51:31 -0700 Subject: [PATCH 36/44] normalize topic map button color on mobile --- app/assets/stylesheets/mobile/topic-post.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/mobile/topic-post.scss b/app/assets/stylesheets/mobile/topic-post.scss index f8ba909fa20..fc07eddb8f8 100644 --- a/app/assets/stylesheets/mobile/topic-post.scss +++ b/app/assets/stylesheets/mobile/topic-post.scss @@ -287,7 +287,7 @@ a.star { .btn { border: 0; padding: 0 15px; - color: $primary; + color: dark-light-choose(scale-color($primary, $lightness: 60%), scale-color($secondary, $lightness: 40%)); background: blend-primary-secondary(5%); border-left: 1px solid dark-light-diff($primary, $secondary, 90%, -65%); border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -65%); From ac6d38ab340fb0b754949a2a0bc05f2c03654a8a Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Sat, 26 Mar 2016 02:02:23 -0700 Subject: [PATCH 37/44] radically simplify our mobile user agent detection --- lib/mobile_detection.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mobile_detection.rb b/lib/mobile_detection.rb index 9dc0e17995a..a9e2702de1b 100644 --- a/lib/mobile_detection.rb +++ b/lib/mobile_detection.rb @@ -1,6 +1,6 @@ module MobileDetection def self.mobile_device?(user_agent) - user_agent =~ /Mobile|Android|webOS/ && !(user_agent =~ /iPad|Nexus (9|10)/) + user_agent =~ /Mobile/ && !(user_agent =~ /iPad/) end # we need this as a reusable chunk that is called from the cache From 0a05c9ee8da22fa29510e0b6cf498ddd5562f968 Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Sat, 26 Mar 2016 02:11:22 -0700 Subject: [PATCH 38/44] remove unnecessary mobile user page padding --- app/assets/stylesheets/mobile/user.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/stylesheets/mobile/user.scss b/app/assets/stylesheets/mobile/user.scss index 5c347a5ba20..2c232e1d634 100644 --- a/app/assets/stylesheets/mobile/user.scss +++ b/app/assets/stylesheets/mobile/user.scss @@ -394,7 +394,6 @@ .user-stream { - padding: 0 10px; .excerpt { margin: 5px 0; font-size: 0.929em; From b3a028acc004e60912e5b46463c3598e28609119 Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Sun, 27 Mar 2016 09:29:27 -0700 Subject: [PATCH 39/44] remove built-in support for bbcode size --- .../discourse/dialects/bbcode_dialect.js | 5 ----- app/assets/stylesheets/common/base/bbcode.scss | 6 ------ test/javascripts/lib/bbcode-test.js.es6 | 14 -------------- 3 files changed, 25 deletions(-) diff --git a/app/assets/javascripts/discourse/dialects/bbcode_dialect.js b/app/assets/javascripts/discourse/dialects/bbcode_dialect.js index 079bb014acb..b13441cfd14 100644 --- a/app/assets/javascripts/discourse/dialects/bbcode_dialect.js +++ b/app/assets/javascripts/discourse/dialects/bbcode_dialect.js @@ -169,11 +169,6 @@ Discourse.BBCode.replaceBBCodeParamsRaw("email", function(param, contents) { return ['a', {href: "mailto:" + param, 'data-bbcode': true}].concat(contents); }); -Discourse.BBCode.register('size', function(contents, params) { - return ['span', {'class': "bbcode-size-" + (parseInt(params, 10) || 1)}].concat(contents); -}); -Discourse.Markdown.whiteListTag('span', 'class', /^bbcode-size-\d+$/); - // Handles `[code] ... [/code]` blocks Discourse.Dialect.replaceBlock({ start: /(\[code\])([\s\S]*)/igm, diff --git a/app/assets/stylesheets/common/base/bbcode.scss b/app/assets/stylesheets/common/base/bbcode.scss index b2ff87815b1..f40d8ac9a7f 100644 --- a/app/assets/stylesheets/common/base/bbcode.scss +++ b/app/assets/stylesheets/common/base/bbcode.scss @@ -13,10 +13,4 @@ span { &.bbcode-s { text-decoration: line-through; } - // Font sizes - @for $i from 4 through 40 { - &.bbcode-size-#{$i} { - font-size: #{$i}px; - } - } } diff --git a/test/javascripts/lib/bbcode-test.js.es6 b/test/javascripts/lib/bbcode-test.js.es6 index 34b3992b843..86ca8d685e2 100644 --- a/test/javascripts/lib/bbcode-test.js.es6 +++ b/test/javascripts/lib/bbcode-test.js.es6 @@ -62,20 +62,6 @@ test('tags with arguments', function() { format("[b]first[/b] [b]second[/b]", "first second", "can bold two things on the same line"); }); -test("size tags", function() { - format("[size=35]BIG [b]whoop[/b][/size]", - "BIG whoop", - "supports [size=]"); - format("[size=asdf]regular[/size]", - "regular", - "it only supports numbers in bbcode"); - format("[size=35]NEWLINE\n\ntest[/size]", - "

NEWLINE

test

", - "works with newlines"); - format("[size=35][quote=\"user\"]quote[/quote][/size]", - "", - "works with nested complex blocks"); -}); test("quotes", function() { From c4176970915a061c117e58b065725de25890e837 Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Sun, 27 Mar 2016 09:47:31 -0700 Subject: [PATCH 40/44] remove unnecessary mobile onebox border --- app/assets/stylesheets/mobile/topic-post.scss | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/assets/stylesheets/mobile/topic-post.scss b/app/assets/stylesheets/mobile/topic-post.scss index fc07eddb8f8..94220ad0cbf 100644 --- a/app/assets/stylesheets/mobile/topic-post.scss +++ b/app/assets/stylesheets/mobile/topic-post.scss @@ -14,11 +14,6 @@ margin-top: 5px; } -.topic-post article { - border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); - padding: 6px 0; -} - .post-stream { padding-bottom: 30px; } From 0f11bc0beb817e1af65b9008034c3aa68536538b Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Sun, 27 Mar 2016 09:58:16 -0700 Subject: [PATCH 41/44] fix tests --- test/javascripts/lib/markdown-test.js.es6 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/javascripts/lib/markdown-test.js.es6 b/test/javascripts/lib/markdown-test.js.es6 index 59222a90a3a..6e8f6e86a00 100644 --- a/test/javascripts/lib/markdown-test.js.es6 +++ b/test/javascripts/lib/markdown-test.js.es6 @@ -510,9 +510,9 @@ test("sanitize", function() { cooked("\n", "


", "it doesn't circumvent XSS with comments"); - cooked("a", "

a

", "it sanitizes spans"); - cooked("a", "

a

", "it sanitizes spans"); - cooked("a", "

a

", "it sanitizes spans"); + cooked("a", "

a

", "it sanitizes spans"); + cooked("a", "

a

", "it sanitizes spans"); + cooked("a", "

a

", "it sanitizes spans"); }); test("URLs in BBCode tags", function() { From 9cc41dea7fb0e7d783f5ec435635c121c0ae05b3 Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Sun, 27 Mar 2016 10:28:18 -0700 Subject: [PATCH 42/44] modernize user agent "is mobile" test strings --- spec/helpers/application_helper_spec.rb | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 5931ec0d3a6..7adf0c2baf4 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -29,28 +29,38 @@ describe ApplicationHelper do context "mobile_view is not set" do it "is false if user agent is not mobile" do - controller.request.stubs(:user_agent).returns('Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36') + controller.request.stubs(:user_agent).returns('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36') expect(helper.mobile_view?).to be_falsey end it "is true for iPhone" do - controller.request.stubs(:user_agent).returns('Mozilla/5.0 (iPhone; U; ru; CPU iPhone OS 4_2_1 like Mac OS X; ru) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148a Safari/6533.18.5') + controller.request.stubs(:user_agent).returns('Mozilla/5.0 (iPhone; CPU iPhone OS 9_2_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13D15 Safari/601.1') + expect(helper.mobile_view?).to eq(true) + end + + it "is true for Android Samsung Galaxy" do + controller.request.stubs(:user_agent).returns('Mozilla/5.0 (Linux; Android 5.0.2; SAMSUNG SM-G925F Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/4.0 Chrome/44.0.2403.133 Mobile Safari/537.36') + expect(helper.mobile_view?).to eq(true) + end + + it "is true for Android Google Nexus 5X" do + controller.request.stubs(:user_agent).returns('Mozilla/5.0 (Linux; Android 6.0; Nexus 5X Build/MDB08I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.43 Mobile Safari/537.36') expect(helper.mobile_view?).to eq(true) end it "is false for iPad" do - controller.request.stubs(:user_agent).returns("Mozilla/5.0 (iPad; CPU OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B176 Safari/7534.48.3") + controller.request.stubs(:user_agent).returns("Mozilla/5.0 (iPad; CPU OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B14 3 Safari/601.1") expect(helper.mobile_view?).to eq(false) end it "is false for Nexus 10 tablet" do - controller.request.stubs(:user_agent).returns("Mozilla/5.0 (Linux; Android 4.2.1; Nexus 10 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19") + controller.request.stubs(:user_agent).returns("Mozilla/5.0 (Linux; Android 5.1.1; Nexus 10 Build/LMY49G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.91 Safari/537.36") expect(helper.mobile_view?).to be_falsey end - it "is true for Nexus 7 tablet" do - controller.request.stubs(:user_agent).returns("Mozilla/5.0 (Linux; Android 4.1.2; Nexus 7 Build/JZ054K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19") - expect(helper.mobile_view?).to eq(true) + it "is false for Nexus 7 tablet" do + controller.request.stubs(:user_agent).returns("Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MMB29Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.91 Safari/537.36") + expect(helper.mobile_view?).to be_falsey end end end From 0aa6dbaa5997d85f3bb5e39a330bd67fce2da035 Mon Sep 17 00:00:00 2001 From: James Kiesel Date: Mon, 28 Mar 2016 07:27:09 +1300 Subject: [PATCH 43/44] Add .byebug_history to gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 3bdbb95c846..95d44c86f8a 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,9 @@ log/ # Ignore Eclipse .buildpath file /.buildpath +# Ignore byebug history +/.byebug_history + # Ignore RubyMine settings /.idea From 6d64b6d39f864947ea1fa52985dc669cd324c481 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Mon, 28 Mar 2016 11:12:08 +0800 Subject: [PATCH 44/44] FIX: Query for category hashtag should be case sensitive. --- app/controllers/category_hashtags_controller.rb | 1 - spec/components/concern/category_hashtag_spec.rb | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/controllers/category_hashtags_controller.rb b/app/controllers/category_hashtags_controller.rb index ca4a1f70062..e779391f374 100644 --- a/app/controllers/category_hashtags_controller.rb +++ b/app/controllers/category_hashtags_controller.rb @@ -3,7 +3,6 @@ class CategoryHashtagsController < ApplicationController def check category_slugs = params[:category_slugs] - category_slugs.each(&:downcase!) ids = category_slugs.map { |category_slug| Category.query_from_hashtag_slug(category_slug).try(:id) } diff --git a/spec/components/concern/category_hashtag_spec.rb b/spec/components/concern/category_hashtag_spec.rb index be60931f795..c57ac891633 100644 --- a/spec/components/concern/category_hashtag_spec.rb +++ b/spec/components/concern/category_hashtag_spec.rb @@ -22,5 +22,13 @@ describe CategoryHashtag do it "should return nil for incorrect parent and child category slug" do expect(Category.query_from_hashtag_slug("random-slug#{CategoryHashtag::SEPARATOR}random-slug")).to eq(nil) end + + it "should be case sensitive" do + parent_category.update_attributes!(slug: "ApPlE") + child_category.update_attributes!(slug: "OraNGE") + + expect(Category.query_from_hashtag_slug("apple")).to eq(nil) + expect(Category.query_from_hashtag_slug("apple:orange")).to eq(nil) + end end end