diff --git a/refstack-ui/app/components/vendors/vendor.html b/refstack-ui/app/components/vendors/vendor.html index ad8f5f9a..7a6e7600 100644 --- a/refstack-ui/app/components/vendors/vendor.html +++ b/refstack-ui/app/components/vendors/vendor.html @@ -80,6 +80,27 @@
+

Vendor Products

+ + + + + + + + + + + + + + + + + + + +
NameProduct TypeDescriptionVisibility
{{product.name}}{{product.name}}{{ctrl.getProductTypeDescription(product.product_type)}}{{product.description}}{{product.public ? 'Public' : 'Private'}}
diff --git a/refstack-ui/app/components/vendors/vendorController.js b/refstack-ui/app/components/vendors/vendorController.js index 621bf430..f7604606 100644 --- a/refstack-ui/app/components/vendors/vendorController.js +++ b/refstack-ui/app/components/vendors/vendorController.js @@ -35,6 +35,8 @@ ctrl.getVendor = getVendor; ctrl.getVendorUsers = getVendorUsers; + ctrl.getVendorProducts = getVendorProducts; + ctrl.getProductTypeDescription = getProductTypeDescription; ctrl.registerVendor = registerVendor; ctrl.approveVendor = approveVendor; ctrl.declineVendor = declineVendor; @@ -51,6 +53,10 @@ $state.go('home'); } + ctrl.getVendor(); + ctrl.getVendorUsers(); + ctrl.getVendorProducts(); + /** * This will contact the Refstack API to get a vendor information. */ @@ -77,7 +83,6 @@ angular.toJson(error); }); } - ctrl.getVendor(); /** * This will 'send' application for registration. @@ -151,7 +156,40 @@ angular.toJson(error); }); } - ctrl.getVendorUsers(); + + /** + * Updates list of users in the vendor's group + */ + function getVendorProducts() { + ctrl.showError = false; + var contentUrl = refstackApiUrl + '/products?organization_id=' + + ctrl.vendorId; + ctrl.productsRequest = + $http.get(contentUrl).success(function(data) { + ctrl.vendorProducts = data.products; + }).error(function(error) { + ctrl.showError = true; + ctrl.error = + 'Error retrieving from server: ' + + angular.toJson(error); + }); + } + + /** + * Get the product type description given the type integer. + */ + function getProductTypeDescription(product_type) { + switch (product_type) { + case 0: + return 'Distro'; + case 1: + return 'Public Cloud'; + case 2: + return 'Hosted Private Cloud'; + default: + return 'Unknown'; + } + } /** * Removes user with specific openid from vendor's group diff --git a/refstack-ui/tests/unit/ControllerSpec.js b/refstack-ui/tests/unit/ControllerSpec.js index fb185e6d..f3d2fdbc 100644 --- a/refstack-ui/tests/unit/ControllerSpec.js +++ b/refstack-ui/tests/unit/ControllerSpec.js @@ -849,6 +849,7 @@ describe('Refstack controllers', function () { var fakeResp = {'id': 'fake-id', 'type': 1, 'can_manage': true, 'properties' : {}}; var fakeUsersResp = [{'openid': 'foo'}]; + var fakeProdResp = {'products': [{'id': 123}]}; var fakeWindow = { location: { href: '' @@ -871,6 +872,8 @@ describe('Refstack controllers', function () { $httpBackend.when('GET', fakeApiUrl + '/vendors/1234').respond(fakeResp); $httpBackend.when('GET', fakeApiUrl + + '/products?organization_id=1234').respond(fakeProdResp); + $httpBackend.when('GET', fakeApiUrl + '/vendors/1234/users').respond(fakeUsersResp); })); @@ -893,6 +896,14 @@ describe('Refstack controllers', function () { expect(ctrl.currentUser).toEqual('foo'); }); + it('should have a function to get vendor products', + function () { + ctrl.vendorProducts = null; + ctrl.getVendorProducts(); + $httpBackend.flush(); + expect(ctrl.vendorProducts).toEqual(fakeProdResp.products); + }); + it('should have a function to register a vendor', function () { $httpBackend.expectPOST( diff --git a/refstack/api/controllers/products.py b/refstack/api/controllers/products.py index 9d054862..776a2f99 100644 --- a/refstack/api/controllers/products.py +++ b/refstack/api/controllers/products.py @@ -145,25 +145,33 @@ class ProductsController(validation.BaseRestControllerWithValidation): @pecan.expose('json') def get(self): """Get information of all products.""" + filters = api_utils.parse_input_params(['organization_id']) + allowed_keys = ['id', 'name', 'description', 'product_ref_id', 'type', 'product_type', 'public', 'organization_id'] user = api_utils.get_user_id() is_admin = user in db.get_foundation_users() try: if is_admin: - products = db.get_products(allowed_keys=allowed_keys) + products = db.get_products(allowed_keys=allowed_keys, + filters=filters) for s in products: s['can_manage'] = True else: result = dict() - products = db.get_public_products(allowed_keys=allowed_keys) + filters['public'] = True + + products = db.get_products(allowed_keys=allowed_keys, + filters=filters) for s in products: _id = s['id'] result[_id] = s result[_id]['can_manage'] = False + filters.pop('public') products = db.get_products_by_user(user, - allowed_keys=allowed_keys) + allowed_keys=allowed_keys, + filters=filters) for s in products: _id = s['id'] if _id not in result: diff --git a/refstack/db/api.py b/refstack/db/api.py index a63b70e0..8e5b2adf 100644 --- a/refstack/db/api.py +++ b/refstack/db/api.py @@ -246,19 +246,15 @@ def get_organizations_by_user(user_openid, allowed_keys=None): allowed_keys=allowed_keys) -def get_public_products(allowed_keys=None): - """Get all public products.""" - return IMPL.get_public_products(allowed_keys=allowed_keys) - - -def get_products(allowed_keys=None): +def get_products(allowed_keys=None, filters=None): """Get all products.""" - return IMPL.get_products(allowed_keys=allowed_keys) + return IMPL.get_products(allowed_keys=allowed_keys, filters=filters) -def get_products_by_user(user_openid, allowed_keys=None): +def get_products_by_user(user_openid, allowed_keys=None, filters=None): """Get all products that user can manage.""" - return IMPL.get_products_by_user(user_openid, allowed_keys=allowed_keys) + return IMPL.get_products_by_user(user_openid, allowed_keys=allowed_keys, + filters=filters) def get_product_by_version(product_version_id, allowed_keys=None): diff --git a/refstack/db/sqlalchemy/api.py b/refstack/db/sqlalchemy/api.py index 72333e02..4c1f0105 100644 --- a/refstack/db/sqlalchemy/api.py +++ b/refstack/db/sqlalchemy/api.py @@ -602,29 +602,31 @@ def get_organizations_by_user(user_openid, allowed_keys=None): return _to_dict(items, allowed_keys=allowed_keys) -def get_public_products(allowed_keys=None): - """Get public products.""" +def get_products(allowed_keys=None, filters=None): + """Get products based on passed in filters.""" + if filters is None: + filters = {} + expected_filters = ['public', 'organization_id'] + filter_args = {} + for key, value in six.iteritems(filters): + if key not in expected_filters: + raise Exception('Unknown filter key "%s"' % key) + filter_args[key] = value + session = get_session() - items = ( - session.query(models.Product) - .filter_by(public=True) - .order_by(models.Product.created_at.desc()).all()) + query = session.query(models.Product) + if filter_args: + query = query.filter_by(**filter_args) + items = query.order_by(models.Product.created_at.desc()).all() return _to_dict(items, allowed_keys=allowed_keys) -def get_products(allowed_keys=None): - """Get all products.""" +def get_products_by_user(user_openid, allowed_keys=None, filters=None): + """Get products that a user can manage.""" + if filters is None: + filters = {} session = get_session() - items = ( - session.query(models.Product) - .order_by(models.Product.created_at.desc()).all()) - return _to_dict(items, allowed_keys=allowed_keys) - - -def get_products_by_user(user_openid, allowed_keys=None): - """Get all products that user can manage.""" - session = get_session() - items = ( + query = ( session.query(models.Product, models.Organization, models.Group, models.UserToGroup) .join(models.Organization, @@ -633,8 +635,15 @@ def get_products_by_user(user_openid, allowed_keys=None): models.Group.id == models.Organization.group_id) .join(models.UserToGroup, models.Group.id == models.UserToGroup.group_id) - .filter(models.UserToGroup.user_openid == user_openid) - .order_by(models.Organization.created_at.desc()).all()) + .filter(models.UserToGroup.user_openid == user_openid)) + + expected_filters = ['organization_id'] + for key, value in six.iteritems(filters): + if key not in expected_filters: + raise Exception('Unknown filter key "%s"' % key) + query = query.filter(getattr(models.Product, key) == + filters[key]) + items = query.order_by(models.Organization.created_at.desc()).all() items = [item[0] for item in items] return _to_dict(items, allowed_keys=allowed_keys) diff --git a/refstack/tests/api/test_products.py b/refstack/tests/api/test_products.py index 51906776..0a66982e 100644 --- a/refstack/tests/api/test_products.py +++ b/refstack/tests/api/test_products.py @@ -108,6 +108,36 @@ class TestProductsEndpoint(api.FunctionalTest): product = json.dumps(FAKE_PRODUCT) post_response = self.post_json(self.URL, params=product) + @mock.patch('refstack.api.utils.get_user_id', return_value='test-open-id') + def test_get_by_org(self, mock_get_user): + """Test getting products of an organization.""" + org1 = db.add_organization({'name': 'test-vendor1'}, 'test-open-id') + org2 = db.add_organization({'name': 'test-vendor2'}, 'test-open-id') + prod_info = {'name': 'product1', + 'description': 'product description', + 'product_type': 1, 'type': 0, + 'organization_id': org1['id'], 'public': True} + prod1 = db.add_product(prod_info, 'test-open-id') + prod_info['name'] = 'product2' + prod_info['organization_id'] = org2['id'] + prod2 = db.add_product(prod_info, 'test-open-id') + get_response = self.get_json(self.URL + + '?organization_id=' + org1['id']) + self.assertEqual(1, len(get_response['products'])) + self.assertEqual(prod1['id'], get_response['products'][0]['id']) + + get_response = self.get_json(self.URL + + '?organization_id=' + org2['id']) + self.assertEqual(1, len(get_response['products'])) + self.assertEqual(prod2['id'], get_response['products'][0]['id']) + + # Test that non-admin can't view non-public products of an org. + db.update_product({'id': prod1['id'], 'public': False}) + mock_get_user.return_value = 'some-user' + get_response = self.get_json(self.URL + + '?organization_id=' + org1['id']) + self.assertFalse(get_response['products']) + @mock.patch('refstack.api.utils.get_user_id', return_value='test-open-id') def test_get_one(self, mock_get_user): """Test get_one request."""