github.com/topsteplocal/gophish@v0.6.0/static/js/src/app/campaigns.js (about) 1 // labels is a map of campaign statuses to 2 // CSS classes 3 var labels = { 4 "In progress": "label-primary", 5 "Queued": "label-info", 6 "Completed": "label-success", 7 "Emails Sent": "label-success", 8 "Error": "label-danger" 9 } 10 11 var campaigns = [] 12 var campaign = {} 13 14 // Launch attempts to POST to /campaigns/ 15 function launch() { 16 swal({ 17 title: "Are you sure?", 18 text: "This will schedule the campaign to be launched.", 19 type: "question", 20 animation: false, 21 showCancelButton: true, 22 confirmButtonText: "Launch", 23 confirmButtonColor: "#428bca", 24 reverseButtons: true, 25 allowOutsideClick: false, 26 showLoaderOnConfirm: true, 27 preConfirm: function () { 28 return new Promise(function (resolve, reject) { 29 groups = [] 30 $("#users").select2("data").forEach(function (group) { 31 groups.push({ 32 name: group.text 33 }); 34 }) 35 // Validate our fields 36 campaign = { 37 name: $("#name").val(), 38 template: { 39 name: $("#template").select2("data")[0].text 40 }, 41 url: $("#url").val(), 42 page: { 43 name: $("#page").select2("data")[0].text 44 }, 45 smtp: { 46 name: $("#profile").select2("data")[0].text 47 }, 48 launch_date: moment($("#launch_date").val(), "MM/DD/YYYY hh:mm a").utc().format(), 49 groups: groups 50 } 51 console.log("Launching campaign at time: " + campaign.launch_date) 52 // Submit the campaign 53 api.campaigns.post(campaign) 54 .success(function (data) { 55 resolve() 56 campaign = data 57 }) 58 .error(function (data) { 59 $("#modal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-danger\">\ 60 <i class=\"fa fa-exclamation-circle\"></i> " + data.responseJSON.message + "</div>") 61 swal.close() 62 }) 63 }) 64 } 65 }).then(function () { 66 swal( 67 'Campaign Scheduled!', 68 'This campaign has been scheduled for launch!', 69 'success' 70 ); 71 $('button:contains("OK")').on('click', function () { 72 window.location = "/campaigns/" + campaign.id.toString() 73 }) 74 }) 75 } 76 77 // Attempts to send a test email by POSTing to /campaigns/ 78 function sendTestEmail() { 79 var test_email_request = { 80 template: { 81 name: $("#template").select2("data")[0].text 82 }, 83 first_name: $("input[name=to_first_name]").val(), 84 last_name: $("input[name=to_last_name]").val(), 85 email: $("input[name=to_email]").val(), 86 position: $("input[name=to_position]").val(), 87 url: $("#url").val(), 88 page: { 89 name: $("#page").select2("data")[0].text 90 }, 91 smtp: { 92 name: $("#profile").select2("data")[0].text 93 } 94 } 95 btnHtml = $("#sendTestModalSubmit").html() 96 $("#sendTestModalSubmit").html('<i class="fa fa-spinner fa-spin"></i> Sending') 97 // Send the test email 98 api.send_test_email(test_email_request) 99 .success(function (data) { 100 $("#sendTestEmailModal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-success\">\ 101 <i class=\"fa fa-check-circle\"></i> Email Sent!</div>") 102 $("#sendTestModalSubmit").html(btnHtml) 103 }) 104 .error(function (data) { 105 $("#sendTestEmailModal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-danger\">\ 106 <i class=\"fa fa-exclamation-circle\"></i> " + data.responseJSON.message + "</div>") 107 $("#sendTestModalSubmit").html(btnHtml) 108 }) 109 } 110 111 function dismiss() { 112 $("#modal\\.flashes").empty(); 113 $("#name").val(""); 114 $("#template").val("").change(); 115 $("#page").val("").change(); 116 $("#url").val(""); 117 $("#profile").val("").change(); 118 $("#users").val("").change(); 119 $("#modal").modal('hide'); 120 } 121 122 function deleteCampaign(idx) { 123 swal({ 124 title: "Are you sure?", 125 text: "This will delete the campaign. This can't be undone!", 126 type: "warning", 127 animation: false, 128 showCancelButton: true, 129 confirmButtonText: "Delete " + campaigns[idx].name, 130 confirmButtonColor: "#428bca", 131 reverseButtons: true, 132 allowOutsideClick: false, 133 preConfirm: function () { 134 return new Promise(function (resolve, reject) { 135 api.campaignId.delete(campaigns[idx].id) 136 .success(function (msg) { 137 resolve() 138 }) 139 .error(function (data) { 140 reject(data.responseJSON.message) 141 }) 142 }) 143 } 144 }).then(function () { 145 swal( 146 'Campaign Deleted!', 147 'This campaign has been deleted!', 148 'success' 149 ); 150 $('button:contains("OK")').on('click', function () { 151 location.reload() 152 }) 153 }) 154 } 155 156 function setupOptions() { 157 api.groups.get() 158 .success(function (groups) { 159 if (groups.length == 0) { 160 modalError("No groups found!") 161 return false; 162 } else { 163 var group_s2 = $.map(groups, function (obj) { 164 obj.text = obj.name 165 return obj 166 }); 167 $("#users.form-control").select2({ 168 placeholder: "Select Groups", 169 data: group_s2, 170 }); 171 } 172 }); 173 api.templates.get() 174 .success(function (templates) { 175 if (templates.length == 0) { 176 modalError("No templates found!") 177 return false 178 } else { 179 var template_s2 = $.map(templates, function (obj) { 180 obj.text = obj.name 181 return obj 182 }); 183 $("#template.form-control").select2({ 184 placeholder: "Select a Template", 185 data: template_s2, 186 }); 187 } 188 }); 189 api.pages.get() 190 .success(function (pages) { 191 if (pages.length == 0) { 192 modalError("No pages found!") 193 return false 194 } else { 195 var page_s2 = $.map(pages, function (obj) { 196 obj.text = obj.name 197 return obj 198 }); 199 $("#page.form-control").select2({ 200 placeholder: "Select a Landing Page", 201 data: page_s2, 202 }); 203 } 204 }); 205 api.SMTP.get() 206 .success(function (profiles) { 207 if (profiles.length == 0) { 208 modalError("No profiles found!") 209 return false 210 } else { 211 var profile_s2 = $.map(profiles, function (obj) { 212 obj.text = obj.name 213 return obj 214 }); 215 $("#profile.form-control").select2({ 216 placeholder: "Select a Sending Profile", 217 data: profile_s2, 218 }); 219 } 220 }); 221 } 222 223 function edit(campaign) { 224 setupOptions(); 225 } 226 227 function copy(idx) { 228 setupOptions(); 229 // Set our initial values 230 api.campaignId.get(campaigns[idx].id) 231 .success(function (campaign) { 232 $("#name").val("Copy of " + campaign.name) 233 if (!campaign.template.id) { 234 $("#template").select2({ 235 placeholder: campaign.template.name 236 }); 237 } else { 238 $("#template").select2("val", campaign.template.id.toString()); 239 } 240 if (!campaign.page.id) { 241 $("#page").select2({ 242 placeholder: campaign.page.name 243 }); 244 } else { 245 $("#page").select2("val", campaign.page.id.toString()); 246 } 247 if (!campaign.smtp.id) { 248 $("#profile").select2({ 249 placeholder: campaign.smtp.name 250 }); 251 } else { 252 $("#profile").select2("val", campaign.smtp.id.toString()); 253 } 254 $("#url").val(campaign.url) 255 }) 256 .error(function (data) { 257 $("#modal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-danger\">\ 258 <i class=\"fa fa-exclamation-circle\"></i> " + data.responseJSON.message + "</div>") 259 }) 260 } 261 262 $(document).ready(function () { 263 $("#launch_date").datetimepicker({ 264 "widgetPositioning": { 265 "vertical": "bottom" 266 }, 267 "showTodayButton": true, 268 "defaultDate": moment() 269 }) 270 // Setup multiple modals 271 // Code based on http://miles-by-motorcycle.com/static/bootstrap-modal/index.html 272 $('.modal').on('hidden.bs.modal', function (event) { 273 $(this).removeClass('fv-modal-stack'); 274 $('body').data('fv_open_modals', $('body').data('fv_open_modals') - 1); 275 }); 276 $('.modal').on('shown.bs.modal', function (event) { 277 // Keep track of the number of open modals 278 if (typeof ($('body').data('fv_open_modals')) == 'undefined') { 279 $('body').data('fv_open_modals', 0); 280 } 281 // if the z-index of this modal has been set, ignore. 282 if ($(this).hasClass('fv-modal-stack')) { 283 return; 284 } 285 $(this).addClass('fv-modal-stack'); 286 // Increment the number of open modals 287 $('body').data('fv_open_modals', $('body').data('fv_open_modals') + 1); 288 // Setup the appropriate z-index 289 $(this).css('z-index', 1040 + (10 * $('body').data('fv_open_modals'))); 290 $('.modal-backdrop').not('.fv-modal-stack').css('z-index', 1039 + (10 * $('body').data('fv_open_modals'))); 291 $('.modal-backdrop').not('fv-modal-stack').addClass('fv-modal-stack'); 292 }); 293 // Scrollbar fix - https://stackoverflow.com/questions/19305821/multiple-modals-overlay 294 $(document).on('hidden.bs.modal', '.modal', function () { 295 $('.modal:visible').length && $(document.body).addClass('modal-open'); 296 }); 297 $('#modal').on('hidden.bs.modal', function (event) { 298 dismiss() 299 }); 300 api.campaigns.summary() 301 .success(function (data) { 302 campaigns = data.campaigns 303 $("#loading").hide() 304 if (campaigns.length > 0) { 305 $("#campaignTable").show() 306 campaignTable = $("#campaignTable").DataTable({ 307 columnDefs: [{ 308 orderable: false, 309 targets: "no-sort" 310 }], 311 order: [ 312 [1, "desc"] 313 ] 314 }); 315 $.each(campaigns, function (i, campaign) { 316 console.log(campaign) 317 console.log(campaign.created_date) 318 label = labels[campaign.status] || "label-default"; 319 320 //section for tooltips on the status of a campaign to show some quick stats 321 var launchDate; 322 if (moment(campaign.launch_date).isAfter(moment())) { 323 launchDate = "Scheduled to start: " + moment(campaign.launch_date).format('MMMM Do YYYY, h:mm:ss a') 324 var quickStats = launchDate + "<br><br>" + "Number of recipients: " + campaign.stats.total 325 } else { 326 launchDate = "Launch Date: " + moment(campaign.launch_date).format('MMMM Do YYYY, h:mm:ss a') 327 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 + "Reported : " + campaign.stats.reported 328 } 329 330 campaignTable.row.add([ 331 escapeHtml(campaign.name), 332 moment(campaign.created_date).format('MMMM Do YYYY, h:mm:ss a'), 333 "<span class=\"label " + label + "\" data-toggle=\"tooltip\" data-placement=\"right\" data-html=\"true\" title=\"" + quickStats + "\">" + campaign.status + "</span>", 334 "<div class='pull-right'><a class='btn btn-primary' href='/campaigns/" + campaign.id + "' data-toggle='tooltip' data-placement='left' title='View Results'>\ 335 <i class='fa fa-bar-chart'></i>\ 336 </a>\ 337 <span data-toggle='modal' data-target='#modal'><button class='btn btn-primary' data-toggle='tooltip' data-placement='left' title='Copy Campaign' onclick='copy(" + i + ")'>\ 338 <i class='fa fa-copy'></i>\ 339 </button></span>\ 340 <button class='btn btn-danger' onclick='deleteCampaign(" + i + ")' data-toggle='tooltip' data-placement='left' title='Delete Campaign'>\ 341 <i class='fa fa-trash-o'></i>\ 342 </button></div>" 343 ]).draw() 344 $('[data-toggle="tooltip"]').tooltip() 345 }) 346 } else { 347 $("#emptyMessage").show() 348 } 349 }) 350 .error(function () { 351 $("#loading").hide() 352 errorFlash("Error fetching campaigns") 353 }) 354 // Select2 Defaults 355 $.fn.select2.defaults.set("width", "100%"); 356 $.fn.select2.defaults.set("dropdownParent", $("#modal_body")); 357 $.fn.select2.defaults.set("theme", "bootstrap"); 358 $.fn.select2.defaults.set("sorter", function (data) { 359 return data.sort(function (a, b) { 360 if (a.text.toLowerCase() > b.text.toLowerCase()) { 361 return 1; 362 } 363 if (a.text.toLowerCase() < b.text.toLowerCase()) { 364 return -1; 365 } 366 return 0; 367 }); 368 }) 369 })