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}