From 79121484b7e6f721f5435a102018152a164ed655 Mon Sep 17 00:00:00 2001
From: Roberto Sánchez <roberto.sanchez@curisit.net>
Date: Wed, 22 Jan 2014 18:55:29 +0000
Subject: [PATCH] #395 feature - Implemented pack section

---
 securis/src/main/java/net/curisit/securis/db/License.java            |    2 
 securis/src/main/resources/static/licenses.html                      |  132 ++++++++++-
 securis/src/main/java/net/curisit/securis/db/User.java               |    1 
 securis/src/main/resources/static/js/licenses.js                     |  214 ++++++++++++------
 securis/src/main/resources/static/js/catalogs.js                     |  163 +++++++-------
 securis/src/main/java/net/curisit/securis/db/LicenseType.java        |    4 
 securis/src/main/resources/static/js/admin.js                        |    7 
 securis/src/main/resources/static/js/main.js                         |    2 
 securis/src/main/java/net/curisit/securis/db/Pack.java               |   32 ++
 securis/src/main/resources/db/schema.sql                             |    6 
 securis/src/main/java/net/curisit/securis/services/PackResource.java |   59 +++-
 11 files changed, 418 insertions(+), 204 deletions(-)

diff --git a/securis/src/main/java/net/curisit/securis/db/License.java b/securis/src/main/java/net/curisit/securis/db/License.java
index 5ab3b78..010b933 100644
--- a/securis/src/main/java/net/curisit/securis/db/License.java
+++ b/securis/src/main/java/net/curisit/securis/db/License.java
@@ -55,7 +55,7 @@
 
 	private int status;
 
-	@JoinColumn(name = "full_name")
+	@Column(name = "full_name")
 	private String fullName;
 
 	private String email;
diff --git a/securis/src/main/java/net/curisit/securis/db/LicenseType.java b/securis/src/main/java/net/curisit/securis/db/LicenseType.java
index ecc0253..d75fb7e 100644
--- a/securis/src/main/java/net/curisit/securis/db/LicenseType.java
+++ b/securis/src/main/java/net/curisit/securis/db/LicenseType.java
@@ -57,6 +57,10 @@
 		return id;
 	}
 
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
 	public String getName() {
 		return name;
 	}
diff --git a/securis/src/main/java/net/curisit/securis/db/Pack.java b/securis/src/main/java/net/curisit/securis/db/Pack.java
index 39e99ab..254d6b0 100644
--- a/securis/src/main/java/net/curisit/securis/db/Pack.java
+++ b/securis/src/main/java/net/curisit/securis/db/Pack.java
@@ -8,6 +8,7 @@
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
 import javax.persistence.Id;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
@@ -31,15 +32,18 @@
 @Table(name = "pack")
 @NamedQueries(
 	{ @NamedQuery(name = "list-packs", query = "SELECT pa FROM Pack pa"),//
-			@NamedQuery(name = "list-packs-by-org", query = "SELECT pa FROM Pack pa where pa.organization = :organization") })
+			@NamedQuery(name = "list-packs-by-orgs", query = "SELECT pa FROM Pack pa where pa.organization.id in :list_ids") })
 public class Pack implements Serializable {
 
 	private static final long serialVersionUID = 1L;
 
 	@Id
+	@GeneratedValue
 	private int id;
 
 	private String code;
+
+	private String comments;
 
 	@Column(name = "creation_timestamp")
 	private Date creationTimestamp;
@@ -63,7 +67,8 @@
 	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "pack")
 	private Set<License> licenses;
 
-	@JoinColumn(name = "num_licenses")
+	@Column(name = "num_licenses")
+	@JsonProperty("num_licenses")
 	private int numLicenses;
 
 	public int getId() {
@@ -190,6 +195,16 @@
 	}
 
 	@JsonProperty("license_type_id")
+	public void setLicTypeId(Integer idLT) {
+		if (idLT == null) {
+			licenseType = null;
+		} else {
+			licenseType = new LicenseType();
+			licenseType.setId(idLT);
+		}
+	}
+
+	@JsonProperty("license_type_id")
 	public Integer getLicTypeId() {
 		return licenseType == null ? null : licenseType.getId();
 	}
@@ -205,9 +220,22 @@
 		createdBy.setUsername(username);
 	}
 
+	@JsonProperty("created_by_name")
+	public String getCreatedByname() {
+		return createdBy == null ? null : String.format("%s %s", createdBy.getFirstName(), createdBy.getFirstName());
+	}
+
 	@JsonProperty("licensetype_code")
 	public String getLicenseTypcode() {
 		return licenseType == null ? null : licenseType.getCode();
 	}
 
+	public String getComments() {
+		return comments;
+	}
+
+	public void setComments(String comments) {
+		this.comments = comments;
+	}
+
 }
diff --git a/securis/src/main/java/net/curisit/securis/db/User.java b/securis/src/main/java/net/curisit/securis/db/User.java
index 79d2aa2..939e993 100644
--- a/securis/src/main/java/net/curisit/securis/db/User.java
+++ b/securis/src/main/java/net/curisit/securis/db/User.java
@@ -52,7 +52,6 @@
 
 	private int roles;
 
-	@JsonProperty(value = "last_login")
 	@Column(name = "last_login")
 	private Date lastLogin;
 
diff --git a/securis/src/main/java/net/curisit/securis/services/PackResource.java b/securis/src/main/java/net/curisit/securis/services/PackResource.java
index 313732f..c6927a2 100644
--- a/securis/src/main/java/net/curisit/securis/services/PackResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/PackResource.java
@@ -1,8 +1,10 @@
 package net.curisit.securis.services;
 
+import java.security.Principal;
 import java.util.Date;
 import java.util.List;
 
+import javax.annotation.security.RolesAllowed;
 import javax.inject.Inject;
 import javax.inject.Provider;
 import javax.persistence.EntityManager;
@@ -23,10 +25,10 @@
 import javax.ws.rs.core.Response.Status;
 
 import net.curisit.integrity.commons.Utils;
-import net.curisit.integrity.exception.CurisException;
 import net.curisit.securis.DefaultExceptionHandler;
 import net.curisit.securis.db.Pack;
-import net.curisit.securis.db.User;
+import net.curisit.securis.security.BasicSecurityContext;
+import net.curisit.securis.security.Securable;
 import net.curisit.securis.utils.TokenHelper;
 
 import org.slf4j.Logger;
@@ -59,17 +61,35 @@
 	 */
 	@GET
 	@Path("/")
+	@Securable
 	@Produces(
 		{ MediaType.APPLICATION_JSON })
-	public Response index() {
+	public Response index(@Context BasicSecurityContext bsc) {
 		log.info("Getting packs list ");
 
 		EntityManager em = emProvider.get();
-		TypedQuery<Pack> q = em.createNamedQuery("list-packs-by-orgs", Pack.class);
+		// TypedQuery<Pack> q = em.createNamedQuery("list-packs-by-orgs", Pack.class);
+
+		TypedQuery<Pack> q;
+		if (bsc.isUserInRole(BasicSecurityContext.ROL_ADMIN)) {
+			log.info("Getting all packs for user: " + bsc.getUserPrincipal());
+			q = em.createNamedQuery("list-packs", Pack.class);
+		} else {
+			q = em.createNamedQuery("list-packs-by-orgs", Pack.class);
+			if (bsc.getOrganizationsIds() == null)
+				Response.ok().build();
+			// log.info("Getting only {} orgs for user: {}", securityContext.getOrganizationsIds(), securityContext.getUserPrincipal());
+			q.setParameter("list_ids", bsc.getOrganizationsIds());
+		}
 
 		List<Pack> list = q.getResultList();
 
 		return Response.ok(list).build();
+	}
+
+	private Response generateErrorUnathorizedAccess(Pack pack, Principal user) {
+		log.error("Pack with id {} not accesible by user {}", pack, user);
+		return Response.status(Status.UNAUTHORIZED).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "Unathorized access to pack").build();
 	}
 
 	/**
@@ -78,9 +98,10 @@
 	 */
 	@GET
 	@Path("/{packId}")
+	@Securable
 	@Produces(
 		{ MediaType.APPLICATION_JSON })
-	public Response get(@PathParam("packId") String packId, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
+	public Response get(@PathParam("packId") String packId, @Context BasicSecurityContext bsc) {
 		log.info("Getting pack data for id: {}: ", packId);
 		if (packId == null || packId.equals("")) {
 			log.error("Pack ID is mandatory");
@@ -88,16 +109,23 @@
 		}
 
 		EntityManager em = emProvider.get();
-		Pack lt = em.find(Pack.class, Integer.parseInt(packId));
-		if (lt == null) {
+		Pack pack = em.find(Pack.class, Integer.parseInt(packId));
+		if (pack == null) {
 			log.error("Pack with id {} not found in DB", packId);
 			return Response.status(Status.NOT_FOUND).build();
 		}
-		return Response.ok(lt).build();
+		if (bsc.isUserInRole(BasicSecurityContext.ROL_ADVANCE)) {
+			if (bsc.getOrganizationsIds() == null || !bsc.getOrganizationsIds().contains(pack.getOrgId())) {
+				return generateErrorUnathorizedAccess(pack, bsc.getUserPrincipal());
+			}
+		}
+		return Response.ok(pack).build();
 	}
 
 	@POST
 	@Path("/")
+	@Securable
+	@RolesAllowed(BasicSecurityContext.ROL_ADMIN)
 	@Consumes(MediaType.APPLICATION_JSON)
 	@Produces(
 		{ MediaType.APPLICATION_JSON })
@@ -112,21 +140,12 @@
 		return Response.ok(pack).build();
 	}
 
-	private User getUser(String username, EntityManager em) throws CurisException {
-		User user = null;
-		if (username != null) {
-			user = em.find(User.class, username);
-			if (user == null) {
-				throw new CurisException("User not found");
-			}
-		}
-		return user;
-	}
-
 	@PUT
 	@POST
 	@Path("/{packId}")
 	@Transactional
+	@Securable
+	@RolesAllowed(BasicSecurityContext.ROL_ADMIN)
 	@Consumes(MediaType.APPLICATION_JSON)
 	@Produces(
 		{ MediaType.APPLICATION_JSON })
@@ -141,6 +160,8 @@
 
 	@DELETE
 	@Path("/{packId}")
+	@Securable
+	@RolesAllowed(BasicSecurityContext.ROL_ADMIN)
 	@Transactional
 	@Produces(
 		{ MediaType.APPLICATION_JSON })
diff --git a/securis/src/main/resources/db/schema.sql b/securis/src/main/resources/db/schema.sql
index ee3bda6..813b45a 100644
--- a/securis/src/main/resources/db/schema.sql
+++ b/securis/src/main/resources/db/schema.sql
@@ -55,9 +55,10 @@
   
 drop table IF EXISTS pack;
 CREATE  TABLE IF NOT EXISTS pack (
-  id INT NOT NULL,
+  id INT NOT NULL auto_increment,
   code VARCHAR(50) NOT NULL ,
   num_licenses INT NOT NULL ,
+  comments VARCHAR(1024) NULL ,
   license_type_id INT NOT NULL,  
   organization_id INT NOT NULL,  
   created_by varchar(45) NULL ,  
@@ -66,13 +67,14 @@
   
 drop table IF EXISTS license;
 CREATE TABLE IF NOT EXISTS license (
-  id INT NOT NULL,
+  id INT NOT NULL auto_increment,
   code VARCHAR(100) NOT NULL ,
   request_data VARCHAR(1024) NULL ,
   license_data VARCHAR(1024) NULL ,
   pack_id INT NOT NULL,  
   full_name VARCHAR(150) NULL,  
   email VARCHAR(100)  NOT NULL,  
+  comments VARCHAR(1024) NULL ,
   creation_timestamp DATETIME NOT NULL ,  
   send_timestamp DATETIME NULL ,  
   modification_timestamp DATETIME NULL ,  
diff --git a/securis/src/main/resources/static/js/admin.js b/securis/src/main/resources/static/js/admin.js
index fc1857a..a9850fe 100644
--- a/securis/src/main/resources/static/js/admin.js
+++ b/securis/src/main/resources/static/js/admin.js
@@ -4,7 +4,8 @@
 	var app = angular.module('securis');
 	
 	var HTTP_ERRORS = {
-			403: "Forbidden action",
+            401: "Unathorized action",
+            403: "Forbidden action",
 			500: "Server error",
 			404: "Element not found"
 	}
@@ -99,8 +100,8 @@
 
 			} ]);
 
-	app.controller('CatalogFormCtrl', [ '$scope', '$http', 'toaster', 'Catalogs',
-			function($scope, $http, toaster, Catalogs) {
+	app.controller('CatalogFormCtrl', [ '$scope', '$http', 'toaster', 'Catalogs', '$L',
+			function($scope, $http, toaster, Catalogs, $L) {
 				$scope.scope = $scope;
 				console.log('Form: currentCatalog:' + $scope.cataLogIndex);
 				
diff --git a/securis/src/main/resources/static/js/catalogs.js b/securis/src/main/resources/static/js/catalogs.js
index 7dc6614..5f244ac 100644
--- a/securis/src/main/resources/static/js/catalogs.js
+++ b/securis/src/main/resources/static/js/catalogs.js
@@ -2,8 +2,8 @@
 	'use strict';
 
 	/*
-	 * Catalogs module
-	 */
+     * Catalogs module
+     */
 
 	angular
 			.module('catalogs', [ 'ngResource' ])
@@ -44,6 +44,12 @@
 											})
 								}
 								this.init = function() {
+								    if (_metadata) {
+								        console.debug('Catalogs already initilizated');
+								        var defer = $q.defer();
+								        defer.resolve(_metadata);
+								        return defer.promise;
+								    }
 									return _list();
 								}
 								this.getList = function() {
@@ -59,7 +65,7 @@
 									if (res === undefined)
 										return _current ? resources[_current.resource]
 												: null;
-									return _current ? resources[res] : null;
+									return resources[res];
 								}
 								this.getPk = function(catalogMetadata) {
 									if (!catalogMetadata)
@@ -72,14 +78,14 @@
 									return null;
 								}
 								/**
-								 * Returns catalog metadata
-								 * 
-								 * @param index:
-								 *            Return current catalog if
-								 *            undefined, if string It find the
-								 *            catalog by resoource name if
-								 *            number it find it by position
-								 */
+                                 * Returns catalog metadata
+                                 * 
+                                 * @param index:
+                                 *            Return current catalog if
+                                 *            undefined, if string It find the
+                                 *            catalog by resoource name if
+                                 *            number it find it by position
+                                 */
 								this.getMetadata = function(index) {
 									if (!_metadata)
 										throw new Error(
@@ -105,14 +111,14 @@
 										_current = _metadata[index];
 								}
 								/***********************************************
-								 * Catalog fields methods *
-								 **********************************************/
+                                 * Catalog fields methods *
+                                 **********************************************/
 
 								/**
-								 * Returns the first field in form that should
-								 * get the focus. We find the first field that
-								 * is not read only
-								 */
+                                 * Returns the first field in form that should
+                                 * get the focus. We find the first field that
+                                 * is not read only
+                                 */
 								this.getFFF = this.getFirstFocusableField = function() {
 									if (!_current)
 										throw new Error(
@@ -126,16 +132,17 @@
 								}
 
 								/**
-								 * Find the field by name or position
-								 */
-								this.getField = function(key) {
-									if (!_current)
+                                 * Find the field by name or position
+                                 */
+								this.getField = function(key, catalog) {
+									catalog = catalog || _current;
+									if (!catalog)
 										throw new Error(
 												'There is no current catalog selected');
 									var index = -1;
 									if (typeof key === 'string') {
-										for (var i = _current.fields.length - 1; i >= 0
-												&& _current.fields[i].name !== key; i--)
+										for (var i = catalog.fields.length - 1; i >= 0
+												&& catalog.fields[i].name !== key; i--)
 											;
 										index = i;
 									} else {
@@ -144,12 +151,12 @@
 									}
 
 									return index === -1 ? {}
-											: _current.fields[index];
+											: catalog.fields[index];
 								}
 
 								/***********************************************
-								 * Catalog resource operations on server *
-								 **********************************************/
+                                 * Catalog resource operations on server *
+                                 **********************************************/
 
 								function _success(response) {
 									console.log('$resource')
@@ -214,16 +221,18 @@
 										refs[field.name] = comboData;
 									})
 								}
-								this.loadRefs = function(refs) {
-									if (!_current)
-										throw new Error(
-												'There is no current catalog selected');
-									var refsFields = [];
-									_current.fields.forEach(function(f) {
-										if (f.resource)
-											refsFields.push(f)
-
-									});
+								this.loadRefs = function(refs, refsFields) {
+									if (!refsFields || refsFields.length === 0) {
+										if (!_current)
+											throw new Error(
+													'There is no current catalog selected');
+										refsFields = [];
+										_current.fields.forEach(function(f) {
+											if (f.resource)
+												refsFields.push(f)
+	
+										});
+									}
 
 									var that = this;
 									var promises = []
@@ -238,56 +247,38 @@
 									console.log('promises: ' + promises.length
 											+ ' ')
 									console.log(promises)
-									$q
-											.all(promises)
-											.then(
-													function() {
-
-														for ( var k in refs) {
-															var field = that
-																	.getField(k);
-															var pk = that
-																	.getPk(that
-																			.getMetadata(field.resource))
-															console
-																	.log('PK field for '
-																			+ k
-																			+ ' is '
-																			+ pk)
-															var comboData = []
-															refs[k]
-																	.forEach(function(
-																			row) {
-																		console
-																				.log('field.resource !== _current.resource: '
-																						+ field.resource
-																						+ ' '
-																						+ _current.resource)
-																		comboData
-																				.push({
-																					id : row[pk],
-																					label : row.label
-																							|| row.name
-																							|| row.code
-																							|| row.first_name
-																							+ ' '
-																							+ (row.last_name || '')
-																				});
-																	})
-															refs[k] = comboData;
-															console
-																	.log('Ready for combo for '
-																			+ k)
-															console
-																	.log(comboData);
-														}
-														_current.fields
-																.forEach(function(
-																		f) {
-																	if (f.values)
-																		refs[f.name] = f.values;
-																});
-													})
+									$q.all(promises)
+									  .then(function() {
+											    for(var i in refsFields) {
+												//for ( var k in refs) {
+											        var rf = refsFields[i];
+													var cat = that.getResource(rf.resource);
+													var pk = that.getPk(that.getMetadata(rf.resource))
+													console.log('PK field for '
+																	+ rf.name
+																	+ ' is '
+																	+ pk)
+													var comboData = []
+													refs[rf.name].forEach(function(row) {
+																comboData.push({
+																			id : row[pk],
+																			label : row.label
+																					|| row.name
+																					|| row.code
+																					|| row.first_name
+																					+ ' '
+																					+ (row.last_name || '')
+																		});
+															})
+													refs[rf.name] = comboData;
+													console.log('Ready for combo for ' + rf.name)
+													console.log(comboData);
+												}
+											    _current && _current.fields.forEach(function(f) {
+															if (f.values)
+																refs[f.name] = f.values;
+														});
+											})
 
 									console.log(refs);
 									return refs;
diff --git a/securis/src/main/resources/static/js/licenses.js b/securis/src/main/resources/static/js/licenses.js
index 3db4b48..73648ee 100644
--- a/securis/src/main/resources/static/js/licenses.js
+++ b/securis/src/main/resources/static/js/licenses.js
@@ -1,92 +1,160 @@
 (function() {
 	'use strict';
 
+	   var HTTP_ERRORS = {
+	            401: "Unathorized action",
+	            403: "Forbidden action",
+	            500: "Server error",
+	            404: "Element not found"
+	    }
+
 	var app = angular.module('securis');
+
+	app.controller('PackAndLicensesCtrl', [
+	                    			'$scope',
+	                    			'$http',
+	                    			'toaster',
+	                    			'$store',
+	                    			'$L',
+	   			function($scope, $http, toaster, $store, $L) {
+	                    				$scope.licenses = [
+	                    					                {id: 1,
+	                    					                	"code": "BP-SA-001-AKSJMS234",
+	                    					                	"user_fullname": "Johnny Belmonte",
+	                    					                	"user_email": "jb@curisit.net",
+	                    					                	"status": 3},
+	                    						                {id: 2,
+	                    						                	"code": "BP-SA-001-KAJSDHAJS",
+	                    						                	"user_fullname": "Walter Simons",
+	                    						                	"user_email": "ws@curisit.net",
+	                    						                	"status": 1},
+	                    						                {id: 3,
+	                    						                	"code": "BP-SA-001-ASKDGHKA",
+	                    						                	"user_fullname": "Frank Belmonte",
+	                    						                	"user_email": "fb@curisit.net",
+	                    						                	"status": 2},
+	                    							                {id: 4,
+	                    							                	"code": "BP-SA-001-BBBGGGG",
+	                    							                	"user_fullname": "John Dalton",
+	                    							                	"user_email": "jd@curisit.net",
+	                    							                	"status": 3},
+	                    							                {id: 5,
+	                    							                	"code": "BP-SA-001-AKADNAJANA",
+	                    							                	"user_fullname": "Walter Martins",
+	                    							                	"user_email": "wm@curisit.net",
+	                    							                	"status": 3},
+	                    							                {id: 6,
+	                    							                	"code": "BP-SA-001-AKANDAKS",
+	                    							                	"user_fullname": "Joe Bolton",
+	                    							                	"user_email": "jbol@curisit.net",
+	                    							                	"status": 2}
+	                    					                ];
+	                    					
+        				$scope.maxLengthErrorMsg = function(displayname, fieldMaxlength) {
+        					return $L.get("{0} length is too long (max: {1}).", $L.get(displayname), fieldMaxlength);
+        				}
+        				$scope.mandatoryFieldErrorMsg = function(displayname) {
+        					return $L.get("'{0}' is required.", $L.get(displayname));
+        				}
+        				$scope.ellipsis = function(txt, len) {
+        					if (!txt || txt.length <= len) return txt;
+        					return txt.substring(0, len) + '...';
+        				}
+                        $scope.currentPackId = $store.get('currentPackId');
+
+	   			}]);
 	
-	app.controller('LicensesCtrl', [
+	app.controller('PacksCtrl', [
 			'$scope',
 			'$http',
+			'$resource',
 			'toaster',
 			'Catalogs',
 			'$store',
 			'$L',
-			function($scope, $http, toaster, Catalogs, $store, $L) {
-				$scope.currentPack = $store.get('currentPack');
-				$scope.packs = [
-				                {id: 1,
-				                	"organization_name": "BP-Spain",
-				                	"application_name": "CurisIntegrity",
-				                	"licensetype_code": "CIBS",
-				                	"code": "BP-SA-0001",
-				                	"licenses": 50,
-				                	"lic_available": 23},
-				                {id: 2,
-				                	"organization_name": "Exxon",
-				                	"application_name": "CurisData",
-				                	"licensetype_code": "CDL1",
-				                	"code": "EX-SA-0001",
-				                	"licenses": 1,
-				                	"lic_available": 0},
-				                {id: 3,
-				                	"organization_name": "Repsol S.A. empresa con nombre muy largo",
-				                	"application_name": "CurisData",
-				                	"licensetype_code": "CDL2",
-				                	"code": "RE-SA-0001",
-				                	"licenses": 5,
-				                	"lic_available": 2},
-				                {id: 4,
-				                	"organization_name": "BP-Spain",
-				                	"application_name": "CurisIntegrity v3.0",
-				                	"code": "BP-SA-0002",
-				                	"licensetype_code": "CISA",
-				                	"licenses": 150,
-				                	"lic_available": 13},
-				                ];
+			function($scope, $http, $resource, toaster, Catalogs, $store, $L) {
+				var packResource = $resource('/pack/:packId', {
+					packId : '@id'
+				});
+				$scope.mandatory = {
+						code: true,
+						num_licenses: true,
+						organization_id: true,
+						license_type_id: true
+				}
+				$scope.maxlength = {
+						code: 50,
+						comments: 1024
+				}
+				$scope.refs = {};
+                Catalogs.init().then(function() {
+                    Catalogs.loadRefs($scope.refs, [{resource: 'organization', name: 'organization_id'},{resource: 'licensetype', name: 'license_type_id'}])
+                }); 
 
-				$scope.licenses = [
-				                {id: 1,
-				                	"code": "BP-SA-001-AKSJMS234",
-				                	"user_fullname": "Johnny Belmonte",
-				                	"user_email": "jb@curisit.net",
-				                	"status": 3},
-					                {id: 2,
-					                	"code": "BP-SA-001-KAJSDHAJS",
-					                	"user_fullname": "Walter Simons",
-					                	"user_email": "ws@curisit.net",
-					                	"status": 1},
-					                {id: 3,
-					                	"code": "BP-SA-001-ASKDGHKA",
-					                	"user_fullname": "Frank Belmonte",
-					                	"user_email": "fb@curisit.net",
-					                	"status": 2},
-						                {id: 4,
-						                	"code": "BP-SA-001-BBBGGGG",
-						                	"user_fullname": "John Dalton",
-						                	"user_email": "jd@curisit.net",
-						                	"status": 3},
-						                {id: 5,
-						                	"code": "BP-SA-001-AKADNAJANA",
-						                	"user_fullname": "Walter Martins",
-						                	"user_email": "wm@curisit.net",
-						                	"status": 3},
-						                {id: 6,
-						                	"code": "BP-SA-001-AKANDAKS",
-						                	"user_fullname": "Joe Bolton",
-						                	"user_email": "jbol@curisit.net",
-						                	"status": 2}
-				                ];
-				
+				// Used to create the form with the appropriate data
+				$scope.isNew = undefined;
 
+				// Selected pack from listing
+				// pack is the edited pack, in creation contains the data for the new pack
+				$scope.pack = null;
+
+				$scope.packs = packResource.query();
 				
-				$scope.ellipsis = function(txt, len) {
-					if (!txt || txt.length <= len) return txt;
-					return txt.substring(0, len) + '...';
+				$scope.save = function() {
+					var _success = function() {
+						$scope.packs = packResource.query();
+					}
+					packResource.save($scope.pack, _success)
 				}
 				
-				$scope.selectPack = function(pack) {
-					console.log('Pack selected: ' + JSON.stringify(pack));
-					$scope.currentPack = pack;
-					$store.put('currentPack', pack);
+				$scope.newPack = function() {
+					$scope.isNew = true;
+					$scope.showForm = true;
+					$scope.pack = {
+					        num_licenses: 1,
+                            license_type_id: !$scope.refs.license_type_id || !$scope.refs.license_type_id.length ? null : $scope.refs.license_type_id[0].id,
+                            organization_id: !$scope.refs.organization_id || !$scope.refs.organization_id.length ? null : $scope.refs.organization_id[0].id
+					}
+                   setTimeout(function() {
+                        $('#code').focus();
+                    }, 0);
+				}
+
+                $scope.editPack = function(selectedPack) {
+                    $scope.isNew = false;
+                    $scope.showForm = true;
+                    $scope.pack = selectedPack;
+                   setTimeout(function() {
+                        $('#code').focus();
+                    }, 0);
+                }
+
+                $scope.deletePack = function(selectedPack) {
+                    $scope.showForm = false;
+                    BootstrapDialog.confirm($L.get("The pack '{0}' will be deleted, are you sure?", selectedPack.code), function(result){
+                        if(result) {
+                            var promise = packResource.remove({}, {id: selectedPack.id}).$promise;
+                            promise.then(function(data) {
+                                $scope.selectPack(null);
+                                $scope.packs = packResource.query();
+                                toaster.pop('success', Catalogs.getName(), $L.get("Pack '{0}' deleted successfully", selectedPack.code));
+                            },function(error) {
+                                console.log(error);
+                                toaster.pop('error', Catalogs.getName(), $L.get("Error deleting pack, reason: {0}. Details: {1}", $L.get(HTTP_ERRORS[error.status]), error.headers('X-SECURIS-ERROR')), 10000);
+                            });
+                        }
+                    });
+                    $scope.isNew = false;
+                }
+
+
+                $scope.cancel = function() {
+                    $scope.showForm = false;
+                }
+
+				$scope.selectPack = function(packId) {
+					$scope.$parent.currentPackId = packId;
+					$store.put('currentPackId', packId);
 				}
 				
 			} ]);
diff --git a/securis/src/main/resources/static/js/main.js b/securis/src/main/resources/static/js/main.js
index 58a7a9b..9a13354 100644
--- a/securis/src/main/resources/static/js/main.js
+++ b/securis/src/main/resources/static/js/main.js
@@ -53,7 +53,7 @@
 		    });
 		    $routeProvider.when('/licenses', {
 			      templateUrl: 'licenses.html',
-			      controller: 'LicensesCtrl'
+			      controller: 'PackAndLicensesCtrl'
 		    });
 		    $routeProvider.when('/admin', {
 			      templateUrl: 'admin.html',
diff --git a/securis/src/main/resources/static/licenses.html b/securis/src/main/resources/static/licenses.html
index 53e911a..63b5b2a 100644
--- a/securis/src/main/resources/static/licenses.html
+++ b/securis/src/main/resources/static/licenses.html
@@ -3,7 +3,7 @@
 
 	<div class="container">
 		<div class="col-md-12">&nbsp;</div>
-		<div id="packs_section" class="col-md-6">
+		<div id="packs_section" class="col-md-6" ng-controller="PacksCtrl">
 						<nav class="navbar navbar-default navbar-static-top">
 					<!-- Brand and toggle get grouped for better mobile display -->
 					<div class="navbar-header">
@@ -14,7 +14,7 @@
 					<div class="collapse navbar-collapse"
 						id="bs-example-navbar-collapse-1">
 						<ul class="nav navbar-nav">
-							<li><a i18n ng-click="editNew()"><span class="glyphicon glyphicon-plus"></span>
+							<li><a i18n ng-click="newPack()"><span class="glyphicon glyphicon-plus"></span>
 									New</a></li>
 							<li><a i18n ng-click="cancel()"> <span
 									class="glyphicon glyphicon-ban-circle"></span> Cancel
@@ -23,12 +23,112 @@
 						<div class="navbar-form navbar-right">
 						<div class="input-group input-group-sm">
 						  	<span class="input-group-addon glyphicon glyphicon-search" style="top: 0px;"></span>
-						  <input type="text" class="form-control" placeholder="Search" ng-model="$parent.searchText" >
-								<span class="btn input-group-addon glyphicon glyphicon-remove" ng-click="$parent.searchText = ''" style="top: 0px;"></span>
+						  <input type="text" class="form-control" placeholder="Search" ng-model="searchText" >
+								<span class="btn input-group-addon glyphicon glyphicon-remove" ng-click="searchText = ''" style="top: 0px;"></span>
 						</div>
 						</div>
 					</div>
 				</nav>
+
+				<div class="panel panel-default animate-show ng-hide" ng-show="showForm">
+					<form role="form" class="form-horizontal " name="packForm" id="packForm" ng-submit="save()" >
+						<div class="form-group" ng-if="!isNew">
+							<label class="col-md-3 control-label" >ID</label>
+							<div class="col-md-8">
+								<p class="form-control-static" ng-bind="pack.id"></p>
+							</div>
+						</div>
+						<div class="form-group" >
+							<label class="col-md-3 control-label" for="code" i18n>Code</label>
+							<div class="col-md-8">
+								<input type="string" id="code" name="code" placeholder="" class="form-control" ng-model="pack.code" ng-required="mandatory.code" ng-maxlength="{{maxlength.code}}" />
+							<div class="alert inline-alert alert-warning" ng-show="packForm.code.$invalid">
+							    <span class="glyphicon glyphicon-warning-sign"></span>
+							    <span ng-show="packForm.code.$error.maxlength" ng-bind="maxlengthErrorMsg('Code', maxlength.code)"></span>
+							    <span ng-show="packForm.code.$error.required" ng-bind="mandatoryFieldErrorMsg('Code')"></span>
+							</div>
+							</div>
+						</div>
+
+						<div class="form-group" >
+							<label class="col-md-3 control-label" for="num_licenses" i18n>Num. Licenses</label>
+							<div class="col-md-8">
+									<input type="number" id="num_licenses" name="num_licenses" placeholder="" class="form-control" ng-model="pack.num_licenses" ng-required="mandatory.num_licenses"  />
+							<div class="alert inline-alert alert-warning" ng-show="packForm.num_licenses.$invalid">
+							    <span class="glyphicon glyphicon-warning-sign"></span>
+							    <span ng-show="packForm.num_licenses.$error.maxlength" ng-bind="maxlengthErrorMsg('Num. Licenses', maxlength.num_licenses)"></span>
+							    <span ng-show="packForm.num_licenses.$error.required" ng-bind="mandatoryFieldErrorMsg('Num. Licenses')"></span>
+							</div>
+							</div>
+						</div>
+
+						<div class="form-group" >
+							<label class="col-md-3 control-label" for="license_type_id" i18n>License type</label>
+							<div class="col-md-8">
+									<select class="form-control" ng-required="mandatory.license_type_id" ng-model="pack.license_type_id"
+										ng-options="o.id as o.label for o in refs.license_type_id" >
+										<option selected="true" ng-if="!mandatory.license_type_id" value=""></option>
+									</select>
+							<div class="alert inline-alert alert-warning" ng-show="packForm.license_type_id.$invalid">
+							    <span class="glyphicon glyphicon-warning-sign"></span>
+							    <span ng-show="packForm.license_type_id.$error.required" ng-bind="mandatoryFieldErrorMsg('License type')"></span>
+							</div>
+							</div>
+						</div>
+
+						<div class="form-group" >
+							<label class="col-md-3 control-label" for="organization_id" i18n>Organization</label>
+							<div class="col-md-8">
+									<select class="form-control" ng-required="field.mandatory" ng-model="pack.organization_id"
+										ng-options="o.id as o.label for o in refs.organization_id" >
+										<option selected="true" ng-if="!mandatory.organization_id" value=""></option>
+									</select>
+							<div class="alert inline-alert alert-warning" ng-show="packForm.organization_id.$invalid">
+							    <span class="glyphicon glyphicon-warning-sign"></span>
+							    <span ng-show="packForm.organization_id.$error.required" ng-bind="mandatoryFieldErrorMsg('Organization')"></span>
+							</div>
+							</div>
+						</div>
+
+
+						<div class="form-group" >
+							<label class="col-md-3 control-label" for="comments" i18n>Comments</label>
+							<div class="col-md-8">
+								<textarea type="string" id="comments" name="comments" placeholder=""
+										class="form-control" ng-model="pack.comments" rows="2" ng-required="mandatory.comments" ng-maxlength="{{maxlength.comments}}"></textarea>
+							<div class="alert inline-alert alert-warning" ng-show="packForm.comments.$invalid">
+							    <span class="glyphicon glyphicon-warning-sign"></span>
+							    <span ng-show="packForm.comments.$error.maxlength" ng-bind="maxlengthErrorMsg('Comments', maxlength.comments)"></span>
+							    <span ng-show="packForm.comments.$error.required" ng-bind="mandatoryFieldErrorMsg('comments')"></span>
+							</div>
+							</div>
+						</div>
+
+						<div class="form-group" ng-if="!isNew">
+							<label class="col-md-3 control-label" >Created by</label>
+							<div class="col-md-8">
+								<p class="form-control-static" ng-bind="pack.created_by_name"></p>
+							</div>
+						</div>
+
+						<div class="form-group" ng-if="!isNew">
+							<label class="col-md-3 control-label" >Creation date</label>
+							<div class="col-md-8">
+								<p class="form-control-static" ng-bind="pack.creationTimestamp | date:'medium'"></p>
+							</div>
+						</div>
+									
+						<div class="form-group">
+							<div class="col-md-offset-3 col-md-10" id="saveContainer">
+								<button id="save" type="submit" class="btn btn-primary" >
+									<span i18n class="glyphicon glyphicon-floppy-disk"></span> Save
+								</button>
+							</div>
+						</div>
+					</form>
+				</div>
+
+
 			<div class="panel panel-default" >
 				<div class="panel-heading">
 					Packs <span class="badge pull-right" ng-bind="packs.length || 0"></span>
@@ -37,22 +137,22 @@
 				<table class="table table-hover table-condensed">
 					<thead>
 						<tr>
+							<th i18n >Code</th>
 							<th i18n >Organization</th>
 							<th i18n >Application</th>
-							<th i18n >Code</th>
 							<th i18n >Licenses</th>
 							<th></th>
 						</tr>
 					</thead>
 					<tbody>
-						<tr ng-repeat="pack in packs | filter:searchText" ng-dblclick="editPack(row)" ng-class="{success: currentPack.id === pack.id}" ng-click="selectPack(pack)">
-						    <td ng-bind="ellipsis(pack.organization_name, 20)" title="{{pack.organization_name}}" ></td>
-						    <td ng-bind="pack.application_name"></td>
-						    <td style="white-space: nowrap;" ng-bind="pack.code"></td>
-						    <td title="Total: {{pack.licenses}}, avaliable: {{pack.lic_available}}">{{pack.licenses}} ({{pack.lic_available}})</td>
-							<td><span ng-click="editPack(row)"
+						<tr ng-repeat="p in packs | filter:searchText" ng-dblclick="editPack(p)" ng-class="{success: currentPackId === p.id}" ng-click="selectPack(p.id)">
+						    <td style="white-space: nowrap;" ng-bind="p.code"></td>
+						    <td ng-bind="ellipsis(p.organization_name, 20)" title="{{pack.organization_name}}" ></td>
+						    <td ng-bind="p.application_name"></td>
+						    <td title="Total: {{p.num_licenses}}, available: {{p.num_available}}">{{p.num_licenses}} ({{p.num_available}})</td>
+							<td><span ng-click="editPack(p)"
 								class="glyphicon glyphicon-pencil"></span>
-								<span ng-click="deletePack(row)"
+								<span ng-click="deletePack(p)"
 								class="glyphicon glyphicon-remove"></span>
 								</td>
 						</tr>
@@ -61,11 +161,11 @@
 					</tfoot>
 				</table>
 			</div>
-		
+			
 		</div>
 
 		<div id="licenses_section" class="col-md-6" >
-				<nav class="navbar navbar-default navbar-static-top" ng-disabled="!!currentPack">
+				<nav class="navbar navbar-default navbar-static-top" ng-disabled="currentPackId === null">
 					<!-- Brand and toggle get grouped for better mobile display -->
 					<div class="navbar-header success">
 						<a class="navbar-brand" i18n>Licenses</a>
@@ -91,12 +191,12 @@
 					</div>
 				</nav>
 				
-				<div ng-if="!currentPack" class="well well-lg">
+				<div ng-if="currentPackId === null" class="well well-lg">
 			      <h4 i18n>No pack selected</h4>
 			      <p i18n>Please, select a pack to manage its licenses</p>
 			    </div>
 
-				<div class="panel panel-default" ng-if="currentPack">
+				<div class="panel panel-default" ng-if="currentPackId !== null">
 					<div class="panel-heading">
 						<span i18n>Licenses for pack: </span>{{currentPack.code}} 
 						<span style="color: lightgreen;" class="badge pull-right" ng-bind="currentPack.lic_available || 0"></span>

--
Gitblit v1.3.2