FEATURE: adds security tab to dashboard (#6768)

FEATURE: adds security tab to dashboard (#6768)

This commit also includes the new staff_logins report

diff --git a/app/assets/javascripts/admin/models/report.js.es6 b/app/assets/javascripts/admin/models/report.js.es6
index 709dac0..6fc812f 100644
--- a/app/assets/javascripts/admin/models/report.js.es6
+++ b/app/assets/javascripts/admin/models/report.js.es6
@@ -276,9 +276,13 @@ const Report = Discourse.Model.extend({
             return this._numberLabel(value, opts);
           }
           if (type === "date") {
-            const date = moment(value, "YYYY-MM-DD");
+            const date = moment(value);
             if (date.isValid()) return this._dateLabel(value, date);
           }
+          if (type === "precise_date") {
+            const date = moment(value);
+            if (date.isValid()) return this._dateLabel(value, date, "LLL");
+          }
           if (type === "text") return this._textLabel(value);
 
           return {
@@ -377,10 +381,10 @@ const Report = Discourse.Model.extend({
     };
   },
 
-  _dateLabel(value, date) {
+  _dateLabel(value, date, format = "LL") {
     return {
       value,
-      formatedValue: value ? date.format("LL") : "—"
+      formatedValue: value ? date.format(format) : "—"
     };
   },
 
diff --git a/app/assets/javascripts/admin/routes/admin-route-map.js.es6 b/app/assets/javascripts/admin/routes/admin-route-map.js.es6
index 89adcfb..4ce0b8f 100644
--- a/app/assets/javascripts/admin/routes/admin-route-map.js.es6
+++ b/app/assets/javascripts/admin/routes/admin-route-map.js.es6
@@ -8,6 +8,10 @@ export default function() {
         path: "/dashboard/moderation",
         resetNamespace: true
       });
+      this.route("admin.dashboardNextSecurity", {
+        path: "/dashboard/security",
+        resetNamespace: true
+      });
     });
 
     this.route(
diff --git a/app/assets/javascripts/admin/templates/dashboard_next.hbs b/app/assets/javascripts/admin/templates/dashboard_next.hbs
index 176f90c..e7b1e1c 100644
--- a/app/assets/javascripts/admin/templates/dashboard_next.hbs
+++ b/app/assets/javascripts/admin/templates/dashboard_next.hbs
@@ -21,6 +21,11 @@
       {{i18n "admin.dashboard.moderation_tab"}}
     {{/link-to}}
   </li>
+  <li class="navigation-item security">
+    {{#link-to "admin.dashboardNextSecurity" class="navigation-link"}}
+      {{i18n "admin.dashboard.security_tab"}}
+    {{/link-to}}
+  </li>
 </ul>
 
 {{outlet}}
diff --git a/app/assets/javascripts/admin/templates/dashboard_next_security.hbs b/app/assets/javascripts/admin/templates/dashboard_next_security.hbs
new file mode 100644
index 0000000..a42e65d
--- /dev/null
+++ b/app/assets/javascripts/admin/templates/dashboard_next_security.hbs
@@ -0,0 +1,15 @@
+<div class="sections">
+  {{plugin-outlet name="admin-dashboard-security-top"}}
+
+  <div class="main-section">
+    {{admin-report
+      dataSourceName="suspicious_logins"
+      filters=lastWeekfilters}}
+
+    {{admin-report
+      dataSourceName="staff_logins"
+      filters=lastWeekfilters}}
+
+    {{plugin-outlet name="admin-dashboard-security-bottom"}}
+  </div>
+</div>
diff --git a/app/assets/stylesheets/common/admin/dashboard_next.scss b/app/assets/stylesheets/common/admin/dashboard_next.scss
index db101eb..1ba8f9a 100644
--- a/app/assets/stylesheets/common/admin/dashboard_next.scss
+++ b/app/assets/stylesheets/common/admin/dashboard_next.scss
@@ -39,6 +39,10 @@
     @include active-navigation-item;
   }
 
+  &.dashboard-next-security .navigation-item.security {
+    @include active-navigation-item;
+  }
+
   &.general .navigation-item.general {
     @include active-navigation-item;
   }
@@ -488,14 +492,8 @@
   margin-bottom: 1.5em;
 }
 
-.dashboard-next-moderation {
-  .admin-dashboard-moderation-top {
-    display: grid;
-    grid-template-columns: repeat(12, 1fr);
-    grid-column-gap: 1em;
-    grid-row-gap: 1em;
-  }
-
+.dashboard-next-moderation,
+.dashboard-next-security {
   .section-body {
     margin-bottom: 1em;
   }
@@ -510,6 +508,7 @@
       grid-column: span 12;
     }
 
+    .admin-dashboard-security-bottom-outlet,
     .admin-dashboard-moderation-bottom-outlet {
       display: grid;
       grid-template-columns: repeat(12, 1fr);
@@ -518,11 +517,16 @@
     }
   }
 
-  .admin-report.flags-status {
+  .admin-report {
     grid-column: span 12;
   }
+}
 
-  .admin-report.post-edits {
-    grid-column: span 12;
+.dashboard-next-moderation {
+  .admin-dashboard-moderation-top {
+    display: grid;
+    grid-template-columns: repeat(12, 1fr);
+    grid-column-gap: 1em;
+    grid-row-gap: 1em;
   }
 }
diff --git a/app/controllers/admin/dashboard_next_controller.rb b/app/controllers/admin/dashboard_next_controller.rb
index 8da41c0..41360bd 100644
--- a/app/controllers/admin/dashboard_next_controller.rb
+++ b/app/controllers/admin/dashboard_next_controller.rb
@@ -12,6 +12,7 @@ class Admin::DashboardNextController < Admin::AdminController
   end
 
   def moderation; end
+  def security; end
 
   def general
     data = AdminDashboardNextGeneralData.fetch_cached_stats
diff --git a/app/models/report.rb b/app/models/report.rb
index 09ad166..19b0b70 100644
--- a/app/models/report.rb
+++ b/app/models/report.rb
@@ -1276,6 +1276,64 @@ class Report
     end
   end
 
+  def self.report_staff_logins(report)
+    report.modes = [:table]
+
+    report.data = []
+
+    report.labels = [
+      {
+        type: :user,
+        properties: {
+          username: :username,
+          id: :user_id,
+          avatar: :avatar_template,
+        },
+        title: I18n.t("reports.staff_logins.labels.user")
+      },
+      {
+        property: :location,
+        title: I18n.t("reports.staff_logins.labels.location")
+      },
+      {
+        property: :created_at,
+        type: :precise_date,
+        title: I18n.t("reports.staff_logins.labels.login_at")
+      }
+    ]
+
+    sql = <<~SQL
+      SELECT
+        t1.created_at created_at,
+        t1.client_ip client_ip,
+        u.username username,
+        u.uploaded_avatar_id uploaded_avatar_id,
+        u.id user_id
+      FROM (
+        SELECT DISTINCT ON (t.client_ip, t.user_id) t.client_ip, t.user_id, t.created_at
+        FROM user_auth_token_logs t
+        WHERE t.user_id IN (#{User.admins.pluck(:id).join(',')})
+          AND t.created_at >= :start_date
+          AND t.created_at <= :end_date
+        ORDER BY t.client_ip, t.user_id, t.created_at DESC
+        LIMIT #{report.limit || 20}
+      ) t1
+      JOIN users u ON u.id = t1.user_id
+      ORDER BY created_at DESC
+    SQL
+
+    DB.query(sql, start_date: report.start_date, end_date: report.end_date).each do |row|
+      data = {}
+      data[:avatar_template] = User.avatar_template(row.username, row.uploaded_avatar_id)
+      data[:user_id] = row.user_id
+      data[:username] = row.username
+      data[:location] = DiscourseIpInfo.get(row.client_ip)[:location]
+      data[:created_at] = row.created_at
+
+      report.data << data
+    end
+  end
+
   def self.report_suspicious_logins(report)
     report.modes = [:table]
 
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 33d9dbd..548fd10 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -2854,6 +2854,7 @@ en:
         all_reports: "All reports"
         general_tab: "General"
         moderation_tab: "Moderation"
+        security_tab: "Security"
         disabled: Disabled
         timeout_error: Sorry, query is taking too long, please pick a shorter interval
         exception_error: Sorry, an error occurred while executing the query
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 4b1d90e..f3eacbe 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -1134,6 +1134,12 @@ en:
         device: Device
         os: Operating System
         login_time: Login Time
+    staff_logins:
+      title: "Staff logins"
+      labels:
+        user: User
+        location: Location
+        login_at: Login at
 
   dashboard:
     rails_env_warning: "Your server is running in %{env} mode."
diff --git a/config/routes.rb b/config/routes.rb

[... diff too long, it was truncated ...]

GitHub
sha: 03014b0d

2 Likes