Show vendor products on vendor page

This patch allows passing in an organization_id
as a GET parameter to the products API endpoint. The vendor
page now lists products of that vendor.

Change-Id: I5373b5e75e1760df24dfc7960571731dcaab3f81
This commit is contained in:
Paul Van Eck 2016-11-21 14:44:51 -08:00
parent 0d494be2f9
commit 7883ed73d8
7 changed files with 147 additions and 34 deletions

View File

@ -80,6 +80,27 @@
</div>
</div>
<hr />
<h3>Vendor Products</h3>
<table ng-show="ctrl.vendorProducts" class="table table-striped table-hover">
<thead>
<tr>
<th>Name</th>
<th>Product Type</th>
<th>Description</th>
<th>Visibility</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="product in ctrl.vendorProducts">
<td ng-if="product.product_type == 0"><a ui-sref="distro({id: product.id})">{{product.name}}</a></td>
<td ng-if="product.product_type != 0"><a ui-sref="cloud({id: product.id})">{{product.name}}</a></td>
<td>{{ctrl.getProductTypeDescription(product.product_type)}}</td>
<td>{{product.description}}</td>
<td>{{product.public ? 'Public' : 'Private'}}</td>
</tr>
</tbody>
</table>
</div>
</div>

View File

@ -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

View File

@ -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(

View File

@ -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:

View File

@ -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):

View File

@ -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)

View File

@ -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."""