mirror of https://github.com/gophish/gophish
Added a "manager" field, to track the manager for each employee.
modified: controllers/api/util.go modified: db/db_mysql/migrations/20160118194630_init.sql modified: db/db_mysql/migrations/20160217211342_0.1.2_create_from_col_results.sql modified: db/db_sqlite3/migrations/20160118194630_init.sql modified: db/db_sqlite3/migrations/20160217211342_0.1.2_create_from_col_results.sql modified: db/db_sqlite3/migrations/20180527213648_0.7.0_store_email_request.sql modified: models/attachment.go modified: models/attachment_test.go modified: models/campaign.go modified: models/group.go modified: models/template_context.go modified: models/testdata/text-file-with-vars.txt modified: static/js/dist/app/autocomplete.min.js modified: static/js/dist/app/groups.min.js modified: static/js/src/app/autocomplete.js modified: static/js/src/app/groups.js modified: templates/campaigns.html modified: templates/groups.html modified: templates/sending_profiles.html modified: util/util.gopull/2424/head
parent
e0acb99734
commit
4b6fa58435
|
@ -38,6 +38,7 @@ func (as *Server) SendTestEmail(w http.ResponseWriter, r *http.Request) {
|
||||||
"{{if .FirstName}} First Name: {{.FirstName}}\n{{end}}" +
|
"{{if .FirstName}} First Name: {{.FirstName}}\n{{end}}" +
|
||||||
"{{if .LastName}} Last Name: {{.LastName}}\n{{end}}" +
|
"{{if .LastName}} Last Name: {{.LastName}}\n{{end}}" +
|
||||||
"{{if .Position}} Position: {{.Position}}\n{{end}}" +
|
"{{if .Position}} Position: {{.Position}}\n{{end}}" +
|
||||||
|
"{{if .Manager}} Manager: {{.Manager}}\n{{end}}" +
|
||||||
"\nNow go send some phish!"
|
"\nNow go send some phish!"
|
||||||
t := models.Template{
|
t := models.Template{
|
||||||
Subject: "Default Email from Gophish",
|
Subject: "Default Email from Gophish",
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
-- SQL in section 'Up' is executed when this migration is applied
|
-- SQL in section 'Up' is executed when this migration is applied
|
||||||
CREATE TABLE IF NOT EXISTS `users` (id integer primary key auto_increment,username varchar(255) NOT NULL UNIQUE,hash varchar(255),api_key varchar(255) NOT NULL UNIQUE );
|
CREATE TABLE IF NOT EXISTS `users` (id integer primary key auto_increment,username varchar(255) NOT NULL UNIQUE,hash varchar(255),api_key varchar(255) NOT NULL UNIQUE );
|
||||||
CREATE TABLE IF NOT EXISTS `templates` (id integer primary key auto_increment,user_id bigint,name varchar(255),subject varchar(255),text text,html text,modified_date datetime );
|
CREATE TABLE IF NOT EXISTS `templates` (id integer primary key auto_increment,user_id bigint,name varchar(255),subject varchar(255),text text,html text,modified_date datetime );
|
||||||
CREATE TABLE IF NOT EXISTS `targets` (id integer primary key auto_increment,first_name varchar(255),last_name varchar(255),email varchar(255),position varchar(255) );
|
CREATE TABLE IF NOT EXISTS `targets` (id integer primary key auto_increment,first_name varchar(255),last_name varchar(255),email varchar(255),position varchar(255),manager varchar(255) );
|
||||||
CREATE TABLE IF NOT EXISTS `smtp` (smtp_id integer primary key auto_increment,campaign_id bigint,host varchar(255),username varchar(255),from_address varchar(255) );
|
CREATE TABLE IF NOT EXISTS `smtp` (smtp_id integer primary key auto_increment,campaign_id bigint,host varchar(255),username varchar(255),from_address varchar(255) );
|
||||||
CREATE TABLE IF NOT EXISTS `results` (id integer primary key auto_increment,campaign_id bigint,user_id bigint,r_id varchar(255),email varchar(255),first_name varchar(255),last_name varchar(255),status varchar(255) NOT NULL ,ip varchar(255),latitude real,longitude real );
|
CREATE TABLE IF NOT EXISTS `results` (id integer primary key auto_increment,campaign_id bigint,user_id bigint,r_id varchar(255),email varchar(255),first_name varchar(255),last_name varchar(255),status varchar(255) NOT NULL ,ip varchar(255),latitude real,longitude real );
|
||||||
CREATE TABLE IF NOT EXISTS `pages` (id integer primary key auto_increment,user_id bigint,name varchar(255),html text,modified_date datetime );
|
CREATE TABLE IF NOT EXISTS `pages` (id integer primary key auto_increment,user_id bigint,name varchar(255),html text,modified_date datetime );
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
-- +goose Up
|
-- +goose Up
|
||||||
-- SQL in section 'Up' is executed when this migration is applied
|
-- SQL in section 'Up' is executed when this migration is applied
|
||||||
ALTER TABLE `results` ADD COLUMN position VARCHAR(255);
|
ALTER TABLE `results` ADD COLUMN position VARCHAR(255);
|
||||||
|
ALTER TABLE `manager` ADD COLUMN position VARCHAR(255);
|
||||||
|
|
||||||
-- +goose Down
|
-- +goose Down
|
||||||
-- SQL section 'Down' is executed when this migration is rolled back
|
-- SQL section 'Down' is executed when this migration is rolled back
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
-- SQL in section 'Up' is executed when this migration is applied
|
-- SQL in section 'Up' is executed when this migration is applied
|
||||||
CREATE TABLE IF NOT EXISTS "users" ("id" integer primary key autoincrement,"username" varchar(255) NOT NULL UNIQUE,"hash" varchar(255),"api_key" varchar(255) NOT NULL UNIQUE );
|
CREATE TABLE IF NOT EXISTS "users" ("id" integer primary key autoincrement,"username" varchar(255) NOT NULL UNIQUE,"hash" varchar(255),"api_key" varchar(255) NOT NULL UNIQUE );
|
||||||
CREATE TABLE IF NOT EXISTS "templates" ("id" integer primary key autoincrement,"user_id" bigint,"name" varchar(255),"subject" varchar(255),"text" varchar(255),"html" varchar(255),"modified_date" datetime );
|
CREATE TABLE IF NOT EXISTS "templates" ("id" integer primary key autoincrement,"user_id" bigint,"name" varchar(255),"subject" varchar(255),"text" varchar(255),"html" varchar(255),"modified_date" datetime );
|
||||||
CREATE TABLE IF NOT EXISTS "targets" ("id" integer primary key autoincrement,"first_name" varchar(255),"last_name" varchar(255),"email" varchar(255),"position" varchar(255) );
|
CREATE TABLE IF NOT EXISTS "targets" ("id" integer primary key autoincrement,"first_name" varchar(255),"last_name" varchar(255),"email" varchar(255),"position" varchar(255),"manager" varchar(255) );
|
||||||
CREATE TABLE IF NOT EXISTS "smtp" ("smtp_id" integer primary key autoincrement,"campaign_id" bigint,"host" varchar(255),"username" varchar(255),"from_address" varchar(255) );
|
CREATE TABLE IF NOT EXISTS "smtp" ("smtp_id" integer primary key autoincrement,"campaign_id" bigint,"host" varchar(255),"username" varchar(255),"from_address" varchar(255) );
|
||||||
CREATE TABLE IF NOT EXISTS "results" ("id" integer primary key autoincrement,"campaign_id" bigint,"user_id" bigint,"r_id" varchar(255),"email" varchar(255),"first_name" varchar(255),"last_name" varchar(255),"status" varchar(255) NOT NULL ,"ip" varchar(255),"latitude" real,"longitude" real );
|
CREATE TABLE IF NOT EXISTS "results" ("id" integer primary key autoincrement,"campaign_id" bigint,"user_id" bigint,"r_id" varchar(255),"email" varchar(255),"first_name" varchar(255),"last_name" varchar(255),"status" varchar(255) NOT NULL ,"ip" varchar(255),"latitude" real,"longitude" real );
|
||||||
CREATE TABLE IF NOT EXISTS "pages" ("id" integer primary key autoincrement,"user_id" bigint,"name" varchar(255),"html" varchar(255),"modified_date" datetime );
|
CREATE TABLE IF NOT EXISTS "pages" ("id" integer primary key autoincrement,"user_id" bigint,"name" varchar(255),"html" varchar(255),"modified_date" datetime );
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
-- +goose Up
|
-- +goose Up
|
||||||
-- SQL in section 'Up' is executed when this migration is applied
|
-- SQL in section 'Up' is executed when this migration is applied
|
||||||
ALTER TABLE results ADD COLUMN position VARCHAR(255);
|
ALTER TABLE results ADD COLUMN position VARCHAR(255);
|
||||||
|
ALTER TABLE results ADD COLUMN manager VARCHAR(255);
|
||||||
|
|
||||||
-- +goose Down
|
-- +goose Down
|
||||||
-- SQL section 'Down' is executed when this migration is rolled back
|
-- SQL section 'Down' is executed when this migration is rolled back
|
||||||
|
|
|
@ -10,6 +10,7 @@ CREATE TABLE IF NOT EXISTS "email_requests" (
|
||||||
"last_name" varchar(255),
|
"last_name" varchar(255),
|
||||||
"email" varchar(255),
|
"email" varchar(255),
|
||||||
"position" varchar(255),
|
"position" varchar(255),
|
||||||
|
"manager" varchar(255),
|
||||||
"url" varchar(255),
|
"url" varchar(255),
|
||||||
"r_id" varchar(255),
|
"r_id" varchar(255),
|
||||||
"from_address" varchar(255)
|
"from_address" varchar(255)
|
||||||
|
|
|
@ -35,6 +35,7 @@ func (a Attachment) Validate() error {
|
||||||
FirstName: "Foo",
|
FirstName: "Foo",
|
||||||
LastName: "Bar",
|
LastName: "Bar",
|
||||||
Position: "Test",
|
Position: "Test",
|
||||||
|
Manager: "TestMan",
|
||||||
},
|
},
|
||||||
RId: "123456",
|
RId: "123456",
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ func (s *ModelsSuite) TestAttachment(c *check.C) {
|
||||||
LastName: "Bar",
|
LastName: "Bar",
|
||||||
Email: "foo@bar.com",
|
Email: "foo@bar.com",
|
||||||
Position: "Space Janitor",
|
Position: "Space Janitor",
|
||||||
|
Manager: "Space Supervisor",
|
||||||
},
|
},
|
||||||
BaseURL: "http://testurl.com",
|
BaseURL: "http://testurl.com",
|
||||||
URL: "http://testurl.com/?rid=1234567",
|
URL: "http://testurl.com/?rid=1234567",
|
||||||
|
|
|
@ -556,6 +556,7 @@ func PostCampaign(c *Campaign, uid int64) error {
|
||||||
Position: t.Position,
|
Position: t.Position,
|
||||||
FirstName: t.FirstName,
|
FirstName: t.FirstName,
|
||||||
LastName: t.LastName,
|
LastName: t.LastName,
|
||||||
|
Manager: t.Manager,
|
||||||
},
|
},
|
||||||
Status: StatusScheduled,
|
Status: StatusScheduled,
|
||||||
CampaignId: c.Id,
|
CampaignId: c.Id,
|
||||||
|
|
|
@ -57,6 +57,7 @@ type BaseRecipient struct {
|
||||||
FirstName string `json:"first_name"`
|
FirstName string `json:"first_name"`
|
||||||
LastName string `json:"last_name"`
|
LastName string `json:"last_name"`
|
||||||
Position string `json:"position"`
|
Position string `json:"position"`
|
||||||
|
Manager string `json:"manager"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FormatAddress returns the email address to use in the "To" header of the email
|
// FormatAddress returns the email address to use in the "To" header of the email
|
||||||
|
@ -346,6 +347,7 @@ func UpdateTarget(tx *gorm.DB, target Target) error {
|
||||||
"first_name": target.FirstName,
|
"first_name": target.FirstName,
|
||||||
"last_name": target.LastName,
|
"last_name": target.LastName,
|
||||||
"position": target.Position,
|
"position": target.Position,
|
||||||
|
"manager": target.Manager,
|
||||||
}
|
}
|
||||||
err := tx.Model(&target).Where("id = ?", target.Id).Updates(targetInfo).Error
|
err := tx.Model(&target).Where("id = ?", target.Id).Updates(targetInfo).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -359,6 +361,6 @@ func UpdateTarget(tx *gorm.DB, target Target) error {
|
||||||
// GetTargets performs a many-to-many select to get all the Targets for a Group
|
// GetTargets performs a many-to-many select to get all the Targets for a Group
|
||||||
func GetTargets(gid int64) ([]Target, error) {
|
func GetTargets(gid int64) ([]Target, error) {
|
||||||
ts := []Target{}
|
ts := []Target{}
|
||||||
err := db.Table("targets").Select("targets.id, targets.email, targets.first_name, targets.last_name, targets.position").Joins("left join group_targets gt ON targets.id = gt.target_id").Where("gt.group_id=?", gid).Scan(&ts).Error
|
err := db.Table("targets").Select("targets.id, targets.email, targets.first_name, targets.last_name, targets.position, targets.manager").Joins("left join group_targets gt ON targets.id = gt.target_id").Where("gt.group_id=?", gid).Scan(&ts).Error
|
||||||
return ts, err
|
return ts, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,7 @@ func ValidateTemplate(text string) error {
|
||||||
FirstName: "Foo",
|
FirstName: "Foo",
|
||||||
LastName: "Bar",
|
LastName: "Bar",
|
||||||
Position: "Test",
|
Position: "Test",
|
||||||
|
Manager: "TestMan",
|
||||||
},
|
},
|
||||||
RId: "123456",
|
RId: "123456",
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ The target's last name: {{.LastName}}
|
||||||
|
|
||||||
The target's position: {{.Position}}
|
The target's position: {{.Position}}
|
||||||
|
|
||||||
|
The target's manager: {{.Manager}}
|
||||||
|
|
||||||
The target's email address: {{.Email}}
|
The target's email address: {{.Email}}
|
||||||
|
|
||||||
The spoofed sender: {{.From}}
|
The spoofed sender: {{.From}}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
var TEMPLATE_TAGS=[{id:1,name:"RId",description:"The unique ID for the recipient."},{id:2,name:"FirstName",description:"The recipient's first name."},{id:3,name:"LastName",description:"The recipient's last name."},{id:4,name:"Position",description:"The recipient's position."},{id:5,name:"From",description:"The address emails are sent from."},{id:6,name:"TrackingURL",description:"The URL to track emails being opened."},{id:7,name:"Tracker",description:"An HTML tag that adds a hidden tracking image (recommended instead of TrackingURL)."},{id:8,name:"URL",description:"The URL to your Gophish listener."},{id:9,name:"BaseURL",description:"The base URL with the path and rid parameter stripped. Useful for making links to static files."}],textTestCallback=function(e){return e.collapsed?CKEDITOR.plugins.textMatch.match(e,matchCallback):null},matchCallback=function(e,t){var i=e.slice(0,t).match(/\{{2}\.?([A-z]|\})*$/);return i?{start:i.index,end:t}:null},dataCallback=function(t,e){e(TEMPLATE_TAGS.filter(function(e){return 0==("{{."+e.name.toLowerCase()+"}}").indexOf(t.query.toLowerCase())}))},setupAutocomplete=function(e){e.on("instanceReady",function(e){new CKEDITOR.plugins.autocomplete(e.editor,{textTestCallback:textTestCallback,dataCallback:dataCallback,itemTemplate:'<li data-id="{id}"><div><strong class="item-title">{name}</strong></div><div><i>{description}</i></div></li>',outputTemplate:"[[.{name}]]"}).getHtmlToInsert=function(e){var t=this.outputTemplate.output(e);return t=t.replace("[[","{{").replace("]]","}}")}})};
|
var TEMPLATE_TAGS=[{id:1,name:"RId",description:"The unique ID for the recipient."},{id:2,name:"FirstName",description:"The recipient's first name."},{id:3,name:"LastName",description:"The recipient's last name."},{id:4,name:"Position",description:"The recipient's position."},{id:5,name:"From",description:"The address emails are sent from."},{id:6,name:"TrackingURL",description:"The URL to track emails being opened."},{id:7,name:"Tracker",description:"An HTML tag that adds a hidden tracking image (recommended instead of TrackingURL)."},{id:8,name:"URL",description:"The URL to your Gophish listener."},{id:9,name:"BaseURL",description:"The base URL with the path and rid parameter stripped. Useful for making links to static files."},{id:10,name:"Manager",description:"The recipient's manager."}],textTestCallback=function(e){return e.collapsed?CKEDITOR.plugins.textMatch.match(e,matchCallback):null},matchCallback=function(e,t){var i=e.slice(0,t).match(/\{{2}\.?([A-z]|\})*$/);return i?{start:i.index,end:t}:null},dataCallback=function(t,e){e(TEMPLATE_TAGS.filter(function(e){return 0==("{{."+e.name.toLowerCase()+"}}").indexOf(t.query.toLowerCase())}))},setupAutocomplete=function(e){e.on("instanceReady",function(e){new CKEDITOR.plugins.autocomplete(e.editor,{textTestCallback:textTestCallback,dataCallback:dataCallback,itemTemplate:'<li data-id="{id}"><div><strong class="item-title">{name}</strong></div><div><i>{description}</i></div></li>',outputTemplate:"[[.{name}]]"}).getHtmlToInsert=function(e){var t=this.outputTemplate.output(e);return t=t.replace("[[","{{").replace("]]","}}")}})};
|
|
@ -1 +1 @@
|
||||||
var groups=[];function save(e){var t=[];$.each($("#targetsTable").DataTable().rows().data(),function(e,a){t.push({first_name:unescapeHtml(a[0]),last_name:unescapeHtml(a[1]),email:unescapeHtml(a[2]),position:unescapeHtml(a[3])})});var a={name:$("#name").val(),targets:t};-1!=e?(a.id=e,api.groupId.put(a).success(function(e){successFlash("Group updated successfully!"),load(),dismiss(),$("#modal").modal("hide")}).error(function(e){modalError(e.responseJSON.message)})):api.groups.post(a).success(function(e){successFlash("Group added successfully!"),load(),dismiss(),$("#modal").modal("hide")}).error(function(e){modalError(e.responseJSON.message)})}function dismiss(){$("#targetsTable").dataTable().DataTable().clear().draw(),$("#name").val(""),$("#modal\\.flashes").empty()}function edit(e){if(targets=$("#targetsTable").dataTable({destroy:!0,columnDefs:[{orderable:!1,targets:"no-sort"}]}),$("#modalSubmit").unbind("click").click(function(){save(e)}),-1==e);else api.groupId.get(e).success(function(e){$("#name").val(e.name),targetRows=[],$.each(e.targets,function(e,a){targetRows.push([escapeHtml(a.first_name),escapeHtml(a.last_name),escapeHtml(a.email),escapeHtml(a.position),'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'])}),targets.DataTable().rows.add(targetRows).draw()}).error(function(){errorFlash("Error fetching group")});$("#csvupload").fileupload({url:"/api/import/group",dataType:"json",beforeSend:function(e){e.setRequestHeader("Authorization","Bearer "+user.api_key)},add:function(e,a){$("#modal\\.flashes").empty();var t=a.originalFiles[0].name;if(t&&!/(csv|txt)$/i.test(t.split(".").pop()))return modalError("Unsupported file extension (use .csv or .txt)"),!1;a.submit()},done:function(e,a){$.each(a.result,function(e,a){addTarget(a.first_name,a.last_name,a.email,a.position)}),targets.DataTable().draw()}})}var downloadCSVTemplate=function(){var e="group_template.csv",a=Papa.unparse([{"First Name":"Example","Last Name":"User",Email:"foobar@example.com",Position:"Systems Administrator"}],{}),t=new Blob([a],{type:"text/csv;charset=utf-8;"});if(navigator.msSaveBlob)navigator.msSaveBlob(t,e);else{var o=window.URL.createObjectURL(t),s=document.createElement("a");s.href=o,s.setAttribute("download",e),document.body.appendChild(s),s.click(),document.body.removeChild(s)}},deleteGroup=function(o){var e=groups.find(function(e){return e.id===o});e&&Swal.fire({title:"Are you sure?",text:"This will delete the group. This can't be undone!",type:"warning",animation:!1,showCancelButton:!0,confirmButtonText:"Delete "+escapeHtml(e.name),confirmButtonColor:"#428bca",reverseButtons:!0,allowOutsideClick:!1,preConfirm:function(){return new Promise(function(a,t){api.groupId.delete(o).success(function(e){a()}).error(function(e){t(e.responseJSON.message)})})}}).then(function(e){e.value&&Swal.fire("Group Deleted!","This group has been deleted!","success"),$('button:contains("OK")').on("click",function(){location.reload()})})};function addTarget(e,a,t,o){var s=escapeHtml(t).toLowerCase(),r=[escapeHtml(e),escapeHtml(a),s,escapeHtml(o),'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'],n=targets.DataTable(),i=n.column(2,{order:"index"}).data().indexOf(s);0<=i?n.row(i,{order:"index"}).data(r):n.row.add(r)}function load(){$("#groupTable").hide(),$("#emptyMessage").hide(),$("#loading").show(),api.groups.summary().success(function(e){if($("#loading").hide(),0<e.total){groups=e.groups,$("#emptyMessage").hide(),$("#groupTable").show();var a=$("#groupTable").DataTable({destroy:!0,columnDefs:[{orderable:!1,targets:"no-sort"}]});a.clear(),groupRows=[],$.each(groups,function(e,a){groupRows.push([escapeHtml(a.name),escapeHtml(a.num_targets),moment(a.modified_date).format("MMMM Do YYYY, h:mm:ss a"),"<div class='pull-right'><button class='btn btn-primary' data-toggle='modal' data-backdrop='static' data-target='#modal' onclick='edit("+a.id+")'> <i class='fa fa-pencil'></i> </button> <button class='btn btn-danger' onclick='deleteGroup("+a.id+")'> <i class='fa fa-trash-o'></i> </button></div>"])}),a.rows.add(groupRows).draw()}else $("#emptyMessage").show()}).error(function(){errorFlash("Error fetching groups")})}$(document).ready(function(){load(),$("#targetForm").submit(function(){var e=document.getElementById("targetForm");if(e.checkValidity())return addTarget($("#firstName").val(),$("#lastName").val(),$("#email").val(),$("#position").val()),targets.DataTable().draw(),$("#targetForm>div>input").val(""),$("#firstName").focus(),!1;e.reportValidity()}),$("#targetsTable").on("click","span>i.fa-trash-o",function(){targets.DataTable().row($(this).parents("tr")).remove().draw()}),$("#modal").on("hide.bs.modal",function(){dismiss()}),$("#csv-template").click(downloadCSVTemplate)});
|
var groups=[];function save(e){var t=[];$.each($("#targetsTable").DataTable().rows().data(),function(e,a){t.push({first_name:unescapeHtml(a[0]),last_name:unescapeHtml(a[1]),email:unescapeHtml(a[2]),position:unescapeHtml(a[3]),manager:unescapeHtml(a[4])})});var a={name:$("#name").val(),targets:t};-1!=e?(a.id=e,api.groupId.put(a).success(function(e){successFlash("Group updated successfully!"),load(),dismiss(),$("#modal").modal("hide")}).error(function(e){modalError(e.responseJSON.message)})):api.groups.post(a).success(function(e){successFlash("Group added successfully!"),load(),dismiss(),$("#modal").modal("hide")}).error(function(e){modalError(e.responseJSON.message)})}function dismiss(){$("#targetsTable").dataTable().DataTable().clear().draw(),$("#name").val(""),$("#modal\\.flashes").empty()}function edit(e){if(targets=$("#targetsTable").dataTable({destroy:!0,columnDefs:[{orderable:!1,targets:"no-sort"}]}),$("#modalSubmit").unbind("click").click(function(){save(e)}),-1==e);else api.groupId.get(e).success(function(e){$("#name").val(e.name),targetRows=[],$.each(e.targets,function(e,a){targetRows.push([escapeHtml(a.first_name),escapeHtml(a.last_name),escapeHtml(a.email),escapeHtml(a.position),escapeHtml(a.manager),'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'])}),targets.DataTable().rows.add(targetRows).draw()}).error(function(){errorFlash("Error fetching group")});$("#csvupload").fileupload({url:"/api/import/group",dataType:"json",beforeSend:function(e){e.setRequestHeader("Authorization","Bearer "+user.api_key)},add:function(e,a){$("#modal\\.flashes").empty();var t=a.originalFiles[0].name;if(t&&!/(csv|txt)$/i.test(t.split(".").pop()))return modalError("Unsupported file extension (use .csv or .txt)"),!1;a.submit()},done:function(e,a){$.each(a.result,function(e,a){addTarget(a.first_name,a.last_name,a.email,a.position,a.manager)}),targets.DataTable().draw()}})}var downloadCSVTemplate=function(){var e="group_template.csv",a=Papa.unparse([{"First Name":"Example","Last Name":"User",Email:"foobar@example.com",Position:"Systems Administrator"}],{}),t=new Blob([a],{type:"text/csv;charset=utf-8;"});if(navigator.msSaveBlob)navigator.msSaveBlob(t,e);else{var o=window.URL.createObjectURL(t),s=document.createElement("a");s.href=o,s.setAttribute("download",e),document.body.appendChild(s),s.click(),document.body.removeChild(s)}},deleteGroup=function(o){var e=groups.find(function(e){return e.id===o});e&&Swal.fire({title:"Are you sure?",text:"This will delete the group. This can't be undone!",type:"warning",animation:!1,showCancelButton:!0,confirmButtonText:"Delete "+escapeHtml(e.name),confirmButtonColor:"#428bca",reverseButtons:!0,allowOutsideClick:!1,preConfirm:function(){return new Promise(function(a,t){api.groupId.delete(o).success(function(e){a()}).error(function(e){t(e.responseJSON.message)})})}}).then(function(e){e.value&&Swal.fire("Group Deleted!","This group has been deleted!","success"),$('button:contains("OK")').on("click",function(){location.reload()})})};function addTarget(e,a,t,o){var s=escapeHtml(t).toLowerCase(),r=[escapeHtml(e),escapeHtml(a),s,escapeHtml(o),'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'],n=targets.DataTable(),i=n.column(2,{order:"index"}).data().indexOf(s);0<=i?n.row(i,{order:"index"}).data(r):n.row.add(r)}function load(){$("#groupTable").hide(),$("#emptyMessage").hide(),$("#loading").show(),api.groups.summary().success(function(e){if($("#loading").hide(),0<e.total){groups=e.groups,$("#emptyMessage").hide(),$("#groupTable").show();var a=$("#groupTable").DataTable({destroy:!0,columnDefs:[{orderable:!1,targets:"no-sort"}]});a.clear(),groupRows=[],$.each(groups,function(e,a){groupRows.push([escapeHtml(a.name),escapeHtml(a.num_targets),moment(a.modified_date).format("MMMM Do YYYY, h:mm:ss a"),"<div class='pull-right'><button class='btn btn-primary' data-toggle='modal' data-backdrop='static' data-target='#modal' onclick='edit("+a.id+")'> <i class='fa fa-pencil'></i> </button> <button class='btn btn-danger' onclick='deleteGroup("+a.id+")'> <i class='fa fa-trash-o'></i> </button></div>"])}),a.rows.add(groupRows).draw()}else $("#emptyMessage").show()}).error(function(){errorFlash("Error fetching groups")})}$(document).ready(function(){load(),$("#targetForm").submit(function(){var e=document.getElementById("targetForm");if(e.checkValidity())return addTarget($("#firstName").val(),$("#lastName").val(),$("#email").val(),$("#position").val(),$("#manager").val()),targets.DataTable().draw(),$("#targetForm>div>input").val(""),$("#firstName").focus(),!1;e.reportValidity()}),$("#targetsTable").on("click","span>i.fa-trash-o",function(){targets.DataTable().row($(this).parents("tr")).remove().draw()}),$("#modal").on("hide.bs.modal",function(){dismiss()}),$("#csv-template").click(downloadCSVTemplate)});
|
|
@ -42,6 +42,11 @@ var TEMPLATE_TAGS = [{
|
||||||
id: 9,
|
id: 9,
|
||||||
name: 'BaseURL',
|
name: 'BaseURL',
|
||||||
description: 'The base URL with the path and rid parameter stripped. Useful for making links to static files.'
|
description: 'The base URL with the path and rid parameter stripped. Useful for making links to static files.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 10,
|
||||||
|
name: 'Manager',
|
||||||
|
description: 'The recipient\'s manager.'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,8 @@ function save(id) {
|
||||||
first_name: unescapeHtml(target[0]),
|
first_name: unescapeHtml(target[0]),
|
||||||
last_name: unescapeHtml(target[1]),
|
last_name: unescapeHtml(target[1]),
|
||||||
email: unescapeHtml(target[2]),
|
email: unescapeHtml(target[2]),
|
||||||
position: unescapeHtml(target[3])
|
position: unescapeHtml(target[3]),
|
||||||
|
manager: unescapeHtml(target[4])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
var group = {
|
var group = {
|
||||||
|
@ -76,6 +77,7 @@ function edit(id) {
|
||||||
escapeHtml(record.last_name),
|
escapeHtml(record.last_name),
|
||||||
escapeHtml(record.email),
|
escapeHtml(record.email),
|
||||||
escapeHtml(record.position),
|
escapeHtml(record.position),
|
||||||
|
escapeHtml(record.manager),
|
||||||
'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'
|
'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'
|
||||||
])
|
])
|
||||||
});
|
});
|
||||||
|
@ -108,7 +110,8 @@ function edit(id) {
|
||||||
record.first_name,
|
record.first_name,
|
||||||
record.last_name,
|
record.last_name,
|
||||||
record.email,
|
record.email,
|
||||||
record.position);
|
record.position,
|
||||||
|
record.manager);
|
||||||
});
|
});
|
||||||
targets.DataTable().draw();
|
targets.DataTable().draw();
|
||||||
}
|
}
|
||||||
|
@ -183,7 +186,7 @@ var deleteGroup = function (id) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function addTarget(firstNameInput, lastNameInput, emailInput, positionInput) {
|
function addTarget(firstNameInput, lastNameInput, emailInput, positionInput, managerInput) {
|
||||||
// Create new data row.
|
// Create new data row.
|
||||||
var email = escapeHtml(emailInput).toLowerCase();
|
var email = escapeHtml(emailInput).toLowerCase();
|
||||||
var newRow = [
|
var newRow = [
|
||||||
|
@ -191,6 +194,7 @@ function addTarget(firstNameInput, lastNameInput, emailInput, positionInput) {
|
||||||
escapeHtml(lastNameInput),
|
escapeHtml(lastNameInput),
|
||||||
email,
|
email,
|
||||||
escapeHtml(positionInput),
|
escapeHtml(positionInput),
|
||||||
|
escapeHtml(managerInput),
|
||||||
'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'
|
'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -272,7 +276,8 @@ $(document).ready(function () {
|
||||||
$("#firstName").val(),
|
$("#firstName").val(),
|
||||||
$("#lastName").val(),
|
$("#lastName").val(),
|
||||||
$("#email").val(),
|
$("#email").val(),
|
||||||
$("#position").val());
|
$("#position").val(),
|
||||||
|
$("#manager").val());
|
||||||
targets.DataTable().draw();
|
targets.DataTable().draw();
|
||||||
|
|
||||||
// Reset user input.
|
// Reset user input.
|
||||||
|
|
|
@ -164,6 +164,9 @@
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input type="text" class="form-control" placeholder="Position" name="to_position">
|
<input type="text" class="form-control" placeholder="Position" name="to_position">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input type="text" class="form-control" placeholder="Manager" name="to_manager">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
|
|
|
@ -75,6 +75,9 @@
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
<input type="text" class="form-control" placeholder="Position" id="position">
|
<input type="text" class="form-control" placeholder="Position" id="position">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<input type="text" class="form-control" placeholder="Manager" id="manager">
|
||||||
|
</div>
|
||||||
<div class="col-sm-1">
|
<div class="col-sm-1">
|
||||||
<button type="submit" class="btn btn-danger btn-lg">
|
<button type="submit" class="btn btn-danger btn-lg">
|
||||||
<i class="fa fa-plus"></i> Add</button>
|
<i class="fa fa-plus"></i> Add</button>
|
||||||
|
@ -89,6 +92,7 @@
|
||||||
<th>Last Name</th>
|
<th>Last Name</th>
|
||||||
<th>Email</th>
|
<th>Email</th>
|
||||||
<th>Position</th>
|
<th>Position</th>
|
||||||
|
<th>Manager</th>
|
||||||
<th class="no-sort"></th>
|
<th class="no-sort"></th>
|
||||||
<tbody>
|
<tbody>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -128,6 +128,9 @@
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input type="text" class="form-control" placeholder="Position" name="to_position">
|
<input type="text" class="form-control" placeholder="Position" name="to_position">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input type="text" class="form-control" placeholder="Manager" name="to_manager">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
|
|
|
@ -28,6 +28,7 @@ var (
|
||||||
lastNameRegex = regexp.MustCompile(`(?i)last[\s_-]*name`)
|
lastNameRegex = regexp.MustCompile(`(?i)last[\s_-]*name`)
|
||||||
emailRegex = regexp.MustCompile(`(?i)email`)
|
emailRegex = regexp.MustCompile(`(?i)email`)
|
||||||
positionRegex = regexp.MustCompile(`(?i)position`)
|
positionRegex = regexp.MustCompile(`(?i)position`)
|
||||||
|
managerRegex = regexp.MustCompile(`(?i)manager`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// ParseMail takes in an HTTP Request and returns an Email object
|
// ParseMail takes in an HTTP Request and returns an Email object
|
||||||
|
@ -70,10 +71,12 @@ func ParseCSV(r *http.Request) ([]models.Target, error) {
|
||||||
li := -1
|
li := -1
|
||||||
ei := -1
|
ei := -1
|
||||||
pi := -1
|
pi := -1
|
||||||
|
mi := -1
|
||||||
fn := ""
|
fn := ""
|
||||||
ln := ""
|
ln := ""
|
||||||
ea := ""
|
ea := ""
|
||||||
ps := ""
|
ps := ""
|
||||||
|
mn := ""
|
||||||
for i, v := range record {
|
for i, v := range record {
|
||||||
switch {
|
switch {
|
||||||
case firstNameRegex.MatchString(v):
|
case firstNameRegex.MatchString(v):
|
||||||
|
@ -84,6 +87,8 @@ func ParseCSV(r *http.Request) ([]models.Target, error) {
|
||||||
ei = i
|
ei = i
|
||||||
case positionRegex.MatchString(v):
|
case positionRegex.MatchString(v):
|
||||||
pi = i
|
pi = i
|
||||||
|
case managerRegex.MatchString(v):
|
||||||
|
mi = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if fi == -1 && li == -1 && ei == -1 && pi == -1 {
|
if fi == -1 && li == -1 && ei == -1 && pi == -1 {
|
||||||
|
@ -110,12 +115,16 @@ func ParseCSV(r *http.Request) ([]models.Target, error) {
|
||||||
if pi != -1 && len(record) > pi {
|
if pi != -1 && len(record) > pi {
|
||||||
ps = record[pi]
|
ps = record[pi]
|
||||||
}
|
}
|
||||||
|
if mi != -1 && len(record) > mi {
|
||||||
|
mn = record[mi]
|
||||||
|
}
|
||||||
t := models.Target{
|
t := models.Target{
|
||||||
BaseRecipient: models.BaseRecipient{
|
BaseRecipient: models.BaseRecipient{
|
||||||
FirstName: fn,
|
FirstName: fn,
|
||||||
LastName: ln,
|
LastName: ln,
|
||||||
Email: ea,
|
Email: ea,
|
||||||
Position: ps,
|
Position: ps,
|
||||||
|
Manager: mn,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ts = append(ts, t)
|
ts = append(ts, t)
|
||||||
|
|
Loading…
Reference in New Issue