diff --git a/static/js/dist/app/dashboard.min.js b/static/js/dist/app/dashboard.min.js
index 59e1e6a7..e2d37f7f 100644
--- a/static/js/dist/app/dashboard.min.js
+++ b/static/js/dist/app/dashboard.min.js
@@ -1 +1 @@
-function deleteCampaign(a){confirm("Delete "+campaigns[a].name+"?")&&api.campaignId.delete(campaigns[a].id).success(function(a){successFlash(a.message),location.reload()})}var campaigns=[],labels={"In progress":"label-primary",Queued:"label-info",Completed:"label-success","Emails Sent":"label-success",Error:"label-danger"};$(document).ready(function(){api.campaigns.summary().success(function(a){if($("#loading").hide(),campaigns=a.campaigns,campaigns.length>0){$("#dashboard").show();var t={labels:[],series:[[]]},e={series:[]},s={axisX:{showGrid:!1},showArea:!0,plugins:[],low:0,high:100},i={donut:!0,donutWidth:40,chartPadding:0,showLabel:!1},o=0;campaignTable=$("#campaignTable").DataTable({columnDefs:[{orderable:!1,targets:"no-sort"}],order:[[1,"desc"]]}),$.each(campaigns,function(a,e){var s,i=moment(e.created_date).format("MMMM Do YYYY, h:mm:ss a"),r=labels[e.status]||"label-default";if(moment(e.launch_date).isAfter(moment())){s="Scheduled to start: "+moment(e.launch_date).format("MMMM Do YYYY, h:mm:ss a");var l=s+"
Number of recipients: "+e.stats.total}else{s="Launch Date: "+moment(e.launch_date).format("MMMM Do YYYY, h:mm:ss a");var l=s+"
Number of recipients: "+e.stats.total+"
Emails opened: "+e.stats.opened+"
Emails clicked: "+e.stats.clicked+"
Submitted Credentials: "+e.stats.submitted_data+"
Errors : "+e.stats.error}campaignTable.row.add([escapeHtml(e.name),i,''+e.status+"","
"]).draw(),$('[data-toggle="tooltip"]').tooltip(),e.y=0,e.y+=e.stats.clicked+e.stats.submitted_data,e.y=Math.floor(e.y/e.stats.total*100),o+=e.y,t.labels.push(i),t.series[0].push({meta:a,value:e.y})}),o=Math.floor(o/a.total),e.series.push({meta:"Unsuccessful Phishes",value:100-o}),e.series.push({meta:"Successful Phishes",value:o});new Chartist.Pie("#average_chart",e,i),new Chartist.Line("#overview_chart",t,s);$piechart=$("#average_chart");var r=$piechart.append('').find(".chartist-tooltip").hide();$piechart.on("mouseenter",".ct-slice-donut",function(){var a=$(this);value=a.attr("ct:value"),label=a.attr("ct:meta"),r.html(label+": "+value.toString()+"%").show()}),$piechart.on("mouseleave",".ct-slice-donut",function(){r.hide()}),$piechart.on("mousemove",function(a){r.css({left:(a.offsetX||a.originalEvent.layerX)-r.width()/2-10,top:(a.offsetY+40||a.originalEvent.layerY)-r.height()-80})}),$chart=$("#overview_chart");var l=$chart.append('').find(".chartist-tooltip").hide();$chart.on("mouseenter",".ct-point",function(){var a=$(this);value=a.attr("ct:value")||0,cidx=a.attr("ct:meta"),l.html(campaigns[cidx].name+"
Successes: "+value.toString()+"%").show()}),$chart.on("mouseleave",".ct-point",function(){l.hide()}),$chart.on("mousemove",function(a){l.css({left:(a.offsetX||a.originalEvent.layerX)-l.width()/2-10,top:(a.offsetY+40||a.originalEvent.layerY)-l.height()-40})}),$("#overview_chart").on("click",".ct-point",function(a){$(this).attr("ct:meta");window.location.href="/campaigns/"+campaigns[cidx].id})}else $("#emptyMessage").show()}).error(function(){errorFlash("Error fetching campaigns")})});
\ No newline at end of file
+function deleteCampaign(e){confirm("Delete "+campaigns[e].name+"?")&&api.campaignId.delete(campaigns[e].id).success(function(e){successFlash(e.message),location.reload()})}function generateStatsPieChart(e){var t={donut:!0,donutWidth:40,chartPadding:0,showLabel:!1},a={},i={series:[]},n=0;$.each(e,function(e,t){$.each(t.stats,function(e,t){return"total"==e?(n+=t,!0):void(a[e]?a[e]+=t:a[e]=t)})}),$.each(a,function(e,t){status_label=statsMapping[e],i.series.push({meta:status_label,value:Math.floor(t/n*100)}),$("#stats_chart_legend").append(''+status_label+"")});new Chartist.Pie("#stats_chart",i,t);$piechart=$("#stats_chart");var s=$piechart.append('').find(".chartist-tooltip").hide();$piechart.get(0).__chartist__.on("draw",function(e){e.element.addClass(statuses[e.meta].slice)}),$piechart.get(0).__chartist__.update(i),$piechart.on("mouseenter",".ct-slice-donut",function(){var e=$(this);value=e.attr("ct:value"),label=e.attr("ct:meta"),s.html(label+": "+value.toString()+"%").show()}),$piechart.on("mouseleave",".ct-slice-donut",function(){s.hide()}),$piechart.on("mousemove",function(e){s.css({left:(e.offsetX||e.originalEvent.layerX)-s.width()/2-10,top:(e.offsetY+40||e.originalEvent.layerY)-s.height()-80})})}var campaigns=[],statuses={"Email Sent":{slice:"ct-slice-donut-sent",legend:"ct-legend-sent",label:"label-success",icon:"fa-envelope",point:"ct-point-sent"},"Email Sent":{slice:"ct-slice-donut-sent",legend:"ct-legend-sent",label:"label-success",icon:"fa-envelope",point:"ct-point-sent"},"Email Opened":{slice:"ct-slice-donut-opened",legend:"ct-legend-opened",label:"label-warning",icon:"fa-envelope",point:"ct-point-opened"},"Clicked Link":{slice:"ct-slice-donut-clicked",legend:"ct-legend-clicked",label:"label-clicked",icon:"fa-mouse-pointer",point:"ct-point-clicked"},Success:{slice:"ct-slice-donut-success",legend:"ct-legend-success",label:"label-danger",icon:"fa-exclamation",point:"ct-point-clicked"},Error:{slice:"ct-slice-donut-error",legend:"ct-legend-error",label:"label-default",icon:"fa-times",point:"ct-point-error"},"Error Sending Email":{slice:"ct-slice-donut-error",legend:"ct-legend-error",label:"label-default",icon:"fa-times",point:"ct-point-error"},"Submitted Data":{slice:"ct-slice-donut-success",legend:"ct-legend-success",label:"label-danger",icon:"fa-exclamation",point:"ct-point-clicked"},Unknown:{slice:"ct-slice-donut-error",legend:"ct-legend-error",label:"label-default",icon:"fa-question",point:"ct-point-error"},Sending:{slice:"ct-slice-donut-sending",legend:"ct-legend-sending",label:"label-primary",icon:"fa-spinner",point:"ct-point-sending"},"Campaign Created":{label:"label-success",icon:"fa-rocket"}},statsMapping={sent:"Email Sent",opened:"Email Opened",clicked:"Clicked Link",submitted_data:"Submitted Data",error:"Error"};$(document).ready(function(){api.campaigns.summary().success(function(e){if($("#loading").hide(),campaigns=e.campaigns,campaigns.length>0){$("#dashboard").show();var t={labels:[],series:[[]]},a={axisX:{showGrid:!1},showArea:!0,plugins:[],low:0,high:100};campaignTable=$("#campaignTable").DataTable({columnDefs:[{orderable:!1,targets:"no-sort"}],order:[[1,"desc"]]}),$.each(campaigns,function(e,a){var i,n=moment(a.created_date).format("MMMM Do YYYY, h:mm:ss a"),s=statuses[a.status]||"label-default";if(moment(a.launch_date).isAfter(moment())){i="Scheduled to start: "+moment(a.launch_date).format("MMMM Do YYYY, h:mm:ss a");var l=i+"
Number of recipients: "+a.stats.total}else{i="Launch Date: "+moment(a.launch_date).format("MMMM Do YYYY, h:mm:ss a");var l=i+"
Number of recipients: "+a.stats.total+"
Emails opened: "+a.stats.opened+"
Emails clicked: "+a.stats.clicked+"
Submitted Credentials: "+a.stats.submitted_data+"
Errors : "+a.stats.error}campaignTable.row.add([escapeHtml(a.name),n,''+a.status+"",""]).draw(),$('[data-toggle="tooltip"]').tooltip(),a.y=0,a.y+=a.stats.clicked+a.stats.submitted_data,a.y=Math.floor(a.y/a.stats.total*100),t.labels.push(n),t.series[0].push({meta:e,value:a.y})}),generateStatsPieChart(campaigns);new Chartist.Line("#overview_chart",t,a);$chart=$("#overview_chart");var i=$chart.append('').find(".chartist-tooltip").hide();$chart.on("mouseenter",".ct-point",function(){var e=$(this);value=e.attr("ct:value")||0,cidx=e.attr("ct:meta"),i.html(campaigns[cidx].name+"
Successes: "+value.toString()+"%").show()}),$chart.on("mouseleave",".ct-point",function(){i.hide()}),$chart.on("mousemove",function(e){i.css({left:(e.offsetX||e.originalEvent.layerX)-i.width()/2-10,top:(e.offsetY+40||e.originalEvent.layerY)-i.height()-40})}),$("#overview_chart").on("click",".ct-point",function(e){$(this).attr("ct:meta");window.location.href="/campaigns/"+campaigns[cidx].id})}else $("#emptyMessage").show()}).error(function(){errorFlash("Error fetching campaigns")})});
\ No newline at end of file
diff --git a/static/js/src/app/dashboard.js b/static/js/src/app/dashboard.js
index 9b3e0efb..64ec4f65 100644
--- a/static/js/src/app/dashboard.js
+++ b/static/js/src/app/dashboard.js
@@ -1,12 +1,89 @@
var campaigns = []
- // labels is a map of campaign statuses to
- // CSS classes
-var labels = {
- "In progress": "label-primary",
- "Queued": "label-info",
- "Completed": "label-success",
- "Emails Sent": "label-success",
- "Error": "label-danger"
+
+// statuses is a helper map to point result statuses to ui classes
+var statuses = {
+ "Email Sent": {
+ slice: "ct-slice-donut-sent",
+ legend: "ct-legend-sent",
+ label: "label-success",
+ icon: "fa-envelope",
+ point: "ct-point-sent"
+ },
+ "Email Sent": {
+ slice: "ct-slice-donut-sent",
+ legend: "ct-legend-sent",
+ label: "label-success",
+ icon: "fa-envelope",
+ point: "ct-point-sent"
+ },
+ "Email Opened": {
+ slice: "ct-slice-donut-opened",
+ legend: "ct-legend-opened",
+ label: "label-warning",
+ icon: "fa-envelope",
+ point: "ct-point-opened"
+ },
+ "Clicked Link": {
+ slice: "ct-slice-donut-clicked",
+ legend: "ct-legend-clicked",
+ label: "label-clicked",
+ icon: "fa-mouse-pointer",
+ point: "ct-point-clicked"
+ },
+ "Success": {
+ slice: "ct-slice-donut-success",
+ legend: "ct-legend-success",
+ label: "label-danger",
+ icon: "fa-exclamation",
+ point: "ct-point-clicked"
+ },
+ "Error": {
+ slice: "ct-slice-donut-error",
+ legend: "ct-legend-error",
+ label: "label-default",
+ icon: "fa-times",
+ point: "ct-point-error"
+ },
+ "Error Sending Email": {
+ slice: "ct-slice-donut-error",
+ legend: "ct-legend-error",
+ label: "label-default",
+ icon: "fa-times",
+ point: "ct-point-error"
+ },
+ "Submitted Data": {
+ slice: "ct-slice-donut-success",
+ legend: "ct-legend-success",
+ label: "label-danger",
+ icon: "fa-exclamation",
+ point: "ct-point-clicked"
+ },
+ "Unknown": {
+ slice: "ct-slice-donut-error",
+ legend: "ct-legend-error",
+ label: "label-default",
+ icon: "fa-question",
+ point: "ct-point-error"
+ },
+ "Sending": {
+ slice: "ct-slice-donut-sending",
+ legend: "ct-legend-sending",
+ label: "label-primary",
+ icon: "fa-spinner",
+ point: "ct-point-sending"
+ },
+ "Campaign Created": {
+ label: "label-success",
+ icon: "fa-rocket"
+ }
+}
+
+var statsMapping = {
+ "sent": "Email Sent",
+ "opened": "Email Opened",
+ "clicked": "Clicked Link",
+ "submitted_data": "Submitted Data",
+ "error": "Error"
}
function deleteCampaign(idx) {
@@ -19,6 +96,75 @@ function deleteCampaign(idx) {
}
}
+function generateStatsPieChart(campaigns) {
+ var stats_opts = {
+ donut: true,
+ donutWidth: 40,
+ chartPadding: 0,
+ showLabel: false
+ }
+ var stats_series_data = {}
+ var stats_data = {
+ series: []
+ }
+ var total = 0
+
+ $.each(campaigns, function(i, campaign) {
+ $.each(campaign.stats, function(status, count) {
+ if (status == "total") {
+ total += count
+ return true
+ }
+ if (!stats_series_data[status]) {
+ stats_series_data[status] = count;
+ } else {
+ stats_series_data[status] += count;
+ }
+ })
+ })
+ $.each(stats_series_data, function(status, count) {
+ // I don't like this, but I guess it'll have to work.
+ // Turns submitted_data into Submitted Data
+ status_label = statsMapping[status]
+ stats_data.series.push({
+ meta: status_label,
+ value: Math.floor((count / total) * 100)
+ })
+ $("#stats_chart_legend").append('' + status_label + '')
+ })
+
+ var stats_chart = new Chartist.Pie("#stats_chart", stats_data, stats_opts)
+
+ $piechart = $("#stats_chart")
+ var $pietoolTip = $piechart
+ .append('')
+ .find('.chartist-tooltip')
+ .hide();
+
+ $piechart.get(0).__chartist__.on('draw', function(data) {
+ data.element.addClass(statuses[data.meta].slice)
+ })
+ // Update with the latest data
+ $piechart.get(0).__chartist__.update(stats_data)
+
+ $piechart.on('mouseenter', '.ct-slice-donut', function() {
+ var $point = $(this)
+ value = $point.attr('ct:value')
+ label = $point.attr('ct:meta')
+ $pietoolTip.html(label + ': ' + value.toString() + "%").show();
+ });
+
+ $piechart.on('mouseleave', '.ct-slice-donut', function() {
+ $pietoolTip.hide();
+ });
+ $piechart.on('mousemove', function(event) {
+ $pietoolTip.css({
+ left: (event.offsetX || event.originalEvent.layerX) - $pietoolTip.width() / 2 - 10,
+ top: (event.offsetY + 40 || event.originalEvent.layerY) - $pietoolTip.height() - 80
+ });
+ });
+}
+
$(document).ready(function() {
api.campaigns.summary()
.success(function(data) {
@@ -33,9 +179,6 @@ $(document).ready(function() {
[]
]
}
- var average_data = {
- series: []
- }
var overview_opts = {
axisX: {
showGrid: false
@@ -45,13 +188,6 @@ $(document).ready(function() {
low: 0,
high: 100
}
- var average_opts = {
- donut: true,
- donutWidth: 40,
- chartPadding: 0,
- showLabel: false
- }
- var average = 0
campaignTable = $("#campaignTable").DataTable({
columnDefs: [{
orderable: false,
@@ -62,19 +198,19 @@ $(document).ready(function() {
]
});
$.each(campaigns, function(i, campaign) {
- var campaign_date = moment(campaign.created_date).format('MMMM Do YYYY, h:mm:ss a')
- var label = labels[campaign.status] || "label-default";
- //section for tooltips on the status of a campaign to show some quick stats
- var launchDate;
- if (moment(campaign.launch_date).isAfter(moment())) {
- launchDate = "Scheduled to start: " + moment(campaign.launch_date).format('MMMM Do YYYY, h:mm:ss a')
- var quickStats = launchDate + "
" + "Number of recipients: " + campaign.stats.total
- } else {
- launchDate = "Launch Date: " + moment(campaign.launch_date).format('MMMM Do YYYY, h:mm:ss a')
- var quickStats = launchDate + "
" + "Number of recipients: " + campaign.stats.total + "
" + "Emails opened: " + campaign.stats.opened + "
" + "Emails clicked: " + campaign.stats.clicked + "
" + "Submitted Credentials: " + campaign.stats.submitted_data + "
" + "Errors : " + campaign.stats.error
- }
- // Add it to the table
- campaignTable.row.add([
+ var campaign_date = moment(campaign.created_date).format('MMMM Do YYYY, h:mm:ss a')
+ var label = statuses[campaign.status] || "label-default";
+ //section for tooltips on the status of a campaign to show some quick stats
+ var launchDate;
+ if (moment(campaign.launch_date).isAfter(moment())) {
+ launchDate = "Scheduled to start: " + moment(campaign.launch_date).format('MMMM Do YYYY, h:mm:ss a')
+ var quickStats = launchDate + "
" + "Number of recipients: " + campaign.stats.total
+ } else {
+ launchDate = "Launch Date: " + moment(campaign.launch_date).format('MMMM Do YYYY, h:mm:ss a')
+ var quickStats = launchDate + "
" + "Number of recipients: " + campaign.stats.total + "
" + "Emails opened: " + campaign.stats.opened + "
" + "Emails clicked: " + campaign.stats.clicked + "
" + "Submitted Credentials: " + campaign.stats.submitted_data + "
" + "Errors : " + campaign.stats.error
+ }
+ // Add it to the table
+ campaignTable.row.add([
escapeHtml(campaign.name),
campaign_date,
"" + campaign.status + "",
@@ -85,54 +221,21 @@ $(document).ready(function() {
\
"
]).draw()
- $('[data-toggle="tooltip"]').tooltip()
- // Add it to the chart data
- campaign.y = 0
- campaign.y += campaign.stats.clicked + campaign.stats.submitted_data
- campaign.y = Math.floor((campaign.y / campaign.stats.total) * 100)
- average += campaign.y
- // Add the data to the overview chart
- overview_data.labels.push(campaign_date)
- overview_data.series[0].push({
- meta: i,
- value: campaign.y
- })
- })
- average = Math.floor(average / data.total);
- average_data.series.push({
- meta: "Unsuccessful Phishes",
- value: 100 - average
- })
- average_data.series.push({
- meta: "Successful Phishes",
- value: average
+ $('[data-toggle="tooltip"]').tooltip()
+ // Add it to the chart data
+ campaign.y = 0
+ campaign.y += campaign.stats.clicked + campaign.stats.submitted_data
+ campaign.y = Math.floor((campaign.y / campaign.stats.total) * 100)
+ // Add the data to the overview chart
+ overview_data.labels.push(campaign_date)
+ overview_data.series[0].push({
+ meta: i,
+ value: campaign.y
+ })
})
// Build the charts
- var average_chart = new Chartist.Pie("#average_chart", average_data, average_opts)
+ generateStatsPieChart(campaigns)
var overview_chart = new Chartist.Line('#overview_chart', overview_data, overview_opts)
- // Setup the average chart listeners
- $piechart = $("#average_chart")
- var $pietoolTip = $piechart
- .append('')
- .find('.chartist-tooltip')
- .hide();
-
- $piechart.on('mouseenter', '.ct-slice-donut', function() {
- var $point = $(this)
- value = $point.attr('ct:value')
- label = $point.attr('ct:meta')
- $pietoolTip.html(label + ': ' + value.toString() + "%").show();
- });
-
- $piechart.on('mouseleave', '.ct-slice-donut', function() {
- $pietoolTip.hide();
- });
- $piechart.on('mousemove', function(event) {
- $pietoolTip.css({
- left: (event.offsetX || event.originalEvent.layerX) - $pietoolTip.width() / 2 - 10,
- top: (event.offsetY + 40 || event.originalEvent.layerY) - $pietoolTip.height() - 80
- });
- });
// Setup the overview chart listeners
$chart = $("#overview_chart")
diff --git a/templates/dashboard.html b/templates/dashboard.html
index f0ba3079..ce798175 100644
--- a/templates/dashboard.html
+++ b/templates/dashboard.html
@@ -45,15 +45,9 @@
Average Phishing Results
-
-
-
- -
- Successful Phishes
-
- -
- Unsuccessful Phishes
-
+
+