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.go
pull/2424/head
Peter Hefley 2022-03-22 09:19:00 -05:00
parent e0acb99734
commit 4b6fa58435
20 changed files with 50 additions and 9 deletions

View File

@ -38,6 +38,7 @@ func (as *Server) SendTestEmail(w http.ResponseWriter, r *http.Request) {
"{{if .FirstName}} First Name: {{.FirstName}}\n{{end}}" +
"{{if .LastName}} Last Name: {{.LastName}}\n{{end}}" +
"{{if .Position}} Position: {{.Position}}\n{{end}}" +
"{{if .Manager}} Manager: {{.Manager}}\n{{end}}" +
"\nNow go send some phish!"
t := models.Template{
Subject: "Default Email from Gophish",

View File

@ -3,7 +3,7 @@
-- 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 `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 `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 );

View File

@ -2,6 +2,7 @@
-- +goose Up
-- SQL in section 'Up' is executed when this migration is applied
ALTER TABLE `results` ADD COLUMN position VARCHAR(255);
ALTER TABLE `manager` ADD COLUMN position VARCHAR(255);
-- +goose Down
-- SQL section 'Down' is executed when this migration is rolled back

View File

@ -3,7 +3,7 @@
-- 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 "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 "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 );

View File

@ -2,6 +2,7 @@
-- +goose Up
-- SQL in section 'Up' is executed when this migration is applied
ALTER TABLE results ADD COLUMN position VARCHAR(255);
ALTER TABLE results ADD COLUMN manager VARCHAR(255);
-- +goose Down
-- SQL section 'Down' is executed when this migration is rolled back

View File

@ -10,6 +10,7 @@ CREATE TABLE IF NOT EXISTS "email_requests" (
"last_name" varchar(255),
"email" varchar(255),
"position" varchar(255),
"manager" varchar(255),
"url" varchar(255),
"r_id" varchar(255),
"from_address" varchar(255)

View File

@ -35,6 +35,7 @@ func (a Attachment) Validate() error {
FirstName: "Foo",
LastName: "Bar",
Position: "Test",
Manager: "TestMan",
},
RId: "123456",
}

View File

@ -20,6 +20,7 @@ func (s *ModelsSuite) TestAttachment(c *check.C) {
LastName: "Bar",
Email: "foo@bar.com",
Position: "Space Janitor",
Manager: "Space Supervisor",
},
BaseURL: "http://testurl.com",
URL: "http://testurl.com/?rid=1234567",

View File

@ -556,6 +556,7 @@ func PostCampaign(c *Campaign, uid int64) error {
Position: t.Position,
FirstName: t.FirstName,
LastName: t.LastName,
Manager: t.Manager,
},
Status: StatusScheduled,
CampaignId: c.Id,

View File

@ -57,6 +57,7 @@ type BaseRecipient struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Position string `json:"position"`
Manager string `json:"manager"`
}
// 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,
"last_name": target.LastName,
"position": target.Position,
"manager": target.Manager,
}
err := tx.Model(&target).Where("id = ?", target.Id).Updates(targetInfo).Error
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
func GetTargets(gid int64) ([]Target, error) {
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
}

View File

@ -111,6 +111,7 @@ func ValidateTemplate(text string) error {
FirstName: "Foo",
LastName: "Bar",
Position: "Test",
Manager: "TestMan",
},
RId: "123456",
}

View File

@ -6,6 +6,8 @@ The target's last name: {{.LastName}}
The target's position: {{.Position}}
The target's manager: {{.Manager}}
The target's email address: {{.Email}}
The spoofed sender: {{.From}}

View File

@ -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("]]","}}")}})};

View File

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

View File

@ -42,6 +42,11 @@ var TEMPLATE_TAGS = [{
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.'
}
];

View File

@ -8,7 +8,8 @@ function save(id) {
first_name: unescapeHtml(target[0]),
last_name: unescapeHtml(target[1]),
email: unescapeHtml(target[2]),
position: unescapeHtml(target[3])
position: unescapeHtml(target[3]),
manager: unescapeHtml(target[4])
})
})
var group = {
@ -76,6 +77,7 @@ function edit(id) {
escapeHtml(record.last_name),
escapeHtml(record.email),
escapeHtml(record.position),
escapeHtml(record.manager),
'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'
])
});
@ -108,7 +110,8 @@ function edit(id) {
record.first_name,
record.last_name,
record.email,
record.position);
record.position,
record.manager);
});
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.
var email = escapeHtml(emailInput).toLowerCase();
var newRow = [
@ -191,6 +194,7 @@ function addTarget(firstNameInput, lastNameInput, emailInput, positionInput) {
escapeHtml(lastNameInput),
email,
escapeHtml(positionInput),
escapeHtml(managerInput),
'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'
];
@ -272,7 +276,8 @@ $(document).ready(function () {
$("#firstName").val(),
$("#lastName").val(),
$("#email").val(),
$("#position").val());
$("#position").val(),
$("#manager").val());
targets.DataTable().draw();
// Reset user input.

View File

@ -164,6 +164,9 @@
<div class="col-sm-4">
<input type="text" class="form-control" placeholder="Position" name="to_position">
</div>
<div class="col-sm-4">
<input type="text" class="form-control" placeholder="Manager" name="to_manager">
</div>
</div>
</div>
<div class="modal-footer">

View File

@ -75,6 +75,9 @@
<div class="col-sm-3">
<input type="text" class="form-control" placeholder="Position" id="position">
</div>
<div class="col-sm-2">
<input type="text" class="form-control" placeholder="Manager" id="manager">
</div>
<div class="col-sm-1">
<button type="submit" class="btn btn-danger btn-lg">
<i class="fa fa-plus"></i> Add</button>
@ -89,6 +92,7 @@
<th>Last Name</th>
<th>Email</th>
<th>Position</th>
<th>Manager</th>
<th class="no-sort"></th>
<tbody>
</tbody>

View File

@ -128,6 +128,9 @@
<div class="col-sm-4">
<input type="text" class="form-control" placeholder="Position" name="to_position">
</div>
<div class="col-sm-4">
<input type="text" class="form-control" placeholder="Manager" name="to_manager">
</div>
</div>
</div>
<div class="modal-footer">

View File

@ -28,6 +28,7 @@ var (
lastNameRegex = regexp.MustCompile(`(?i)last[\s_-]*name`)
emailRegex = regexp.MustCompile(`(?i)email`)
positionRegex = regexp.MustCompile(`(?i)position`)
managerRegex = regexp.MustCompile(`(?i)manager`)
)
// 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
ei := -1
pi := -1
mi := -1
fn := ""
ln := ""
ea := ""
ps := ""
mn := ""
for i, v := range record {
switch {
case firstNameRegex.MatchString(v):
@ -84,6 +87,8 @@ func ParseCSV(r *http.Request) ([]models.Target, error) {
ei = i
case positionRegex.MatchString(v):
pi = i
case managerRegex.MatchString(v):
mi = i
}
}
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 {
ps = record[pi]
}
if mi != -1 && len(record) > mi {
mn = record[mi]
}
t := models.Target{
BaseRecipient: models.BaseRecipient{
FirstName: fn,
LastName: ln,
Email: ea,
Position: ps,
Manager: mn,
},
}
ts = append(ts, t)