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 })