Adding handling for campaign events

Cleaned up user import button
Cleaning up modal interfacing
Added ability to set result status
pull/24/head
Jordan 2014-06-25 21:01:01 -05:00
parent efec86ae56
commit 49da412538
9 changed files with 88 additions and 24 deletions

View File

@ -36,6 +36,17 @@ func (c *Campaign) Validate() (string, bool) {
return "", true return "", true
} }
func (c *Campaign) UpdateStatus(s string) error {
// This could be made simpler, but I think there's a bug in gorm
return db.Table("campaigns").Where("id=?", c.Id).Update("status", s).Error
}
func (c *Campaign) AddEvent (e Event) error {
e.CampaignId = c.Id
e.Time = time.Now()
return db.Debug().Save(&e).Error
}
type Result struct { type Result struct {
Id int64 `json:"-"` Id int64 `json:"-"`
CampaignId int64 `json:"-"` CampaignId int64 `json:"-"`
@ -43,12 +54,16 @@ type Result struct {
Status string `json:"status" sql:"not null"` Status string `json:"status" sql:"not null"`
} }
func (r *Result) UpdateStatus(s string) error {
return db.Debug().Table("results").Where("id=?", r.Id).Update("status", s).Error
}
type Event struct { type Event struct {
Id int64 `json:"-"` Id int64 `json:"-"`
CampaignId int64 `json:"-"` CampaignId int64 `json:"-"`
Email string `json:"email"` Email string `json:"email"`
Time time.Time `json:"time"` Time time.Time `json:"time"`
Message time.Time `json:"message"` Message string `json:"message"`
} }
// GetCampaigns returns the campaigns owned by the given user. // GetCampaigns returns the campaigns owned by the given user.
@ -81,10 +96,10 @@ func GetCampaign(id int64, uid int64) (Campaign, error) {
// PostCampaign inserts a campaign and all associated records into the database. // PostCampaign inserts a campaign and all associated records into the database.
func PostCampaign(c *Campaign, uid int64) error { func PostCampaign(c *Campaign, uid int64) error {
// Fill in the details // Fill in the details
c.UserId = uid
c.CreatedDate = time.Now() c.CreatedDate = time.Now()
c.CompletedDate = time.Time{} c.CompletedDate = time.Time{}
c.Status = QUEUED c.Status = QUEUED
c.Events = append(c.Events)
// Check to make sure all the groups already exist // Check to make sure all the groups already exist
for i, g := range c.Groups { for i, g := range c.Groups {
c.Groups[i], err = GetGroupByName(g.Name, uid) c.Groups[i], err = GetGroupByName(g.Name, uid)
@ -113,27 +128,26 @@ func PostCampaign(c *Campaign, uid int64) error {
Logger.Println(err) Logger.Println(err)
return err return err
} }
err = c.AddEvent(Event{Message:"Campaign Created"})
if err != nil {
Logger.Println(err)
}
// Insert all the results // Insert all the results
for _, g := range c.Groups { for _, g := range c.Groups {
// Insert a result for each target in the group // Insert a result for each target in the group
for _, t := range g.Targets { for _, t := range g.Targets {
r := Result{Email: t.Email, Status: "Unknown", CampaignId: c.Id} r := Result{Email: t.Email, Status: "Unknown", CampaignId: c.Id}
c.Results = append(c.Results, r)
err := db.Save(&r).Error err := db.Save(&r).Error
if err != nil { if err != nil {
Logger.Printf("Error adding result record for target %s\n", t.Email) Logger.Printf("Error adding result record for target %s\n", t.Email)
Logger.Println(err) Logger.Println(err)
} }
c.Results = append(c.Results, r)
} }
} }
return nil return nil
} }
func UpdateCampaignStatus(c *Campaign, s string) error {
// This could be made simpler, but I think there's a bug in gorm
return db.Table("campaigns").Where("id=?", c.Id).Update("status", s).Error
}
//DeleteCampaign deletes the specified campaign //DeleteCampaign deletes the specified campaign
func DeleteCampaign(id int64) error { func DeleteCampaign(id int64) error {
// Delete all the campaign results // Delete all the campaign results

View File

@ -57,6 +57,7 @@ func Setup() error {
db.CreateTable(GroupTarget{}) db.CreateTable(GroupTarget{})
db.CreateTable(Template{}) db.CreateTable(Template{})
db.CreateTable(SMTP{}) db.CreateTable(SMTP{})
db.CreateTable(Event{})
db.CreateTable(Campaign{}) db.CreateTable(Campaign{})
//Create the default user //Create the default user
init_user := User{ init_user := User{

View File

@ -128,3 +128,23 @@
.dropdown-menu > li > a { .dropdown-menu > li > a {
cursor:pointer; cursor:pointer;
} }
.btn-file {
position: relative;
overflow: hidden;
}
.btn-file input[type=file] {
position: absolute;
top: 0;
right: 0;
min-width: 100%;
min-height: 100%;
font-size: 999px;
text-align: right;
filter: alpha(opacity=0);
opacity: 0;
outline: none;
background: white;
cursor: inherit;
display: block;
}

View File

@ -35,6 +35,19 @@ app.config(function($routeProvider) {
}) })
}); });
app.filter('cut', function() {
return function(value, max, tail) {
if (!value) return '';
max = parseInt(max, 10);
truncd = []
for(var i=0; i < Math.min(value.length,max); i++) {
if (i == max-1) truncd.push("...")
else truncd.push(value[i].email);
}
return truncd;
};
});
// Example provided by http://docs.angularjs.org/api/ng/type/ngModel.NgModelController // Example provided by http://docs.angularjs.org/api/ng/type/ngModel.NgModelController
app.directive('contenteditable', function() { app.directive('contenteditable', function() {
return { return {
@ -59,9 +72,9 @@ app.directive('contenteditable', function() {
var html = element.html(); var html = element.html();
// When we clear the content editable the browser leaves a <br> behind // When we clear the content editable the browser leaves a <br> behind
// If strip-br attribute is provided then we strip this out // If strip-br attribute is provided then we strip this out
if (attrs.stripBr && html == '<br>') { //if (attrs.stripBr && html == '<br>') {
html = ''; // html = '';
} //}
ngModel.$setViewValue(html); ngModel.$setViewValue(html);
} }
} }

View File

@ -124,6 +124,10 @@ var CampaignModalCtrl = function($scope, $modalInstance) {
$scope.cancel = function() { $scope.cancel = function() {
$modalInstance.dismiss('cancel'); $modalInstance.dismiss('cancel');
}; };
$scope.ok = function(campaign) {
$modalInstance.dismiss("")
$scope.saveCampaign(campaign)
}
}; };
app.controller('CampaignResultsCtrl', function($scope, CampaignService, GroupService, ngTableParams, $http, $window) { app.controller('CampaignResultsCtrl', function($scope, CampaignService, GroupService, ngTableParams, $http, $window) {
@ -333,7 +337,6 @@ var GroupModalCtrl = function($scope, $modalInstance, $upload) {
}).progress(function(evt) { }).progress(function(evt) {
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total)); console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
}).success(function(data, status, headers, config) { }).success(function(data, status, headers, config) {
// file is uploaded successfully
angular.forEach(data, function(record, key) { angular.forEach(data, function(record, key) {
$scope.group.targets.push({ $scope.group.targets.push({
email: record.email email: record.email
@ -451,6 +454,10 @@ var TemplateModalCtrl = function($scope, $modalInstance) {
$scope.cancel = function() { $scope.cancel = function() {
$modalInstance.dismiss('cancel'); $modalInstance.dismiss('cancel');
}; };
$scope.ok = function(template) {
$modalInstance.dismiss('')
$scope.saveTemplate(template)
};
}; };
app.controller('SettingsCtrl', function($scope, $http, $window) { app.controller('SettingsCtrl', function($scope, $http, $window) {

View File

@ -39,5 +39,5 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="cancel()">Cancel</button> <button type="button" class="btn btn-default" ng-click="cancel()">Cancel</button>
<button type="button" class="btn btn-primary" ng-click="saveTemplate(template)" data-dismiss="modal">Save Template</button> <button type="button" class="btn btn-primary" ng-click="ok(template)" data-dismiss="modal">Save Template</button>
</div> </div>

View File

@ -10,12 +10,11 @@
<div class="form-group"> <div class="form-group">
<input type="text" class="form-control" ng-model="group.name" placeholder="Group name" id="name" autofocus/> <input type="text" class="form-control" ng-model="group.name" placeholder="Group name" id="name" autofocus/>
</div> </div>
<input type="file" ng-file-select="onFileSelect($files)">
<fieldset disabled>
<div class="form-group"> <div class="form-group">
<button class="btn btn-danger"><i class="fa fa-plus"></i> Bulk Import Users (Coming Soon!)</button> <span class="btn btn-danger btn-file" tooltip="Supports CSV files" tooltip-placement="right"><i class="fa fa-plus"></i> Bulk Import Users
<input type="file" ng-file-select="onFileSelect($files)">
</span>
</div> </div>
</fieldset>
<label class="control-label" for="users">Users:</label> <label class="control-label" for="users">Users:</label>
<form ng:submit="addTarget()"> <form ng:submit="addTarget()">
<div class="input-group"> <div class="input-group">

View File

@ -37,8 +37,8 @@
<tr ng-repeat="group in $data" class="editable-row"> <tr ng-repeat="group in $data" class="editable-row">
<td data-title="'Name'" sortable="'name'" class="col-sm-1">{{group.name}}</td> <td data-title="'Name'" sortable="'name'" class="col-sm-1">{{group.name}}</td>
<td data-title="'Members'" class="col-sm-2"> <td data-title="'Members'" class="col-sm-2">
<span ng-repeat="target in group.targets"> <span ng-repeat="target in group.targets | cut:5 track by $index ">
{{target.email}}{{$last ? '' : ', '}} {{target}}{{$last ? '' : ', '}}
</span> </span>
<div class="btn-group" style="float: right;"> <div class="btn-group" style="float: right;">
<button type="button" class="btn btn-primary dropdown-toggle edit-button" data-toggle="dropdown"> <button type="button" class="btn btn-primary dropdown-toggle edit-button" data-toggle="dropdown">
@ -49,7 +49,7 @@
<li><a ng-click="editGroup(group)">Edit</a> <li><a ng-click="editGroup(group)">Edit</a>
</li> </li>
<li class="divider"></li> <li class="divider"></li>
<li><a ng-click="deleteGroup(group)" ng-href="#">Delete</a> <li><a ng-click="deleteGroup(group)">Delete</a>
</li> </li>
</ul> </ul>
</div> </div>

View File

@ -33,7 +33,7 @@ func (w *Worker) Start() {
func processCampaign(c *models.Campaign) { func processCampaign(c *models.Campaign) {
Logger.Printf("Worker received: %s", c.Name) Logger.Printf("Worker received: %s", c.Name)
err := models.UpdateCampaignStatus(c, models.IN_PROGRESS) err := c.UpdateStatus(models.IN_PROGRESS)
if err != nil { if err != nil {
Logger.Println(err) Logger.Println(err)
} }
@ -56,9 +56,19 @@ func processCampaign(c *models.Campaign) {
Logger.Println(e.To) Logger.Println(e.To)
Logger.Println(e.From) Logger.Println(e.From)
err := e.Send(c.SMTP.Host, auth) err := e.Send(c.SMTP.Host, auth)
if err != nil {
Logger.Println(err)
err = t.UpdateStatus("Error")
if err != nil { if err != nil {
Logger.Println(err) Logger.Println(err)
} }
} else {
err = t.UpdateStatus("Email Sent")
if err != nil {
Logger.Println(err)
}
}
Logger.Printf("Sending Email to %s\n", t.Email) Logger.Printf("Sending Email to %s\n", t.Email)
} }
} }