From 15120bb5832d49eb1d4cb6055c8b2d1986df5767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= <regis@hanol.fr> Date: Mon, 30 Jun 2014 22:46:47 +0200 Subject: [PATCH] FEATURE: add staff counters on user profile --- .../templates/user/user.js.handlebars | 43 +++-- app/assets/stylesheets/desktop/user.scss | 37 ++++ app/serializers/user_serializer.rb | 181 ++++++++++++------ config/locales/client.en.yml | 6 + 4 files changed, 190 insertions(+), 77 deletions(-) diff --git a/app/assets/javascripts/discourse/templates/user/user.js.handlebars b/app/assets/javascripts/discourse/templates/user/user.js.handlebars index 68115932082..e9ee00f74a3 100644 --- a/app/assets/javascripts/discourse/templates/user/user.js.handlebars +++ b/app/assets/javascripts/discourse/templates/user/user.js.handlebars @@ -64,25 +64,40 @@ <div class='details'> <div class='primary'> - {{bound-avatar model "huge"}} + <div class='staff-counters'> + {{#if number_of_flags_given}} + <div><span class="pill helpful-flags">{{number_of_flags_given}}</span> {{i18n user.staff_counters.flags_given}}</div> + {{/if}} + {{#if number_of_flagged_posts}} + <div><span class="pill flagged-posts">{{number_of_flagged_posts}}</span> {{i18n user.staff_counters.flagged_posts}}</div> + {{/if}} + {{#if number_of_deleted_posts}} + <div><span class="pill deleted-posts">{{number_of_deleted_posts}}</span> {{i18n user.staff_counters.deleted_posts}}</div> + {{/if}} + {{#if number_of_suspensions}} + <div><span class="pill suspensions">{{number_of_suspensions}}</span> {{i18n user.staff_counters.suspensions}}</div> + {{/if}} + </div> - <div class="primary-textual"> - <h1>{{username}} {{{statusIcon}}}</h1> - <h2>{{name}}</h2> + {{bound-avatar model "huge"}} - <div class='bio'>{{{bio_cooked}}}</div> + <div class="primary-textual"> + <h1>{{username}} {{{statusIcon}}}</h1> + <h2>{{name}}</h2> - {{groups-list groups=custom_groups}} + <div class='bio'>{{{bio_cooked}}}</div> - {{plugin-outlet "user-profile-primary"}} + {{groups-list groups=custom_groups}} - {{#if isSuspended}} - <div class='suspended'> - <i class='fa fa-ban'></i> - <b>{{i18n user.suspended_notice date="suspendedTillDate"}}</b><br/> - <b>{{i18n user.suspended_reason}}</b> {{suspend_reason}} - </div> - {{/if}} + {{plugin-outlet "user-profile-primary"}} + + {{#if isSuspended}} + <div class='suspended'> + <i class='fa fa-ban'></i> + <b>{{i18n user.suspended_notice date="suspendedTillDate"}}</b><br/> + <b>{{i18n user.suspended_reason}}</b> {{suspend_reason}} + </div> + {{/if}} </div> </div> diff --git a/app/assets/stylesheets/desktop/user.scss b/app/assets/stylesheets/desktop/user.scss index 4ff58176e56..ccb8650db82 100644 --- a/app/assets/stylesheets/desktop/user.scss +++ b/app/assets/stylesheets/desktop/user.scss @@ -190,6 +190,7 @@ } .primary { + position: relative; margin-top: 20px; float: left; width: 65%; @@ -248,6 +249,10 @@ margin-top: 0; } + .staff-counters { + display: none; + } + .details { .secondary { display: none; } .bio { display: none; } @@ -332,4 +337,36 @@ margin-top: -4px; } } + + .staff-counters { + text-align: left; + position: absolute; + top: -20px; + > div { + margin-bottom: 10px; + } + } + + .pill { + font-size: 2em; + border-radius: 100%; + display: inline-block; + height: 30px; + width: 40px; + text-align: center; + vertical-align: middle; + padding-top: 10px; + } + .helpful-flags { + background-color: green; + } + .flagged-posts { + background-color: #E49735; + } + .deleted-posts { + background-color: #EC441B; + } + .suspensions { + background-color: #c22020; + } } diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb index 279b76b9d8c..72b0211a04f 100644 --- a/app/serializers/user_serializer.rb +++ b/app/serializers/user_serializer.rb @@ -1,5 +1,23 @@ class UserSerializer < BasicUserSerializer + def self.staff_attributes(*attrs) + attributes(*attrs) + attrs.each do |attr| + define_method "include_#{attr}?" do + scope.is_staff? + end + end + end + + def self.private_attributes(*attrs) + attributes(*attrs) + attrs.each do |attr| + define_method "include_#{attr}?" do + can_edit + end + end + end + attributes :name, :email, :last_posted_at, @@ -30,27 +48,12 @@ class UserSerializer < BasicUserSerializer has_many :custom_groups, embed: :object, serializer: BasicGroupSerializer has_many :featured_user_badges, embed: :ids, serializer: UserBadgeSerializer, root: :user_badges - def self.private_attributes(*attrs) - attributes(*attrs) - attrs.each do |attr| - define_method "include_#{attr}?" do - can_edit - end - end - end - def bio_excerpt - # If they have a bio return it - excerpt = object.user_profile.bio_excerpt - return excerpt if excerpt.present? + staff_attributes :number_of_deleted_posts, + :number_of_flagged_posts, + :number_of_flags_given, + :number_of_suspensions - # Without a bio, determine what message to show - if scope.user && scope.user.id == object.id - I18n.t('user_profile.no_info_me', username_lower: object.username_lower) - else - I18n.t('user_profile.no_info_other', name: object.name) - end - end private_attributes :email, :locale, @@ -74,24 +77,44 @@ class UserSerializer < BasicUserSerializer :custom_avatar_upload_id, :custom_fields - def gravatar_avatar_upload_id - object.user_avatar.try(:gravatar_upload_id) + ### + ### ATTRIBUTES + ### + + def bio_raw + object.user_profile.bio_raw end - def custom_avatar_upload_id - object.user_avatar.try(:custom_upload_id) + def include_bio_raw? + bio_raw.present? end - def auto_track_topics_after_msecs - object.auto_track_topics_after_msecs || SiteSetting.auto_track_topics_after + def bio_cooked + object.user_profile.bio_processed end - def new_topic_duration_minutes - object.new_topic_duration_minutes || SiteSetting.new_topic_duration_minutes + def website + object.user_profile.website end - def can_send_private_message_to_user - scope.can_send_private_message?(object) + def include_website? + website.present? + end + + def profile_background + object.user_profile.profile_background + end + + def include_profile_background? + profile_background.present? + end + + def location + object.user_profile.location + end + + def include_location? + location.present? end def can_edit @@ -110,45 +133,27 @@ class UserSerializer < BasicUserSerializer scope.can_edit_name?(object) end - def location - object.user_profile.location - end - def include_location? - location.present? - end - - def website - object.user_profile.website - end - def include_website? - website.present? - end - - def include_bio_raw? - bio_raw.present? - end - def bio_raw - object.user_profile.bio_raw - end - - def bio_cooked - object.user_profile.bio_processed - end - - def profile_background - object.user_profile.profile_background - end - def include_profile_background? - profile_background.present? - end - def stats UserAction.stats(object.id, scope) end - def include_suspended? - object.suspended? + def can_send_private_message_to_user + scope.can_send_private_message?(object) end + + def bio_excerpt + # If they have a bio return it + excerpt = object.user_profile.bio_excerpt + return excerpt if excerpt.present? + + # Without a bio, determine what message to show + if scope.user && scope.user.id == object.id + I18n.t('user_profile.no_info_me', username_lower: object.username_lower) + else + I18n.t('user_profile.no_info_other', name: object.name) + end + end + def include_suspend_reason? object.suspended? end @@ -157,6 +162,47 @@ class UserSerializer < BasicUserSerializer object.suspended? end + ### + ### STAFF ATTRIBUTES + ### + + def number_of_deleted_posts + Post.with_deleted + .where(user_id: object.id) + .where(user_deleted: false) + .where.not(deleted_by: object.id) + .count + end + + def number_of_flagged_posts + Post.with_deleted + .where(user_id: object.id) + .where(hidden: true) + .count + end + + def number_of_flags_given + PostAction.where(post_action_type_id: PostActionType.notify_flag_type_ids) + .where(user_id: object.id) + .count + end + + def number_of_suspensions + UserHistory.for(object, :suspend_user).count + end + + ### + ### PRIVATE ATTRIBUTES + ### + + def auto_track_topics_after_msecs + object.auto_track_topics_after_msecs || SiteSetting.auto_track_topics_after + end + + def new_topic_duration_minutes + object.new_topic_duration_minutes || SiteSetting.new_topic_duration_minutes + end + def muted_category_ids CategoryUser.lookup(object, :muted).pluck(:category_id) end @@ -172,4 +218,13 @@ class UserSerializer < BasicUserSerializer def private_messages_stats UserAction.private_messages_stats(object.id, scope) end + + def gravatar_avatar_upload_id + object.user_avatar.try(:gravatar_upload_id) + end + + def custom_avatar_upload_id + object.user_avatar.try(:custom_upload_id) + end + end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 547fa6b7e4e..80715f16f74 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -291,6 +291,12 @@ en: delete_yourself_not_allowed: "You cannot delete your account right now. Contact an admin to do delete your account for you." unread_message_count: "Messages" + staff_counters: + flags_given: "helpful flags cast" + flagged_posts: "flagged posts" + deleted_posts: "deleted posts" + suspensions: "suspensions" + messages: all: "All" mine: "Mine"