diff --git a/lemur/__init__.py b/lemur/__init__.py
index 32d65e06..5d91aacf 100644
--- a/lemur/__init__.py
+++ b/lemur/__init__.py
@@ -14,10 +14,8 @@ from lemur.users.views import mod as users_bp
from lemur.roles.views import mod as roles_bp
from lemur.auth.views import mod as auth_bp
from lemur.domains.views import mod as domains_bp
-from lemur.elbs.views import mod as elbs_bp
from lemur.destinations.views import mod as destinations_bp
from lemur.authorities.views import mod as authorities_bp
-from lemur.listeners.views import mod as listeners_bp
from lemur.certificates.views import mod as certificates_bp
from lemur.status.views import mod as status_bp
from lemur.plugins.views import mod as plugins_bp
@@ -30,10 +28,8 @@ LEMUR_BLUEPRINTS = (
roles_bp,
auth_bp,
domains_bp,
- elbs_bp,
destinations_bp,
authorities_bp,
- listeners_bp,
certificates_bp,
status_bp,
plugins_bp,
diff --git a/lemur/certificates/models.py b/lemur/certificates/models.py
index 012b5566..cbe37019 100644
--- a/lemur/certificates/models.py
+++ b/lemur/certificates/models.py
@@ -226,7 +226,6 @@ class Certificate(db.Model):
destinations = relationship("Destination", secondary=certificate_destination_associations, backref='certificate')
sources = relationship("Source", secondary=certificate_source_associations, backref='certificate')
domains = relationship("Domain", secondary=certificate_associations, backref="certificate")
- elb_listeners = relationship("Listener", lazy='dynamic', backref='certificate')
def __init__(self, body, private_key=None, chain=None):
self.body = body
diff --git a/lemur/manage.py b/lemur/manage.py
index df2dd120..877b34e1 100755
--- a/lemur/manage.py
+++ b/lemur/manage.py
@@ -30,8 +30,6 @@ from lemur.authorities.models import Authority # noqa
from lemur.certificates.models import Certificate # noqa
from lemur.destinations.models import Destination # noqa
from lemur.domains.models import Domain # noqa
-from lemur.elbs.models import ELB # noqa
-from lemur.listeners.models import Listener # noqa
from lemur.notifications.models import Notification # noqa
from lemur.sources.models import Source # noqa
diff --git a/lemur/models.py b/lemur/models.py
index 761c2da9..2ca4f6dd 100644
--- a/lemur/models.py
+++ b/lemur/models.py
@@ -25,7 +25,7 @@ certificate_destination_associations = db.Table('certificate_destination_associa
certificate_source_associations = db.Table('certificate_source_associations',
Column('source_id', Integer,
- ForeignKey('destinations.id', ondelete='cascade')),
+ ForeignKey('sources.id', ondelete='cascade')),
Column('certificate_id', Integer,
ForeignKey('certificates.id', ondelete='cascade'))
)
diff --git a/lemur/static/app/angular/notifications/notification/notification.js b/lemur/static/app/angular/notifications/notification/notification.js
index a8135c22..5df01e04 100644
--- a/lemur/static/app/angular/notifications/notification/notification.js
+++ b/lemur/static/app/angular/notifications/notification/notification.js
@@ -35,7 +35,7 @@ angular.module('lemur')
PluginService.getByType('notification').then(function (plugins) {
$scope.plugins = plugins;
_.each($scope.plugins, function (plugin) {
- if (plugin.slug == $scope.notification.pluginName) {
+ if (plugin.slug === $scope.notification.pluginName) {
plugin.pluginOptions = $scope.notification.notificationOptions;
$scope.notification.plugin = plugin;
};
diff --git a/lemur/static/app/angular/sources/services.js b/lemur/static/app/angular/sources/services.js
new file mode 100644
index 00000000..d29897d1
--- /dev/null
+++ b/lemur/static/app/angular/sources/services.js
@@ -0,0 +1,59 @@
+'use strict';
+angular.module('lemur')
+ .service('SourceApi', function (LemurRestangular) {
+ return LemurRestangular.all('sources');
+ })
+ .service('SourceService', function ($location, SourceApi, PluginService, toaster) {
+ var SourceService = this;
+ SourceService.findSourcesByName = function (filterValue) {
+ return SourceApi.getList({'filter[label]': filterValue})
+ .then(function (sources) {
+ return sources;
+ });
+ };
+
+ SourceService.create = function (source) {
+ return SourceApi.post(source).then(
+ function () {
+ toaster.pop({
+ type: 'success',
+ title: source.label,
+ body: 'Successfully created!'
+ });
+ $location.path('sources');
+ },
+ function (response) {
+ toaster.pop({
+ type: 'error',
+ title: source.label,
+ body: 'Was not created! ' + response.data.message
+ });
+ });
+ };
+
+ SourceService.update = function (source) {
+ return source.put().then(
+ function () {
+ toaster.pop({
+ type: 'success',
+ title: source.label,
+ body: 'Successfully updated!'
+ });
+ $location.path('sources');
+ },
+ function (response) {
+ toaster.pop({
+ type: 'error',
+ title: source.label,
+ body: 'Was not updated! ' + response.data.message
+ });
+ });
+ };
+
+ SourceService.getPlugin = function (source) {
+ return PluginService.getByName(source.pluginName).then(function (plugin) {
+ source.plugin = plugin;
+ });
+ };
+ return SourceService;
+ });
diff --git a/lemur/static/app/angular/sources/source/source.js b/lemur/static/app/angular/sources/source/source.js
new file mode 100644
index 00000000..7c75e3ad
--- /dev/null
+++ b/lemur/static/app/angular/sources/source/source.js
@@ -0,0 +1,47 @@
+'use strict';
+
+angular.module('lemur')
+
+ .controller('SourcesCreateController', function ($scope, $modalInstance, PluginService, SourceService, LemurRestangular){
+ $scope.source = LemurRestangular.restangularizeElement(null, {}, 'sources');
+
+ PluginService.getByType('source').then(function (plugins) {
+ $scope.plugins = plugins;
+ });
+
+ $scope.save = function (source) {
+ SourceService.create(source).then(function () {
+ $modalInstance.close();
+ });
+ };
+
+ $scope.cancel = function () {
+ $modalInstance.dismiss('cancel');
+ };
+ })
+
+ .controller('SourcesEditController', function ($scope, $modalInstance, SourceService, SourceApi, PluginService, editId) {
+ SourceApi.get(editId).then(function (source) {
+ $scope.source = source;
+ });
+
+ PluginService.getByType('source').then(function (plugins) {
+ $scope.plugins = plugins;
+ _.each($scope.plugins, function (plugin) {
+ if (plugin.slug === $scope.source.pluginName) {
+ plugin.pluginOptions = $scope.source.sourceOptions;
+ $scope.source.plugin = plugin;
+ }
+ });
+ });
+
+ $scope.save = function (source) {
+ SourceService.update(source).then(function () {
+ $modalInstance.close();
+ });
+ };
+
+ $scope.cancel = function () {
+ $modalInstance.dismiss('cancel');
+ };
+ });
diff --git a/lemur/static/app/angular/sources/source/source.tpl.html b/lemur/static/app/angular/sources/source/source.tpl.html
new file mode 100644
index 00000000..39e8c277
--- /dev/null
+++ b/lemur/static/app/angular/sources/source/source.tpl.html
@@ -0,0 +1,56 @@
+
+
diff --git a/lemur/static/app/angular/sources/view/view.js b/lemur/static/app/angular/sources/view/view.js
new file mode 100644
index 00000000..031ea8d7
--- /dev/null
+++ b/lemur/static/app/angular/sources/view/view.js
@@ -0,0 +1,88 @@
+'use strict';
+
+angular.module('lemur')
+
+ .config(function config($routeProvider) {
+ $routeProvider.when('/sources', {
+ templateUrl: '/angular/sources/view/view.tpl.html',
+ controller: 'SourcesViewController'
+ });
+ })
+
+ .controller('SourcesViewController', function ($scope, $modal, SourceApi, SourceService, ngTableParams, toaster) {
+ $scope.filter = {};
+ $scope.sourcesTable = new ngTableParams({
+ page: 1, // show first page
+ count: 10, // count per page
+ sorting: {
+ id: 'desc' // initial sorting
+ },
+ filter: $scope.filter
+ }, {
+ total: 0, // length of data
+ getData: function ($defer, params) {
+ SourceApi.getList(params.url()).then(
+ function (data) {
+ _.each(data, function (source) {
+ SourceService.getPlugin(source);
+ });
+ params.total(data.total);
+ $defer.resolve(data);
+ }
+ );
+ }
+ });
+
+ $scope.remove = function (source) {
+ source.remove().then(
+ function () {
+ $scope.sourcesTable.reload();
+ },
+ function (response) {
+ toaster.pop({
+ type: 'error',
+ title: 'Opps',
+ body: 'I see what you did there' + response.data.message
+ });
+ }
+ );
+ };
+
+ $scope.edit = function (sourceId) {
+ var modalInstance = $modal.open({
+ animation: true,
+ templateUrl: '/angular/sources/source/source.tpl.html',
+ controller: 'SourcesEditController',
+ size: 'lg',
+ resolve: {
+ editId: function () {
+ return sourceId;
+ }
+ }
+ });
+
+ modalInstance.result.then(function () {
+ $scope.sourcesTable.reload();
+ });
+
+ };
+
+ $scope.create = function () {
+ var modalInstance = $modal.open({
+ animation: true,
+ controller: 'SourcesCreateController',
+ templateUrl: '/angular/sources/source/source.tpl.html',
+ size: 'lg'
+ });
+
+ modalInstance.result.then(function () {
+ $scope.sourcesTable.reload();
+ });
+
+ };
+
+ $scope.toggleFilter = function (params) {
+ params.settings().$scope.show_filter = !params.settings().$scope.show_filter;
+ };
+
+ });
diff --git a/lemur/static/app/angular/sources/view/view.tpl.html b/lemur/static/app/angular/sources/view/view.tpl.html
new file mode 100644
index 00000000..9655a7e2
--- /dev/null
+++ b/lemur/static/app/angular/sources/view/view.tpl.html
@@ -0,0 +1,47 @@
+
+
+
Sources
+ where are you from?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - {{ source.label }}
+ - {{ source.description }}
+
+ |
+
+
+ - {{ source.plugin.title }}
+ - {{ source.plugin.description }}
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
diff --git a/lemur/tests/test_sources.py b/lemur/tests/test_sources.py
new file mode 100644
index 00000000..8704ca23
--- /dev/null
+++ b/lemur/tests/test_sources.py
@@ -0,0 +1,134 @@
+from lemur.sources.service import * # noqa
+from lemur.sources.views import * # noqa
+
+from json import dumps
+
+
+def test_crud(session):
+ source = create('testdest', 'aws-source', {}, description='source1')
+ assert source.id > 0
+
+ source = update(source.id, 'testdest2', {}, 'source2')
+ assert source.label == 'testdest2'
+
+ assert len(get_all()) == 1
+
+ delete(1)
+ assert len(get_all()) == 0
+
+
+def test_source_get(client):
+ assert client.get(api.url_for(Sources, source_id=1)).status_code == 401
+
+
+def test_source_post(client):
+ assert client.post(api.url_for(Sources, source_id=1), data={}).status_code == 405
+
+
+def test_source_put(client):
+ assert client.put(api.url_for(Sources, source_id=1), data={}).status_code == 401
+
+
+def test_source_delete(client):
+ assert client.delete(api.url_for(Sources, source_id=1)).status_code == 401
+
+
+def test_source_patch(client):
+ assert client.patch(api.url_for(Sources, source_id=1), data={}).status_code == 405
+
+
+VALID_USER_HEADER_TOKEN = {
+ 'Authorization': 'Basic ' + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MzUyMzMzNjksInN1YiI6MSwiZXhwIjoxNTIxNTQ2OTY5fQ.1qCi0Ip7mzKbjNh0tVd3_eJOrae3rNa_9MCVdA4WtQI'}
+
+
+def test_auth_source_get(client):
+ assert client.get(api.url_for(Sources, source_id=1), headers=VALID_USER_HEADER_TOKEN).status_code == 200
+
+
+def test_auth_source_post_(client):
+ assert client.post(api.url_for(Sources, source_id=1), data={}, headers=VALID_USER_HEADER_TOKEN).status_code == 405
+
+
+def test_auth_source_put(client):
+ assert client.put(api.url_for(Sources, source_id=1), data={}, headers=VALID_USER_HEADER_TOKEN).status_code == 403
+
+
+def test_auth_source_delete(client):
+ assert client.delete(api.url_for(Sources, source_id=1), headers=VALID_USER_HEADER_TOKEN).status_code == 403
+
+
+def test_auth_source_patch(client):
+ assert client.patch(api.url_for(Sources, source_id=1), data={}, headers=VALID_USER_HEADER_TOKEN).status_code == 405
+
+
+VALID_ADMIN_HEADER_TOKEN = {
+ 'Authorization': 'Basic ' + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MzUyNTAyMTgsInN1YiI6MiwiZXhwIjoxNTIxNTYzODE4fQ.6mbq4-Ro6K5MmuNiTJBB153RDhlM5LGJBjI7GBKkfqA'}
+
+
+def test_admin_source_get(client):
+ assert client.get(api.url_for(Sources, source_id=1), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 200
+
+
+def test_admin_source_post(client):
+ assert client.post(api.url_for(Sources, source_id=1), data={}, headers=VALID_ADMIN_HEADER_TOKEN).status_code == 405
+
+
+def test_admin_source_put(client):
+ assert client.put(api.url_for(Sources, source_id=1), data={}, headers=VALID_ADMIN_HEADER_TOKEN).status_code == 400
+
+
+def test_admin_source_delete(client):
+ assert client.delete(api.url_for(Sources, source_id=1), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 200
+
+
+def test_admin_source_patch(client):
+ assert client.patch(api.url_for(Sources, source_id=1), data={}, headers=VALID_ADMIN_HEADER_TOKEN).status_code == 405
+
+
+def test_sources_get(client):
+ assert client.get(api.url_for(SourcesList)).status_code == 401
+
+
+def test_sources_post(client):
+ assert client.post(api.url_for(SourcesList), data={}).status_code == 401
+
+
+def test_sources_put(client):
+ assert client.put(api.url_for(SourcesList), data={}).status_code == 405
+
+
+def test_sources_delete(client):
+ assert client.delete(api.url_for(SourcesList)).status_code == 405
+
+
+def test_sources_patch(client):
+ assert client.patch(api.url_for(SourcesList), data={}).status_code == 405
+
+
+def test_auth_sources_get(client):
+ assert client.get(api.url_for(SourcesList), headers=VALID_USER_HEADER_TOKEN).status_code == 200
+
+
+def test_auth_sources_post(client):
+ assert client.post(api.url_for(SourcesList), data={}, headers=VALID_USER_HEADER_TOKEN).status_code == 403
+
+
+def test_admin_sources_get(client):
+ resp = client.get(api.url_for(SourcesList), headers=VALID_ADMIN_HEADER_TOKEN)
+ assert resp.status_code == 200
+ assert resp.json == {'items': [], 'total': 0}
+
+
+def test_admin_sources_crud(client):
+ assert client.post(api.url_for(SourcesList), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 400
+ data = {'plugin': {'slug': 'aws-source', 'pluginOptions': {}}, 'label': 'test', 'description': 'test'}
+ resp = client.post(api.url_for(SourcesList), data=dumps(data), content_type='application/json', headers=VALID_ADMIN_HEADER_TOKEN)
+ assert resp.status_code == 200
+ assert client.get(api.url_for(Sources, source_id=resp.json['id']), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 200
+ resp = client.get(api.url_for(SourcesList), headers=VALID_ADMIN_HEADER_TOKEN)
+ assert resp.status_code == 200
+ assert resp.json['items'][0]['description'] == 'test'
+ assert client.delete(api.url_for(Sources, source_id=2), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 200
+ resp = client.get(api.url_for(SourcesList), headers=VALID_ADMIN_HEADER_TOKEN)
+ assert resp.status_code == 200
+ assert resp.json == {'items': [], 'total': 0}