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
+
+
+
+ Name |
+ Product Type |
+ Description |
+ Visibility |
+
+
+
+
+
+ {{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."""