Added ng-table support (for future pagination, sorting, etc.)

Created services for campaigns/groups
Changed modals to be binded to the data. Will improve on this soon!
Added trailing slash to api endpoints (I hope to be able to remove this later)
pull/24/head
Jordan 2014-02-07 19:40:16 -06:00
parent f1aade0bfa
commit 6cbc47e80c
8 changed files with 103 additions and 58 deletions

View File

@ -32,10 +32,10 @@ func CreateRouter() *nosurf.CSRFHandler {
api := router.PathPrefix("/api").Subrouter() api := router.PathPrefix("/api").Subrouter()
api.HandleFunc("/", Use(API, mid.RequireLogin)) api.HandleFunc("/", Use(API, mid.RequireLogin))
api.HandleFunc("/reset", Use(API_Reset, mid.RequireLogin)) api.HandleFunc("/reset", Use(API_Reset, mid.RequireLogin))
api.HandleFunc("/campaigns", Use(API_Campaigns, mid.RequireAPIKey)) api.HandleFunc("/campaigns/", Use(API_Campaigns, mid.RequireAPIKey))
api.HandleFunc("/campaigns/{id:[0-9]+}", Use(API_Campaigns_Id, mid.RequireAPIKey)) api.HandleFunc("/campaigns/{id:[0-9]+}", Use(API_Campaigns_Id, mid.RequireAPIKey))
api.HandleFunc("/campaigns/id:[0-9]+}", Use(API_Campaigns_Id_Launch, mid.RequireAPIKey)) api.HandleFunc("/campaigns/id:[0-9]+}", Use(API_Campaigns_Id_Launch, mid.RequireAPIKey))
api.HandleFunc("/groups", Use(API_Groups, mid.RequireAPIKey)) api.HandleFunc("/groups/", Use(API_Groups, mid.RequireAPIKey))
api.HandleFunc("/groups/{id:[0-9]+}", Use(API_Groups_Id, mid.RequireAPIKey)) api.HandleFunc("/groups/{id:[0-9]+}", Use(API_Groups_Id, mid.RequireAPIKey))
// Setup static file serving // Setup static file serving

View File

@ -1,13 +0,0 @@
var gophishApp = angular.module('gophishApp', []);
gophishApp.controller('CampaignCtrl', function($scope, $http) {
$http.get('/api/campaigns?api_key=' + API_KEY).success(function(data) {
$scope.campaigns = data;
})
})
gophishApp.controller('GroupCtrl', function($scope, $http) {
$http.get('/api/groups?api_key=' + API_KEY).success(function(data) {
$scope.groups = data;
})
})

38
static/js/app/gophish.js Normal file
View File

@ -0,0 +1,38 @@
var app = angular.module('gophish', ['ngTable', 'ngResource']);
app.factory('CampaignService', function($resource) {
return $resource('/api/campaigns/:id?api_key=' + API_KEY);
});
app.factory('GroupService', function($resource) {
return $resource('/api/groups/:id?api_key=' + API_KEY);
});
app.controller('CampaignCtrl', function($scope, CampaignService) {
CampaignService.query(function(campaigns){
$scope.campaigns = campaigns
})
});
app.controller('GroupCtrl', function($scope, GroupService) {
GroupService.query(function(groups) {
$scope.groups = groups
})
$scope.editGroup = function(group) {
if (group === 'new') {
$scope.newGroup = true;
$scope.group = {
name: '',
targets: [{
email: ''
}],
id: 0
};
} else {
$scope.newGroup = false;
$scope.group = group;
}
};
})

13
static/js/ng-resource.min.js vendored Normal file
View File

@ -0,0 +1,13 @@
/*
AngularJS v1.2.11
(c) 2010-2014 Google, Inc. http://angularjs.org
License: MIT
*/
(function(H,a,A){'use strict';function D(p,g){g=g||{};a.forEach(g,function(a,c){delete g[c]});for(var c in p)p.hasOwnProperty(c)&&("$"!==c.charAt(0)&&"$"!==c.charAt(1))&&(g[c]=p[c]);return g}var v=a.$$minErr("$resource"),C=/^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;a.module("ngResource",["ng"]).factory("$resource",["$http","$q",function(p,g){function c(a,c){this.template=a;this.defaults=c||{};this.urlParams={}}function t(n,w,l){function r(h,d){var e={};d=x({},w,d);s(d,function(b,d){u(b)&&(b=b());var k;if(b&&
b.charAt&&"@"==b.charAt(0)){k=h;var a=b.substr(1);if(null==a||""===a||"hasOwnProperty"===a||!C.test("."+a))throw v("badmember",a);for(var a=a.split("."),f=0,c=a.length;f<c&&k!==A;f++){var g=a[f];k=null!==k?k[g]:A}}else k=b;e[d]=k});return e}function e(a){return a.resource}function f(a){D(a||{},this)}var F=new c(n);l=x({},B,l);s(l,function(h,d){var c=/^(POST|PUT|PATCH)$/i.test(h.method);f[d]=function(b,d,k,w){var q={},n,l,y;switch(arguments.length){case 4:y=w,l=k;case 3:case 2:if(u(d)){if(u(b)){l=
b;y=d;break}l=d;y=k}else{q=b;n=d;l=k;break}case 1:u(b)?l=b:c?n=b:q=b;break;case 0:break;default:throw v("badargs",arguments.length);}var t=this instanceof f,m=t?n:h.isArray?[]:new f(n),z={},B=h.interceptor&&h.interceptor.response||e,C=h.interceptor&&h.interceptor.responseError||A;s(h,function(a,b){"params"!=b&&("isArray"!=b&&"interceptor"!=b)&&(z[b]=G(a))});c&&(z.data=n);F.setUrlParams(z,x({},r(n,h.params||{}),q),h.url);q=p(z).then(function(b){var d=b.data,k=m.$promise;if(d){if(a.isArray(d)!==!!h.isArray)throw v("badcfg",
h.isArray?"array":"object",a.isArray(d)?"array":"object");h.isArray?(m.length=0,s(d,function(b){m.push(new f(b))})):(D(d,m),m.$promise=k)}m.$resolved=!0;b.resource=m;return b},function(b){m.$resolved=!0;(y||E)(b);return g.reject(b)});q=q.then(function(b){var a=B(b);(l||E)(a,b.headers);return a},C);return t?q:(m.$promise=q,m.$resolved=!1,m)};f.prototype["$"+d]=function(b,a,k){u(b)&&(k=a,a=b,b={});b=f[d].call(this,b,this,a,k);return b.$promise||b}});f.bind=function(a){return t(n,x({},w,a),l)};return f}
var B={get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}},E=a.noop,s=a.forEach,x=a.extend,G=a.copy,u=a.isFunction;c.prototype={setUrlParams:function(c,g,l){var r=this,e=l||r.template,f,p,h=r.urlParams={};s(e.split(/\W/),function(a){if("hasOwnProperty"===a)throw v("badname");!/^\d+$/.test(a)&&(a&&RegExp("(^|[^\\\\]):"+a+"(\\W|$)").test(e))&&(h[a]=!0)});e=e.replace(/\\:/g,":");g=g||{};s(r.urlParams,function(d,c){f=g.hasOwnProperty(c)?
g[c]:r.defaults[c];a.isDefined(f)&&null!==f?(p=encodeURIComponent(f).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"%20").replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+"),e=e.replace(RegExp(":"+c+"(\\W|$)","g"),function(a,c){return p+c})):e=e.replace(RegExp("(/?):"+c+"(\\W|$)","g"),function(a,c,d){return"/"==d.charAt(0)?d:c+d})});e=e.replace(/\/+$/,"")||"/";e=e.replace(/\/\.(?=\w+($|\?))/,".");c.url=e.replace(/\/\\\./,"/.");s(g,function(a,
e){r.urlParams[e]||(c.params=c.params||{},c.params[e]=a)})}};return t}])})(window,window.angular);
//# sourceMappingURL=angular-resource.min.js.map

4
static/js/ng-table.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{{% define "base" %}} {{% define "base" %}}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" ng-app="gophishApp"> <html lang="en" ng-app="gophish">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
@ -37,7 +37,9 @@
<script src="/js/jquery.js"></script> <script src="/js/jquery.js"></script>
<script src="/js/bootstrap.min.js"></script> <script src="/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script>
<script src="/js/app/controllers.js"></script> <script src="/js/ng-resource.min.js"></script>
<script src="/js/ng-table.min.js"></script>
<script src="/js/app/gophish.js"></script>
</body> </body>
</html> </html>

View File

@ -25,7 +25,7 @@
</div> </div>
&nbsp; &nbsp;
<div class="row"> <div class="row">
<table class="table table-hover table-striped table-bordered"> <table ng-table class="table table-hover table-striped table-bordered">
<thead> <thead>
<tr> <tr>
<th class="col-sm-1">Date</th> <th class="col-sm-1">Date</th>
@ -43,12 +43,12 @@
<span class="sr-only">Toggle Dropdown</span> <span class="sr-only">Toggle Dropdown</span>
</button> </button>
<ul class="dropdown-menu" style="left:auto; right:0;" role="menu"> <ul class="dropdown-menu" style="left:auto; right:0;" role="menu">
<li><a href="/settings">View</a> <li><a ng-href="/campaigns/{{campaign.id}}">View</a>
</li> </li>
<li><a href="/settings">Edit</a> <li><a href="/campaigns/{{campaign.id}}/relaunch">Relaunch</a>
</li> </li>
<li class="divider"></li> <li class="divider"></li>
<li><a href="/logout">Delete</a> <li><a href="/campaigns/{{campaign.id}}/delete">Delete</a>
</li> </li>
</ul> </ul>
</div> </div>

View File

@ -6,7 +6,7 @@
</h1> </h1>
</div> </div>
</div> </div>
<div class="container"> <div class="container" ng-controller="GroupCtrl">
<div class="col-md-3 sidebar"> <div class="col-md-3 sidebar">
<ul class="nav nav-pills nav-stacked"> <ul class="nav nav-pills nav-stacked">
<li><a href="/">Dashboard</a> <li><a href="/">Dashboard</a>
@ -19,13 +19,13 @@
</li> </li>
</ul> </ul>
</div> </div>
<div class="col-md-9" ng-controller="GroupCtrl"> <div class="col-md-9">
<div class="row"> <div class="row">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#newGroupModal"><i class="fa fa-plus"></i> New Group</button> <button type="button" class="btn btn-primary" ng-click="editGroup('new')" data-toggle="modal" data-target="#newGroupModal"><i class="fa fa-plus"></i> New Group</button>
</div> </div>
&nbsp; &nbsp;
<div class="row"> <div class="row">
<table class="table table-hover table-striped table-bordered"> <table ng-table class="table table-hover table-striped table-bordered">
<thead> <thead>
<tr> <tr>
<th class="col-sm-1">Name</th> <th class="col-sm-1">Name</th>
@ -46,12 +46,12 @@
<span class="sr-only">Toggle Dropdown</span> <span class="sr-only">Toggle Dropdown</span>
</button> </button>
<ul class="dropdown-menu" style="left:auto; right:0;" role="menu"> <ul class="dropdown-menu" style="left:auto; right:0;" role="menu">
<li><a href="/settings">View</a> <li><a ng-href="/groups/{{group.id}}">View</a>
</li> </li>
<li><a href="/settings">Edit</a> <li><a ng-click="editGroup(group)" data-toggle="modal" ng-href="#" data-target="#newGroupModal">Edit</a>
</li> </li>
<li class="divider"></li> <li class="divider"></li>
<li><a href="/logout">Delete</a> <li><a ng-href="/groups/{{group.id}}/delete">Delete</a>
</li> </li>
</ul> </ul>
</div> </div>
@ -62,37 +62,38 @@
</table> </table>
</div> </div>
</div> </div>
</div> <!-- New Campaign Modal -->
<!-- New Campaign Modal --> <div class="modal" id="newGroupModal" tabindex="-1" role="dialog" aria-labelledby="groupModalLabel" aria-hidden="true" ng-controller="GroupCtrl">
<div class="modal" id="newGroupModal" tabindex="-1" role="dialog" aria-labelledby="groupModalLabel" aria-hidden="true"> <div class="modal-dialog">
<div class="modal-dialog"> <div class="modal-content">
<div class="modal-content"> <div class="modal-header">
<div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button> <h4 class="modal-title" ng-hide="newGroup" id="groupModalLabel">Edit Group: {{group.name}}</h4>
<h4 class="modal-title" id="groupModalLabel">New Group</h4> <h4 class="modal-title" ng-show="newGroup" id="groupModalLabel">New Group</h4>
</div>
<form action="/">
<div class="modal-body">
<label class="control-label" for="name">Name:</label>
<div class="form-group">
<input type="text" class="form-control" placeholder="Group name" id="name" value={{group.name}} />
</div>
<div class="form-group">
<button class="btn btn-danger"><i class="fa fa-plus"></i> Bulk Import Users</button>
</div>
<label class="control-label" for="users">Users:</label>
<div class="input-group">
<input type="email" class="form-control" placeholder="test@example.com" id="users" />
<span class="input-group-btn">
<button class="btn btn-primary"><i class="fa fa-plus"></i> Add</button>
</span>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" type="submit">Save Group</button>
</div>
</form>
</div> </div>
<form action="/">
<div class="modal-body">
<label class="control-label" for="name">Name:</label>
<div class="form-group">
<input type="text" class="form-control" placeholder="Group name" id="name" />
</div>
<div class="form-group">
<button class="btn btn-danger"><i class="fa fa-plus"></i> Bulk Import Users</button>
</div>
<label class="control-label" for="users">Users:</label>
<div class="input-group">
<input type="email" class="form-control" placeholder="test@example.com" id="users" />
<span class="input-group-btn">
<button class="btn btn-primary"><i class="fa fa-plus"></i> Add</button>
</span>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" type="submit">Save Group</button>
</div>
</form>
</div> </div>
</div> </div>
</div> </div>