mirror of https://github.com/gophish/gophish
Cleaned up error messages - *all* errors in JSON format
Cleaned up flashes - fixes #13 Added specified errors - more to come soon Added Campaign validation Added Group validation Cleaned up the way angular errors are handled. Will double check, but for the most part fixes #11 Results are now shown on the webui with most recent shown first Added comments, additional cleanup, etc.pull/24/head
parent
ab8dfc8bb3
commit
66dbe2e799
|
@ -69,15 +69,13 @@ func API_Campaigns(w http.ResponseWriter, r *http.Request) {
|
|||
c := models.Campaign{}
|
||||
// Put the request into a campaign
|
||||
err := json.NewDecoder(r.Body).Decode(&c)
|
||||
if checkError(err, w, "Invalid Request", http.StatusBadRequest) {
|
||||
return
|
||||
}
|
||||
if m, ok := c.Validate(); !ok {
|
||||
http.Error(w, "Error: "+m, http.StatusBadRequest)
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Invalid JSON structure"}, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
err = models.PostCampaign(&c, ctx.Get(r, "user_id").(int64))
|
||||
if checkError(err, w, "Cannot insert campaign into database", http.StatusInternalServerError) {
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
Worker.Queue <- &c
|
||||
|
@ -91,7 +89,8 @@ func API_Campaigns_Id(w http.ResponseWriter, r *http.Request) {
|
|||
vars := mux.Vars(r)
|
||||
id, _ := strconv.ParseInt(vars["id"], 0, 64)
|
||||
c, err := models.GetCampaign(id, ctx.Get(r, "user_id").(int64))
|
||||
if checkError(err, w, "Campaign not found", http.StatusNotFound) {
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Campaign not found"}, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
switch {
|
||||
|
@ -99,7 +98,8 @@ func API_Campaigns_Id(w http.ResponseWriter, r *http.Request) {
|
|||
JSONResponse(w, c, http.StatusOK)
|
||||
case r.Method == "DELETE":
|
||||
err = models.DeleteCampaign(id)
|
||||
if checkError(err, w, "Error deleting campaign", http.StatusInternalServerError) {
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Error deleting campaign"}, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
JSONResponse(w, models.Response{Success: true, Message: "Campaign deleted successfully!"}, http.StatusOK)
|
||||
|
@ -112,7 +112,8 @@ func API_Groups(w http.ResponseWriter, r *http.Request) {
|
|||
switch {
|
||||
case r.Method == "GET":
|
||||
gs, err := models.GetGroups(ctx.Get(r, "user_id").(int64))
|
||||
if checkError(err, w, "Groups not found", http.StatusNotFound) {
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "No groups found"}, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
JSONResponse(w, gs, http.StatusOK)
|
||||
|
@ -121,7 +122,8 @@ func API_Groups(w http.ResponseWriter, r *http.Request) {
|
|||
g := models.Group{}
|
||||
// Put the request into a group
|
||||
err := json.NewDecoder(r.Body).Decode(&g)
|
||||
if checkError(err, w, "Invalid Request", http.StatusBadRequest) {
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Invalid JSON structure"}, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
_, err = models.GetGroupByName(g.Name, ctx.Get(r, "user_id").(int64))
|
||||
|
@ -129,15 +131,11 @@ func API_Groups(w http.ResponseWriter, r *http.Request) {
|
|||
JSONResponse(w, models.Response{Success: false, Message: "Group name already in use"}, http.StatusConflict)
|
||||
return
|
||||
}
|
||||
// Check to make sure targets were specified
|
||||
if len(g.Targets) == 0 {
|
||||
http.Error(w, "Error: No targets specified", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
g.ModifiedDate = time.Now()
|
||||
g.UserId = ctx.Get(r, "user_id").(int64)
|
||||
err = models.PostGroup(&g)
|
||||
if checkError(err, w, "Error inserting group", http.StatusInternalServerError) {
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Location", "http://localhost:3333/api/groups/"+string(g.Id))
|
||||
|
@ -151,7 +149,8 @@ func API_Groups_Id(w http.ResponseWriter, r *http.Request) {
|
|||
vars := mux.Vars(r)
|
||||
id, _ := strconv.ParseInt(vars["id"], 0, 64)
|
||||
g, err := models.GetGroup(id, ctx.Get(r, "user_id").(int64))
|
||||
if checkError(err, w, "Group not found", http.StatusNotFound) {
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Group not found"}, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
switch {
|
||||
|
@ -159,7 +158,8 @@ func API_Groups_Id(w http.ResponseWriter, r *http.Request) {
|
|||
JSONResponse(w, g, http.StatusOK)
|
||||
case r.Method == "DELETE":
|
||||
err = models.DeleteGroup(&g)
|
||||
if checkError(err, w, "Error deleting group", http.StatusInternalServerError) {
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Error deleting group"}, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
JSONResponse(w, models.Response{Success: true, Message: "Group deleted successfully!"}, http.StatusOK)
|
||||
|
@ -168,18 +168,14 @@ func API_Groups_Id(w http.ResponseWriter, r *http.Request) {
|
|||
g = models.Group{}
|
||||
err = json.NewDecoder(r.Body).Decode(&g)
|
||||
if g.Id != id {
|
||||
http.Error(w, "Error: /:id and group_id mismatch", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// Check to make sure targets were specified
|
||||
if len(g.Targets) == 0 {
|
||||
http.Error(w, "Error: No targets specified", http.StatusBadRequest)
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Error: /:id and group_id mismatch"}, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
g.ModifiedDate = time.Now()
|
||||
g.UserId = ctx.Get(r, "user_id").(int64)
|
||||
err = models.PutGroup(&g)
|
||||
if checkError(err, w, "Error updating group", http.StatusInternalServerError) {
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Error updating group"}, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
JSONResponse(w, g, http.StatusOK)
|
||||
|
@ -199,11 +195,11 @@ func API_Templates(w http.ResponseWriter, r *http.Request) {
|
|||
t := models.Template{}
|
||||
// Put the request into a template
|
||||
err := json.NewDecoder(r.Body).Decode(&t)
|
||||
if checkError(err, w, "Invalid Request", http.StatusBadRequest) {
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Invalid JSON structure"}, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
_, err = models.GetTemplateByName(t.Name, ctx.Get(r, "user_id").(int64))
|
||||
fmt.Println(err)
|
||||
if err != gorm.RecordNotFound {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Template name already in use"}, http.StatusConflict)
|
||||
return
|
||||
|
@ -219,7 +215,9 @@ func API_Templates(w http.ResponseWriter, r *http.Request) {
|
|||
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if checkError(err, w, "Error inserting template", http.StatusInternalServerError) {
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Error inserting template into database"}, http.StatusInternalServerError)
|
||||
Logger.Println(err)
|
||||
return
|
||||
}
|
||||
JSONResponse(w, t, http.StatusCreated)
|
||||
|
@ -230,8 +228,8 @@ func API_Templates_Id(w http.ResponseWriter, r *http.Request) {
|
|||
vars := mux.Vars(r)
|
||||
id, _ := strconv.ParseInt(vars["id"], 0, 64)
|
||||
t, err := models.GetTemplate(id, ctx.Get(r, "user_id").(int64))
|
||||
if checkError(err, w, "Template not found", http.StatusNotFound) {
|
||||
Logger.Println(err)
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Template not found"}, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
switch {
|
||||
|
@ -239,7 +237,8 @@ func API_Templates_Id(w http.ResponseWriter, r *http.Request) {
|
|||
JSONResponse(w, t, http.StatusOK)
|
||||
case r.Method == "DELETE":
|
||||
err = models.DeleteTemplate(id, ctx.Get(r, "user_id").(int64))
|
||||
if checkError(err, w, "Error deleting template", http.StatusInternalServerError) {
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Error deleting template"}, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
JSONResponse(w, models.Response{Success: true, Message: "Template deleted successfully!"}, http.StatusOK)
|
||||
|
@ -250,17 +249,14 @@ func API_Templates_Id(w http.ResponseWriter, r *http.Request) {
|
|||
Logger.Println(err)
|
||||
}
|
||||
if t.Id != id {
|
||||
http.Error(w, "Error: /:id and template_id mismatch", http.StatusBadRequest)
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Error: /:id and template_id mismatch"}, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
err = t.Validate()
|
||||
/* if checkError(err, w, http.StatusBadRequest) {
|
||||
return
|
||||
}*/
|
||||
t.ModifiedDate = time.Now()
|
||||
t.UserId = ctx.Get(r, "user_id").(int64)
|
||||
err = models.PutTemplate(&t)
|
||||
if checkError(err, w, "Error updating group", http.StatusInternalServerError) {
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
JSONResponse(w, t, http.StatusOK)
|
||||
|
@ -306,8 +302,8 @@ func API_Pages_Id(w http.ResponseWriter, r *http.Request) {
|
|||
vars := mux.Vars(r)
|
||||
id, _ := strconv.ParseInt(vars["id"], 0, 64)
|
||||
p, err := models.GetPage(id, ctx.Get(r, "user_id").(int64))
|
||||
if checkError(err, w, "Page not found", http.StatusNotFound) {
|
||||
Logger.Println(err)
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Page not found"}, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
switch {
|
||||
|
@ -315,7 +311,8 @@ func API_Pages_Id(w http.ResponseWriter, r *http.Request) {
|
|||
JSONResponse(w, p, http.StatusOK)
|
||||
case r.Method == "DELETE":
|
||||
err = models.DeletePage(id, ctx.Get(r, "user_id").(int64))
|
||||
if checkError(err, w, "Error deleting page", http.StatusInternalServerError) {
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Error deleting page"}, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
JSONResponse(w, models.Response{Success: true, Message: "Page Deleted Successfully"}, http.StatusOK)
|
||||
|
@ -348,7 +345,8 @@ func API_Pages_Id(w http.ResponseWriter, r *http.Request) {
|
|||
// API_Import_Group imports a CSV of group members
|
||||
func API_Import_Group(w http.ResponseWriter, r *http.Request) {
|
||||
ts, err := util.ParseCSV(r)
|
||||
if checkError(err, w, "Error deleting template", http.StatusInternalServerError) {
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Error parsing CSV"}, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
JSONResponse(w, ts, http.StatusOK)
|
||||
|
@ -371,8 +369,9 @@ func API_Import_Email(w http.ResponseWriter, r *http.Request) {
|
|||
// is written to the given ResponseWriter.
|
||||
func JSONResponse(w http.ResponseWriter, d interface{}, c int) {
|
||||
dj, err := json.MarshalIndent(d, "", " ")
|
||||
if checkError(err, w, "Error creating JSON response", http.StatusInternalServerError) {
|
||||
return
|
||||
if err != nil {
|
||||
http.Error(w, "Error creating JSON response", http.StatusInternalServerError)
|
||||
Logger.Println(err)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(c)
|
||||
|
|
|
@ -264,16 +264,6 @@ func getTemplate(w http.ResponseWriter, tmpl string) *template.Template {
|
|||
return template.Must(templates, err)
|
||||
}
|
||||
|
||||
func checkError(e error, w http.ResponseWriter, m string, c int) bool {
|
||||
if e != nil {
|
||||
Logger.Println(e)
|
||||
w.WriteHeader(c)
|
||||
JSONResponse(w, models.Response{Success: false, Message: m}, http.StatusBadRequest)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Flash handles the rendering flash messages
|
||||
func Flash(w http.ResponseWriter, r *http.Request, t string, m string) {
|
||||
session := ctx.Get(r, "session").(*sessions.Session)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
|
@ -26,17 +27,32 @@ type Campaign struct {
|
|||
SMTP SMTP `json:"smtp"`
|
||||
}
|
||||
|
||||
// ErrCampaignNameNotSpecified indicates there was no template given by the user
|
||||
var ErrCampaignNameNotSpecified = errors.New("Campaign name not specified")
|
||||
|
||||
// ErrGroupNotSpecified indicates there was no template given by the user
|
||||
var ErrGroupNotSpecified = errors.New("No groups specified")
|
||||
|
||||
// ErrTemplateNotSpecified indicates there was no template given by the user
|
||||
var ErrTemplateNotSpecified = errors.New("No email template specified")
|
||||
|
||||
// ErrTemplateNotFound indicates the template specified does not exist in the database
|
||||
var ErrTemplateNotFound = errors.New("Template not found")
|
||||
|
||||
// ErrGroupnNotFound indicates a group specified by the user does not exist in the database
|
||||
var ErrGroupNotFound = errors.New("Group not found")
|
||||
|
||||
// Validate checks to make sure there are no invalid fields in a submitted campaign
|
||||
func (c *Campaign) Validate() (string, bool) {
|
||||
func (c *Campaign) Validate() error {
|
||||
switch {
|
||||
case c.Name == "":
|
||||
return "Must specify campaign name", false
|
||||
return ErrCampaignNameNotSpecified
|
||||
case len(c.Groups) == 0:
|
||||
return "No groups specified", false
|
||||
return ErrGroupNotSpecified
|
||||
case c.Template.Name == "":
|
||||
return "No template specified", false
|
||||
return ErrTemplateNotSpecified
|
||||
}
|
||||
return "", true
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateStatus changes the campaign status appropriately
|
||||
|
@ -105,6 +121,9 @@ func GetCampaign(id int64, uid int64) (Campaign, error) {
|
|||
|
||||
// PostCampaign inserts a campaign and all associated records into the database.
|
||||
func PostCampaign(c *Campaign, uid int64) error {
|
||||
if err := c.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
// Fill in the details
|
||||
c.UserId = uid
|
||||
c.CreatedDate = time.Now()
|
||||
|
@ -115,7 +134,7 @@ func PostCampaign(c *Campaign, uid int64) error {
|
|||
c.Groups[i], err = GetGroupByName(g.Name, uid)
|
||||
if err == gorm.RecordNotFound {
|
||||
Logger.Printf("Error - Group %s does not exist", g.Name)
|
||||
return err
|
||||
return ErrGroupNotFound
|
||||
} else if err != nil {
|
||||
Logger.Println(err)
|
||||
return err
|
||||
|
@ -125,7 +144,7 @@ func PostCampaign(c *Campaign, uid int64) error {
|
|||
t, err := GetTemplateByName(c.Template.Name, uid)
|
||||
if err == gorm.RecordNotFound {
|
||||
Logger.Printf("Error - Template %s does not exist", t.Name)
|
||||
return err
|
||||
return ErrTemplateNotFound
|
||||
} else if err != nil {
|
||||
Logger.Println(err)
|
||||
return err
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/mail"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
// Group contains the fields needed for a user -> group mapping
|
||||
// Groups contain 1..* Targets
|
||||
type Group struct {
|
||||
Id int64 `json:"id"`
|
||||
UserId int64 `json:"-"`
|
||||
|
@ -15,11 +18,14 @@ type Group struct {
|
|||
Targets []Target `json:"targets" sql:"-"`
|
||||
}
|
||||
|
||||
// GroupTarget is used for a many-to-many relationship between 1..* Groups and 1..* Targets
|
||||
type GroupTarget struct {
|
||||
GroupId int64 `json:"-"`
|
||||
TargetId int64 `json:"-"`
|
||||
}
|
||||
|
||||
// Target contains the fields needed for individual targets specified by the user
|
||||
// Groups contain 1..* Targets, but 1 Target may belong to 1..* Groups
|
||||
type Target struct {
|
||||
Id int64 `json:"-"`
|
||||
FirstName string `json:"first_name"`
|
||||
|
@ -27,6 +33,23 @@ type Target struct {
|
|||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
// ErrGroupNameNotSpecified is thrown when a group name is not specified
|
||||
var ErrGroupNameNotSpecified = errors.New("Group name not specified")
|
||||
|
||||
// ErrNoTargetsSpecified is thrown when no targets are specified by the user
|
||||
var ErrNoTargetsSpecified = errors.New("No targets specified")
|
||||
|
||||
// Validate performs validation on a group given by the user
|
||||
func (g *Group) Validate() error {
|
||||
switch {
|
||||
case g.Name == "":
|
||||
return ErrGroupNameNotSpecified
|
||||
case len(g.Targets) == 0:
|
||||
return ErrNoTargetsSpecified
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetGroups returns the groups owned by the given user.
|
||||
func GetGroups(uid int64) ([]Group, error) {
|
||||
gs := []Group{}
|
||||
|
@ -76,7 +99,11 @@ func GetGroupByName(n string, uid int64) (Group, error) {
|
|||
|
||||
// PostGroup creates a new group in the database.
|
||||
func PostGroup(g *Group) error {
|
||||
// Insert into the DB
|
||||
Logger.Printf("%v", g.Targets)
|
||||
if err := g.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
// Insert the group into the DB
|
||||
err = db.Save(g).Error
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
|
@ -189,6 +216,7 @@ func insertTargetIntoGroup(t Target, gid int64) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// 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").Joins("left join group_targets gt ON targets.id = gt.target_id").Where("gt.group_id=?", gid).Scan(&ts).Error
|
||||
|
|
|
@ -20,7 +20,7 @@ type Template struct {
|
|||
}
|
||||
|
||||
// ErrTemplateNameNotSpecified is thrown when a template name is not specified
|
||||
var ErrTemplateNameNotSpecified = errors.New("Template Name not specified")
|
||||
var ErrTemplateNameNotSpecified = errors.New("Template name not specified")
|
||||
|
||||
// ErrTemplateMissingParameter is thrown when a needed parameter is not provided
|
||||
var ErrTemplateMissingParameter = errors.New("Need to specify at least plaintext or HTML content")
|
||||
|
@ -112,8 +112,11 @@ func PostTemplate(t *Template) error {
|
|||
// PutTemplate edits an existing template in the database.
|
||||
// Per the PUT Method RFC, it presumes all data for a template is provided.
|
||||
func PutTemplate(t *Template) error {
|
||||
if err := t.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
// Delete all attachments, and replace with new ones
|
||||
err := db.Debug().Where("template_id=?", t.Id).Delete(&Attachment{}).Error
|
||||
err = db.Where("template_id=?", t.Id).Delete(&Attachment{}).Error
|
||||
if err != nil && err != gorm.RecordNotFound {
|
||||
Logger.Println(err)
|
||||
return err
|
||||
|
@ -129,7 +132,7 @@ func PutTemplate(t *Template) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
err = db.Debug().Where("id=?", t.Id).Save(t).Error
|
||||
err = db.Where("id=?", t.Id).Save(t).Error
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
return err
|
||||
|
|
|
@ -132,7 +132,23 @@ app.controller('DashboardCtrl', function($scope, $filter, $location, CampaignSer
|
|||
});
|
||||
})
|
||||
app.controller('CampaignCtrl', function($scope, $modal, CampaignService, GroupService, TemplateService, ngTableParams, $http) {
|
||||
$scope.flashes = []
|
||||
$scope.errorFlash = function(message) {
|
||||
$scope.flashes = {"main" : [], "modal" : []};
|
||||
$scope.flashes.main.push({
|
||||
"type": "danger",
|
||||
"message": message,
|
||||
"icon": "fa-exclamation-circle"
|
||||
})
|
||||
}
|
||||
|
||||
$scope.successFlash = function(message) {
|
||||
$scope.flashes = {"main" : [], "modal" : []};;
|
||||
$scope.flashes.main.push({
|
||||
"type": "success",
|
||||
"message": message,
|
||||
"icon": "fa-check-circle"
|
||||
})
|
||||
}
|
||||
$scope.mainTableParams = new ngTableParams({
|
||||
page: 1, // show first page
|
||||
count: 10, // count per page
|
||||
|
@ -158,21 +174,6 @@ app.controller('CampaignCtrl', function($scope, $modal, CampaignService, GroupSe
|
|||
$scope.templates = templates;
|
||||
})
|
||||
|
||||
$scope.addGroup = function(group) {
|
||||
if (group.name != "") {
|
||||
$scope.campaign.groups.push({
|
||||
name: group.name
|
||||
});
|
||||
group.name = ""
|
||||
$scope.editGroupTableParams.reload()
|
||||
}
|
||||
};
|
||||
|
||||
$scope.removeGroup = function(group) {
|
||||
$scope.campaign.groups.splice($scope.campaign.groups.indexOf(group), 1);
|
||||
$scope.editGroupTableParams.reload()
|
||||
};
|
||||
|
||||
$scope.newCampaign = function() {
|
||||
$scope.campaign = {
|
||||
name: '',
|
||||
|
@ -188,11 +189,19 @@ app.controller('CampaignCtrl', function($scope, $modal, CampaignService, GroupSe
|
|||
scope: $scope
|
||||
});
|
||||
|
||||
modalInstance.result.then(function(selectedItem) {
|
||||
$scope.selected = selectedItem;
|
||||
modalInstance.result.then(function(message) {
|
||||
$scope.successFlash(message)
|
||||
$scope.campaign = {
|
||||
name: '',
|
||||
groups: [],
|
||||
};
|
||||
}, function() {
|
||||
console.log('closed')
|
||||
$scope.campaign = {
|
||||
name: '',
|
||||
groups: [],
|
||||
};
|
||||
});
|
||||
$scope.mainTableParams.reload()
|
||||
};
|
||||
|
||||
$scope.editGroupTableParams = new ngTableParams({
|
||||
|
@ -209,35 +218,64 @@ app.controller('CampaignCtrl', function($scope, $modal, CampaignService, GroupSe
|
|||
}
|
||||
});
|
||||
|
||||
$scope.saveCampaign = function(campaign) {
|
||||
$scope.flashes = []
|
||||
$scope.validated = true
|
||||
var newCampaign = new CampaignService(campaign);
|
||||
newCampaign.$save({}, function() {
|
||||
$scope.successFlash("Campaign added successfully")
|
||||
$scope.campaigns.push(newCampaign);
|
||||
$scope.mainTableParams.reload()
|
||||
}, function(response) {
|
||||
$scope.errorFlash(response.data)
|
||||
});
|
||||
$scope.campaign = {
|
||||
groups: [],
|
||||
};
|
||||
$scope.editGroupTableParams.reload()
|
||||
}
|
||||
|
||||
$scope.deleteCampaign = function(campaign) {
|
||||
var deleteCampaign = new CampaignService(campaign);
|
||||
deleteCampaign.$delete({
|
||||
id: deleteCampaign.id
|
||||
}, function() {
|
||||
$scope.successFlash("Campaign deleted successfully")
|
||||
}, function(response) {
|
||||
if (response.success) {
|
||||
$scope.successFlash(response.message)
|
||||
} else {
|
||||
$scope.errorFlash(response.message)
|
||||
}
|
||||
$scope.mainTableParams.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var CampaignModalCtrl = function($scope, CampaignService, $modalInstance) {
|
||||
$scope.errorFlash = function(message) {
|
||||
$scope.flashes.push({
|
||||
$scope.flashes = {"main" : [], "modal" : []};
|
||||
$scope.flashes.modal.push({
|
||||
"type": "danger",
|
||||
"message": message,
|
||||
"icon": "fa-exclamation-circle"
|
||||
})
|
||||
}
|
||||
$scope.addGroup = function(group) {
|
||||
if (group.name != "") {
|
||||
$scope.campaign.groups.push({
|
||||
name: group.name
|
||||
});
|
||||
group.name = ""
|
||||
$scope.editGroupTableParams.reload()
|
||||
}
|
||||
};
|
||||
|
||||
$scope.removeGroup = function(group) {
|
||||
$scope.campaign.groups.splice($scope.campaign.groups.indexOf(group), 1);
|
||||
$scope.editGroupTableParams.reload()
|
||||
};
|
||||
$scope.cancel = function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
$scope.ok = function(campaign) {
|
||||
var newCampaign = new CampaignService(campaign);
|
||||
newCampaign.$save({}, function() {
|
||||
$modalInstance.close("Campaign added successfully")
|
||||
$scope.campaigns.push(newCampaign);
|
||||
$scope.mainTableParams.reload()
|
||||
}, function(response) {
|
||||
$scope.errorFlash(response.data.message)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
app.controller('CampaignResultsCtrl', function($scope, $filter, CampaignService, GroupService, ngTableParams, $http, $window) {
|
||||
id = $window.location.hash.split('/')[2];
|
||||
$scope.errorFlash = function(message) {
|
||||
$scope.flashes = {"main" : [], "modal" : []};
|
||||
$scope.flashes.main.push({
|
||||
"type": "danger",
|
||||
"message": message,
|
||||
"icon": "fa-exclamation-circle"
|
||||
|
@ -245,27 +283,13 @@ app.controller('CampaignCtrl', function($scope, $modal, CampaignService, GroupSe
|
|||
}
|
||||
|
||||
$scope.successFlash = function(message) {
|
||||
$scope.flashes.push({
|
||||
$scope.flashes = {"main" : [], "modal" : []};;
|
||||
$scope.flashes.main.push({
|
||||
"type": "success",
|
||||
"message": message,
|
||||
"icon": "fa-check-circle"
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
var CampaignModalCtrl = function($scope, $modalInstance) {
|
||||
$scope.cancel = function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
$scope.ok = function(campaign) {
|
||||
$modalInstance.dismiss("")
|
||||
$scope.saveCampaign(campaign)
|
||||
}
|
||||
};
|
||||
|
||||
app.controller('CampaignResultsCtrl', function($scope, $filter, CampaignService, GroupService, ngTableParams, $http, $window) {
|
||||
id = $window.location.hash.split('/')[2];
|
||||
$scope.flashes = []
|
||||
$scope.mainTableParams = new ngTableParams({
|
||||
page: 1, // show first page
|
||||
count: 10, // count per page
|
||||
|
@ -378,51 +402,43 @@ app.controller('CampaignResultsCtrl', function($scope, $filter, CampaignService,
|
|||
xAxis: {
|
||||
type: 'datetime',
|
||||
dateTimeLabelFormats: { // don't display the dummy year
|
||||
day: "%e of %b",
|
||||
hour: "%l:%M",
|
||||
second: '%l:%M:%S',
|
||||
minute: '%l:%M'
|
||||
},
|
||||
max: Date.now(),
|
||||
title: {
|
||||
text: 'Date'
|
||||
}
|
||||
day: "%e of %b",
|
||||
hour: "%l:%M",
|
||||
second: '%l:%M:%S',
|
||||
minute: '%l:%M'
|
||||
},
|
||||
max: Date.now(),
|
||||
title: {
|
||||
text: 'Date'
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
name: "Events",
|
||||
data: $scope.campaign.timeline
|
||||
}],
|
||||
title: {
|
||||
text: 'Campaign Timeline'
|
||||
},
|
||||
size: {
|
||||
height: 300
|
||||
},
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
loading: false,
|
||||
}
|
||||
params.total(campaign.results.length)
|
||||
$defer.resolve(campaign.results.slice((params.page() - 1) * params.count(), params.page() * params.count()));
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
$scope.errorFlash = function(message) {
|
||||
$scope.flashes.push({
|
||||
"type": "danger",
|
||||
"message": message,
|
||||
"icon": "fa-exclamation-circle"
|
||||
},
|
||||
series: [{
|
||||
name: "Events",
|
||||
data: $scope.campaign.timeline
|
||||
}],
|
||||
title: {
|
||||
text: 'Campaign Timeline'
|
||||
},
|
||||
size: {
|
||||
height: 300
|
||||
},
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
loading: false,
|
||||
}
|
||||
params.total(campaign.results.length)
|
||||
$defer.resolve(campaign.results.slice((params.page() - 1) * params.count(), params.page() * params.count()));
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
app.controller('GroupCtrl', function($scope, $modal, GroupService, ngTableParams) {
|
||||
$scope.errorFlash = function(message) {
|
||||
$scope.flashes = [];
|
||||
$scope.flashes.push({
|
||||
$scope.flashes = {"main" : [], "modal" : []};
|
||||
$scope.flashes.main.push({
|
||||
"type": "danger",
|
||||
"message": message,
|
||||
"icon": "fa-exclamation-circle"
|
||||
|
@ -430,8 +446,8 @@ app.controller('GroupCtrl', function($scope, $modal, GroupService, ngTableParams
|
|||
}
|
||||
|
||||
$scope.successFlash = function(message) {
|
||||
$scope.flashes = [];
|
||||
$scope.flashes.push({
|
||||
$scope.flashes = {"main" : [], "modal" : []};;
|
||||
$scope.flashes.main.push({
|
||||
"type": "success",
|
||||
"message": message,
|
||||
"icon": "fa-check-circle"
|
||||
|
@ -487,8 +503,64 @@ app.controller('GroupCtrl', function($scope, $modal, GroupService, ngTableParams
|
|||
controller: GroupModalCtrl,
|
||||
scope: $scope
|
||||
});
|
||||
modalInstance.result.then(function(message) {
|
||||
$scope.successFlash(message)
|
||||
$scope.group = {
|
||||
name: '',
|
||||
targets: [],
|
||||
};
|
||||
}, function() {
|
||||
$scope.group = {
|
||||
name: '',
|
||||
targets: [],
|
||||
};
|
||||
});
|
||||
$scope.mainTableParams.reload()
|
||||
|
||||
};
|
||||
|
||||
$scope.deleteGroup = function(group) {
|
||||
var deleteGroup = new GroupService(group);
|
||||
deleteGroup.$delete({
|
||||
id: deleteGroup.id
|
||||
}, function(response) {
|
||||
if (response.success) {
|
||||
$scope.successFlash(response.message)
|
||||
} else {
|
||||
$scope.errorFlash(response.message)
|
||||
}
|
||||
$scope.mainTableParams.reload();
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
var GroupModalCtrl = function($scope, GroupService, $modalInstance, $upload) {
|
||||
$scope.errorFlash = function(message) {
|
||||
$scope.flashes = {"main" : [], "modal" : []};
|
||||
$scope.flashes.modal.push({
|
||||
"type": "danger",
|
||||
"message": message,
|
||||
"icon": "fa-exclamation-circle"
|
||||
})
|
||||
}
|
||||
$scope.onFileSelect = function($file) {
|
||||
$scope.upload = $upload.upload({
|
||||
url: '/api/import/group',
|
||||
data: {},
|
||||
file: $file,
|
||||
}).progress(function(evt) {
|
||||
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
|
||||
}).success(function(data, status, headers, config) {
|
||||
angular.forEach(data, function(record, key) {
|
||||
$scope.group.targets.push({
|
||||
first_name : record.first_name,
|
||||
last_name : record.last_name,
|
||||
email: record.email
|
||||
});
|
||||
});
|
||||
$scope.editGroupTableParams.reload();
|
||||
});
|
||||
};
|
||||
$scope.addTarget = function() {
|
||||
if ($scope.newTarget.email != "") {
|
||||
$scope.group.targets.push({
|
||||
|
@ -502,60 +574,27 @@ app.controller('GroupCtrl', function($scope, $modal, GroupService, ngTableParams
|
|||
$scope.group.targets.splice($scope.group.targets.indexOf(target), 1);
|
||||
$scope.editGroupTableParams.reload()
|
||||
};
|
||||
$scope.saveGroup = function(group) {
|
||||
$scope.cancel = function() {
|
||||
$modalInstance.dismiss();
|
||||
};
|
||||
$scope.ok = function(group) {
|
||||
var newGroup = new GroupService(group);
|
||||
if ($scope.newGroup) {
|
||||
newGroup.$save({}, function() {
|
||||
$scope.groups.push(newGroup);
|
||||
$scope.mainTableParams.reload()
|
||||
$modalInstance.close("Group created successfully!")
|
||||
}, function(error){
|
||||
$scope.errorFlash(error.data.message)
|
||||
});
|
||||
} else {
|
||||
newGroup.$update({
|
||||
id: newGroup.id
|
||||
},function(){
|
||||
$modalInstance.close("Group updated successfully!")
|
||||
}, function(error){
|
||||
$scope.errorFlash(error.data.message)
|
||||
})
|
||||
}
|
||||
$scope.group = {
|
||||
name: '',
|
||||
targets: [],
|
||||
};
|
||||
$scope.editGroupTableParams.reload()
|
||||
}
|
||||
$scope.deleteGroup = function(group) {
|
||||
var deleteGroup = new GroupService(group);
|
||||
deleteGroup.$delete({
|
||||
id: deleteGroup.id
|
||||
}, function() {
|
||||
$scope.mainTableParams.reload();
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
var GroupModalCtrl = function($scope, $modalInstance, $upload) {
|
||||
$scope.onFileSelect = function($file) {
|
||||
$scope.upload = $upload.upload({
|
||||
url: '/api/import/group',
|
||||
data: {},
|
||||
file: $file,
|
||||
}).progress(function(evt) {
|
||||
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
|
||||
}).success(function(data, status, headers, config) {
|
||||
angular.forEach(data, function(record, key) {
|
||||
$scope.group.targets.push({
|
||||
first_name : record.first_name,
|
||||
last_name : record.last_name,
|
||||
email: record.email
|
||||
});
|
||||
});
|
||||
$scope.editGroupTableParams.reload();
|
||||
//.error(...)
|
||||
});
|
||||
};
|
||||
$scope.cancel = function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
$scope.ok = function(group) {
|
||||
$modalInstance.dismiss('')
|
||||
$scope.saveGroup(group)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -623,11 +662,11 @@ app.controller('TemplateCtrl', function($scope, $modal, TemplateService, ngTable
|
|||
text: '',
|
||||
};
|
||||
}, function() {
|
||||
$scope.template = {
|
||||
$scope.template = {
|
||||
name: '',
|
||||
html: '',
|
||||
text: '',
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -648,7 +687,7 @@ app.controller('TemplateCtrl', function($scope, $modal, TemplateService, ngTable
|
|||
|
||||
var TemplateModalCtrl = function($scope, TemplateService, $upload, $modalInstance, $modal) {
|
||||
$scope.editorOptions = {
|
||||
fullPage: true,
|
||||
fullPage: true,
|
||||
allowedContent: true,
|
||||
}
|
||||
$scope.errorFlash = function(message) {
|
||||
|
@ -673,9 +712,9 @@ var TemplateModalCtrl = function($scope, TemplateService, $upload, $modalInstanc
|
|||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
$scope.template.attachments.push({
|
||||
name : file.name,
|
||||
content : reader.result.split(",")[1],
|
||||
type : file.type || "application/octet-stream"
|
||||
name : file.name,
|
||||
content : reader.result.split(",")[1],
|
||||
type : file.type || "application/octet-stream"
|
||||
})
|
||||
$scope.$apply();
|
||||
}
|
||||
|
@ -700,9 +739,8 @@ var TemplateModalCtrl = function($scope, TemplateService, $upload, $modalInstanc
|
|||
// Close the dialog, returning the template
|
||||
$modalInstance.close("Template created successfully!")
|
||||
}, function(error){
|
||||
// Otherwise, leave the dialog open, showing the error
|
||||
console.log(error.data)
|
||||
$scope.errorFlash(error.data.message)
|
||||
// Otherwise, leave the dialog open, showing the error
|
||||
$scope.errorFlash(error.data.message)
|
||||
});
|
||||
} else {
|
||||
newTemplate.$update({
|
||||
|
@ -710,7 +748,6 @@ var TemplateModalCtrl = function($scope, TemplateService, $upload, $modalInstanc
|
|||
}, function(){
|
||||
$modalInstance.close("Template updated successfully!")
|
||||
}, function(error){
|
||||
console.log(error.data)
|
||||
$scope.errorFlash(error.data.message)
|
||||
})
|
||||
}
|
||||
|
@ -733,109 +770,109 @@ var TemplateModalCtrl = function($scope, TemplateService, $upload, $modalInstanc
|
|||
};
|
||||
|
||||
var ImportEmailCtrl = function($scope, $http, $modalInstance) {
|
||||
$scope.email = {}
|
||||
$scope.ok = function() {
|
||||
// Simple POST request example (passing data) :
|
||||
$http.post('/api/import/email', $scope.email.raw,
|
||||
{ headers : {"Content-Type" : "text/plain"}}
|
||||
$scope.email = {}
|
||||
$scope.ok = function() {
|
||||
// Simple POST request example (passing data) :
|
||||
$http.post('/api/import/email', $scope.email.raw,
|
||||
{ headers : {"Content-Type" : "text/plain"}}
|
||||
).success(function(data) {console.log("Success: " + data)})
|
||||
.error(function(data) {console.log("Error: " + data)});
|
||||
$modalInstance.close($scope.email.raw)
|
||||
};
|
||||
$scope.cancel = function() {$modalInstance.dismiss()}
|
||||
};
|
||||
$scope.cancel = function() {$modalInstance.dismiss()}
|
||||
};
|
||||
|
||||
app.controller('LandingPageCtrl', function($scope, $modal, LandingPageService, ngTableParams) {
|
||||
$scope.errorFlash = function(message) {
|
||||
$scope.flashes = [];
|
||||
$scope.flashes.push({
|
||||
"type": "danger",
|
||||
"message": message,
|
||||
"icon": "fa-exclamation-circle"
|
||||
})
|
||||
}
|
||||
$scope.errorFlash = function(message) {
|
||||
$scope.flashes = [];
|
||||
$scope.flashes.push({
|
||||
"type": "danger",
|
||||
"message": message,
|
||||
"icon": "fa-exclamation-circle"
|
||||
})
|
||||
}
|
||||
|
||||
$scope.successFlash = function(message) {
|
||||
$scope.flashes = [];
|
||||
$scope.flashes.push({
|
||||
"type": "success",
|
||||
"message": message,
|
||||
"icon": "fa-check-circle"
|
||||
})
|
||||
}
|
||||
$scope.successFlash = function(message) {
|
||||
$scope.flashes = [];
|
||||
$scope.flashes.push({
|
||||
"type": "success",
|
||||
"message": message,
|
||||
"icon": "fa-check-circle"
|
||||
})
|
||||
}
|
||||
|
||||
$scope.mainTableParams = new ngTableParams({
|
||||
page: 1, // show first page
|
||||
count: 10, // count per page
|
||||
sorting: {
|
||||
name: 'asc' // initial sorting
|
||||
}
|
||||
}, {
|
||||
total: 0, // length of data
|
||||
getData: function($defer, params) {
|
||||
LandingPageService.query(function(pages) {
|
||||
$scope.pages = pages
|
||||
params.total(pages.length)
|
||||
$defer.resolve(pages.slice((params.page() - 1) * params.count(), params.page() * params.count()));
|
||||
})
|
||||
}
|
||||
});
|
||||
$scope.mainTableParams = new ngTableParams({
|
||||
page: 1, // show first page
|
||||
count: 10, // count per page
|
||||
sorting: {
|
||||
name: 'asc' // initial sorting
|
||||
}
|
||||
}, {
|
||||
total: 0, // length of data
|
||||
getData: function($defer, params) {
|
||||
LandingPageService.query(function(pages) {
|
||||
$scope.pages = pages
|
||||
params.total(pages.length)
|
||||
$defer.resolve(pages.slice((params.page() - 1) * params.count(), params.page() * params.count()));
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
$scope.editPage = function(page) {
|
||||
if (page === 'new') {
|
||||
$scope.newPage = true;
|
||||
$scope.page = {
|
||||
name: '',
|
||||
html: '',
|
||||
};
|
||||
$scope.editPage = function(page) {
|
||||
if (page === 'new') {
|
||||
$scope.newPage = true;
|
||||
$scope.page = {
|
||||
name: '',
|
||||
html: '',
|
||||
};
|
||||
|
||||
} else {
|
||||
$scope.newPage = false;
|
||||
$scope.page = page;
|
||||
}
|
||||
var modalInstance = $modal.open({
|
||||
templateUrl: '/js/app/partials/modals/LandingPageModal.html',
|
||||
controller: LandingPageModalCtrl,
|
||||
scope: $scope
|
||||
});
|
||||
} else {
|
||||
$scope.newPage = false;
|
||||
$scope.page = page;
|
||||
}
|
||||
var modalInstance = $modal.open({
|
||||
templateUrl: '/js/app/partials/modals/LandingPageModal.html',
|
||||
controller: LandingPageModalCtrl,
|
||||
scope: $scope
|
||||
});
|
||||
|
||||
modalInstance.result.then(function(selectedItem) {
|
||||
$scope.selected = selectedItem;
|
||||
}, function() {
|
||||
console.log('closed')
|
||||
});
|
||||
};
|
||||
modalInstance.result.then(function(selectedItem) {
|
||||
$scope.selected = selectedItem;
|
||||
}, function() {
|
||||
console.log('closed')
|
||||
});
|
||||
};
|
||||
|
||||
$scope.savePage = function(page) {
|
||||
var newPage = new LandingPageService(page);
|
||||
if ($scope.newPage) {
|
||||
newPage.$save({}, function() {
|
||||
$scope.pages.push(newPage);
|
||||
$scope.mainTableParams.reload()
|
||||
});
|
||||
} else {
|
||||
newPage.$update({
|
||||
id: newPage.id
|
||||
})
|
||||
}
|
||||
$scope.page = {
|
||||
name: '',
|
||||
html: '',
|
||||
};
|
||||
}
|
||||
$scope.deletePage = function(page) {
|
||||
var deletePage = new LandingPageService(page);
|
||||
deletePage.$delete({
|
||||
id: deletePage.id
|
||||
}, function(response) {
|
||||
if (response.success) {
|
||||
$scope.successFlash(response.message)
|
||||
} else {
|
||||
$scope.errorFlash(response.message)
|
||||
}
|
||||
$scope.mainTableParams.reload();
|
||||
});
|
||||
}
|
||||
$scope.savePage = function(page) {
|
||||
var newPage = new LandingPageService(page);
|
||||
if ($scope.newPage) {
|
||||
newPage.$save({}, function() {
|
||||
$scope.pages.push(newPage);
|
||||
$scope.mainTableParams.reload()
|
||||
});
|
||||
} else {
|
||||
newPage.$update({
|
||||
id: newPage.id
|
||||
})
|
||||
}
|
||||
$scope.page = {
|
||||
name: '',
|
||||
html: '',
|
||||
};
|
||||
}
|
||||
$scope.deletePage = function(page) {
|
||||
var deletePage = new LandingPageService(page);
|
||||
deletePage.$delete({
|
||||
id: deletePage.id
|
||||
}, function(response) {
|
||||
if (response.success) {
|
||||
$scope.successFlash(response.message)
|
||||
} else {
|
||||
$scope.errorFlash(response.message)
|
||||
}
|
||||
$scope.mainTableParams.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var LandingPageModalCtrl = function($scope, $modalInstance) {
|
||||
|
@ -887,13 +924,13 @@ app.controller('SettingsCtrl', function($scope, $http, $window) {
|
|||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
} // set the headers so angular passing info as form data (not request payload)
|
||||
})
|
||||
.success(function(response) {
|
||||
if (response.success) {
|
||||
$scope.user.api_key = response.data;
|
||||
$window.user.api_key = response.data;
|
||||
$scope.successFlash(response.message)
|
||||
}
|
||||
})
|
||||
.success(function(response) {
|
||||
if (response.success) {
|
||||
$scope.user.api_key = response.data;
|
||||
$window.user.api_key = response.data;
|
||||
$scope.successFlash(response.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
$scope.save_settings = function() {
|
||||
$http({
|
||||
|
@ -904,12 +941,12 @@ app.controller('SettingsCtrl', function($scope, $http, $window) {
|
|||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
})
|
||||
.success(function(data) {
|
||||
if (data.success) {
|
||||
$scope.successFlash(data.message)
|
||||
} else {
|
||||
$scope.errorFlash(data.message)
|
||||
}
|
||||
})
|
||||
.success(function(data) {
|
||||
if (data.success) {
|
||||
$scope.successFlash(data.message)
|
||||
} else {
|
||||
$scope.errorFlash(data.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
Campaigns
|
||||
</h1>
|
||||
<div class="row">
|
||||
<div ng-repeat="flash in flashes" style="text-align:center" class="alert alert-{{flash.type}}">
|
||||
<div ng-repeat="flash in flashes.main" style="text-align:center" class="alert alert-{{flash.type}}">
|
||||
<i class="fa {{flash.icon}}"></i> {{flash.message}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -43,7 +43,7 @@
|
|||
<div ng-show="campaigns.length" class="row">
|
||||
<table ng-table="mainTableParams" class="table table-hover table-striped table-bordered">
|
||||
<tbody>
|
||||
<tr ng-repeat="campaign in $data" class="editable-row">
|
||||
<tr ng-repeat="campaign in $data | orderBy: '-modified_date'" class="editable-row">
|
||||
<td data-title="'Created Date'" class="col-sm-1">{{campaign.created_date | date:'medium'}}</td>
|
||||
<td data-title="'Name'" class="col-sm-2">{{campaign.name}}
|
||||
<div class="btn-group" style="float: right;">
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
<div ng-show="pages.length" class="row">
|
||||
<table ng-table="mainTableParams" class="table table-hover table-striped table-bordered">
|
||||
<tbody>
|
||||
<tr ng-repeat="page in $data" class="editable-row">
|
||||
<tr ng-repeat="page in $data | orderBy: '-modified_date'" class="editable-row">
|
||||
<td data-title="'Name'" sortable="'name'" class="col-sm-2">{{page.name}}
|
||||
<div class="btn-group" style="float: right;">
|
||||
<button type="button" class="btn btn-primary dropdown-toggle edit-button" data-toggle="dropdown">
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
<h4 class="modal-title" id="campaignModalLabel">New Campaign</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div ng-repeat="flash in flashes.modal" style="text-align:center" class="alert alert-{{flash.type}}">
|
||||
<i class="fa {{flash.icon}}"></i> {{flash.message}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" class="form-control" ng-model="campaign.name" id="name" placeholder="Campaign name" autofocus>
|
||||
|
@ -54,7 +59,7 @@
|
|||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" ng-click="cancel()">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal" ng-click="saveCampaign(campaign)" type="submit">Launch Campaign</button>
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal" ng-click="ok(campaign)" type="submit">Launch Campaign</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
<h4 class="modal-title" ng-show="newGroup" id="groupModalLabel">New Group</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div ng-repeat="flash in flashes.modal" style="text-align:center" class="alert alert-{{flash.type}}">
|
||||
<i class="fa {{flash.icon}}"></i> {{flash.message}}
|
||||
</div>
|
||||
</div>
|
||||
<label class="control-label" for="name">Name:</label>
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" ng-model="group.name" placeholder="Group name" id="name" autofocus/>
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
<div ng-show="templates.length" class="row">
|
||||
<table ng-table="mainTableParams" class="table table-hover table-striped table-bordered">
|
||||
<tbody>
|
||||
<tr ng-repeat="template in $data" class="editable-row">
|
||||
<tr ng-repeat="template in $data | orderBy: '-modified_date'" class="editable-row">
|
||||
<td data-title="'Name'" sortable="'name'" class="col-sm-2">{{template.name}}
|
||||
<div class="btn-group" style="float: right;">
|
||||
<button type="button" class="btn btn-primary dropdown-toggle edit-button" data-toggle="dropdown">
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
Users & Groups
|
||||
</h1>
|
||||
<div class="row">
|
||||
<div ng-repeat="flash in flashes" style="text-align:center" class="alert alert-{{flash.type}}">
|
||||
<div ng-repeat="flash in flashes.main" style="text-align:center" class="alert alert-{{flash.type}}">
|
||||
<i class="fa {{flash.icon}}"></i> {{flash.message}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -43,7 +43,7 @@
|
|||
<div ng-show="groups.length" class="row">
|
||||
<table ng-table="mainTableParams" class="table table-hover table-striped table-bordered">
|
||||
<tbody>
|
||||
<tr ng-repeat="group in $data" class="editable-row">
|
||||
<tr ng-repeat="group in $data | orderBy: '-modified_date'" class="editable-row">
|
||||
<td data-title="'Name'" sortable="'name'" class="col-sm-1">{{group.name}}</td>
|
||||
<td data-title="'Members'" class="col-sm-2">
|
||||
<span ng-repeat="target in group.targets | cut:5 track by $index ">
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
|
||||
var Logger = log.New(os.Stdout, " ", log.Ldate|log.Ltime|log.Lshortfile)
|
||||
|
||||
// Worker is the background worker that handles watching for new campaigns and sending emails appropriately.
|
||||
type Worker struct {
|
||||
Queue chan *models.Campaign
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue