diff --git a/static/js/app/campaign_results.js b/static/js/app/campaign_results.js index 8574f619..002f0a57 100644 --- a/static/js/app/campaign_results.js +++ b/static/js/app/campaign_results.js @@ -2,254 +2,267 @@ var map = null // statuses is a helper map to point result statuses to ui classes var statuses = { - "Email Sent" : { + "Email Sent": { slice: "ct-slice-donut-sent", legend: "ct-legend-sent", label: "label-success" }, - "Email Opened" : { + "Email Opened": { slice: "ct-slice-donut-opened", legend: "ct-legend-opened", label: "label-warning" }, - "Clicked Link" : { + "Clicked Link": { slice: "ct-slice-donut-clicked", legend: "ct-legend-clicked", label: "label-danger" }, - "Success" : { + "Success": { slice: "ct-slice-donut-clicked", legend: "ct-legend-clicked", label: "label-danger" }, - "Error" : { + "Error": { slice: "ct-slice-donut-error", legend: "ct-legend-error", label: "label-default" }, - "Unknown" : { - slice: "ct-slice-donut-error", - legend: "ct-legend-error", - label: "label-default" + "Unknown": { + slice: "ct-slice-donut-error", + legend: "ct-legend-error", + label: "label-default" } } var campaign = {} -function dismiss(){ +function dismiss() { $("#modal\\.flashes").empty() $("#modal").modal('hide') $("#resultsTable").dataTable().DataTable().clear().draw() } // Deletes a campaign after prompting the user -function deleteCampaign(){ - if (confirm("Are you sure you want to delete: " + campaign.name + "?")){ +function deleteCampaign() { + if (confirm("Are you sure you want to delete: " + campaign.name + "?")) { api.campaignId.delete(campaign.id) - .success(function(msg){ - console.log(msg) - }) - .error(function(e){ - $("#modal\\.flashes").empty().append("
\ + .success(function(msg) { + console.log(msg) + }) + .error(function(e) { + $("#modal\\.flashes").empty().append("
\ " + data.responseJSON.message + "
") - }) + }) } } -$(document).ready(function(){ +$(document).ready(function() { campaign.id = window.location.pathname.split('/').slice(-1)[0] api.campaignId.get(campaign.id) - .success(function(c){ - campaign = c - if (campaign){ - // Set the title - $("#page-title").text("Results for " + c.name) - // Setup tooltips - $('[data-toggle="tooltip"]').tooltip() - // Setup our graphs - var timeline_data = {series:[{ - name: "Events", - data: [] - }]} - var email_data = {series:[]} - var email_legend = {} - var email_series_data = {} - var timeline_opts = { - axisX: { - showGrid: false, - type: Chartist.FixedScaleAxis, - divisor: 5, - labelInterpolationFnc: function(value){ - return moment(value).format('MMMM Do YYYY h:mm') - } - }, - axisY: { - type: Chartist.FixedScaleAxis, - ticks: [0, 1, 2], - low: 0, - showLabel: false - }, - showArea: false, - plugins: [] - } - var email_opts = { - donut : true, - donutWidth: 40, - chartPadding: 0, - showLabel: false - } - // Setup the results table - resultsTable = $("#resultsTable").DataTable(); - $.each(campaign.results, function(i, result){ - label = statuses[result.status].label || "label-default"; - resultsTable.row.add([ - result.first_name || "", - result.last_name || "", - result.email || "", - result.position || "", - "" + result.status + "" - ]).draw() - if (!email_series_data[result.status]){ - email_series_data[result.status] = 1 - } else { - email_series_data[result.status]++; + .success(function(c) { + campaign = c + if (campaign) { + // Set the title + $("#page-title").text("Results for " + c.name) + // Setup tooltips + $('[data-toggle="tooltip"]').tooltip() + // Setup our graphs + var timeline_data = { + series: [{ + name: "Events", + data: [] + }] } - }) - // Setup the graphs - $.each(campaign.timeline, function(i, event){ - timeline_data.series[0].data.push({meta : i, x: new Date(event.time), y:1}) - }) - $.each(email_series_data, function(status, count){ - email_data.series.push({meta: status, value: count}) - }) - var timeline_chart = new Chartist.Line('#timeline_chart', timeline_data, timeline_opts) - // Setup the overview chart listeners - $chart = $("#timeline_chart") - var $toolTip = $chart - .append('
') - .find('.chartist-tooltip') - .hide(); - $chart.on('mouseenter', '.ct-point', function() { - var $point = $(this) - value = $point.attr('ct:value') - cidx = $point.attr('ct:meta') - html = "Event: " + campaign.timeline[cidx].message - if (campaign.timeline[cidx].email) { - html += '
' + "Email: " + campaign.timeline[cidx].email + var email_data = { + series: [] } - $toolTip.html(html).show() - }); - $chart.on('mouseleave', '.ct-point', function() { - $toolTip.hide(); - }); - $chart.on('mousemove', function(event) { - $toolTip.css({ - left: (event.offsetX || event.originalEvent.layerX) - $toolTip.width() / 2 - 10, - top: (event.offsetY + 70 || event.originalEvent.layerY) - $toolTip.height() - 40 - }); - }); - var email_chart = new Chartist.Pie("#email_chart", email_data, email_opts) - email_chart.on('draw', function(data){ - // We don't want to create the legend twice - if (!email_legend[data.meta]) { - console.log(data.meta) - $("#email_chart_legend").append('
  • ' + data.meta + '
  • ') - email_legend[data.meta] = true - } - data.element.addClass(statuses[data.meta].slice) - }) - // Setup the average chart listeners - $piechart = $("#email_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 - }); - }); - $("#loading").hide() - $("#campaignResults").show() - map = new Datamap({ - element: document.getElementById("resultsMap"), - responsive: true, - fills: { - defaultFill: "#ffffff", - point: "#283F50" - }, - geographyConfig: { - highlightFillColor : "#1abc9c", - borderColor:"#283F50" - }, - bubblesConfig: { - borderColor: "#283F50" - } - }); - bubbles = [] - $.each(campaign.results, function(i, result){ - // Check that it wasn't an internal IP - if (result.latitude == 0 && result.longitude == 0) { return true; } - newIP = true - $.each(bubbles, function(i, bubble){ - if (bubble.ip == result.ip){ - bubbles[i].radius += 1 - newIP = false - return false - } - }) - if (newIP){ - console.log("Adding bubble at: ") - console.log({ - latitude : result.latitude, - longitude: result.longitude, - name : result.ip, - fillKey: "point" - }) - bubbles.push({ - latitude : result.latitude, - longitude: result.longitude, - name : result.ip, - fillKey: "point", - radius: 2 - }) - } - }) - map.bubbles(bubbles) - } - // Load up the map data (only once!) - $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { - if ($(e.target).attr('href') == "#overview"){ - if (!map){ - map = new Datamap({ - element: document.getElementById("resultsMap"), - responsive: true, - fills: { - defaultFill: "#ffffff" - }, - geographyConfig: { - highlightFillColor : "#1abc9c", - borderColor:"#283F50" + var email_legend = {} + var email_series_data = {} + var timeline_opts = { + axisX: { + showGrid: false, + type: Chartist.FixedScaleAxis, + divisor: 5, + labelInterpolationFnc: function(value) { + return moment(value).format('MMMM Do YYYY h:mm') } - }); + }, + axisY: { + type: Chartist.FixedScaleAxis, + ticks: [0, 1, 2], + low: 0, + showLabel: false + }, + showArea: false, + plugins: [] } + var email_opts = { + donut: true, + donutWidth: 40, + chartPadding: 0, + showLabel: false + } + // Setup the results table + resultsTable = $("#resultsTable").DataTable(); + $.each(campaign.results, function(i, result) { + label = statuses[result.status].label || "label-default"; + resultsTable.row.add([ + result.first_name || "", + result.last_name || "", + result.email || "", + result.position || "", + "" + result.status + "" + ]).draw() + if (!email_series_data[result.status]) { + email_series_data[result.status] = 1 + } else { + email_series_data[result.status]++; + } + }) + // Setup the graphs + $.each(campaign.timeline, function(i, event) { + timeline_data.series[0].data.push({ + meta: i, + x: new Date(event.time), + y: 1 + }) + }) + $.each(email_series_data, function(status, count) { + email_data.series.push({ + meta: status, + value: count + }) + }) + var timeline_chart = new Chartist.Line('#timeline_chart', timeline_data, timeline_opts) + // Setup the overview chart listeners + $chart = $("#timeline_chart") + var $toolTip = $chart + .append('
    ') + .find('.chartist-tooltip') + .hide(); + $chart.on('mouseenter', '.ct-point', function() { + var $point = $(this) + value = $point.attr('ct:value') + cidx = $point.attr('ct:meta') + html = "Event: " + campaign.timeline[cidx].message + if (campaign.timeline[cidx].email) { + html += '
    ' + "Email: " + campaign.timeline[cidx].email + } + $toolTip.html(html).show() + }); + $chart.on('mouseleave', '.ct-point', function() { + $toolTip.hide(); + }); + $chart.on('mousemove', function(event) { + $toolTip.css({ + left: (event.offsetX || event.originalEvent.layerX) - $toolTip.width() / 2 - 10, + top: (event.offsetY + 70 || event.originalEvent.layerY) - $toolTip.height() - 40 + }); + }); + var email_chart = new Chartist.Pie("#email_chart", email_data, email_opts) + email_chart.on('draw', function(data) { + // We don't want to create the legend twice + if (!email_legend[data.meta]) { + console.log(data.meta) + $("#email_chart_legend").append('
  • ' + data.meta + '
  • ') + email_legend[data.meta] = true + } + data.element.addClass(statuses[data.meta].slice) + }) + // Setup the average chart listeners + $piechart = $("#email_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 + }); + }); + $("#loading").hide() + $("#campaignResults").show() + map = new Datamap({ + element: document.getElementById("resultsMap"), + responsive: true, + fills: { + defaultFill: "#ffffff", + point: "#283F50" + }, + geographyConfig: { + highlightFillColor: "#1abc9c", + borderColor: "#283F50" + }, + bubblesConfig: { + borderColor: "#283F50" + } + }); + bubbles = [] + $.each(campaign.results, function(i, result) { + // Check that it wasn't an internal IP + if (result.latitude == 0 && result.longitude == 0) { + return true; + } + newIP = true + $.each(bubbles, function(i, bubble) { + if (bubble.ip == result.ip) { + bubbles[i].radius += 1 + newIP = false + return false + } + }) + if (newIP) { + console.log("Adding bubble at: ") + console.log({ + latitude: result.latitude, + longitude: result.longitude, + name: result.ip, + fillKey: "point" + }) + bubbles.push({ + latitude: result.latitude, + longitude: result.longitude, + name: result.ip, + fillKey: "point", + radius: 2 + }) + } + }) + map.bubbles(bubbles) } + // Load up the map data (only once!) + $('a[data-toggle="tab"]').on('shown.bs.tab', function(e) { + if ($(e.target).attr('href') == "#overview") { + if (!map) { + map = new Datamap({ + element: document.getElementById("resultsMap"), + responsive: true, + fills: { + defaultFill: "#ffffff" + }, + geographyConfig: { + highlightFillColor: "#1abc9c", + borderColor: "#283F50" + } + }); + } + } + }) + }) + .error(function() { + $("#loading").hide() + errorFlash(" Campaign not found!") }) - }) - .error(function(){ - $("#loading").hide() - errorFlash(" Campaign not found!") - }) }) diff --git a/static/js/app/campaigns.js b/static/js/app/campaigns.js index 4c3a1045..c3a64ee0 100644 --- a/static/js/app/campaigns.js +++ b/static/js/app/campaigns.js @@ -1,212 +1,226 @@ // 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" + "In progress": "label-primary", + "Queued": "label-info", + "Completed": "label-success", + "Emails Sent": "label-success", + "Error": "label-danger" } // Save attempts to POST to /campaigns/ -function save(){ +function save() { groups = [] - $.each($("#groupTable").DataTable().rows().data(), function(i, group){ - groups.push({name: group[0]}) - }) + $.each($("#groupTable").DataTable().rows().data(), function(i, group) { + groups.push({ + name: group[0] + }) + }) console.log(groups) var campaign = { - name: $("#name").val(), - template:{ - name: $("#template").val() - }, - url: $("#url").val(), - page: { - name: $("#page").val() - }, - smtp: { - from_address: $("input[name=from]").val(), - host: $("input[name=host]").val(), - username: $("input[name=username]").val(), - password: $("input[name=password]").val(), - }, - groups: groups - } - // Submit the campaign + name: $("#name").val(), + template: { + name: $("#template").val() + }, + url: $("#url").val(), + page: { + name: $("#page").val() + }, + smtp: { + from_address: $("input[name=from]").val(), + host: $("input[name=host]").val(), + username: $("input[name=username]").val(), + password: $("input[name=password]").val(), + }, + groups: groups + } + // Submit the campaign api.campaigns.post(campaign) - .success(function(data){ - successFlash("Campaign successfully launched!") - window.location = "/campaigns/" + campaign.id.toString() - }) - .error(function(data){ - $("#modal\\.flashes").empty().append("
    \ + .success(function(data) { + successFlash("Campaign successfully launched!") + window.location = "/campaigns/" + campaign.id.toString() + }) + .error(function(data) { + $("#modal\\.flashes").empty().append("
    \ " + data.responseJSON.message + "
    ") - }) + }) } -function dismiss(){ +function dismiss() { $("#modal\\.flashes").empty() $("#modal").modal('hide') $("#groupTable").dataTable().DataTable().clear().draw() } -function edit(campaign){ +function edit(campaign) { // Clear the bloodhound instance group_bh.clear(); template_bh.clear(); page_bh.clear(); if (campaign == "new") { api.groups.get() - .success(function(groups){ - if (groups.length == 0){ - modalError("No groups found!") - return false; - } - else { - group_bh.add(groups) - } - }) - api.templates.get() - .success(function(templates){ - if (templates.length == 0){ - modalError("No templates found!") - return false - } - else { - template_bh.add(templates) - } - }) - api.pages.get() - .success(function(pages){ - if (pages.length == 0){ - modalError("No pages found!") - return false - } - else { - page_bh.add(pages) - } - }) + .success(function(groups) { + if (groups.length == 0) { + modalError("No groups found!") + return false; + } else { + group_bh.add(groups) + } + }) + api.templates.get() + .success(function(templates) { + if (templates.length == 0) { + modalError("No templates found!") + return false + } else { + template_bh.add(templates) + } + }) + api.pages.get() + .success(function(pages) { + if (pages.length == 0) { + modalError("No pages found!") + return false + } else { + page_bh.add(pages) + } + }) } } -$(document).ready(function(){ +$(document).ready(function() { api.campaigns.get() - .success(function(campaigns){ - $("#loading").hide() - if (campaigns.length > 0){ - $("#campaignTable").show() - campaignTable = $("#campaignTable").DataTable(); - $.each(campaigns, function(i, campaign){ - label = labels[campaign.status] || "label-default"; - campaignTable.row.add([ - campaign.name, - moment(campaign.created_date).format('MMMM Do YYYY, h:mm:ss a'), - "" + campaign.status + "", - "
    \ + .success(function(campaigns) { + $("#loading").hide() + if (campaigns.length > 0) { + $("#campaignTable").show() + campaignTable = $("#campaignTable").DataTable(); + $.each(campaigns, function(i, campaign) { + label = labels[campaign.status] || "label-default"; + campaignTable.row.add([ + campaign.name, + moment(campaign.created_date).format('MMMM Do YYYY, h:mm:ss a'), + "" + campaign.status + "", + "
    \ \ \
    " - ]).draw() - }) - } else { - $("#emptyMessage").show() - } - }) - .error(function(){ - $("#loading").hide() - errorFlash("Error fetching campaigns") - }) - $("#groupForm").submit(function(){ - groupTable.row.add([ - $("#groupSelect").val(), - '' - ]).draw() - $("#groupTable").on("click", "span>i.fa-trash-o", function(){ - groupTable.row( $(this).parents('tr') ) - .remove() - .draw(); + ]).draw() + }) + } else { + $("#emptyMessage").show() + } }) - return false; - }) - // Create the group typeahead objects + .error(function() { + $("#loading").hide() + errorFlash("Error fetching campaigns") + }) + $("#groupForm").submit(function() { + groupTable.row.add([ + $("#groupSelect").val(), + '' + ]).draw() + $("#groupTable").on("click", "span>i.fa-trash-o", function() { + groupTable.row($(this).parents('tr')) + .remove() + .draw(); + }) + return false; + }) + // Create the group typeahead objects groupTable = $("#groupTable").DataTable() group_bh = new Bloodhound({ - datumTokenizer: function(g) { return Bloodhound.tokenizers.whitespace(g.name) }, + datumTokenizer: function(g) { + return Bloodhound.tokenizers.whitespace(g.name) + }, queryTokenizer: Bloodhound.tokenizers.whitespace, local: [] }) group_bh.initialize() $("#groupSelect.typeahead.form-control").typeahead({ - hint: true, - highlight: true, - minLength: 1 - }, - { - name: "groups", - source: group_bh, - templates: { - empty: function(data) {return '
    No groups matched that query
    ' }, - suggestion: function(data){ return '
    ' + data.name + '
    ' } - } - }) - .bind('typeahead:select', function(ev, group){ - $("#groupSelect").typeahead('val', group.name) - }) - .bind('typeahead:autocomplete', function(ev, group){ - $("#groupSelect").typeahead('val', group.name) - }); + hint: true, + highlight: true, + minLength: 1 + }, { + name: "groups", + source: group_bh, + templates: { + empty: function(data) { + return '
    No groups matched that query
    ' + }, + suggestion: function(data) { + return '
    ' + data.name + '
    ' + } + } + }) + .bind('typeahead:select', function(ev, group) { + $("#groupSelect").typeahead('val', group.name) + }) + .bind('typeahead:autocomplete', function(ev, group) { + $("#groupSelect").typeahead('val', group.name) + }); // Create the template typeahead objects template_bh = new Bloodhound({ - datumTokenizer: function(t) { return Bloodhound.tokenizers.whitespace(t.name) }, + datumTokenizer: function(t) { + return Bloodhound.tokenizers.whitespace(t.name) + }, queryTokenizer: Bloodhound.tokenizers.whitespace, local: [] }) template_bh.initialize() $("#template.typeahead.form-control").typeahead({ - hint: true, - highlight: true, - minLength: 1 - }, - { - name: "templates", - source: template_bh, - templates: { - empty: function(data) {return '
    No templates matched that query
    ' }, - suggestion: function(data){ return '
    ' + data.name + '
    ' } - } - }) - .bind('typeahead:select', function(ev, template){ - $("#template").typeahead('val', template.name) - }) - .bind('typeahead:autocomplete', function(ev, template){ - $("#template").typeahead('val', template.name) - }); + hint: true, + highlight: true, + minLength: 1 + }, { + name: "templates", + source: template_bh, + templates: { + empty: function(data) { + return '
    No templates matched that query
    ' + }, + suggestion: function(data) { + return '
    ' + data.name + '
    ' + } + } + }) + .bind('typeahead:select', function(ev, template) { + $("#template").typeahead('val', template.name) + }) + .bind('typeahead:autocomplete', function(ev, template) { + $("#template").typeahead('val', template.name) + }); // Create the landing page typeahead objects page_bh = new Bloodhound({ - datumTokenizer: function(p) { return Bloodhound.tokenizers.whitespace(p.name) }, + datumTokenizer: function(p) { + return Bloodhound.tokenizers.whitespace(p.name) + }, queryTokenizer: Bloodhound.tokenizers.whitespace, local: [] }) page_bh.initialize() $("#page.typeahead.form-control").typeahead({ - hint: true, - highlight: true, - minLength: 1 - }, - { - name: "pages", - source: page_bh, - templates: { - empty: function(data) {return '
    No pages matched that query
    ' }, - suggestion: function(data){ return '
    ' + data.name + '
    ' } - } - }) - .bind('typeahead:select', function(ev, page){ - $("#page").typeahead('val', page.name) - }) - .bind('typeahead:autocomplete', function(ev, page){ - $("#page").typeahead('val', page.name) - }); + hint: true, + highlight: true, + minLength: 1 + }, { + name: "pages", + source: page_bh, + templates: { + empty: function(data) { + return '
    No pages matched that query
    ' + }, + suggestion: function(data) { + return '
    ' + data.name + '
    ' + } + } + }) + .bind('typeahead:select', function(ev, page) { + $("#page").typeahead('val', page.name) + }) + .bind('typeahead:autocomplete', function(ev, page) { + $("#page").typeahead('val', page.name) + }); }) diff --git a/static/js/app/dashboard.js b/static/js/app/dashboard.js index c8445b9f..23ed7752 100644 --- a/static/js/app/dashboard.js +++ b/static/js/app/dashboard.js @@ -1,129 +1,145 @@ var campaigns = [] -// labels is a map of campaign statuses to -// CSS classes + // 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" + "In progress": "label-primary", + "Queued": "label-info", + "Completed": "label-success", + "Emails Sent": "label-success", + "Error": "label-danger" } -$(document).ready(function(){ +$(document).ready(function() { api.campaigns.get() - .success(function(cs){ - $("#loading").hide() - campaigns = cs - if (campaigns.length > 0){ - $("#dashboard").show() - // Create the overview chart data - var overview_data = {labels:[],series:[[]]} - var average_data = {series:[]} - var overview_opts = { - axisX: { - showGrid: false - }, - showArea: true, - plugins: [] - } - var average_opts = { - donut : true, - donutWidth: 40, - chartPadding: 0, - showLabel: false - } - var average = 0 - campaignTable = $("#campaignTable").DataTable(); - $.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"; - // Add it to the table - campaignTable.row.add([ - campaign.name, - campaign_date, - "" + campaign.status + "", - "
    \ + .success(function(cs) { + $("#loading").hide() + campaigns = cs + if (campaigns.length > 0) { + $("#dashboard").show() + // Create the overview chart data + var overview_data = { + labels: [], + series: [ + [] + ] + } + var average_data = { + series: [] + } + var overview_opts = { + axisX: { + showGrid: false + }, + showArea: true, + plugins: [] + } + var average_opts = { + donut: true, + donutWidth: 40, + chartPadding: 0, + showLabel: false + } + var average = 0 + campaignTable = $("#campaignTable").DataTable(); + $.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"; + // Add it to the table + campaignTable.row.add([ + campaign.name, + campaign_date, + "" + campaign.status + "", + "
    \ \ \
    " - ]).draw() - // Add it to the chart data - campaign.y = 0 - $.each(campaign.results, function(j, result){ - if (result.status == "Success"){ - campaign.y++; - } + ]).draw() + // Add it to the chart data + campaign.y = 0 + $.each(campaign.results, function(j, result) { + if (result.status == "Success") { + campaign.y++; + } + }) + campaign.y = Math.floor((campaign.y / campaign.results.length) * 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 + }) }) - campaign.y = Math.floor((campaign.y / campaign.results.length) * 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 / campaigns.length); - average_data.series.push({meta: "Unsuccessful Phishes", value: 100 - average}) - average_data.series.push({meta: "Successful Phishes", value: average}) - // Build the charts - var average_chart = new Chartist.Pie("#average_chart", average_data, average_opts) - 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(); + average = Math.floor(average / campaigns.length); + average_data.series.push({ + meta: "Unsuccessful Phishes", + value: 100 - average + }) + average_data.series.push({ + meta: "Successful Phishes", + value: average + }) + // Build the charts + var average_chart = new Chartist.Pie("#average_chart", average_data, average_opts) + 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 + $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(); }); - }); - // Setup the overview chart listeners - $chart = $("#overview_chart") - var $toolTip = $chart - .append('
    ') - .find('.chartist-tooltip') - .hide(); - - $chart.on('mouseenter', '.ct-point', function() { - var $point = $(this) - value = $point.attr('ct:value') || 0 - cidx = $point.attr('ct:meta') - $toolTip.html(campaigns[cidx].name + '
    ' + "Successes: " + value.toString() + "%").show(); - }); - - $chart.on('mouseleave', '.ct-point', function() { - $toolTip.hide(); - }); - $chart.on('mousemove', function(event) { - $toolTip.css({ - left: (event.offsetX || event.originalEvent.layerX) - $toolTip.width() / 2 - 10, - top: (event.offsetY + 40 || event.originalEvent.layerY) - $toolTip.height() - 40 + $piechart.on('mouseleave', '.ct-slice-donut', function() { + $pietoolTip.hide(); }); - }); - $("#overview_chart").on("click", ".ct-point", function(e) { - var $cidx = $(this).attr('ct:meta'); - window.location.href = "/campaigns/" + campaigns[cidx].id - }); - } else { - $("#emptyMessage").show() - } - }) - .error(function(){ - errorFlash("Error fetching campaigns") - }) + $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") + var $toolTip = $chart + .append('
    ') + .find('.chartist-tooltip') + .hide(); + + $chart.on('mouseenter', '.ct-point', function() { + var $point = $(this) + value = $point.attr('ct:value') || 0 + cidx = $point.attr('ct:meta') + $toolTip.html(campaigns[cidx].name + '
    ' + "Successes: " + value.toString() + "%").show(); + }); + + $chart.on('mouseleave', '.ct-point', function() { + $toolTip.hide(); + }); + $chart.on('mousemove', function(event) { + $toolTip.css({ + left: (event.offsetX || event.originalEvent.layerX) - $toolTip.width() / 2 - 10, + top: (event.offsetY + 40 || event.originalEvent.layerY) - $toolTip.height() - 40 + }); + }); + $("#overview_chart").on("click", ".ct-point", function(e) { + var $cidx = $(this).attr('ct:meta'); + window.location.href = "/campaigns/" + campaigns[cidx].id + }); + } else { + $("#emptyMessage").show() + } + }) + .error(function() { + errorFlash("Error fetching campaigns") + }) }) diff --git a/static/js/app/landing_pages.js b/static/js/app/landing_pages.js index dd7b30cb..c2df241e 100644 --- a/static/js/app/landing_pages.js +++ b/static/js/app/landing_pages.js @@ -4,72 +4,75 @@ Author: Jordan Wright */ var pages = [] + // Save attempts to POST to /templates/ -function save(idx){ +function save(idx) { var page = {} page.name = $("#name").val() page.html = CKEDITOR.instances["html_editor"].getData(); - if (idx != -1){ + if (idx != -1) { page.id = pages[idx].id api.pageId.put(page) - .success(function(data){ - successFlash("Page edited successfully!") - load() - dismiss() - }) + .success(function(data) { + successFlash("Page edited successfully!") + load() + dismiss() + }) } else { // Submit the page api.pages.post(page) - .success(function(data){ - successFlash("Page added successfully!") - load() - dismiss() - }) - .error(function(data){ - modalError(data.responseJSON.message) - }) + .success(function(data) { + successFlash("Page added successfully!") + load() + dismiss() + }) + .error(function(data) { + modalError(data.responseJSON.message) + }) } } -function dismiss(){ +function dismiss() { $("#modal\\.flashes").empty() $("#name").val("") $("#html_editor").val("") $("#newLandingPageModal").modal('hide') } -function deletePage(idx){ - if (confirm("Delete " + pages[idx].name + "?")){ +function deletePage(idx) { + if (confirm("Delete " + pages[idx].name + "?")) { api.pageId.delete(pages[idx].id) - .success(function(data){ - successFlash(data.message) - load() - }) + .success(function(data) { + successFlash(data.message) + load() + }) } } -function importSite(){ +function importSite() { url = $("#url").val() - if (!url){ + if (!url) { modalError("No URL Specified!") } else { api.clone_site({ - url: url, - include_resources: false - }) - .success(function(data){ - console.log($("#html_editor")) - $("#html_editor").val(data.html) - $("#importSiteModal").modal("hide") - }) - .error(function(data){ - modalError(data.responseJSON.message) - }) + url: url, + include_resources: false + }) + .success(function(data) { + console.log($("#html_editor")) + $("#html_editor").val(data.html) + $("#importSiteModal").modal("hide") + }) + .error(function(data) { + modalError(data.responseJSON.message) + }) } } -function edit(idx){ - $("#modalSubmit").unbind('click').click(function(){save(idx)}) +function edit(idx) { + $("#modalSubmit").unbind('click').click(function() { + save(idx) + }) $("#html_editor").ckeditor() var page = {} if (idx != -1) { @@ -79,82 +82,80 @@ function edit(idx){ } } -function load(){ -/* - load() - Loads the current pages using the API -*/ +function load() { + /* + load() - Loads the current pages using the API + */ $("#pagesTable").hide() $("#emptyMessage").hide() $("#loading").show() api.pages.get() - .success(function(ps){ - pages = ps - $("#loading").hide() - if (pages.length > 0){ - $("#pagesTable").show() - pagesTable = $("#pagesTable").DataTable(); - pagesTable.clear() - $.each(pages, function(i, page){ - pagesTable.row.add([ - page.name, - moment(page.modified_date).format('MMMM Do YYYY, h:mm:ss a'), - "
    \
    " - ]).draw() - }) - } else { - $("#emptyMessage").show() - } - }) - .error(function(){ - $("#loading").hide() - errorFlash("Error fetching pages") - }) + ]).draw() + }) + } else { + $("#emptyMessage").show() + } + }) + .error(function() { + $("#loading").hide() + errorFlash("Error fetching pages") + }) } -$(document).ready(function(){ +$(document).ready(function() { // Setup multiple modals // Code based on http://miles-by-motorcycle.com/static/bootstrap-modal/index.html - $('.modal').on('hidden.bs.modal', function( event ) { - $(this).removeClass( 'fv-modal-stack' ); - $('body').data( 'fv_open_modals', $('body').data( 'fv_open_modals' ) - 1 ); + $('.modal').on('hidden.bs.modal', function(event) { + $(this).removeClass('fv-modal-stack'); + $('body').data('fv_open_modals', $('body').data('fv_open_modals') - 1); }); - $( '.modal' ).on( 'shown.bs.modal', function ( event ) { + $('.modal').on('shown.bs.modal', function(event) { // Keep track of the number of open modals - if ( typeof( $('body').data( 'fv_open_modals' ) ) == 'undefined' ) - { - $('body').data( 'fv_open_modals', 0 ); + if (typeof($('body').data('fv_open_modals')) == 'undefined') { + $('body').data('fv_open_modals', 0); } // if the z-index of this modal has been set, ignore. - if ( $(this).hasClass( 'fv-modal-stack' ) ) - { + if ($(this).hasClass('fv-modal-stack')) { return; } - $(this).addClass( 'fv-modal-stack' ); - // Increment the number of open modals - $('body').data( 'fv_open_modals', $('body').data( 'fv_open_modals' ) + 1 ); - // Setup the appropriate z-index - $(this).css('z-index', 1040 + (10 * $('body').data( 'fv_open_modals' ))); - $( '.modal-backdrop' ).not( '.fv-modal-stack' ).css( 'z-index', 1039 + (10 * $('body').data( 'fv_open_modals' ))); - $( '.modal-backdrop' ).not( 'fv-modal-stack' ).addClass( 'fv-modal-stack' ); + $(this).addClass('fv-modal-stack'); + // Increment the number of open modals + $('body').data('fv_open_modals', $('body').data('fv_open_modals') + 1); + // Setup the appropriate z-index + $(this).css('z-index', 1040 + (10 * $('body').data('fv_open_modals'))); + $('.modal-backdrop').not('.fv-modal-stack').css('z-index', 1039 + (10 * $('body').data('fv_open_modals'))); + $('.modal-backdrop').not('fv-modal-stack').addClass('fv-modal-stack'); }); $.fn.modal.Constructor.prototype.enforceFocus = function() { - $( document ) - .off( 'focusin.bs.modal' ) // guard against infinite focus loop - .on( 'focusin.bs.modal', $.proxy( function( e ) { - if ( - this.$element[ 0 ] !== e.target && !this.$element.has( e.target ).length - // CKEditor compatibility fix start. - && !$( e.target ).closest( '.cke_dialog, .cke' ).length - // CKEditor compatibility fix end. - ) { - this.$element.trigger( 'focus' ); - } - }, this ) ); - }; + $(document) + .off('focusin.bs.modal') // guard against infinite focus loop + .on('focusin.bs.modal', $.proxy(function(e) { + if ( + this.$element[0] !== e.target && !this.$element.has(e.target).length + // CKEditor compatibility fix start. + && !$(e.target).closest('.cke_dialog, .cke').length + // CKEditor compatibility fix end. + ) { + this.$element.trigger('focus'); + } + }, this)); + }; load() }) diff --git a/static/js/app/settings.js b/static/js/app/settings.js index 36fd712a..87e6e98b 100644 --- a/static/js/app/settings.js +++ b/static/js/app/settings.js @@ -1,24 +1,24 @@ -$(document).ready(function(){ - $("#apiResetForm").submit(function(e){ +$(document).ready(function() { + $("#apiResetForm").submit(function(e) { $.post("/api/reset", $(this).serialize()) - .done(function(data){ - api_key = data.data - successFlash(data.message) - $("#api_key").val(api_key) - }) - .fail(function(data){ - errorFlash(data.message) - }) + .done(function(data) { + api_key = data.data + successFlash(data.message) + $("#api_key").val(api_key) + }) + .fail(function(data) { + errorFlash(data.message) + }) return false }) - $("#settingsForm").submit(function(e){ + $("#settingsForm").submit(function(e) { $.post("/settings", $(this).serialize()) - .done(function(data){ - successFlash(data.message) - }) - .fail(function(data){ - errorFlash(data.responseJSON.message) - }) + .done(function(data) { + successFlash(data.message) + }) + .fail(function(data) { + errorFlash(data.responseJSON.message) + }) return false }) }) diff --git a/static/js/app/templates.js b/static/js/app/templates.js index 4da16ac1..6f487e73 100644 --- a/static/js/app/templates.js +++ b/static/js/app/templates.js @@ -1,64 +1,66 @@ var templates = [] var icons = { - "application/vnd.ms-excel" : "fa-file-excel-o", - "text/plain" : "fa-file-text-o", - "image/gif" : "fa-file-image-o", - "image/png" : "fa-file-image-o", - "application/pdf" : "fa-file-pdf-o", - "application/x-zip-compressed" : "fa-file-archive-o", - "application/x-gzip" : "fa-file-archive-o", - "application/vnd.openxmlformats-officedocument.presentationml.presentation" : "fa-file-powerpoint-o", - "application/vnd.openxmlformats-officedocument.wordprocessingml.document" : "fa-file-word-o", - "application/octet-stream" : "fa-file-o", - "application/x-msdownload" : "fa-file-o" + "application/vnd.ms-excel": "fa-file-excel-o", + "text/plain": "fa-file-text-o", + "image/gif": "fa-file-image-o", + "image/png": "fa-file-image-o", + "application/pdf": "fa-file-pdf-o", + "application/x-zip-compressed": "fa-file-archive-o", + "application/x-gzip": "fa-file-archive-o", + "application/vnd.openxmlformats-officedocument.presentationml.presentation": "fa-file-powerpoint-o", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "fa-file-word-o", + "application/octet-stream": "fa-file-o", + "application/x-msdownload": "fa-file-o" } // Save attempts to POST to /templates/ -function save(idx){ - var template = {attachments:[]} +function save(idx) { + var template = { + attachments: [] + } template.name = $("#name").val() template.subject = $("#subject").val() template.html = CKEDITOR.instances["html_editor"].getData(); // Fix the URL Scheme added by CKEditor (until we can remove it from the plugin) template.html = template.html.replace(/https?:\/\/{{\.URL}}/gi, "{{.URL}}") - // If the "Add Tracker Image" checkbox is checked, add the tracker - if ($("#use_tracker_checkbox").prop("checked") && - template.html.indexOf("{{.Tracker}}") == -1 && - template.html.indexOf("{{.TrackingUrl}}") == -1){ - template.html = template.html.replace("", "{{.Tracker}}") + // If the "Add Tracker Image" checkbox is checked, add the tracker + if ($("#use_tracker_checkbox").prop("checked") && + template.html.indexOf("{{.Tracker}}") == -1 && + template.html.indexOf("{{.TrackingUrl}}") == -1) { + template.html = template.html.replace("", "{{.Tracker}}") } template.text = $("#text_editor").val() - // Add the attachments - $.each($("#attachmentsTable").DataTable().rows().data(), function(i, target){ + // Add the attachments + $.each($("#attachmentsTable").DataTable().rows().data(), function(i, target) { template.attachments.push({ - name : target[1], + name: target[1], content: target[3], type: target[4], }) }) - if (idx != -1){ + if (idx != -1) { template.id = templates[idx].id api.templateId.put(template) - .success(function(data){ - successFlash("Template edited successfully!") - load() - dismiss() - }) + .success(function(data) { + successFlash("Template edited successfully!") + load() + dismiss() + }) } else { // Submit the template api.templates.post(template) - .success(function(data){ - successFlash("Template added successfully!") - load() - dismiss() - }) - .error(function(data){ - modalError(data.responseJSON.message) - }) + .success(function(data) { + successFlash("Template added successfully!") + load() + dismiss() + }) + .error(function(data) { + modalError(data.responseJSON.message) + }) } } -function dismiss(){ +function dismiss() { $("#modal\\.flashes").empty() $("#attachmentsTable").dataTable().DataTable().clear().draw() $("#name").val("") @@ -67,24 +69,24 @@ function dismiss(){ $("#modal").modal('hide') } -function deleteTemplate(idx){ - if (confirm("Delete " + templates[idx].name + "?")){ +function deleteTemplate(idx) { + if (confirm("Delete " + templates[idx].name + "?")) { api.templateId.delete(templates[idx].id) - .success(function(data){ - successFlash(data.message) - load() - }) + .success(function(data) { + successFlash(data.message) + load() + }) } } -function attach(files){ +function attach(files) { attachmentsTable = $("#attachmentsTable").DataTable(); - $.each(files, function(i, file){ + $.each(files, function(i, file) { var reader = new FileReader(); /* Make this a datatable */ - reader.onload = function(e){ + reader.onload = function(e) { var icon = icons[file.type] || "fa-file-o" - // Add the record to the modal + // Add the record to the modal attachmentsTable.row.add([ '', file.name, @@ -100,33 +102,38 @@ function attach(files){ }) } -function edit(idx){ - $("#modalSubmit").unbind('click').click(function(){save(idx)}) - $("#attachmentUpload").unbind('click').click(function(){this.value=null}) +function edit(idx) { + $("#modalSubmit").unbind('click').click(function() { + save(idx) + }) + $("#attachmentUpload").unbind('click').click(function() { + this.value = null + }) $("#html_editor").ckeditor() $("#attachmentsTable").show() attachmentsTable = null - if ( $.fn.dataTable.isDataTable('#attachmentsTable') ) { + if ($.fn.dataTable.isDataTable('#attachmentsTable')) { attachmentsTable = $('#attachmentsTable').DataTable(); - } - else { + } else { attachmentsTable = $("#attachmentsTable").DataTable({ - "aoColumnDefs" : [{ - "targets" : [3,4], - "sClass" : "datatable_hidden" + "aoColumnDefs": [{ + "targets": [3, 4], + "sClass": "datatable_hidden" }] }); } - var template = {attachments:[]} + var template = { + attachments: [] + } if (idx != -1) { template = templates[idx] $("#name").val(template.name) - $("#subject").val(template.subject) + $("#subject").val(template.subject) $("#html_editor").val(template.html) $("#text_editor").val(template.text) - $.each(template.attachments, function(i, file){ + $.each(template.attachments, function(i, file) { var icon = icons[file.type] || "fa-file-o" - // Add the record to the modal + // Add the record to the modal attachmentsTable.row.add([ '', file.name, @@ -137,110 +144,108 @@ function edit(idx){ }) } // Handle Deletion - $("#attachmentsTable").unbind('click').on("click", "span>i.fa-trash-o", function(){ - attachmentsTable.row( $(this).parents('tr') ) - .remove() - .draw(); + $("#attachmentsTable").unbind('click').on("click", "span>i.fa-trash-o", function() { + attachmentsTable.row($(this).parents('tr')) + .remove() + .draw(); }) } -function importEmail(){ +function importEmail() { raw = $("#email_content").val() - if (!raw){ + if (!raw) { modalError("No Content Specified!") } else { - $.ajax({ - type: "POST", - url: "/api/import/email", - data: raw, - dataType: "json", - contentType: "text/plain" - }) - .success(function(data){ - $("#text_editor").val(data.text) - $("#html_editor").val(data.html) - $("#subject").val(data.subject) - $("#importEmailModal").modal("hide") - }) - .error(function(data){ - modalError(data.responseJSON.message) - }) + $.ajax({ + type: "POST", + url: "/api/import/email", + data: raw, + dataType: "json", + contentType: "text/plain" + }) + .success(function(data) { + $("#text_editor").val(data.text) + $("#html_editor").val(data.html) + $("#subject").val(data.subject) + $("#importEmailModal").modal("hide") + }) + .error(function(data) { + modalError(data.responseJSON.message) + }) } } -function load(){ +function load() { $("#templateTable").hide() $("#emptyMessage").hide() $("#loading").show() api.templates.get() - .success(function(ts){ - templates = ts - $("#loading").hide() - if (templates.length > 0){ - $("#templateTable").show() - templateTable = $("#templateTable").DataTable(); - templateTable.clear() - $.each(templates, function(i, template){ - templateTable.row.add([ - template.name, - moment(template.modified_date).format('MMMM Do YYYY, h:mm:ss a'), - "
    \
    " - ]).draw() - }) - } else { - $("#emptyMessage").show() - } - }) - .error(function(){ - $("#loading").hide() - errorFlash("Error fetching templates") - }) + ]).draw() + }) + } else { + $("#emptyMessage").show() + } + }) + .error(function() { + $("#loading").hide() + errorFlash("Error fetching templates") + }) } -$(document).ready(function(){ +$(document).ready(function() { // Setup multiple modals // Code based on http://miles-by-motorcycle.com/static/bootstrap-modal/index.html - $('.modal').on('hidden.bs.modal', function( event ) { - $(this).removeClass( 'fv-modal-stack' ); - $('body').data( 'fv_open_modals', $('body').data( 'fv_open_modals' ) - 1 ); + $('.modal').on('hidden.bs.modal', function(event) { + $(this).removeClass('fv-modal-stack'); + $('body').data('fv_open_modals', $('body').data('fv_open_modals') - 1); }); - $( '.modal' ).on( 'shown.bs.modal', function ( event ) { + $('.modal').on('shown.bs.modal', function(event) { // Keep track of the number of open modals - if ( typeof( $('body').data( 'fv_open_modals' ) ) == 'undefined' ) - { - $('body').data( 'fv_open_modals', 0 ); + if (typeof($('body').data('fv_open_modals')) == 'undefined') { + $('body').data('fv_open_modals', 0); } // if the z-index of this modal has been set, ignore. - if ( $(this).hasClass( 'fv-modal-stack' ) ) - { + if ($(this).hasClass('fv-modal-stack')) { return; } - $(this).addClass( 'fv-modal-stack' ); - // Increment the number of open modals - $('body').data( 'fv_open_modals', $('body').data( 'fv_open_modals' ) + 1 ); - // Setup the appropriate z-index - $(this).css('z-index', 1040 + (10 * $('body').data( 'fv_open_modals' ))); - $( '.modal-backdrop' ).not( '.fv-modal-stack' ).css( 'z-index', 1039 + (10 * $('body').data( 'fv_open_modals' ))); - $( '.modal-backdrop' ).not( 'fv-modal-stack' ).addClass( 'fv-modal-stack' ); + $(this).addClass('fv-modal-stack'); + // Increment the number of open modals + $('body').data('fv_open_modals', $('body').data('fv_open_modals') + 1); + // Setup the appropriate z-index + $(this).css('z-index', 1040 + (10 * $('body').data('fv_open_modals'))); + $('.modal-backdrop').not('.fv-modal-stack').css('z-index', 1039 + (10 * $('body').data('fv_open_modals'))); + $('.modal-backdrop').not('fv-modal-stack').addClass('fv-modal-stack'); }); $.fn.modal.Constructor.prototype.enforceFocus = function() { - $( document ) - .off( 'focusin.bs.modal' ) // guard against infinite focus loop - .on( 'focusin.bs.modal', $.proxy( function( e ) { - if ( - this.$element[ 0 ] !== e.target && !this.$element.has( e.target ).length - // CKEditor compatibility fix start. - && !$( e.target ).closest( '.cke_dialog, .cke' ).length - // CKEditor compatibility fix end. - ) { - this.$element.trigger( 'focus' ); - } - }, this ) ); - }; + $(document) + .off('focusin.bs.modal') // guard against infinite focus loop + .on('focusin.bs.modal', $.proxy(function(e) { + if ( + this.$element[0] !== e.target && !this.$element.has(e.target).length + // CKEditor compatibility fix start. + && !$(e.target).closest('.cke_dialog, .cke').length + // CKEditor compatibility fix end. + ) { + this.$element.trigger('focus'); + } + }, this)); + }; load() }) diff --git a/static/js/app/users.js b/static/js/app/users.js index 10f310f1..c2a62dab 100644 --- a/static/js/app/users.js +++ b/static/js/app/users.js @@ -1,60 +1,62 @@ var groups = [] // Save attempts to POST or PUT to /groups/ -function save(idx){ +function save(idx) { var targets = [] - $.each($("#targetsTable").DataTable().rows().data(), function(i, target){ + $.each($("#targetsTable").DataTable().rows().data(), function(i, target) { targets.push({ - first_name : target[0], + first_name: target[0], last_name: target[1], email: target[2], position: target[3] }) }) var group = { - name: $("#name").val(), - targets: targets - } - // Submit the group + name: $("#name").val(), + targets: targets + } + // Submit the group if (idx != -1) { // If we're just editing an existing group, // we need to PUT /groups/:id group.id = groups[idx].id api.groupId.put(group) - .success(function(data){ - successFlash("Group updated successfully!") - load() - dismiss() - $("#modal").modal('hide') - }) - .error(function(data){ - modalError(data.responseJSON.message) - }) + .success(function(data) { + successFlash("Group updated successfully!") + load() + dismiss() + $("#modal").modal('hide') + }) + .error(function(data) { + modalError(data.responseJSON.message) + }) } else { // Else, if this is a new group, POST it // to /groups api.groups.post(group) - .success(function(data){ - successFlash("Group added successfully!") - load() - dismiss() - $("#modal").modal('hide') - }) - .error(function(data){ - modalError(data.responseJSON.message) - }) + .success(function(data) { + successFlash("Group added successfully!") + load() + dismiss() + $("#modal").modal('hide') + }) + .error(function(data) { + modalError(data.responseJSON.message) + }) } } -function dismiss(){ +function dismiss() { $("#targetsTable").dataTable().DataTable().clear().draw() $("#name").val("") $("#modal\\.flashes").empty() } -function edit(idx){ +function edit(idx) { targets = $("#targetsTable").dataTable() - $("#modalSubmit").unbind('click').click(function(){save(idx)}) + $("#modalSubmit").unbind('click').click(function() { + save(idx) + }) if (idx == -1) { group = {} } else { @@ -62,31 +64,6 @@ function edit(idx){ $("#name").val(group.name) $.each(group.targets, function(i, record) { targets.DataTable() - .row.add([ - record.first_name, - record.last_name, - record.email, - record.position, - '' - ]).draw() - }); - } - // Handle file uploads - $("#csvupload").fileupload({ - dataType:"json", - add: function(e, data){ - $("#modal\\.flashes").empty() - var acceptFileTypes= /(csv|txt)$/i; - var filename = data.originalFiles[0]['name'] - if (filename && !acceptFileTypes.test(filename.split(".").pop())) { - modalError("Unsupported file extension (use .csv or .txt)") - return false; - } - data.submit(); - }, - done: function(e, data){ - $.each(data.result, function(i, record) { - targets.DataTable() .row.add([ record.first_name, record.last_name, @@ -94,90 +71,115 @@ function edit(idx){ record.position, '' ]).draw() + }); + } + // Handle file uploads + $("#csvupload").fileupload({ + dataType: "json", + add: function(e, data) { + $("#modal\\.flashes").empty() + var acceptFileTypes = /(csv|txt)$/i; + var filename = data.originalFiles[0]['name'] + if (filename && !acceptFileTypes.test(filename.split(".").pop())) { + modalError("Unsupported file extension (use .csv or .txt)") + return false; + } + data.submit(); + }, + done: function(e, data) { + $.each(data.result, function(i, record) { + targets.DataTable() + .row.add([ + record.first_name, + record.last_name, + record.email, + record.position, + '' + ]).draw() }); } }) } -function deleteGroup(idx){ - if (confirm("Delete " + groups[idx].name + "?")){ +function deleteGroup(idx) { + if (confirm("Delete " + groups[idx].name + "?")) { api.groupId.delete(groups[idx].id) - .success(function(data){ - successFlash(data.message) - load() - }) + .success(function(data) { + successFlash(data.message) + load() + }) } } -function load(){ +function load() { $("#groupTable").hide() $("#emptyMessage").hide() $("#loading").show() api.groups.get() - .success(function(gs){ - $("#loading").hide() - if (gs.length > 0){ - groups = gs - $("#emptyMessage").hide() - $("#groupTable").show() - groupTable = $("#groupTable").DataTable(); - groupTable.clear(); - $.each(groups, function(i, group){ - var targets = "" - $.each(group.targets, function(i, target){ - targets += target.email + ", " - if (targets.length > 50) { - targets = targets.slice(0,-3) + "..." - return false; - } - }) - groupTable.row.add([ - group.name, - targets, - moment(group.modified_date).format('MMMM Do YYYY, h:mm:ss a'), - "
    \
    " - ]).draw() - }) - } else { - $("#emptyMessage").show() - } - }) - .error(function(){ - errorFlash("Error fetching groups") - }) + ]).draw() + }) + } else { + $("#emptyMessage").show() + } + }) + .error(function() { + errorFlash("Error fetching groups") + }) } -$(document).ready(function(){ +$(document).ready(function() { load() - // Setup the event listeners - // Handle manual additions - $("#targetForm").submit(function(){ + // Setup the event listeners + // Handle manual additions + $("#targetForm").submit(function() { + targets.DataTable() + .row.add([ + $("#firstName").val(), + $("#lastName").val(), + $("#email").val(), + $("#position").val(), + '' + ]) + .draw() + $("#targetForm>div>input").val('') + $("#firstName").focus() + return false + }) + // Handle Deletion + $("#targetsTable").on("click", "span>i.fa-trash-o", function() { targets.DataTable() - .row.add([ - $("#firstName").val(), - $("#lastName").val(), - $("#email").val(), - $("#position").val(), - '' - ]) - .draw() - $("#targetForm>div>input").val('') - $("#firstName").focus() - return false + .row($(this).parents('tr')) + .remove() + .draw(); }) - // Handle Deletion - $("#targetsTable").on("click", "span>i.fa-trash-o", function(){ - targets.DataTable() - .row( $(this).parents('tr') ) - .remove() - .draw(); - }) - $("#modal").on("hide.bs.modal", function(){ - dismiss() + $("#modal").on("hide.bs.modal", function() { + dismiss() }) }) diff --git a/static/js/gophish.js b/static/js/gophish.js index 4e4dc6d8..b95ec7cd 100644 --- a/static/js/gophish.js +++ b/static/js/gophish.js @@ -1,18 +1,16 @@ function errorFlash(message) { $("#flashes").empty() $("#flashes").append("
    \ - " + message + "
    " - ) + " + message + "
    ") } function successFlash(message) { $("#flashes").empty() $("#flashes").append("
    \ - " + message + "
    " - ) + " + message + "
    ") } -function modalError(message){ +function modalError(message) { $("#modal\\.flashes").empty().append("
    \ " + message + "
    ") } @@ -23,7 +21,7 @@ function query(endpoint, method, data) { async: false, method: method, data: JSON.stringify(data), - dataType:"json", + dataType: "json", contentType: "application/json" }) } @@ -33,117 +31,117 @@ Define our API Endpoints */ var api = { // campaigns contains the endpoints for /campaigns - campaigns : { + campaigns: { // get() - Queries the API for GET /campaigns - get: function(){ + get: function() { return query("/campaigns/", "GET", {}) }, // post() - Posts a campaign to POST /campaigns - post: function(data){ + post: function(data) { return query("/campaigns/", "POST", data) } }, // campaignId contains the endpoints for /campaigns/:id - campaignId : { + campaignId: { // get() - Queries the API for GET /campaigns/:id - get: function(id){ + get: function(id) { return query("/campaigns/" + id, "GET", {}) }, // delete() - Deletes a campaign at DELETE /campaigns/:id - delete: function(id){ + delete: function(id) { return query("/campaigns/" + id, "DELETE", data) } }, // groups contains the endpoints for /groups - groups : { + groups: { // get() - Queries the API for GET /groups - get: function(){ + get: function() { return query("/groups/", "GET", {}) }, // post() - Posts a campaign to POST /groups - post: function(group){ + post: function(group) { return query("/groups/", "POST", group) } }, // groupId contains the endpoints for /groups/:id - groupId : { + groupId: { // get() - Queries the API for GET /groups/:id - get: function(id){ + get: function(id) { return query("/groups/" + id, "GET", {}) }, // put() - Puts a campaign to PUT /groups/:id - put: function (group){ + put: function(group) { return query("/groups/" + group.id, "PUT", group) }, // delete() - Deletes a campaign at DELETE /groups/:id - delete: function(id){ + delete: function(id) { return query("/groups/" + id, "DELETE", {}) } }, // templates contains the endpoints for /templates - templates : { + templates: { // get() - Queries the API for GET /templates - get: function(){ + get: function() { return query("/templates/", "GET", {}) }, // post() - Posts a campaign to POST /templates - post: function(template){ + post: function(template) { return query("/templates/", "POST", template) } }, // templateId contains the endpoints for /templates/:id - templateId : { + templateId: { // get() - Queries the API for GET /templates/:id - get: function(id){ + get: function(id) { return query("/templates/" + id, "GET", {}) }, // put() - Puts a campaign to PUT /templates/:id - put: function (template){ + put: function(template) { return query("/templates/" + template.id, "PUT", template) }, // delete() - Deletes a campaign at DELETE /templates/:id - delete: function(id){ + delete: function(id) { return query("/templates/" + id, "DELETE", {}) } }, // pages contains the endpoints for /pages - pages : { + pages: { // get() - Queries the API for GET /pages - get: function(){ + get: function() { return query("/pages/", "GET", {}) }, // post() - Posts a campaign to POST /pages - post: function(page){ + post: function(page) { return query("/pages/", "POST", page) } }, // templateId contains the endpoints for /templates/:id - pageId : { + pageId: { // get() - Queries the API for GET /templates/:id - get: function(id){ + get: function(id) { return query("/pages/" + id, "GET", {}) }, // put() - Puts a campaign to PUT /templates/:id - put: function (page){ + put: function(page) { return query("/pages/" + page.id, "PUT", page) }, // delete() - Deletes a campaign at DELETE /templates/:id - delete: function(id){ + delete: function(id) { return query("/pages/" + id, "DELETE", {}) } }, // import handles all of the "import" functions in the api - import_email : function(raw) { - return query("/import/email", "POST", {}) + import_email: function(raw) { + return query("/import/email", "POST", {}) }, - clone_site : function(req){ - return query("/import/site", "POST", req) + clone_site: function(req) { + return query("/import/site", "POST", req) } } // Register our moment.js datatables listeners -$(document).ready(function(){ - $.fn.dataTable.moment('MMMM Do YYYY, h:mm:ss a'); - // Setup tooltips - $('[data-toggle="tooltip"]').tooltip() +$(document).ready(function() { + $.fn.dataTable.moment('MMMM Do YYYY, h:mm:ss a'); + // Setup tooltips + $('[data-toggle="tooltip"]').tooltip() });