mirror of
https://github.com/gophish/gophish
synced 2024-11-14 16:27:23 +00:00
Updates all datetimes to use UTC on the backend. This includes a DB migration to convert existing dates.
Fixes #316
This commit is contained in:
parent
779e419ab4
commit
58a57589bd
11 changed files with 130 additions and 88 deletions
|
@ -203,7 +203,7 @@ func API_Groups(w http.ResponseWriter, r *http.Request) {
|
|||
JSONResponse(w, models.Response{Success: false, Message: "Group name already in use"}, http.StatusConflict)
|
||||
return
|
||||
}
|
||||
g.ModifiedDate = time.Now()
|
||||
g.ModifiedDate = time.Now().UTC()
|
||||
g.UserId = ctx.Get(r, "user_id").(int64)
|
||||
err = models.PostGroup(&g)
|
||||
if err != nil {
|
||||
|
@ -256,7 +256,7 @@ func API_Groups_Id(w http.ResponseWriter, r *http.Request) {
|
|||
JSONResponse(w, models.Response{Success: false, Message: "Error: /:id and group_id mismatch"}, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
g.ModifiedDate = time.Now()
|
||||
g.ModifiedDate = time.Now().UTC()
|
||||
g.UserId = ctx.Get(r, "user_id").(int64)
|
||||
err = models.PutGroup(&g)
|
||||
if err != nil {
|
||||
|
@ -305,7 +305,7 @@ func API_Templates(w http.ResponseWriter, r *http.Request) {
|
|||
JSONResponse(w, models.Response{Success: false, Message: "Template name already in use"}, http.StatusConflict)
|
||||
return
|
||||
}
|
||||
t.ModifiedDate = time.Now()
|
||||
t.ModifiedDate = time.Now().UTC()
|
||||
t.UserId = ctx.Get(r, "user_id").(int64)
|
||||
err = models.PostTemplate(&t)
|
||||
if err == models.ErrTemplateNameNotSpecified {
|
||||
|
@ -354,7 +354,7 @@ func API_Templates_Id(w http.ResponseWriter, r *http.Request) {
|
|||
JSONResponse(w, models.Response{Success: false, Message: "Error: /:id and template_id mismatch"}, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
t.ModifiedDate = time.Now()
|
||||
t.ModifiedDate = time.Now().UTC()
|
||||
t.UserId = ctx.Get(r, "user_id").(int64)
|
||||
err = models.PutTemplate(&t)
|
||||
if err != nil {
|
||||
|
@ -390,7 +390,7 @@ func API_Pages(w http.ResponseWriter, r *http.Request) {
|
|||
Logger.Println(err)
|
||||
return
|
||||
}
|
||||
p.ModifiedDate = time.Now()
|
||||
p.ModifiedDate = time.Now().UTC()
|
||||
p.UserId = ctx.Get(r, "user_id").(int64)
|
||||
err = models.PostPage(&p)
|
||||
if err != nil {
|
||||
|
@ -431,7 +431,7 @@ func API_Pages_Id(w http.ResponseWriter, r *http.Request) {
|
|||
JSONResponse(w, models.Response{Success: false, Message: "/:id and /:page_id mismatch"}, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
p.ModifiedDate = time.Now()
|
||||
p.ModifiedDate = time.Now().UTC()
|
||||
p.UserId = ctx.Get(r, "user_id").(int64)
|
||||
err = models.PutPage(&p)
|
||||
if err != nil {
|
||||
|
@ -467,7 +467,7 @@ func API_SMTP(w http.ResponseWriter, r *http.Request) {
|
|||
Logger.Println(err)
|
||||
return
|
||||
}
|
||||
s.ModifiedDate = time.Now()
|
||||
s.ModifiedDate = time.Now().UTC()
|
||||
s.UserId = ctx.Get(r, "user_id").(int64)
|
||||
err = models.PostSMTP(&s)
|
||||
if err != nil {
|
||||
|
@ -513,7 +513,7 @@ func API_SMTP_Id(w http.ResponseWriter, r *http.Request) {
|
|||
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
s.ModifiedDate = time.Now()
|
||||
s.ModifiedDate = time.Now().UTC()
|
||||
s.UserId = ctx.Get(r, "user_id").(int64)
|
||||
err = models.PutSMTP(&s)
|
||||
if err != nil {
|
||||
|
|
16
db/db_mysql/migrations/20170828220440_0.4_utc_dates.sql
Normal file
16
db/db_mysql/migrations/20170828220440_0.4_utc_dates.sql
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
-- +goose Up
|
||||
-- SQL in section 'Up' is executed when this migration is applied
|
||||
UPDATE campaigns SET `created_date`=CONVERT_TZ(`created_date`, @@session.time_zone, '+00:00');
|
||||
UPDATE campaigns SET `completed_date`=CONVERT_TZ(`completed_date`, @@session.time_zone, '+00:00');
|
||||
UPDATE campaigns SET `launch_date`=CONVERT_TZ(`launch_date`, @@session.time_zone, '+00:00');
|
||||
UPDATE events SET `time`=CONVERT_TZ(`time`, @@session.time_zone, '+00:00');
|
||||
UPDATE groups SET `modified_date`=CONVERT_TZ(`modified_date`, @@session.time_zone, '+00:00');
|
||||
UPDATE templates SET `modified_date`=CONVERT_TZ(`modified_date`, @@session.time_zone, '+00:00');
|
||||
UPDATE pages SET `modified_date`=CONVERT_TZ(`modified_date`, @@session.time_zone, '+00:00');
|
||||
UPDATE smtp SET `modified_date`=CONVERT_TZ(`modified_date`, @@session.time_zone, '+00:00');
|
||||
|
||||
|
||||
-- +goose Down
|
||||
-- SQL section 'Down' is executed when this migration is rolled back
|
||||
|
15
db/db_sqlite3/migrations/20170827141312_0.4_utc_dates.sql
Normal file
15
db/db_sqlite3/migrations/20170827141312_0.4_utc_dates.sql
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
-- +goose Up
|
||||
-- SQL in section 'Up' is executed when this migration is applied
|
||||
UPDATE campaigns SET created_date=STRFTIME('%Y-%m-%d %H:%M:%S+00:00', DATETIME(created_date, 'utc'));
|
||||
UPDATE campaigns SET completed_date=STRFTIME('%Y-%m-%d %H:%M:%S+00:00', DATETIME(completed_date, 'utc'));
|
||||
UPDATE campaigns SET launch_date=STRFTIME('%Y-%m-%d %H:%M:%S+00:00', DATETIME(launch_date, 'utc'));
|
||||
UPDATE events SET `time`=STRFTIME('%Y-%m-%d %H:%M:%S+00:00', DATETIME(`time`, 'utc'));
|
||||
UPDATE groups SET modified_date=STRFTIME('%Y-%m-%d %H:%M:%S+00:00', DATETIME(modified_date, 'utc'));
|
||||
UPDATE templates SET modified_date=STRFTIME('%Y-%m-%d %H:%M:%S+00:00', DATETIME(modified_date, 'utc'));
|
||||
UPDATE pages SET modified_date=STRFTIME('%Y-%m-%d %H:%M:%S+00:00', DATETIME(modified_date, 'utc'));
|
||||
UPDATE smtp SET modified_date=STRFTIME('%Y-%m-%d %H:%M:%S+00:00', DATETIME(modified_date, 'utc'));
|
||||
|
||||
-- +goose Down
|
||||
-- SQL section 'Down' is executed when this migration is rolled back
|
||||
|
|
@ -140,7 +140,7 @@ func (c *Campaign) UpdateStatus(s string) error {
|
|||
// AddEvent creates a new campaign event in the database
|
||||
func (c *Campaign) AddEvent(e Event) error {
|
||||
e.CampaignId = c.Id
|
||||
e.Time = time.Now()
|
||||
e.Time = time.Now().UTC()
|
||||
return db.Debug().Save(&e).Error
|
||||
}
|
||||
|
||||
|
@ -226,7 +226,7 @@ func getCampaignStats(cid int64) (CampaignStats, error) {
|
|||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
// Every opened email event implies the email was sent
|
||||
// Every opened email event implies the email was sent
|
||||
s.EmailsSent += s.OpenedEmail
|
||||
err = query.Where("status=?", ERROR).Count(&s.Error).Error
|
||||
return s, err
|
||||
|
@ -279,6 +279,7 @@ func GetCampaignSummaries(uid int64) (CampaignSummaries, error) {
|
|||
return overview, err
|
||||
}
|
||||
cs[i].Stats = s
|
||||
Logger.Println(cs[i].CreatedDate.String())
|
||||
}
|
||||
overview.Total = int64(len(cs))
|
||||
overview.Campaigns = cs
|
||||
|
@ -361,11 +362,13 @@ func PostCampaign(c *Campaign, uid int64) error {
|
|||
}
|
||||
// Fill in the details
|
||||
c.UserId = uid
|
||||
c.CreatedDate = time.Now()
|
||||
c.CreatedDate = time.Now().UTC()
|
||||
c.CompletedDate = time.Time{}
|
||||
c.Status = CAMPAIGN_CREATED
|
||||
if c.LaunchDate.IsZero() {
|
||||
c.LaunchDate = time.Now()
|
||||
c.LaunchDate = time.Now().UTC()
|
||||
} else {
|
||||
c.LaunchDate = c.LaunchDate.UTC()
|
||||
}
|
||||
// Check to make sure all the groups already exist
|
||||
for i, g := range c.Groups {
|
||||
|
@ -479,7 +482,7 @@ func CompleteCampaign(id int64, uid int64) error {
|
|||
return nil
|
||||
}
|
||||
// Mark the campaign as complete
|
||||
c.CompletedDate = time.Now()
|
||||
c.CompletedDate = time.Now().UTC()
|
||||
c.Status = CAMPAIGN_COMPLETE
|
||||
err = db.Where("id=? and user_id=?", id, uid).Save(&c).Error
|
||||
if err != nil {
|
||||
|
|
2
static/js/dist/app/campaign_results.min.js
vendored
2
static/js/dist/app/campaign_results.min.js
vendored
File diff suppressed because one or more lines are too long
2
static/js/dist/app/campaigns.min.js
vendored
2
static/js/dist/app/campaigns.min.js
vendored
File diff suppressed because one or more lines are too long
2
static/js/dist/app/dashboard.min.js
vendored
2
static/js/dist/app/dashboard.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -282,7 +282,7 @@ function renderTimeline(data) {
|
|||
' <div class="timeline-icon ' + statuses[event.message].label + '">' +
|
||||
' <i class="fa ' + statuses[event.message].icon + '"></i></div>' +
|
||||
' <div class="timeline-message">' + escapeHtml(event.message) +
|
||||
' <span class="timeline-date">' + moment(event.time).format('MMMM Do YYYY h:mm a') + '</span>'
|
||||
' <span class="timeline-date">' + moment.utc(event.time).local().format('MMMM Do YYYY h:mm a') + '</span>'
|
||||
if (event.details) {
|
||||
if (event.message == "Submitted Data") {
|
||||
results += '<div class="timeline-replay-button"><button onclick="replay(' + i + ')" class="btn btn-success">'
|
||||
|
@ -461,7 +461,7 @@ function poll() {
|
|||
/* Update the timeline */
|
||||
var timeline_series_data = []
|
||||
$.each(campaign.timeline, function (i, event) {
|
||||
var event_date = moment(event.time)
|
||||
var event_date = moment.utc(event.time).local()
|
||||
timeline_series_data.push({
|
||||
email: event.email,
|
||||
x: event_date.valueOf(),
|
||||
|
@ -470,7 +470,7 @@ function poll() {
|
|||
})
|
||||
var timeline_series_data = []
|
||||
$.each(campaign.timeline, function (i, event) {
|
||||
var event_date = moment(event.time)
|
||||
var event_date = moment.utc(event.time).local()
|
||||
timeline_series_data.push({
|
||||
email: event.email,
|
||||
message: event.message,
|
||||
|
@ -661,7 +661,7 @@ function load() {
|
|||
});
|
||||
// Setup the graphs
|
||||
$.each(campaign.timeline, function (i, event) {
|
||||
var event_date = moment(event.time)
|
||||
var event_date = moment.utc(event.time).local()
|
||||
timeline_series_data.push({
|
||||
email: event.email,
|
||||
message: event.message,
|
||||
|
|
|
@ -24,48 +24,49 @@ function launch() {
|
|||
reverseButtons: true,
|
||||
allowOutsideClick: false,
|
||||
showLoaderOnConfirm: true,
|
||||
preConfirm: function() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
preConfirm: function () {
|
||||
return new Promise(function (resolve, reject) {
|
||||
groups = []
|
||||
$("#users").select2("data").forEach(function(group){
|
||||
groups.push({name: group.text});
|
||||
$("#users").select2("data").forEach(function (group) {
|
||||
groups.push({ name: group.text });
|
||||
})
|
||||
// Validate our fields
|
||||
campaign = {
|
||||
name: $("#name").val(),
|
||||
template: {
|
||||
name: $("#template").select2("data")[0].text
|
||||
},
|
||||
url: $("#url").val(),
|
||||
page: {
|
||||
name: $("#page").select2("data")[0].text
|
||||
},
|
||||
smtp: {
|
||||
name: $("#profile").select2("data")[0].text
|
||||
},
|
||||
launch_date: moment($("#launch_date").val(), "MM/DD/YYYY hh:mm a").format(),
|
||||
groups: groups
|
||||
}
|
||||
// Submit the campaign
|
||||
name: $("#name").val(),
|
||||
template: {
|
||||
name: $("#template").select2("data")[0].text
|
||||
},
|
||||
url: $("#url").val(),
|
||||
page: {
|
||||
name: $("#page").select2("data")[0].text
|
||||
},
|
||||
smtp: {
|
||||
name: $("#profile").select2("data")[0].text
|
||||
},
|
||||
launch_date: moment($("#launch_date").val(), "MM/DD/YYYY hh:mm a").utc().format(),
|
||||
groups: groups
|
||||
}
|
||||
console.log("Launching campaign at time: " + campaign.launch_date)
|
||||
// Submit the campaign
|
||||
api.campaigns.post(campaign)
|
||||
.success(function(data) {
|
||||
.success(function (data) {
|
||||
resolve()
|
||||
campaign = data
|
||||
})
|
||||
.error(function(data) {
|
||||
.error(function (data) {
|
||||
$("#modal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-danger\">\
|
||||
<i class=\"fa fa-exclamation-circle\"></i> " + data.responseJSON.message + "</div>")
|
||||
swal.close()
|
||||
})
|
||||
})
|
||||
}
|
||||
}).then(function() {
|
||||
}).then(function () {
|
||||
swal(
|
||||
'Campaign Scheduled!',
|
||||
'This campaign has been scheduled for launch!',
|
||||
'success'
|
||||
);
|
||||
$('button:contains("OK")').on('click', function() {
|
||||
$('button:contains("OK")').on('click', function () {
|
||||
window.location = "/campaigns/" + campaign.id.toString()
|
||||
})
|
||||
})
|
||||
|
@ -91,14 +92,14 @@ function sendTestEmail() {
|
|||
}
|
||||
btnHtml = $("#sendTestModalSubmit").html()
|
||||
$("#sendTestModalSubmit").html('<i class="fa fa-spinner fa-spin"></i> Sending')
|
||||
// Send the test email
|
||||
// Send the test email
|
||||
api.send_test_email(test_email_request)
|
||||
.success(function(data) {
|
||||
.success(function (data) {
|
||||
$("#sendTestEmailModal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-success\">\
|
||||
<i class=\"fa fa-check-circle\"></i> Email Sent!</div>")
|
||||
$("#sendTestModalSubmit").html(btnHtml)
|
||||
})
|
||||
.error(function(data) {
|
||||
.error(function (data) {
|
||||
$("#sendTestEmailModal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-danger\">\
|
||||
<i class=\"fa fa-exclamation-circle\"></i> " + data.responseJSON.message + "</div>")
|
||||
$("#sendTestModalSubmit").html(btnHtml)
|
||||
|
@ -127,24 +128,24 @@ function deleteCampaign(idx) {
|
|||
confirmButtonColor: "#428bca",
|
||||
reverseButtons: true,
|
||||
allowOutsideClick: false,
|
||||
preConfirm: function() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
preConfirm: function () {
|
||||
return new Promise(function (resolve, reject) {
|
||||
api.campaignId.delete(campaigns[idx].id)
|
||||
.success(function(msg) {
|
||||
.success(function (msg) {
|
||||
resolve()
|
||||
})
|
||||
.error(function(data) {
|
||||
.error(function (data) {
|
||||
reject(data.responseJSON.message)
|
||||
})
|
||||
})
|
||||
}
|
||||
}).then(function() {
|
||||
}).then(function () {
|
||||
swal(
|
||||
'Campaign Deleted!',
|
||||
'This campaign has been deleted!',
|
||||
'success'
|
||||
);
|
||||
$('button:contains("OK")').on('click', function() {
|
||||
$('button:contains("OK")').on('click', function () {
|
||||
location.reload()
|
||||
})
|
||||
})
|
||||
|
@ -152,12 +153,12 @@ function deleteCampaign(idx) {
|
|||
|
||||
function setupOptions() {
|
||||
api.groups.get()
|
||||
.success(function(groups) {
|
||||
.success(function (groups) {
|
||||
if (groups.length == 0) {
|
||||
modalError("No groups found!")
|
||||
return false;
|
||||
} else {
|
||||
var group_s2 = $.map(groups, function(obj) {
|
||||
var group_s2 = $.map(groups, function (obj) {
|
||||
obj.text = obj.name
|
||||
return obj
|
||||
});
|
||||
|
@ -168,12 +169,12 @@ function setupOptions() {
|
|||
}
|
||||
});
|
||||
api.templates.get()
|
||||
.success(function(templates) {
|
||||
.success(function (templates) {
|
||||
if (templates.length == 0) {
|
||||
modalError("No templates found!")
|
||||
return false
|
||||
} else {
|
||||
var template_s2 = $.map(templates, function(obj) {
|
||||
var template_s2 = $.map(templates, function (obj) {
|
||||
obj.text = obj.name
|
||||
return obj
|
||||
});
|
||||
|
@ -184,12 +185,12 @@ function setupOptions() {
|
|||
}
|
||||
});
|
||||
api.pages.get()
|
||||
.success(function(pages) {
|
||||
.success(function (pages) {
|
||||
if (pages.length == 0) {
|
||||
modalError("No pages found!")
|
||||
return false
|
||||
} else {
|
||||
var page_s2 = $.map(pages, function(obj) {
|
||||
var page_s2 = $.map(pages, function (obj) {
|
||||
obj.text = obj.name
|
||||
return obj
|
||||
});
|
||||
|
@ -200,12 +201,12 @@ function setupOptions() {
|
|||
}
|
||||
});
|
||||
api.SMTP.get()
|
||||
.success(function(profiles) {
|
||||
.success(function (profiles) {
|
||||
if (profiles.length == 0) {
|
||||
modalError("No profiles found!")
|
||||
return false
|
||||
} else {
|
||||
var profile_s2 = $.map(profiles, function(obj) {
|
||||
var profile_s2 = $.map(profiles, function (obj) {
|
||||
obj.text = obj.name
|
||||
return obj
|
||||
});
|
||||
|
@ -223,9 +224,9 @@ function edit(campaign) {
|
|||
|
||||
function copy(idx) {
|
||||
setupOptions();
|
||||
// Set our initial values
|
||||
// Set our initial values
|
||||
api.campaignId.get(campaigns[idx].id)
|
||||
.success(function(campaign) {
|
||||
.success(function (campaign) {
|
||||
$("#name").val("Copy of " + campaign.name)
|
||||
if (!campaign.template.id) {
|
||||
$("#template").select2({
|
||||
|
@ -250,29 +251,29 @@ function copy(idx) {
|
|||
}
|
||||
$("#url").val(campaign.url)
|
||||
})
|
||||
.error(function(data) {
|
||||
.error(function (data) {
|
||||
$("#modal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-danger\">\
|
||||
<i class=\"fa fa-exclamation-circle\"></i> " + data.responseJSON.message + "</div>")
|
||||
})
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
$(document).ready(function () {
|
||||
$("#launch_date").datetimepicker({
|
||||
"widgetPositioning": {
|
||||
"vertical": "bottom"
|
||||
},
|
||||
"showTodayButton": true,
|
||||
"defaultDate": moment()
|
||||
})
|
||||
// Setup multiple modals
|
||||
// Code based on http://miles-by-motorcycle.com/static/bootstrap-modal/index.html
|
||||
$('.modal').on('hidden.bs.modal', function(event) {
|
||||
"widgetPositioning": {
|
||||
"vertical": "bottom"
|
||||
},
|
||||
"showTodayButton": true,
|
||||
"defaultDate": moment()
|
||||
})
|
||||
// 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('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') {
|
||||
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.
|
||||
|
@ -291,11 +292,11 @@ $(document).ready(function() {
|
|||
$(document).on('hidden.bs.modal', '.modal', function () {
|
||||
$('.modal:visible').length && $(document.body).addClass('modal-open');
|
||||
});
|
||||
$('#modal').on('hidden.bs.modal', function(event) {
|
||||
$('#modal').on('hidden.bs.modal', function (event) {
|
||||
dismiss()
|
||||
});
|
||||
api.campaigns.summary()
|
||||
.success(function(data) {
|
||||
.success(function (data) {
|
||||
campaigns = data.campaigns
|
||||
$("#loading").hide()
|
||||
if (campaigns.length > 0) {
|
||||
|
@ -309,23 +310,25 @@ $(document).ready(function() {
|
|||
[1, "desc"]
|
||||
]
|
||||
});
|
||||
$.each(campaigns, function(i, campaign) {
|
||||
$.each(campaigns, function (i, campaign) {
|
||||
console.log(campaign)
|
||||
console.log(campaign.created_date)
|
||||
label = labels[campaign.status] || "label-default";
|
||||
|
||||
//section for tooltips on the status of a campaign to show some quick stats
|
||||
//section for tooltips on the status of a campaign to show some quick stats
|
||||
var launchDate;
|
||||
if(moment(campaign.launch_date).isAfter(moment())){
|
||||
launchDate = "Scheduled to start: "+moment(campaign.launch_date).format('MMMM Do YYYY, h:mm:ss a')
|
||||
var quickStats = launchDate+"<br><br>"+"Number of recipients: "+campaign.stats.total
|
||||
if (moment(campaign.launch_date).isAfter(moment())) {
|
||||
launchDate = "Scheduled to start: " + moment(campaign.launch_date).format('MMMM Do YYYY, h:mm:ss a')
|
||||
var quickStats = launchDate + "<br><br>" + "Number of recipients: " + campaign.stats.total
|
||||
} else {
|
||||
launchDate = "Launch Date: "+moment(campaign.launch_date).format('MMMM Do YYYY, h:mm:ss a')
|
||||
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
|
||||
launchDate = "Launch Date: " + moment(campaign.launch_date).format('MMMM Do YYYY, h:mm:ss a')
|
||||
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
|
||||
}
|
||||
|
||||
campaignTable.row.add([
|
||||
escapeHtml(campaign.name),
|
||||
moment(campaign.created_date).format('MMMM Do YYYY, h:mm:ss a'),
|
||||
"<span class=\"label " + label + "\" data-toggle=\"tooltip\" data-placement=\"right\" data-html=\"true\" title=\""+quickStats+"\">" + campaign.status + "</span>",
|
||||
"<span class=\"label " + label + "\" data-toggle=\"tooltip\" data-placement=\"right\" data-html=\"true\" title=\"" + quickStats + "\">" + campaign.status + "</span>",
|
||||
"<div class='pull-right'><a class='btn btn-primary' href='/campaigns/" + campaign.id + "' data-toggle='tooltip' data-placement='left' title='View Results'>\
|
||||
<i class='fa fa-bar-chart'></i>\
|
||||
</a>\
|
||||
|
@ -342,7 +345,7 @@ $(document).ready(function() {
|
|||
$("#emptyMessage").show()
|
||||
}
|
||||
})
|
||||
.error(function() {
|
||||
.error(function () {
|
||||
$("#loading").hide()
|
||||
errorFlash("Error fetching campaigns")
|
||||
})
|
||||
|
|
|
@ -197,7 +197,7 @@ function generateStatsPieCharts(campaigns) {
|
|||
function generateTimelineChart(campaigns) {
|
||||
var overview_data = []
|
||||
$.each(campaigns, function (i, campaign) {
|
||||
var campaign_date = moment(campaign.created_date)
|
||||
var campaign_date = moment.utc(campaign.created_date).local()
|
||||
// Add it to the chart data
|
||||
campaign.y = 0
|
||||
// Clicked events also contain our data submitted events
|
||||
|
@ -275,6 +275,11 @@ function generateTimelineChart(campaigns) {
|
|||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
Highcharts.setOptions({
|
||||
global: {
|
||||
useUTC: false
|
||||
}
|
||||
})
|
||||
api.campaigns.summary()
|
||||
.success(function (data) {
|
||||
$("#loading").hide()
|
||||
|
|
|
@ -36,7 +36,7 @@ func New() *Worker {
|
|||
func (w *Worker) Start() {
|
||||
Logger.Println("Background Worker Started Successfully - Waiting for Campaigns")
|
||||
for t := range time.Tick(1 * time.Minute) {
|
||||
cs, err := models.GetQueuedCampaigns(t)
|
||||
cs, err := models.GetQueuedCampaigns(t.UTC())
|
||||
// Not really sure of a clean way to catch errors per campaign...
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
|
|
Loading…
Reference in a new issue