Various bug fixes. (#314)

This commit is contained in:
kevgliss 2016-05-12 12:38:44 -07:00
parent 9022059dc6
commit a0c8765588
32 changed files with 329 additions and 329 deletions

View File

@ -11,7 +11,7 @@ from marshmallow import fields, validates_schema
from marshmallow import validate from marshmallow import validate
from marshmallow.exceptions import ValidationError from marshmallow.exceptions import ValidationError
from lemur.schemas import PluginSchema, ExtensionSchema, AssociatedAuthoritySchema, AssociatedRoleSchema from lemur.schemas import PluginInputSchema, ExtensionSchema, AssociatedAuthoritySchema, AssociatedRoleSchema
from lemur.common.schema import LemurInputSchema, LemurOutputSchema from lemur.common.schema import LemurInputSchema, LemurOutputSchema
from lemur.common import validators from lemur.common import validators
@ -33,7 +33,7 @@ class AuthorityInputSchema(LemurInputSchema):
country = fields.String(missing=lambda: current_app.config.get('LEMUR_DEFAULT_COUNTRY')) country = fields.String(missing=lambda: current_app.config.get('LEMUR_DEFAULT_COUNTRY'))
state = fields.String(missing=lambda: current_app.config.get('LEMUR_DEFAULT_STATE')) state = fields.String(missing=lambda: current_app.config.get('LEMUR_DEFAULT_STATE'))
plugin = fields.Nested(PluginSchema) plugin = fields.Nested(PluginInputSchema)
# signing related options # signing related options
type = fields.String(validate=validate.OneOf(['root', 'subca']), missing='root') type = fields.String(validate=validate.OneOf(['root', 'subca']), missing='root')

View File

@ -11,7 +11,7 @@ from marshmallow import fields, validates_schema
from marshmallow.exceptions import ValidationError from marshmallow.exceptions import ValidationError
from lemur.schemas import AssociatedAuthoritySchema, AssociatedDestinationSchema, AssociatedCertificateSchema, \ from lemur.schemas import AssociatedAuthoritySchema, AssociatedDestinationSchema, AssociatedCertificateSchema, \
AssociatedNotificationSchema, PluginSchema, ExtensionSchema AssociatedNotificationSchema, PluginInputSchema, ExtensionSchema
from lemur.common.schema import LemurInputSchema, LemurOutputSchema from lemur.common.schema import LemurInputSchema, LemurOutputSchema
from lemur.common import validators from lemur.common import validators
@ -89,7 +89,7 @@ class CertificateUploadInputSchema(LemurInputSchema):
class CertificateExportInputSchema(LemurInputSchema): class CertificateExportInputSchema(LemurInputSchema):
export = fields.Nested(PluginSchema) export = fields.Nested(PluginInputSchema)
certificate_input_schema = CertificateInputSchema() certificate_input_schema = CertificateInputSchema()

View File

@ -6,22 +6,31 @@
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com> .. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
""" """
from marshmallow import fields from marshmallow import fields, post_dump
from lemur.common.schema import LemurInputSchema, LemurOutputSchema from lemur.common.schema import LemurInputSchema, LemurOutputSchema
from lemur.schemas import PluginSchema from lemur.schemas import PluginInputSchema, PluginOutputSchema
class DestinationInputSchema(LemurInputSchema): class DestinationInputSchema(LemurInputSchema):
id = fields.Integer()
label = fields.String(required=True) label = fields.String(required=True)
options = fields.Dict(required=True) description = fields.String(required=True)
description = fields.String() active = fields.Boolean()
plugin = fields.Nested(PluginSchema, required=True) plugin = fields.Nested(PluginInputSchema, required=True)
class DestinationOutputSchema(LemurOutputSchema): class DestinationOutputSchema(LemurOutputSchema):
id = fields.Integer()
label = fields.String() label = fields.String()
options = fields.Dict(dump_to='destination_options')
description = fields.String() description = fields.String()
active = fields.Boolean()
plugin = fields.Nested(PluginOutputSchema)
options = fields.List(fields.Dict())
@post_dump
def fill_object(self, data):
data['plugin']['pluginOptions'] = data['options']
return data
destination_input_schema = DestinationInputSchema() destination_input_schema = DestinationInputSchema()

View File

@ -148,7 +148,7 @@ class DestinationsList(AuthenticatedResource):
:reqheader Authorization: OAuth token to authenticate :reqheader Authorization: OAuth token to authenticate
:statuscode 200: no error :statuscode 200: no error
""" """
return service.create(data['label'], data['plugin']['slug'], data['plugin']['pluginOptions'], data['description']) return service.create(data['label'], data['plugin']['slug'], data['plugin']['plugin_options'], data['description'])
class Destinations(AuthenticatedResource): class Destinations(AuthenticatedResource):
@ -265,7 +265,7 @@ class Destinations(AuthenticatedResource):
:reqheader Authorization: OAuth token to authenticate :reqheader Authorization: OAuth token to authenticate
:statuscode 200: no error :statuscode 200: no error
""" """
return service.update(destination_id, data['label'], data['plugin']['pluginOptions'], data['description']) return service.update(destination_id, data['label'], data['plugin']['plugin_options'], data['description'])
@admin_permission.require(http_exception=403) @admin_permission.require(http_exception=403)
def delete(self, destination_id): def delete(self, destination_id):

View File

@ -5,28 +5,33 @@
:license: Apache, see LICENSE for more details. :license: Apache, see LICENSE for more details.
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com> .. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
""" """
from marshmallow import fields from marshmallow import fields, post_dump
from lemur.common.schema import LemurInputSchema, LemurOutputSchema from lemur.common.schema import LemurInputSchema, LemurOutputSchema
from lemur.schemas import PluginSchema, AssociatedCertificateSchema from lemur.schemas import PluginInputSchema, PluginOutputSchema, AssociatedCertificateSchema
class NotificationInputSchema(LemurInputSchema): class NotificationInputSchema(LemurInputSchema):
id = fields.Integer()
label = fields.String(required=True) label = fields.String(required=True)
options = fields.Dict(required=True)
description = fields.String() description = fields.String()
active = fields.Boolean() active = fields.Boolean()
plugin = fields.Nested(PluginSchema, required=True) plugin = fields.Nested(PluginInputSchema, required=True)
certificates = fields.Nested(AssociatedCertificateSchema, many=True) certificates = fields.Nested(AssociatedCertificateSchema, many=True, missing=[])
class NotificationOutputSchema(LemurOutputSchema): class NotificationOutputSchema(LemurOutputSchema):
id = fields.Integer() id = fields.Integer()
label = fields.String() label = fields.String()
description = fields.String() description = fields.String()
options = fields.Dict(dump_to='notification_options')
active = fields.Boolean() active = fields.Boolean()
plugin = fields.Nested(PluginSchema) options = fields.List(fields.Dict())
certificates = fields.Nested(AssociatedCertificateSchema, many=True) plugin = fields.Nested(PluginOutputSchema)
certificates = fields.Nested(AssociatedCertificateSchema, many=True, missing=[])
@post_dump
def fill_object(self, data):
data['plugin']['pluginOptions'] = data['options']
return data
notification_input_schema = NotificationInputSchema() notification_input_schema = NotificationInputSchema()

View File

@ -217,7 +217,7 @@ class NotificationsList(AuthenticatedResource):
return service.create( return service.create(
data['label'], data['label'],
data['plugin']['slug'], data['plugin']['slug'],
data['plugin']['pluginOptions'], data['plugin']['plugin_options'],
data['description'], data['description'],
data['certificates'] data['certificates']
) )

View File

@ -45,7 +45,7 @@ class ExpirationNotificationPlugin(NotificationPlugin):
] ]
@property @property
def options(self): def plugin_options(self):
return list(self.default_options) + self.additional_options return list(self.default_options) + self.additional_options
def send(self): def send(self):

View File

@ -11,6 +11,7 @@ from lemur.schemas import AssociatedUserSchema, AssociatedAuthoritySchema
class RoleInputSchema(LemurInputSchema): class RoleInputSchema(LemurInputSchema):
id = fields.Integer()
name = fields.String(required=True) name = fields.String(required=True)
username = fields.String() username = fields.String()
password = fields.String() password = fields.String()
@ -20,6 +21,7 @@ class RoleInputSchema(LemurInputSchema):
class RoleOutputSchema(LemurOutputSchema): class RoleOutputSchema(LemurOutputSchema):
id = fields.Integer()
name = fields.String() name = fields.String()
username = fields.String() username = fields.String()
password = fields.String() password = fields.String()

View File

@ -113,4 +113,4 @@ def render(args):
terms = filt.split(';') terms = filt.split(';')
query = database.filter(query, Role, terms) query = database.filter(query, Role, terms)
database.sort_and_page(query, Role, args) return database.sort_and_page(query, Role, args)

View File

@ -17,7 +17,7 @@ from lemur.notifications.models import Notification
from lemur.users.models import User from lemur.users.models import User
from lemur.common import validators from lemur.common import validators
from lemur.common.schema import LemurSchema, LemurInputSchema from lemur.common.schema import LemurSchema, LemurInputSchema, LemurOutputSchema
from lemur.plugins import plugins from lemur.plugins import plugins
@ -96,18 +96,26 @@ class AssociatedUserSchema(LemurInputSchema):
return User.query.filter(User.id == data['id']).one() return User.query.filter(User.id == data['id']).one()
class PluginSchema(LemurInputSchema): class PluginInputSchema(LemurInputSchema):
plugin_options = fields.Dict() plugin_options = fields.List(fields.Dict())
slug = fields.String() slug = fields.String(required=True)
title = fields.String() title = fields.String()
description = fields.String() description = fields.String()
@post_load @post_load
def get_object(self, data, many=False): def get_object(self, data, many=False):
if many: data['plugin_object'] = plugins.get(data['slug'])
return [plugins.get(plugin['slug']) for plugin in data] return data
else:
return plugins.get(data['slug'])
class PluginOutputSchema(LemurOutputSchema):
id = fields.Integer()
label = fields.String()
description = fields.String()
active = fields.Boolean()
plugin_options = fields.List(fields.Dict())
slug = fields.String()
title = fields.String()
class BaseExtensionSchema(LemurSchema): class BaseExtensionSchema(LemurSchema):

View File

@ -5,27 +5,32 @@
:license: Apache, see LICENSE for more details. :license: Apache, see LICENSE for more details.
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com> .. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
""" """
from marshmallow import fields from marshmallow import fields, post_dump
from lemur.schemas import PluginSchema from lemur.schemas import PluginInputSchema, PluginOutputSchema
from lemur.common.schema import LemurInputSchema, LemurOutputSchema from lemur.common.schema import LemurInputSchema, LemurOutputSchema
class SourceInputSchema(LemurInputSchema): class SourceInputSchema(LemurInputSchema):
id = fields.Integer()
label = fields.String(required=True) label = fields.String(required=True)
options = fields.Dict(load_from='sourceOptions', required=True)
description = fields.String() description = fields.String()
plugin = fields.Nested(PluginSchema) plugin = fields.Nested(PluginInputSchema)
active = fields.Boolean() active = fields.Boolean()
class SourceOutputSchema(LemurOutputSchema): class SourceOutputSchema(LemurOutputSchema):
id = fields.Integer()
label = fields.String() label = fields.String()
options = fields.Dict(dump_to='sourceOptions')
description = fields.String() description = fields.String()
plugin = fields.Nested(PluginSchema) plugin = fields.Nested(PluginOutputSchema)
options = fields.List(fields.Dict())
fields.Boolean() fields.Boolean()
@post_dump
def fill_object(self, data):
data['plugin']['pluginOptions'] = data['options']
return data
source_input_schema = SourceInputSchema() source_input_schema = SourceInputSchema()
sources_output_schema = SourceOutputSchema(many=True) sources_output_schema = SourceOutputSchema(many=True)

View File

@ -151,7 +151,7 @@ class SourcesList(AuthenticatedResource):
:reqheader Authorization: OAuth token to authenticate :reqheader Authorization: OAuth token to authenticate
:statuscode 200: no error :statuscode 200: no error
""" """
return service.create(data['label'], data['plugin']['slug'], data['plugin']['pluginOptions'], data['description']) return service.create(data['label'], data['plugin']['slug'], data['plugin']['plugin_options'], data['description'])
class Sources(AuthenticatedResource): class Sources(AuthenticatedResource):
@ -271,7 +271,7 @@ class Sources(AuthenticatedResource):
:reqheader Authorization: OAuth token to authenticate :reqheader Authorization: OAuth token to authenticate
:statuscode 200: no error :statuscode 200: no error
""" """
return service.update(source_id, data['label'], data['plugin']['pluginOptions'], data['description']) return service.update(source_id, data['label'], data['plugin']['plugin_options'], data['description'])
@admin_permission.require(http_exception=403) @admin_permission.require(http_exception=403)
def delete(self, source_id): def delete(self, source_id):

View File

@ -2,7 +2,7 @@
angular.module('lemur') angular.module('lemur')
.controller('DestinationsCreateController', function ($scope, $modalInstance, PluginService, DestinationService, LemurRestangular){ .controller('DestinationsCreateController', function ($scope, $uibModalInstance, PluginService, DestinationService, LemurRestangular, toaster){
$scope.destination = LemurRestangular.restangularizeElement(null, {}, 'destinations'); $scope.destination = LemurRestangular.restangularizeElement(null, {}, 'destinations');
PluginService.getByType('destination').then(function (plugins) { PluginService.getByType('destination').then(function (plugins) {
@ -10,24 +10,38 @@ angular.module('lemur')
}); });
$scope.save = function (destination) { $scope.save = function (destination) {
DestinationService.create(destination).then(function () { DestinationService.create(destination).then(
$modalInstance.close(); function () {
toaster.pop({
type: 'success',
title: destination.label,
body: 'Successfully Created!'
});
$uibModalInstance.close();
}, function (response) {
toaster.pop({
type: 'error',
title: destination.label,
body: 'lemur-bad-request',
bodyOutputType: 'directive',
directiveData: response.data,
timeout: 100000
});
}); });
}; };
$scope.cancel = function () { $scope.cancel = function () {
$modalInstance.dismiss('cancel'); $uibModalInstance.dismiss('cancel');
}; };
}) })
.controller('DestinationsEditController', function ($scope, $modalInstance, DestinationService, DestinationApi, PluginService, editId) { .controller('DestinationsEditController', function ($scope, $uibModalInstance, DestinationService, DestinationApi, PluginService, toaster, editId) {
DestinationApi.get(editId).then(function (destination) { DestinationApi.get(editId).then(function (destination) {
$scope.destination = destination; $scope.destination = destination;
PluginService.getByType('destination').then(function (plugins) { PluginService.getByType('destination').then(function (plugins) {
$scope.plugins = plugins; $scope.plugins = plugins;
_.each($scope.plugins, function (plugin) { _.each($scope.plugins, function (plugin) {
if (plugin.slug === $scope.destination.pluginName) { if (plugin.slug === $scope.destination.pluginName) {
plugin.pluginOptions = $scope.destination.destinationOptions;
$scope.destination.plugin = plugin; $scope.destination.plugin = plugin;
} }
}); });
@ -35,12 +49,27 @@ angular.module('lemur')
}); });
$scope.save = function (destination) { $scope.save = function (destination) {
DestinationService.update(destination).then(function () { DestinationService.update(destination).then(
$modalInstance.close(); function () {
toaster.pop({
type: 'success',
title: destination.label,
body: 'Successfully Updated!'
});
$uibModalInstance.close();
}, function (response) {
toaster.pop({
type: 'error',
title: destination.label,
body: 'lemur-bad-request',
bodyOutputType: 'directive',
directiveData: response.data,
timeout: 100000
});
}); });
}; };
$scope.cancel = function () { $scope.cancel = function () {
$modalInstance.dismiss('cancel'); $uibModalInstance.dismiss('cancel');
}; };
}); });

View File

@ -3,7 +3,7 @@ angular.module('lemur')
.service('DestinationApi', function (LemurRestangular) { .service('DestinationApi', function (LemurRestangular) {
return LemurRestangular.all('destinations'); return LemurRestangular.all('destinations');
}) })
.service('DestinationService', function ($location, DestinationApi, PluginService, toaster) { .service('DestinationService', function ($location, DestinationApi, PluginService) {
var DestinationService = this; var DestinationService = this;
DestinationService.findDestinationsByName = function (filterValue) { DestinationService.findDestinationsByName = function (filterValue) {
return DestinationApi.getList({'filter[label]': filterValue}) return DestinationApi.getList({'filter[label]': filterValue})
@ -13,41 +13,11 @@ angular.module('lemur')
}; };
DestinationService.create = function (destination) { DestinationService.create = function (destination) {
return DestinationApi.post(destination).then( return DestinationApi.post(destination);
function () {
toaster.pop({
type: 'success',
title: destination.label,
body: 'Successfully created!'
});
$location.path('destinations');
},
function (response) {
toaster.pop({
type: 'error',
title: destination.label,
body: 'Was not created! ' + response.data.message
});
});
}; };
DestinationService.update = function (destination) { DestinationService.update = function (destination) {
return destination.put().then( return destination.put();
function () {
toaster.pop({
type: 'success',
title: destination.label,
body: 'Successfully updated!'
});
$location.path('destinations');
},
function (response) {
toaster.pop({
type: 'error',
title: destination.label,
body: 'Was not updated! ' + response.data.message
});
});
}; };
DestinationService.getPlugin = function (destination) { DestinationService.getPlugin = function (destination) {

View File

@ -10,7 +10,7 @@ angular.module('lemur')
}); });
}) })
.controller('DestinationsViewController', function ($scope, $modal, DestinationApi, DestinationService, ngTableParams, toaster) { .controller('DestinationsViewController', function ($scope, $uibModal, DestinationApi, DestinationService, ngTableParams, toaster) {
$scope.filter = {}; $scope.filter = {};
$scope.destinationsTable = new ngTableParams({ $scope.destinationsTable = new ngTableParams({
page: 1, // show first page page: 1, // show first page
@ -24,9 +24,6 @@ angular.module('lemur')
getData: function ($defer, params) { getData: function ($defer, params) {
DestinationApi.getList(params.url()).then( DestinationApi.getList(params.url()).then(
function (data) { function (data) {
_.each(data, function (destination) {
DestinationService.getPlugin(destination);
});
params.total(data.total); params.total(data.total);
$defer.resolve(data); $defer.resolve(data);
} }
@ -50,7 +47,7 @@ angular.module('lemur')
}; };
$scope.edit = function (destinationId) { $scope.edit = function (destinationId) {
var modalInstance = $modal.open({ var uibModalInstance = $uibModal.open({
animation: true, animation: true,
templateUrl: '/angular/destinations/destination/destination.tpl.html', templateUrl: '/angular/destinations/destination/destination.tpl.html',
controller: 'DestinationsEditController', controller: 'DestinationsEditController',
@ -63,14 +60,14 @@ angular.module('lemur')
} }
}); });
modalInstance.result.then(function () { uibModalInstance.result.then(function () {
$scope.destinationsTable.reload(); $scope.destinationsTable.reload();
}); });
}; };
$scope.create = function () { $scope.create = function () {
var modalInstance = $modal.open({ var uibModalInstance = $uibModal.open({
animation: true, animation: true,
controller: 'DestinationsCreateController', controller: 'DestinationsCreateController',
templateUrl: '/angular/destinations/destination/destination.tpl.html', templateUrl: '/angular/destinations/destination/destination.tpl.html',
@ -78,7 +75,7 @@ angular.module('lemur')
backdrop: 'static' backdrop: 'static'
}); });
modalInstance.result.then(function () { uibModalInstance.result.then(function () {
$scope.destinationsTable.reload(); $scope.destinationsTable.reload();
}); });

View File

@ -2,12 +2,27 @@
angular.module('lemur') angular.module('lemur')
.controller('DomainsCreateController', function ($scope, $uibModalInstance, PluginService, DomainService, LemurRestangular){ .controller('DomainsCreateController', function ($scope, $uibModalInstance, PluginService, DomainService, LemurRestangular, toaster){
$scope.domain = LemurRestangular.restangularizeElement(null, {}, 'domains'); $scope.domain = LemurRestangular.restangularizeElement(null, {}, 'domains');
$scope.save = function (domain) { $scope.save = function (domain) {
DomainService.create(domain).then(function () { DomainService.create(domain).then(
function () {
toaster.pop({
type: 'success',
title: domain,
body: 'Successfully Created!'
});
$uibModalInstance.close(); $uibModalInstance.close();
}, function (response) {
toaster.pop({
type: 'error',
title: domain,
body: 'lemur-bad-request',
bodyOutputType: 'directive',
directiveData: response.data,
timeout: 100000
});
}); });
}; };
@ -16,14 +31,29 @@ angular.module('lemur')
}; };
}) })
.controller('DomainsEditController', function ($scope, $uibModalInstance, DomainService, DomainApi, editId) { .controller('DomainsEditController', function ($scope, $uibModalInstance, DomainService, DomainApi, toaster, editId) {
DomainApi.get(editId).then(function (domain) { DomainApi.get(editId).then(function (domain) {
$scope.domain = domain; $scope.domain = domain;
}); });
$scope.save = function (domain) { $scope.save = function (domain) {
DomainService.update(domain).then(function () { DomainService.update(domain).then(
function () {
toaster.pop({
type: 'success',
title: domain,
body: 'Successfully Created!'
});
$uibModalInstance.close(); $uibModalInstance.close();
}, function (response) {
toaster.pop({
type: 'error',
title: domain,
body: 'lemur-bad-request',
bodyOutputType: 'directive',
directiveData: response.data,
timeout: 100000
});
}); });
}; };

View File

@ -2,7 +2,7 @@
angular.module('lemur') angular.module('lemur')
.controller('NotificationsCreateController', function ($scope, $uibModalInstance, PluginService, NotificationService, CertificateService, LemurRestangular){ .controller('NotificationsCreateController', function ($scope, $uibModalInstance, PluginService, NotificationService, CertificateService, LemurRestangular, toaster){
$scope.notification = LemurRestangular.restangularizeElement(null, {}, 'notifications'); $scope.notification = LemurRestangular.restangularizeElement(null, {}, 'notifications');
PluginService.getByType('notification').then(function (plugins) { PluginService.getByType('notification').then(function (plugins) {
@ -11,12 +11,22 @@ angular.module('lemur')
$scope.save = function (notification) { $scope.save = function (notification) {
NotificationService.create(notification).then( NotificationService.create(notification).then(
function () { function () {
toaster.pop({
type: 'success',
title: notification.label,
body: 'Successfully Created!'
});
$uibModalInstance.close(); $uibModalInstance.close();
}, }, function (response) {
function () { toaster.pop({
type: 'error',
} title: notification.label,
); body: 'lemur-bad-request',
bodyOutputType: 'directive',
directiveData: response.data,
timeout: 100000
});
});
}; };
$scope.cancel = function () { $scope.cancel = function () {
@ -26,7 +36,7 @@ angular.module('lemur')
$scope.certificateService = CertificateService; $scope.certificateService = CertificateService;
}) })
.controller('NotificationsEditController', function ($scope, $uibModalInstance, NotificationService, NotificationApi, PluginService, CertificateService, editId) { .controller('NotificationsEditController', function ($scope, $uibModalInstance, NotificationService, NotificationApi, PluginService, CertificateService, toaster, editId) {
NotificationApi.get(editId).then(function (notification) { NotificationApi.get(editId).then(function (notification) {
$scope.notification = notification; $scope.notification = notification;
PluginService.getByType('notification').then(function (plugins) { PluginService.getByType('notification').then(function (plugins) {
@ -52,8 +62,23 @@ angular.module('lemur')
}); });
$scope.save = function (notification) { $scope.save = function (notification) {
NotificationService.update(notification).then(function () { NotificationService.update(notification).then(
function () {
toaster.pop({
type: 'success',
title: notification.label,
body: 'Successfully Created!'
});
$uibModalInstance.close(); $uibModalInstance.close();
}, function (response) {
toaster.pop({
type: 'error',
title: notification.label,
body: 'lemur-bad-request',
bodyOutputType: 'directive',
directiveData: response.data,
timeout: 100000
});
}); });
}; };

View File

@ -17,7 +17,7 @@ angular.module('lemur')
}); });
return LemurRestangular.all('notifications'); return LemurRestangular.all('notifications');
}) })
.service('NotificationService', function ($location, NotificationApi, PluginService, toaster) { .service('NotificationService', function ($location, NotificationApi, PluginService) {
var NotificationService = this; var NotificationService = this;
NotificationService.findNotificationsByName = function (filterValue) { NotificationService.findNotificationsByName = function (filterValue) {
return NotificationApi.getList({'filter[label]': filterValue}) return NotificationApi.getList({'filter[label]': filterValue})
@ -48,59 +48,15 @@ angular.module('lemur')
}; };
NotificationService.create = function (notification) { NotificationService.create = function (notification) {
return NotificationApi.post(notification).then( return NotificationApi.post(notification);
function () {
toaster.pop({
type: 'success',
title: notification.label,
body: 'Successfully created!'
});
$location.path('notifications');
},
function (response) {
toaster.pop({
type: 'error',
title: notification.label,
body: 'Was not created! ' + response.data.message
});
});
}; };
NotificationService.update = function (notification) { NotificationService.update = function (notification) {
return notification.put().then( return notification.put();
function () {
toaster.pop({
type: 'success',
title: notification.label,
body: 'Successfully updated!'
});
$location.path('notifications');
},
function (response) {
toaster.pop({
type: 'error',
title: notification.label,
body: 'Was not updated! ' + response.data.message
});
});
}; };
NotificationService.updateActive = function (notification) { NotificationService.updateActive = function (notification) {
notification.put().then( notification.put();
function () {
toaster.pop({
type: 'success',
title: notification.name,
body: 'Successfully updated!'
});
},
function (response) {
toaster.pop({
type: 'error',
title: notification.name,
body: 'Was not updated! ' + response.data.message
});
});
}; };
return NotificationService; return NotificationService;
}); });

View File

@ -2,15 +2,30 @@
angular.module('lemur') angular.module('lemur')
.controller('RolesEditController', function ($scope, $uibModalInstance, RoleApi, RoleService, UserService, editId) { .controller('RolesEditController', function ($scope, $uibModalInstance, RoleApi, RoleService, UserService, toaster, editId) {
RoleApi.get(editId).then(function (role) { RoleApi.get(editId).then(function (role) {
$scope.role = role; $scope.role = role;
RoleService.getUsers(role); RoleService.getUsers(role);
}); });
$scope.save = function (role) { $scope.save = function (role) {
RoleService.update(role).then(function () { RoleService.update(role).then(
function () {
toaster.pop({
type: 'success',
title: role.name,
body: 'Successfully Created!'
});
$uibModalInstance.close(); $uibModalInstance.close();
}, function (response) {
toaster.pop({
type: 'error',
title: role.name,
body: 'lemur-bad-request',
bodyOutputType: 'directive',
directiveData: response.data,
timeout: 100000
});
}); });
}; };
@ -28,13 +43,28 @@ angular.module('lemur')
$scope.roleService = RoleService; $scope.roleService = RoleService;
}) })
.controller('RolesCreateController', function ($scope,$uibModalInstance, RoleApi, RoleService, UserService, LemurRestangular) { .controller('RolesCreateController', function ($scope,$uibModalInstance, RoleApi, RoleService, UserService, LemurRestangular, toaster) {
$scope.role = LemurRestangular.restangularizeElement(null, {}, 'roles'); $scope.role = LemurRestangular.restangularizeElement(null, {}, 'roles');
$scope.userService = UserService; $scope.userService = UserService;
$scope.save = function (role) { $scope.save = function (role) {
RoleService.create(role).then(function () { RoleService.create(role).then(
function () {
toaster.pop({
type: 'success',
title: role.name,
body: 'Successfully Created!'
});
$uibModalInstance.close(); $uibModalInstance.close();
}, function (response) {
toaster.pop({
type: 'error',
title: role.name,
body: 'lemur-bad-request',
bodyOutputType: 'directive',
directiveData: response.data,
timeout: 100000
});
}); });
}; };

View File

@ -18,7 +18,7 @@ angular.module('lemur')
}); });
return LemurRestangular.all('roles'); return LemurRestangular.all('roles');
}) })
.service('RoleService', function ($location, RoleApi, toaster) { .service('RoleService', function ($location, RoleApi) {
var RoleService = this; var RoleService = this;
RoleService.findRoleByName = function (filterValue) { RoleService.findRoleByName = function (filterValue) {
return RoleApi.getList({'filter[name]': filterValue}) return RoleApi.getList({'filter[name]': filterValue})
@ -48,80 +48,18 @@ angular.module('lemur')
}; };
RoleService.create = function (role) { RoleService.create = function (role) {
return RoleApi.post(role).then( return RoleApi.post(role);
function () {
toaster.pop({
type: 'success',
title: role.name,
body: 'Has been successfully created!'
});
},
function (response) {
toaster.pop({
type: 'error',
title: role.name,
body: 'Has not been created! ' + response.data.message
});
});
}; };
RoleService.update = function (role) { RoleService.update = function (role) {
return role.put().then( return role.put();
function () {
toaster.pop({
type: 'success',
title: role.name,
body: 'Successfully updated!'
});
},
function (response) {
toaster.pop({
type: 'error',
title: role.name,
body: 'Was not updated!' + response.data.message
});
});
}; };
RoleService.remove = function (role) { RoleService.remove = function (role) {
return role.remove().then( return role.remove();
function () {
toaster.pop({
type: 'success',
title: role.name,
body: 'Successfully deleted!'
});
},
function (response) {
toaster.pop({
type: 'error',
title: role.name,
body: 'Was not deleted!' + response.data.message
});
}
);
}; };
RoleService.loadPassword = function (role) { RoleService.loadPassword = function (role) {
return role.customGET('credentials').then( return role.customGET('credentials');
function (response) {
if ( response.password === null) {
toaster.pop({
type: 'info',
title: role.name,
body: 'Has no password associated'
});
} else {
role.password = response.password;
role.username = response.username;
}
},
function () {
toaster.pop({
type: 'error',
title: role.name,
body: 'You do not have permission to view this password!'
});
});
}; };
}); });

View File

@ -3,7 +3,7 @@ angular.module('lemur')
.service('SourceApi', function (LemurRestangular) { .service('SourceApi', function (LemurRestangular) {
return LemurRestangular.all('sources'); return LemurRestangular.all('sources');
}) })
.service('SourceService', function ($location, SourceApi, PluginService, toaster) { .service('SourceService', function ($location, SourceApi, PluginService) {
var SourceService = this; var SourceService = this;
SourceService.findSourcesByName = function (filterValue) { SourceService.findSourcesByName = function (filterValue) {
return SourceApi.getList({'filter[label]': filterValue}) return SourceApi.getList({'filter[label]': filterValue})
@ -13,41 +13,11 @@ angular.module('lemur')
}; };
SourceService.create = function (source) { SourceService.create = function (source) {
return SourceApi.post(source).then( return SourceApi.post(source);
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) { SourceService.update = function (source) {
return source.put().then( return source.put();
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) { SourceService.getPlugin = function (source) {

View File

@ -2,7 +2,7 @@
angular.module('lemur') angular.module('lemur')
.controller('SourcesCreateController', function ($scope, $uibModalInstance, PluginService, SourceService, LemurRestangular){ .controller('SourcesCreateController', function ($scope, $uibModalInstance, PluginService, SourceService, LemurRestangular, toaster){
$scope.source = LemurRestangular.restangularizeElement(null, {}, 'sources'); $scope.source = LemurRestangular.restangularizeElement(null, {}, 'sources');
PluginService.getByType('source').then(function (plugins) { PluginService.getByType('source').then(function (plugins) {
@ -10,8 +10,23 @@ angular.module('lemur')
}); });
$scope.save = function (source) { $scope.save = function (source) {
SourceService.create(source).then(function () { SourceService.create(source).then(
function () {
toaster.pop({
type: 'success',
title: source.label,
body: 'Successfully Created!'
});
$uibModalInstance.close(); $uibModalInstance.close();
}, function (response) {
toaster.pop({
type: 'error',
title: source.label,
body: 'lemur-bad-request',
bodyOutputType: 'directive',
directiveData: response.data,
timeout: 100000
});
}); });
}; };
@ -20,14 +35,13 @@ angular.module('lemur')
}; };
}) })
.controller('SourcesEditController', function ($scope, $uibModalInstance, SourceService, SourceApi, PluginService, editId) { .controller('SourcesEditController', function ($scope, $uibModalInstance, SourceService, SourceApi, PluginService, toaster, editId) {
SourceApi.get(editId).then(function (source) { SourceApi.get(editId).then(function (source) {
$scope.source = source; $scope.source = source;
PluginService.getByType('source').then(function (plugins) { PluginService.getByType('source').then(function (plugins) {
$scope.plugins = plugins; $scope.plugins = plugins;
_.each($scope.plugins, function (plugin) { _.each($scope.plugins, function (plugin) {
if (plugin.slug === $scope.source.pluginName) { if (plugin.slug === $scope.source.pluginName) {
plugin.pluginOptions = $scope.source.sourceOptions;
$scope.source.plugin = plugin; $scope.source.plugin = plugin;
} }
}); });
@ -38,15 +52,29 @@ angular.module('lemur')
$scope.plugins = plugins; $scope.plugins = plugins;
_.each($scope.plugins, function (plugin) { _.each($scope.plugins, function (plugin) {
if (plugin.slug === $scope.source.pluginName) { if (plugin.slug === $scope.source.pluginName) {
plugin.pluginOptions = $scope.source.sourceOptions;
$scope.source.plugin = plugin; $scope.source.plugin = plugin;
} }
}); });
}); });
$scope.save = function (source) { $scope.save = function (source) {
SourceService.update(source).then(function () { SourceService.update(source).then(
function () {
toaster.pop({
type: 'success',
title: source.label,
body: 'Successfully Updated!'
});
$uibModalInstance.close(); $uibModalInstance.close();
}, function (response) {
toaster.pop({
type: 'error',
title: source.label,
body: 'lemur-bad-request',
bodyOutputType: 'directive',
directiveData: response.data,
timeout: 100000
});
}); });
}; };

View File

@ -24,9 +24,6 @@ angular.module('lemur')
getData: function ($defer, params) { getData: function ($defer, params) {
SourceApi.getList(params.url()).then( SourceApi.getList(params.url()).then(
function (data) { function (data) {
_.each(data, function (source) {
SourceService.getPlugin(source);
});
params.total(data.total); params.total(data.total);
$defer.resolve(data); $defer.resolve(data);
} }

View File

@ -20,7 +20,7 @@ angular.module('lemur')
}); });
return LemurRestangular.all('users'); return LemurRestangular.all('users');
}) })
.service('UserService', function ($location, UserApi, AuthenticationApi, toaster) { .service('UserService', function ($location, UserApi, AuthenticationApi) {
var UserService = this; var UserService = this;
UserService.getCurrentUser = function () { UserService.getCurrentUser = function () {
return AuthenticationApi.customGET('me').then(function (user) { return AuthenticationApi.customGET('me').then(function (user) {
@ -50,40 +50,10 @@ angular.module('lemur')
}; };
UserService.create = function (user) { UserService.create = function (user) {
return UserApi.post(user).then( return UserApi.post(user);
function () {
toaster.pop({
type: 'success',
title: user.username,
body: 'Has been successfully created!'
});
$location.path('users');
},
function (response) {
toaster.pop({
type: 'error',
title: user.username,
body: 'Has not been created!' + response.data.message
});
});
}; };
UserService.update = function (user) { UserService.update = function (user) {
return user.put().then( return user.put();
function () {
toaster.pop({
type: 'success',
title: user.username,
body: 'Has been successfully updated!'
});
$location.path('users');
},
function (response) {
toaster.pop({
type: 'error',
title: user.username,
body: 'Has not been updated!' + response.data.message
});
});
}; };
}); });

View File

@ -2,7 +2,7 @@
angular.module('lemur') angular.module('lemur')
.controller('UsersEditController', function ($scope, $uibModalInstance, UserApi, UserService, RoleService, editId) { .controller('UsersEditController', function ($scope, $uibModalInstance, UserApi, UserService, RoleService, toaster, editId) {
UserApi.get(editId).then(function (user) { UserApi.get(editId).then(function (user) {
UserService.getRoles(user); UserService.getRoles(user);
$scope.user = user; $scope.user = user;
@ -15,8 +15,23 @@ angular.module('lemur')
$scope.save = function (user) { $scope.save = function (user) {
UserService.update(user).then(function () { UserService.update(user).then(
function () {
toaster.pop({
type: 'success',
title: user.username,
body: 'Successfully Updated!'
});
$uibModalInstance.close(); $uibModalInstance.close();
}, function (response) {
toaster.pop({
type: 'error',
title: user.username,
body: 'lemur-bad-request',
bodyOutputType: 'directive',
directiveData: response.data,
timeout: 100000
});
}); });
}; };
@ -30,14 +45,29 @@ angular.module('lemur')
}; };
}) })
.controller('UsersCreateController', function ($scope, $uibModalInstance, UserService, LemurRestangular, RoleService) { .controller('UsersCreateController', function ($scope, $uibModalInstance, UserService, LemurRestangular, RoleService, toaster) {
$scope.user = LemurRestangular.restangularizeElement(null, {}, 'users'); $scope.user = LemurRestangular.restangularizeElement(null, {}, 'users');
$scope.save = UserService.create; $scope.save = UserService.create;
$scope.roleService = RoleService; $scope.roleService = RoleService;
$scope.create = function (user) { $scope.create = function (user) {
UserService.create(user).then(function () { UserService.create(user).then(
function () {
toaster.pop({
type: 'success',
title: user.username,
body: 'Successfully Created!'
});
$uibModalInstance.close(); $uibModalInstance.close();
}, function (response) {
toaster.pop({
type: 'error',
title: user.username,
body: 'lemur-bad-request',
bodyOutputType: 'directive',
directiveData: response.data,
timeout: 100000
});
}); });
}; };

View File

@ -10,7 +10,7 @@ angular.module('lemur')
}); });
}) })
.controller('UsersViewController', function ($scope, $modal, UserApi, UserService, ngTableParams) { .controller('UsersViewController', function ($scope, $uibModal, UserApi, UserService, ngTableParams) {
$scope.filter = {}; $scope.filter = {};
$scope.usersTable = new ngTableParams({ $scope.usersTable = new ngTableParams({
page: 1, // show first page page: 1, // show first page
@ -38,7 +38,7 @@ angular.module('lemur')
}; };
$scope.edit = function (userId) { $scope.edit = function (userId) {
var modalInstance = $modal.open({ var uibModalInstance = $uibModal.open({
animation: true, animation: true,
templateUrl: '/angular/users/user/user.tpl.html', templateUrl: '/angular/users/user/user.tpl.html',
controller: 'UsersEditController', controller: 'UsersEditController',
@ -51,14 +51,14 @@ angular.module('lemur')
} }
}); });
modalInstance.result.then(function () { uibModalInstance.result.then(function () {
$scope.usersTable.reload(); $scope.usersTable.reload();
}); });
}; };
$scope.create = function () { $scope.create = function () {
var modalInstance = $modal.open({ var uibModalInstance = $uibModal.open({
animation: true, animation: true,
controller: 'UsersCreateController', controller: 'UsersCreateController',
templateUrl: '/angular/users/user/user.tpl.html', templateUrl: '/angular/users/user/user.tpl.html',
@ -66,7 +66,7 @@ angular.module('lemur')
backdrop: 'static' backdrop: 'static'
}); });
modalInstance.result.then(function () { uibModalInstance.result.then(function () {
$scope.usersTable.reload(); $scope.usersTable.reload();
}); });

View File

@ -73,8 +73,8 @@ def test_role_list_post_(client, token, status):
@pytest.mark.parametrize("token,status", [ @pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 404), (VALID_USER_HEADER_TOKEN, 200),
(VALID_ADMIN_HEADER_TOKEN, 404), (VALID_ADMIN_HEADER_TOKEN, 200),
('', 401) ('', 401)
]) ])
def test_role_list_get(client, token, status): def test_role_list_get(client, token, status):

View File

@ -75,8 +75,8 @@ def test_user_list_post_(client, token, status):
@pytest.mark.parametrize("token,status", [ @pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 404), (VALID_USER_HEADER_TOKEN, 200),
(VALID_ADMIN_HEADER_TOKEN, 404), (VALID_ADMIN_HEADER_TOKEN, 200),
('', 401) ('', 401)
]) ])
def test_user_list_get(client, token, status): def test_user_list_get(client, token, status):

View File

@ -21,6 +21,7 @@ class UserInputSchema(LemurInputSchema):
class UserOutputSchema(LemurOutputSchema): class UserOutputSchema(LemurOutputSchema):
id = fields.Integer()
username = fields.String() username = fields.String()
email = fields.Email() email = fields.Email()
password = fields.String() password = fields.String()

View File

@ -135,4 +135,4 @@ def render(args):
terms = filt.split(';') terms = filt.split(';')
query = database.filter(query, User, terms) query = database.filter(query, User, terms)
database.sort_and_page(query, User, args) return database.sort_and_page(query, User, args)

View File

@ -229,7 +229,7 @@ class CertificateUsers(AuthenticatedResource):
self.reqparse = reqparse.RequestParser() self.reqparse = reqparse.RequestParser()
super(CertificateUsers, self).__init__() super(CertificateUsers, self).__init__()
@validate_schema(None, user_output_schema) @validate_schema(None, users_output_schema)
def get(self, certificate_id): def get(self, certificate_id):
""" """
.. http:get:: /certificates/1/creator .. http:get:: /certificates/1/creator
@ -271,7 +271,7 @@ class RoleUsers(AuthenticatedResource):
self.reqparse = reqparse.RequestParser() self.reqparse = reqparse.RequestParser()
super(RoleUsers, self).__init__() super(RoleUsers, self).__init__()
@validate_schema(None, user_output_schema) @validate_schema(None, users_output_schema)
def get(self, role_id): def get(self, role_id):
""" """
.. http:get:: /roles/1/users .. http:get:: /roles/1/users

View File

@ -53,7 +53,7 @@ install_requires = [
'marshmallow-sqlalchemy==0.8.0', 'marshmallow-sqlalchemy==0.8.0',
'marshmallow==2.4.0', 'marshmallow==2.4.0',
'pycrypto==2.6.1', 'pycrypto==2.6.1',
'cryptography==1.3.1', 'cryptography==1.3.2',
'pyopenssl==0.15.1', 'pyopenssl==0.15.1',
'pyjwt==1.4.0', 'pyjwt==1.4.0',
'xmltodict==0.9.2', 'xmltodict==0.9.2',