From c78cd607b623384a28b01a22ddcf186519ca10f2 Mon Sep 17 00:00:00 2001
From: ArtOfCode- <hello@artofcode.co.uk>
Date: Thu, 6 Aug 2020 16:59:12 +0100
Subject: [PATCH] Rework role toggles and sparklify indicators

---
 app/assets/javascripts/application.js | 24 ------------
 app/assets/javascripts/users.js       | 17 ++++++++
 app/assets/stylesheets/users.scss     | 17 +++++++-
 app/controllers/users_controller.rb   | 56 +++++++--------------------
 app/views/users/mod.html.erb          | 26 ++++++-------
 app/views/users/show.html.erb         |  6 +--
 6 files changed, 63 insertions(+), 83 deletions(-)

diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index ebccb1ea8..8a0134af9 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -139,28 +139,4 @@ $(document).on('ready', function() {
   $('.js-first-visit-notice').on('close.bs.alert', async () => {
     document.cookie = 'dismiss_fvn=true; path=/; expires=Fri, 31 Dec 9999 23:59:59 GMT';
   });
-
-
-  $('.js-role-grant-btn').on("click", (e) => {
-    const $this = $(e.target);
-
-    $.ajax({
-      'type': 'POST',
-      'url': '/users/' + $this.attr("data-user") + "/mod/toggle-role",
-      'data': { role: $this.attr("data-toggle") },
-      'target': $this
-    })
-    .done((response) => {
-      if (response.status !== 'success') {
-        QPixel.createNotification('danger', '<strong>Failed:</strong> ' + response.message);
-      }
-      else {
-        window.location.reload();
-      }
-    })
-    .fail((jqXHR, textStatus, errorThrown) => {
-      QPixel.createNotification('danger', '<strong>Failed:</strong> ' + jqXHR.status);
-      console.log(jqXHR.responseText);
-    });
-  });
 });
diff --git a/app/assets/javascripts/users.js b/app/assets/javascripts/users.js
index 38f6bdade..a818d0466 100644
--- a/app/assets/javascripts/users.js
+++ b/app/assets/javascripts/users.js
@@ -3,4 +3,21 @@ $(() => {
     $('input[type="submit"]').attr('disabled', true).addClass('is-muted is-outlined');
     $('.js-errors').text('Cookies must be enabled in your browser for you to be able to sign up or sign in.');
   }
+
+  $('.js-role-grant-btn').on('click', async ev => {
+    const $tgt = $(ev.target);
+    const resp = await fetch(`/users/${$tgt.attr('data-user')}/mod/toggle-role`, {
+      method: 'POST',
+      body: JSON.stringify({ role: $tgt.attr('data-role') }),
+      headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': QPixel.csrfToken() },
+      credentials: 'include'
+    });
+    const data = await resp.json();
+    if (resp.status !== 200 || data.status !== 'success') {
+      QPixel.createNotification('danger', `<strong>Failed:</strong> ${data.message}`);
+    }
+    else {
+      location.reload();
+    }
+  });
 });
\ No newline at end of file
diff --git a/app/assets/stylesheets/users.scss b/app/assets/stylesheets/users.scss
index 977e46746..af3d4ee29 100644
--- a/app/assets/stylesheets/users.scss
+++ b/app/assets/stylesheets/users.scss
@@ -55,10 +55,17 @@
     flex-grow: 1;
     padding: 1em;
     border-right: 1px solid #ddd;
+
     h1 {
       word-wrap: break-word;
       overflow: auto;
       margin: 0;
+      display: flex;
+      align-items: center;
+
+      > * {
+        margin: 0 0.2em;
+      }
     }
   }
   .user-profile--sidebar {
@@ -101,8 +108,7 @@
     .user-profile--name {
       flex-grow: 0;
       border-right: 0;
-      padding: 0.5em;
-      padding-right: 0;
+      padding: 0.5em 0 0.5em 0.5em;
     }
 
     .user-profile--sidebar {
@@ -117,4 +123,11 @@
   .profile-text {
     max-height: none;
   }
+}
+
+.staff-badge {
+  display: inline-block !important;
+  padding: 3px 6px !important;
+  border-radius: 2px !important;
+  font-weight: 700 !important;
 }
\ No newline at end of file
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index cd2a0c323..908e23793 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -1,6 +1,4 @@
 require 'net/http'
-
-# rubocop:disable Metrics/ClassLength
 class UsersController < ApplicationController
   before_action :authenticate_user!, only: [:edit_profile, :update_profile, :stack_redirect, :transfer_se_content,
                                             :qr_login_code, :me]
@@ -228,50 +226,27 @@ class UsersController < ApplicationController
     end
   end
 
-  # rubocop:disable Metrics/AbcSize
-  # rubocop:disable Metrics/CyclomaticComplexity
   def role_toggle
-    if params[:role] == 'mod'
-      @user.community_user.update(is_moderator: !@user.is_moderator)
-      AuditLog.admin_audit(event_type: 'role_toggle', related: @user, user: current_user,
-                           comment: "moderator to #{@user.is_moderator}")
-      render json: { status: 'success' } && return
+    role_map = { mod: :is_moderator, admin: :is_admin, mod_global: :is_global_moderator, admin_global: :is_global_admin,
+                 staff: :staff }
+    unless role_map.keys.include?(params[:role].underscore.to_sym)
+      render json: { status: 'error', message: "Role not found: #{params[:role]}" }, status: 400
     end
 
-    if current_user.is_global_admin
-      if params[:role] == 'admin'
-        @user.community_user.update(is_admin: !@user.is_admin)
-        AuditLog.admin_audit(event_type: 'role_toggle', related: @user, user: current_user,
-                             comment: "admin to #{@user.is_admin}")
-        render json: { status: 'success' } && return
-      end
-
-      if params[:role] == 'mod-global'
-        @user.update(is_global_moderator: !@user.is_global_moderator)
-        AuditLog.admin_audit(event_type: 'role_toggle', related: @user, user: current_user,
-                             comment: "global mod to #{@user.is_global_moderator}")
-        render json: { status: 'success' } && return
-      end
-
-      if params[:role] == 'admin-global'
-        @user.update(is_global_admin: true)
-        AuditLog.admin_audit(event_type: 'role_toggle', related: @user, user: current_user,
-                             comment: "global admin to #{@user.is_global_admin}")
-        render json: { status: 'success' } && return
-      end
-
-      if params[:role] == 'staff'
-        @user.update(staff: !@user.staff)
-        AuditLog.admin_audit(event_type: 'role_toggle', related: @user, user: current_user,
-                             comment: "staff to #{@user.staff}")
-        render json: { status: 'success' } && return
-      end
+    key = params[:role].underscore.to_sym
+    attrib = role_map[key]
+    if [:mod, :admin].include? key
+      new_value = !@user.community_user.send(attrib)
+      @user.community_user.update(attrib => new_value)
+    else
+      new_value = !@user.send(attrib)
+      @user.update(attrib => new_value)
     end
+    AuditLog.admin_audit(event_type: 'role_toggle', related: @user, user: current_user,
+                         comment: "#{attrib} to #{new_value}")
 
-    render json: { status: 'error', message: "Role not found: #{params[:role]}" }
+    render json: { status: 'success' }
   end
-  # rubocop:enable Metrics/AbcSize
-  # rubocop:enable Metrics/CyclomaticComplexity
 
   def stack_redirect
     response = Net::HTTP.post_form(URI('https://stackoverflow.com/oauth/access_token/json'),
@@ -365,4 +340,3 @@ class UsersController < ApplicationController
     User.joins(:community_user).includes(:community_user, :avatar_attachment)
   end
 end
-# rubocop:enable Metrics/ClassLength
diff --git a/app/views/users/mod.html.erb b/app/views/users/mod.html.erb
index 94b5d8ab3..a9fd72324 100644
--- a/app/views/users/mod.html.erb
+++ b/app/views/users/mod.html.erb
@@ -20,22 +20,22 @@
   <div class="widget--header">Granting / revoking special permissions</div>
   <div class="widget--body">
     <p>You can grant or revoke special user permissions to this user.</p>
-    <% if @user.is_moderator %>
-      <button class="button is-filled js-role-grant-btn" data-toggle="mod" data-user="<%= @user.id %>">Revoke Moderator</button>
+    <% if @user.community_user.is_moderator %>
+      <button class="button is-filled js-role-grant-btn" data-role="mod" data-user="<%= @user.id %>">Revoke Moderator</button>
     <% else %>
-      <button class="button is-outlined js-role-grant-btn" data-toggle="mod" data-user="<%= @user.id %>">Grant Moderator</button>
+      <button class="button is-outlined js-role-grant-btn" data-role="mod" data-user="<%= @user.id %>">Grant Moderator</button>
     <% end %>
     <% if @current_user.is_global_admin %>
-      <% if @user.is_admin %>
-        <button class="button is-filled js-role-grant-btn" data-toggle="admin" data-user="<%= @user.id %>">Revoke Admin</button>
+      <% if @user.community_user.is_admin %>
+        <button class="button is-filled js-role-grant-btn" data-role="admin" data-user="<%= @user.id %>">Revoke Admin</button>
       <% else %>
-        <button class="button is-outlined js-role-grant-btn" data-toggle="admin" data-user="<%= @user.id %>">Grant Admin</button>
+        <button class="button is-outlined js-role-grant-btn" data-role="admin" data-user="<%= @user.id %>">Grant Admin</button>
       <% end %>
   
       <% if @user.is_global_moderator %>
-        <button class="button is-filled js-role-grant-btn" data-toggle="mod-global" data-user="<%= @user.id %>">Revoke Global Moderator</button>
+        <button class="button is-filled js-role-grant-btn" data-role="mod-global" data-user="<%= @user.id %>">Revoke Global Moderator</button>
       <% else %>
-        <button class="button is-outlined js-role-grant-btn" data-toggle="mod-global" data-user="<%= @user.id %>">Grant Gobal Moderator</button>
+        <button class="button is-outlined js-role-grant-btn" data-role="mod-global" data-user="<%= @user.id %>">Grant Global Moderator</button>
       <% end %>
   
       <p>
@@ -44,9 +44,9 @@
       </p>
   
       <% if @user.is_global_admin %>
-        <button class="button is-muted is-filled" disabled>This user is a Global Admin</button>
+        <button class="button is-filled js-role-grant-btn" data-role="admin-global" data-user="<%= @user.id %>">Revoke Global Admin</button>
       <% else %>
-        <button class="button is-outlined js-role-grant-btn" data-toggle="admin-global" data-user="<%= @user.id %>">Grant Gobal Admin</button>
+        <button class="button is-outlined js-role-grant-btn" data-role="admin-global" data-user="<%= @user.id %>">Grant Global Admin</button>
       <% end %>
 
       <p>
@@ -54,10 +54,10 @@
         to help others identify who's who.
       </p>
 
-      <% if @user.is_global_moderator %>
-        <button class="button is-filled js-role-grant-btn" data-toggle="staff" data-user="<%= @user.id %>">Revoke Staff</button>
+      <% if @user.staff? %>
+        <button class="button is-filled js-role-grant-btn" data-role="staff" data-user="<%= @user.id %>">Revoke Staff</button>
       <% else %>
-        <button class="button is-outlined js-role-grant-btn" data-toggle="staff" data-user="<%= @user.id %>">Grant Staff</button>
+        <button class="button is-outlined js-role-grant-btn" data-role="staff" data-user="<%= @user.id %>">Grant Staff</button>
       <% end %>
     <% end %>
   </div>
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb
index 5e85b2326..c08c01bbb 100644
--- a/app/views/users/show.html.erb
+++ b/app/views/users/show.html.erb
@@ -26,12 +26,12 @@
     <h1>
       <%= @user.username %>
       <% if @user.is_admin && SiteSetting['AdminBadgeCharacter'] %>
-        <span class="badge is-user-role"><%= SiteSetting['AdminBadgeCharacter'] %></span>
+        <span class="badge is-user-role" title="Administrator"><%= SiteSetting['AdminBadgeCharacter'] %></span>
       <% elsif @user.is_moderator && SiteSetting['ModBadgeCharacter'] %>
-        <span class="badge is-user-role"><%= SiteSetting['ModBadgeCharacter'] %></span>
+        <span class="badge is-user-role" title="Moderator"><%= SiteSetting['ModBadgeCharacter'] %></span>
       <% end %>
       <% if @user.staff? %>
-        <span class="badge is-tag is-green">staff</span>
+        <span class="badge is-tag is-filled is-green staff-badge">staff</span>
       <% end %>
     </h1>
     <div class="profile-text">
-- 
GitLab