github.com/jonathaningram/gophish@v0.3.1-0.20170829042651-ac3fe6aeae6c/static/js/src/app/dashboard.js (about)

     1  var campaigns = []
     2  
     3  // statuses is a helper map to point result statuses to ui classes
     4  var statuses = {
     5      "Email Sent": {
     6          color: "#1abc9c",
     7          label: "label-success",
     8          icon: "fa-envelope",
     9          point: "ct-point-sent"
    10      },
    11      "Emails Sent": {
    12          color: "#1abc9c",
    13          label: "label-success",
    14          icon: "fa-envelope",
    15          point: "ct-point-sent"
    16      },
    17      "In progress": {
    18          label: "label-primary"
    19      },
    20      "Queued": {
    21          label: "label-info"
    22      },
    23      "Completed": {
    24          label: "label-success"
    25      },
    26      "Email Opened": {
    27          color: "#f9bf3b",
    28          label: "label-warning",
    29          icon: "fa-envelope",
    30          point: "ct-point-opened"
    31      },
    32      "Clicked Link": {
    33          color: "#F39C12",
    34          label: "label-clicked",
    35          icon: "fa-mouse-pointer",
    36          point: "ct-point-clicked"
    37      },
    38      "Success": {
    39          color: "#f05b4f",
    40          label: "label-danger",
    41          icon: "fa-exclamation",
    42          point: "ct-point-clicked"
    43      },
    44      "Error": {
    45          color: "#6c7a89",
    46          label: "label-default",
    47          icon: "fa-times",
    48          point: "ct-point-error"
    49      },
    50      "Error Sending Email": {
    51          color: "#6c7a89",
    52          label: "label-default",
    53          icon: "fa-times",
    54          point: "ct-point-error"
    55      },
    56      "Submitted Data": {
    57          color: "#f05b4f",
    58          label: "label-danger",
    59          icon: "fa-exclamation",
    60          point: "ct-point-clicked"
    61      },
    62      "Unknown": {
    63          color: "#6c7a89",
    64          label: "label-default",
    65          icon: "fa-question",
    66          point: "ct-point-error"
    67      },
    68      "Sending": {
    69          color: "#428bca",
    70          label: "label-primary",
    71          icon: "fa-spinner",
    72          point: "ct-point-sending"
    73      },
    74      "Campaign Created": {
    75          label: "label-success",
    76          icon: "fa-rocket"
    77      }
    78  }
    79  
    80  var statsMapping = {
    81      "sent": "Email Sent",
    82      "opened": "Email Opened",
    83      "clicked": "Clicked Link",
    84      "submitted_data": "Submitted Data",
    85  }
    86  
    87  function deleteCampaign(idx) {
    88      if (confirm("Delete " + campaigns[idx].name + "?")) {
    89          api.campaignId.delete(campaigns[idx].id)
    90              .success(function (data) {
    91                  successFlash(data.message)
    92                  location.reload()
    93              })
    94      }
    95  }
    96  
    97  /* Renders a pie chart using the provided chartops */
    98  function renderPieChart(chartopts) {
    99      return Highcharts.chart(chartopts['elemId'], {
   100          chart: {
   101              type: 'pie',
   102              events: {
   103                  load: function () {
   104                      var chart = this,
   105                          rend = chart.renderer,
   106                          pie = chart.series[0],
   107                          left = chart.plotLeft + pie.center[0],
   108                          top = chart.plotTop + pie.center[1];
   109                      this.innerText = rend.text(chartopts['data'][0].count, left, top).
   110                          attr({
   111                              'text-anchor': 'middle',
   112                              'font-size': '24px',
   113                              'font-weight': 'bold',
   114                              'fill': chartopts['colors'][0],
   115                              'font-family': 'Helvetica,Arial,sans-serif'
   116                          }).add();
   117                  },
   118                  render: function () {
   119                      this.innerText.attr({ text: chartopts['data'][0].count })
   120                  }
   121              }
   122          },
   123          title: {
   124              text: chartopts['title']
   125          },
   126          plotOptions: {
   127              pie: {
   128                  innerSize: '80%',
   129                  dataLabels: {
   130                      enabled: false
   131                  }
   132              }
   133          },
   134          credits: {
   135              enabled: false
   136          },
   137          tooltip: {
   138              formatter: function () {
   139                  if (this.key == undefined) {
   140                      return false
   141                  }
   142                  return '<span style="color:' + this.color + '">\u25CF</span>' + this.point.name + ': <b>' + this.y + '%</b><br/>'
   143              }
   144          },
   145          series: [{
   146              data: chartopts['data'],
   147              colors: chartopts['colors'],
   148          }]
   149      })
   150  }
   151  
   152  function generateStatsPieCharts(campaigns) {
   153      var stats_data = []
   154      var stats_series_data = {}
   155      var total = 0
   156  
   157      $.each(campaigns, function (i, campaign) {
   158          $.each(campaign.stats, function (status, count) {
   159              if (status == "total") {
   160                  total += count
   161                  return true
   162              }
   163              if (!stats_series_data[status]) {
   164                  stats_series_data[status] = count;
   165              } else {
   166                  stats_series_data[status] += count;
   167              }
   168          })
   169      })
   170      $.each(stats_series_data, function (status, count) {
   171          // I don't like this, but I guess it'll have to work.
   172          // Turns submitted_data into Submitted Data
   173          if (!(status in statsMapping)) {
   174              return true
   175          }
   176          status_label = statsMapping[status]
   177          stats_data.push({
   178              name: status_label,
   179              y: Math.floor((count / total) * 100),
   180              count: count
   181          })
   182          stats_data.push({
   183              name: '',
   184              y: 100 - Math.floor((count / total) * 100)
   185          })
   186          var stats_chart = renderPieChart({
   187              elemId: status + '_chart',
   188              title: status_label,
   189              name: status,
   190              data: stats_data,
   191              colors: [statuses[status_label].color, "#dddddd"]
   192          })
   193          stats_data = []
   194      });
   195  }
   196  
   197  function generateTimelineChart(campaigns) {
   198      var overview_data = []
   199      $.each(campaigns, function (i, campaign) {
   200          var campaign_date = moment.utc(campaign.created_date).local()
   201          // Add it to the chart data
   202          campaign.y = 0
   203          // Clicked events also contain our data submitted events
   204          campaign.y += campaign.stats.clicked
   205          campaign.y = Math.floor((campaign.y / campaign.stats.total) * 100)
   206          // Add the data to the overview chart
   207          overview_data.push({
   208              campaign_id: campaign.id,
   209              name: campaign.name,
   210              x: campaign_date.valueOf(),
   211              y: campaign.y
   212          })
   213      })
   214      Highcharts.chart('overview_chart', {
   215          chart: {
   216              zoomType: 'x',
   217              type: 'areaspline'
   218          },
   219          title: {
   220              text: 'Phishing Success Overview'
   221          },
   222          xAxis: {
   223              type: 'datetime',
   224              dateTimeLabelFormats: {
   225                  second: '%l:%M:%S',
   226                  minute: '%l:%M',
   227                  hour: '%l:%M',
   228                  day: '%b %d, %Y',
   229                  week: '%b %d, %Y',
   230                  month: '%b %Y'
   231              }
   232          },
   233          yAxis: {
   234              min: 0,
   235              max: 100,
   236              title: {
   237                  text: "% of Success"
   238              }
   239          },
   240          tooltip: {
   241              formatter: function () {
   242                  return Highcharts.dateFormat('%A, %b %d %l:%M:%S %P', new Date(this.x)) +
   243                      '<br>' + this.point.name + '<br>% Success: <b>' + this.y + '%</b>'
   244              }
   245          },
   246          legend: {
   247              enabled: false
   248          },
   249          plotOptions: {
   250              series: {
   251                  marker: {
   252                      enabled: true,
   253                      symbol: 'circle',
   254                      radius: 3
   255                  },
   256                  cursor: 'pointer',
   257                  point: {
   258                      events: {
   259                          click: function (e) {
   260                              window.location.href = "/campaigns/" + this.campaign_id
   261                          }
   262                      }
   263                  }
   264              }
   265          },
   266          credits: {
   267              enabled: false
   268          },
   269          series: [{
   270              data: overview_data,
   271              color: "#f05b4f",
   272              fillOpacity: 0.5
   273          }]
   274      })
   275  }
   276  
   277  $(document).ready(function () {
   278      Highcharts.setOptions({
   279          global: {
   280              useUTC: false
   281          }
   282      })
   283      api.campaigns.summary()
   284          .success(function (data) {
   285              $("#loading").hide()
   286              campaigns = data.campaigns
   287              if (campaigns.length > 0) {
   288                  $("#dashboard").show()
   289                  // Create the overview chart data
   290                  campaignTable = $("#campaignTable").DataTable({
   291                      columnDefs: [{
   292                          orderable: false,
   293                          targets: "no-sort"
   294                      },
   295                      { className: "color-sent", targets: [2] },
   296                      { className: "color-opened", targets: [3] },
   297                      { className: "color-clicked", targets: [4] },
   298                      { className: "color-success", targets: [5] }],
   299                      order: [
   300                          [1, "desc"]
   301                      ]
   302                  });
   303                  $.each(campaigns, function (i, campaign) {
   304                      var campaign_date = moment(campaign.created_date).format('MMMM Do YYYY, h:mm:ss a')
   305                      var label = statuses[campaign.status].label || "label-default";
   306                      //section for tooltips on the status of a campaign to show some quick stats
   307                      var launchDate;
   308                      if (moment(campaign.launch_date).isAfter(moment())) {
   309                          launchDate = "Scheduled to start: " + moment(campaign.launch_date).format('MMMM Do YYYY, h:mm:ss a')
   310                          var quickStats = launchDate + "<br><br>" + "Number of recipients: " + campaign.stats.total
   311                      } else {
   312                          launchDate = "Launch Date: " + moment(campaign.launch_date).format('MMMM Do YYYY, h:mm:ss a')
   313                          var quickStats = launchDate + "<br><br>" + "Number of recipients: " + campaign.stats.total + "<br><br>" + "Emails opened: " + campaign.stats.opened + "<br><br>" + "Emails clicked: " + campaign.stats.clicked + "<br><br>" + "Submitted Credentials: " + campaign.stats.submitted_data + "<br><br>" + "Errors : " + campaign.stats.error
   314                      }
   315                      // Add it to the table
   316                      campaignTable.row.add([
   317                          escapeHtml(campaign.name),
   318                          campaign_date,
   319                          campaign.stats.sent,
   320                          campaign.stats.opened,
   321                          campaign.stats.clicked,
   322                          campaign.stats.submitted_data,
   323                          "<span class=\"label " + label + "\" data-toggle=\"tooltip\" data-placement=\"right\" data-html=\"true\" title=\"" + quickStats + "\">" + campaign.status + "</span>",
   324                          "<div class='pull-right'><a class='btn btn-primary' href='/campaigns/" + campaign.id + "' data-toggle='tooltip' data-placement='left' title='View Results'>\
   325                      <i class='fa fa-bar-chart'></i>\
   326                      </a>\
   327                      <button class='btn btn-danger' onclick='deleteCampaign(" + i + ")' data-toggle='tooltip' data-placement='left' title='Delete Campaign'>\
   328                      <i class='fa fa-trash-o'></i>\
   329                      </button></div>"
   330                      ]).draw()
   331                      $('[data-toggle="tooltip"]').tooltip()
   332                  })
   333                  // Build the charts
   334                  generateStatsPieCharts(campaigns)
   335                  generateTimelineChart(campaigns)
   336              } else {
   337                  $("#emptyMessage").show()
   338              }
   339          })
   340          .error(function () {
   341              errorFlash("Error fetching campaigns")
   342          })
   343  })