Commit 4539d4c4 authored by Michal-MK's avatar Michal-MK
Browse files

Initial Commit for Step2

parent 9a3deae1
/**
* This package contains exceptions which are converted to specific HTTP status codes by the REST controllers.
*
* @author Martin Kuba makub@ics.muni.cz
*/
package cz.muni.fi.pa165.restapi.exceptions;
......@@ -11,6 +11,9 @@ pa165eshopApp.config(['$routeProvider',
$routeProvider.
when('/shopping', {templateUrl: 'partials/shopping.html', controller: 'ShoppingCtrl'}).
when('/product/:productId', {templateUrl: 'partials/product_detail.html', controller: 'ProductDetailCtrl'}).
when('/category/:categoryId', {templateUrl: 'partials/category_detail.html', controller: 'CategoryDetailCtrl'}).
when('/admin/products', {templateUrl: 'partials/admin_products.html', controller: 'AdminProductsCtrl'}).
when('/admin/newproduct', {templateUrl: 'partials/admin_new_product.html', controller: 'AdminNewProductCtrl'}).
otherwise({redirectTo: '/shopping'});
}
]);
......@@ -80,3 +83,130 @@ eshopControllers.controller('ProductDetailCtrl', function ($scope, $rootScope, $
);
});
/*
* Category detail page
*/
eshopControllers.controller('CategoryDetailCtrl', ['$scope', '$routeParams', '$http',
function ($scope, $routeParams, $http) {
var categoryId = $routeParams.categoryId;
$http.get('/eshop/api/v1/categories/' + categoryId).then(function (response) {
var category = response.data;
$scope.category = category;
console.log('AJAX loaded detail of category ' + category.name);
loadCategoryProducts($http, category, category['_links'].products.href);
});
}]);
/*
* Administration interface
*/
/*
* Admin Products page
*/
function loadAdminProducts($http, $scope) {
$http.get('/eshop/api/v1/products').then(function (response) {
$scope.products = response.data['_embedded']['productDTOList'];
console.log('AJAX loaded all products ');
});
}
eshopControllers.controller('AdminProductsCtrl',
function ($scope, $rootScope, $routeParams, $http) {
// Initial load of all products
loadAdminProducts($http, $scope);
// Function called when Delete button is clicked
$scope.deleteProduct = function (product) {
console.log("deleting product with id=" + product.id + ' (' + product.name + ')');
$http.delete(product._links.delete.href).then(
function success(response) {
console.log('deleted product ' + product.id + ' on server');
// Display confirmation alert
$rootScope.successAlert = 'Deleted product "' + product.name + '"';
// Load new list of all products
loadAdminProducts($http, $scope);
},
function error(response) {
console.log("error when deleting product");
console.log(response);
switch (response.data.code) {
case 'ResourceNotFoundException':
$rootScope.errorAlert = 'Cannot delete non-existent product ! ';
break;
default:
$rootScope.errorAlert = 'Cannot delete product ! Reason given by the server: ' + response.data.message;
break;
}
}
);
};
});
/*
* Page with form for creating new product
*/
eshopControllers.controller('AdminNewProductCtrl',
function ($scope, $routeParams, $http, $location, $rootScope) {
// Prepare data for selection lists
$scope.colors = ['RED', 'GREEN', 'BLUE', 'BLACK'];
$scope.currencies = ['CZK', 'EUR', 'USD'];
// Get categories from server
$http.get('/eshop/api/v1/categories/').then(function (response) {
$scope.categories = response.data['_embedded']['categoryDTOList'];
});
// Set object bound to form fields
$scope.product = {
'name': '',
'description': '',
'categoryId': 1,
'price': 0,
'color': $scope.colors[1],
'currency': $scope.currencies[0]
};
// Function called when submit button is clicked, creates product on server
$scope.create = function (product) {
$http({
method: 'POST',
url: '/eshop/api/v1/products/create',
data: product
}).then(function success(response) {
console.log('created product');
const createdProduct = response.data;
// Display confirmation alert
$rootScope.successAlert = 'A new product "' + createdProduct.name + '" was created';
// Change view to list of products
$location.path("/admin/products");
}, function error(response) {
// Display error
console.log("error when creating product");
console.log(response);
switch (response.data.code) {
case 'InvalidRequestException':
$rootScope.errorAlert = 'Sent data were found to be invalid by server ! ';
break;
default:
$rootScope.errorAlert = 'Cannot create product ! Reason given by the server: '+response.data.message;
break;
}
});
};
});
// Defines new directive (HTML attribute "convert-to-int") for conversion between string and int
// of the value of a selection list in a form
// without this, the value of the selected option is always a string, not an integer
eshopControllers.directive('convertToInt', function () {
return {
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
ngModel.$parsers.push(function (val) {
return parseInt(val, 10);
});
ngModel.$formatters.push(function (val) {
return '' + val;
});
}
};
});
......@@ -32,6 +32,12 @@
<ul class="nav navbar-nav">
<li><a href="#!/shopping">Go shopping</a></li>
</ul>
<ul class="nav navbar-nav">
<li><a href="#!/admin/products">Manage Products</a></li>
</ul>
<ul class="nav navbar-nav">
<li><a href="#!/admin/categories">Manage Categories</a></li>
</ul>
</div>
</div>
</nav>
......@@ -39,6 +45,20 @@
<div class="container">
<div ng-app="pa165eshopApp"><!-- AngularJS takes care of this element -->
<!-- Bootstrap-styled alerts, visible when $rootScope.xxxAlert is defined -->
<div ng-show="warningAlert" class="alert alert-warning alert-dismissible" role="alert">
<button type="button" class="close" aria-label="Close" ng-click="hideWarningAlert()"> <span aria-hidden="true">&times;</span></button>
<strong>Warning!</strong> <span>{{warningAlert}}</span>
</div>
<div ng-show="errorAlert" class="alert alert-danger alert-dismissible" role="alert">
<button type="button" class="close" aria-label="Close" ng-click="hideErrorAlert()"> <span aria-hidden="true">&times;</span></button>
<strong>Error!</strong> <span>{{errorAlert}}</span>
</div>
<div ng-show="successAlert" class="alert alert-success alert-dismissible" role="alert">
<button type="button" class="close" aria-label="Close" ng-click="hideSuccessAlert()"> <span aria-hidden="true">&times;</span></button>
<strong>Success !</strong> <span>{{successAlert}}</span>
</div>
<div ng-view></div><!-- The place where HTML templates are replaced by AngularJS routing -->
</div>
......
......@@ -12,6 +12,9 @@
url: '/eshop/api/v1/products',
success: function (data) {
const products = data._embedded.productDTOList;
const productsTable = $('#products_list');
productsTable.empty(); // Remove all existing rows
for (let i = 0; i < products.length; i++) {
const p = products[i];
$('#products_list').append('<tr><td>'+p.id+'</td><td>'+p.name+'</td><td>'+p.currentPrice.value+' '+p.currentPrice.currency+'</td></tr>');
......@@ -19,6 +22,23 @@
}
});
}
function loadCategories() {
$.ajax({
type: 'GET',
url: '/eshop/api/v1/categories',
success: function (data) {
const categories = data._embedded.categoryDTOList;
const categoriesTable = $('#categories_list');
categoriesTable.empty();
for (let i = 0; i < categories.length; i++) {
const p = categories[i];
categoriesTable.append('<tr><td>'+p.id+'</td><td>'+p.name+'</td></tr>');
}
}
});
}
</script>
<style>
table.basic { border-collapse: collapse; margin: 10px; }
......
<form name="form" novalidate class="form-horizontal">
<div class="form-group">
<label for="categoryId" class="col-sm-2 control-label">Category</label>
<div class="col-sm-10">
<select id="categoryId" class="form-control" ng-model="product.categoryId" convert-to-int>
<option ng-repeat="category in categories" value="{{category.id}}">{{category.name}}</option>
</select>
</div>
</div>
<div class="form-group" ng-class="{'has-error': !(form.name.$valid)}">
<label for="name" class="col-sm-2 control-label">Name</label>
<div class="col-sm-10">
<input placeholder="name" id="name" type="text" ng-minlength="3" name="name" class="form-control" ng-model="product.name" required/>
<p class="help-block" ng-show="form.name.$error.required">name is required</p>
<p class="help-block" ng-show="form.name.$error.minlength">name must be at least 3 characters</p>
</div>
</div>
<div class="form-group" ng-class="{'has-error': !(form.description.$valid)}">
<label for="description" class="col-sm-2 control-label">Description</label>
<div class="col-sm-10">
<textarea placeholder="description" ng-minlength="3" required cols="80" rows="20" id="description" name="description" class="form-control" ng-model="product.description"></textarea>
<p class="help-block" ng-show="form.description.$error.minlength">description must be ate least 3 characters</p>
</div>
</div>
<div class="form-group">
<label for="color" class="col-sm-2 control-label">Color</label>
<div class="col-sm-10">
<select id="color" name="color" class="form-control" ng-model="product.color">
<option ng-repeat="color in colors" value="{{color}}">{{color}}</option>
</select>
</div>
</div>
<div class="form-group" ng-class="{'has-error': !(form.price.$valid)}" >
<label for="price" class="col-sm-2 control-label">Price</label>
<div class="col-sm-10">
<input type="number" min="1" integer required id="price" name="price" class="form-control" ng-model="product.price" />
<p class="help-block" ng-show="form.price.$error.required">price is required</p>
<p class="help-block" ng-show="form.price.$error.min">price greater than zero is required</p>
</div>
</div>
<div class="form-group">
<label for="currency" class="col-sm-2 control-label">currency</label>
<div class="col-sm-10">
<select id="currency" name="currency" class="form-control" ng-model="product.currency">
<option ng-repeat="currency in currencies" value="{{currency}}">{{currency}}</option>
</select>
</div>
</div>
<!-- show disabled button if form is not valid -->
<button ng-disabled="!form.$valid" class="btn btn-primary" type="submit" ng-click="create(product)">Create product</button>
</form>
<h1>Administration of products</h1>
<!-- button for adding a new product -->
<a href="#!/admin/newproduct" class="btn btn-primary">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
New product
</a>
<table class="table">
<thead>
<tr>
<th>id</th>
<th>added</th>
<th>product name</th>
<th>color</th>
<th>price</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="product in products track by $index">
<td>{{product.id}}</td>
<td>{{product.addedDate}}</td>
<td>{{product.name}}</td>
<td>{{product.color}}</td>
<td>{{product.currentPrice.value}} {{product.currentPrice.currency}}</td>
<td>
<button ng-click="deleteProduct(product)" type="submit" class="btn btn-primary">Delete</button>
</td>
</tr>
</tbody>
</table>
<div>
<h1>{{category.name}}</h1>
<div class="row">
<div class="col-xs-12 col-sm-4 col-md-3 col-lg-2" ng-repeat="product in category.products">
<a href="#!/product/{{product.id}}">
<div class="thumbnail">
<img ng-src="{{product._links.image.href}}"><br>
<div class="caption">
<h3>{{product.name}}</h3>
<span style="color: red; font-weight: bold;">{{product.currentPrice.value}}&nbsp;{{product.currentPrice.currency}}</span>
</div>
</div>
</a>
</div>
</div>
</div>
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment