From cbfe9207ad7c9bba96b39c550d250d12097fd06f Mon Sep 17 00:00:00 2001
From: Roberto Sánchez <roberto.sanchez@curisit.net>
Date: Thu, 23 Jan 2014 19:21:10 +0000
Subject: [PATCH] #395 feature - Implemented license section at 75%

---
 securis/src/main/java/net/curisit/securis/db/License.java               |   39 ++++
 securis/src/main/resources/static/licenses.html                         |  196 ++++++++++++++++++++-
 securis/src/main/java/net/curisit/securis/services/LicenseResource.java |  137 ++++++++++----
 securis/src/main/resources/static/js/licenses.js                        |  128 +++++++++++++
 securis/src/main/resources/static/js/main.js                            |   31 +-
 securis/src/main/java/net/curisit/securis/services/PackResource.java    |    8 
 securis/src/main/resources/static/css/securis.css                       |    1 
 7 files changed, 463 insertions(+), 77 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 010b933..f683161 100644
--- a/securis/src/main/java/net/curisit/securis/db/License.java
+++ b/securis/src/main/java/net/curisit/securis/db/License.java
@@ -15,6 +15,7 @@
 
 import org.codehaus.jackson.annotate.JsonAutoDetect;
 import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
 import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
 
@@ -26,8 +27,9 @@
 @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
 @Entity
 @Table(name = "license")
+@JsonIgnoreProperties(ignoreUnknown = true)
 @NamedQueries(
-	{ @NamedQuery(name = "list-licenses", query = "SELECT l FROM License l") })
+	{ @NamedQuery(name = "list-licenses-by-pack", query = "SELECT l FROM License l where l.pack.id = :packId") })
 public class License implements Serializable {
 
 	private static final long serialVersionUID = 1L;
@@ -56,9 +58,18 @@
 	private int status;
 
 	@Column(name = "full_name")
+	@JsonProperty("full_name")
 	private String fullName;
 
 	private String email;
+
+	@Column(name = "request_data")
+	@JsonProperty("request_data")
+	private String requestData;
+
+	@Column(name = "license_data")
+	@JsonProperty("license_data")
+	private String licenseData;
 
 	@Column(name = "creation_timestamp")
 	private Date creationTimestamp;
@@ -77,6 +88,8 @@
 
 	@Column(name = "last_access_timestamp")
 	private Date lastAccessTimestamp;
+
+	private String comments;
 
 	public int getId() {
 		return id;
@@ -240,6 +253,30 @@
 		this.lastAccessTimestamp = lastAccessTimestamp;
 	}
 
+	public String getRequestData() {
+		return requestData;
+	}
+
+	public void setRequestData(String requestData) {
+		this.requestData = requestData;
+	}
+
+	public String getLicenseData() {
+		return licenseData;
+	}
+
+	public void setLicenseData(String licenseData) {
+		this.licenseData = licenseData;
+	}
+
+	public String getComments() {
+		return comments;
+	}
+
+	public void setComments(String comments) {
+		this.comments = comments;
+	}
+
 	public static class Status {
 		public static final int CREATED = 0;
 		public static final int SENT = 1;
diff --git a/securis/src/main/java/net/curisit/securis/services/LicenseResource.java b/securis/src/main/java/net/curisit/securis/services/LicenseResource.java
index 0722d55..005ef97 100644
--- a/securis/src/main/java/net/curisit/securis/services/LicenseResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/LicenseResource.java
@@ -7,16 +7,15 @@
 import javax.inject.Provider;
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
-import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
-import javax.ws.rs.HeaderParam;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -28,6 +27,8 @@
 import net.curisit.securis.db.License;
 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;
@@ -40,7 +41,7 @@
  * 
  * @author roberto <roberto.sanchez@curisit.net>
  */
-@Path("/organization")
+@Path("/license")
 public class LicenseResource {
 
 	private static final Logger log = LoggerFactory.getLogger(LicenseResource.class);
@@ -60,14 +61,25 @@
 	 */
 	@GET
 	@Path("/")
+	@Securable
 	@Produces(
 		{ MediaType.APPLICATION_JSON })
-	public Response index() {
+	public Response index(@QueryParam("packId") Integer packId, @Context BasicSecurityContext bsc) {
 		log.info("Getting licenses list ");
 
 		EntityManager em = emProvider.get();
-		TypedQuery<License> q = em.createNamedQuery("list-licenses-by-pack", License.class);
 
+		if (!bsc.isUserInRole(BasicSecurityContext.ROL_ADMIN)) {
+			Pack pack = em.find(Pack.class, packId);
+			if (pack == null)
+				return Response.ok().build();
+			if (!bsc.getOrganizationsIds().contains(pack.getOrganization().getId())) {
+				log.error("Pack with id {} not accesible by user {}", pack, bsc.getUserPrincipal());
+				return Response.status(Status.UNAUTHORIZED).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "Unathorized access to pack licenses").build();
+			}
+		}
+		TypedQuery<License> q = em.createNamedQuery("list-licenses-by-pack", License.class);
+		q.setParameter("packId", packId);
 		List<License> list = q.getResultList();
 
 		return Response.ok(list).build();
@@ -79,9 +91,10 @@
 	 */
 	@GET
 	@Path("/{licId}")
+	@Securable
 	@Produces(
 		{ MediaType.APPLICATION_JSON })
-	public Response get(@PathParam("licId") String licId, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
+	public Response get(@PathParam("licId") Integer licId, @Context BasicSecurityContext bsc) {
 		log.info("Getting organization data for id: {}: ", licId);
 		if (licId == null || licId.equals("")) {
 			log.error("License ID is mandatory");
@@ -89,21 +102,28 @@
 		}
 
 		EntityManager em = emProvider.get();
-		License lt = em.find(License.class, Integer.parseInt(licId));
-		if (lt == null) {
+		License lic = em.find(License.class, licId);
+		if (lic == null) {
 			log.error("License with id {} not found in DB", licId);
-			return Response.status(Status.NOT_FOUND).build();
+			return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License not found for ID: " + licId).build();
 		}
-		return Response.ok(lt).build();
+		if (!bsc.isUserInRole(BasicSecurityContext.ROL_ADMIN)) {
+			if (!bsc.getOrganizationsIds().contains(lic.getPack().getOrganization().getId())) {
+				log.error("License with id {} is not accesible by user {}", licId, bsc.getUserPrincipal());
+				return Response.status(Status.UNAUTHORIZED).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "Unathorized access to license data").build();
+			}
+		}
+		return Response.ok(lic).build();
 	}
 
 	@POST
 	@Path("/")
 	@Consumes(MediaType.APPLICATION_JSON)
+	@Securable
 	@Produces(
 		{ MediaType.APPLICATION_JSON })
 	@Transactional
-	public Response create(License lic, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
+	public Response create(License lic, @Context BasicSecurityContext bsc) {
 		log.info("Creating new organization");
 		EntityManager em = emProvider.get();
 		Pack pack = null;
@@ -112,6 +132,13 @@
 			if (pack == null) {
 				log.error("License pack with id {} not found in DB", lic.getPackId());
 				return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License's pack not found with ID: " + lic.getPackId()).build();
+			} else {
+				if (!bsc.isUserInRole(BasicSecurityContext.ROL_ADMIN)) {
+					if (!bsc.getOrganizationsIds().contains(pack.getOrganization().getId())) {
+						log.error("License for pack with id {} can not be created by user {}", pack.getId(), bsc.getUserPrincipal());
+						return Response.status(Status.UNAUTHORIZED).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "Unathorized action on pack license").build();
+					}
+				}
 			}
 		}
 
@@ -124,16 +151,11 @@
 			return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License's created by user not found with ID: " + createdByUsername).build();
 		}
 
-		try {
-			User canceledBy = getUser(lic.getCanceledById(), em);
-			lic.setCanceledBy(canceledBy);
-		} catch (CurisException ex) {
-			String canceledByUsername = lic.getCreatedById();
-			log.error("License canceled by user with id {} not found in DB", canceledByUsername);
-			return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License's canceled by user not found with ID: " + canceledByUsername).build();
-		}
-
+		// ODO: Manage status if request data is set
+		lic.setCanceledBy(null);
+		lic.setStatus(License.Status.CREATED);
 		lic.setCreationTimestamp(new Date());
+		lic.setModificationTimestamp(lic.getCreationTimestamp());
 		em.persist(lic);
 
 		return Response.ok(lic).build();
@@ -153,22 +175,30 @@
 	@PUT
 	@POST
 	@Path("/{licId}")
+	@Securable
 	@Transactional
 	@Consumes(MediaType.APPLICATION_JSON)
 	@Produces(
 		{ MediaType.APPLICATION_JSON })
-	public Response modify(License lic, @PathParam("licId") String licId, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
+	public Response modify(License lic, @PathParam("licId") Integer licId, @Context BasicSecurityContext bsc) {
 		log.info("Modifying organization with id: {}", licId);
 		EntityManager em = emProvider.get();
 
-		Pack pack = null;
-		if (lic.getPackId() != null) {
-			pack = em.find(Pack.class, lic.getPackId());
-			if (pack == null) {
-				log.error("License pack with id {} not found in DB", lic.getPackId());
-				return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License's pack not found with ID: " + lic.getPackId()).build();
-			}
-		}
+		// Pack pack = null;
+		// if (lic.getPackId() != null) {
+		// pack = em.find(Pack.class, lic.getPackId());
+		// if (pack == null) {
+		// log.error("License pack with id {} not found in DB", lic.getPackId());
+		// return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License's pack not found with ID: " + lic.getPackId()).build();
+		// } else {
+		// if (!bsc.isUserInRole(BasicSecurityContext.ROL_ADMIN)) {
+		// if (!bsc.getOrganizationsIds().contains(pack.getOrganization().getId())) {
+		// log.error("License for pack with id {} can not be modified by user {}", pack.getId(), bsc.getUserPrincipal());
+		// return Response.status(Status.UNAUTHORIZED).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "Unathorized action on pack license").build();
+		// }
+		// }
+		// }
+		// }
 		User createdBy = null;
 		try {
 			createdBy = getUser(lic.getCreatedById(), em);
@@ -186,30 +216,59 @@
 			log.error("License canceled by user with id {} not found in DB", canceledByUsername);
 			return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License's canceled by user not found with ID: " + canceledByUsername).build();
 		}
+		License currentLicense = em.find(License.class, lic.getId());
+		if (currentLicense == null) {
+			log.error("License with id {} not found in DB", licId);
+			return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License not found for ID: " + licId).build();
+		}
+		if (!bsc.isUserInRole(BasicSecurityContext.ROL_ADMIN)) {
+			if (!bsc.getOrganizationsIds().contains(lic.getPack().getOrganization().getId())) {
+				log.error("License with id {} is not accesible by user {}", licId, bsc.getUserPrincipal());
+				return Response.status(Status.UNAUTHORIZED).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "Unathorized access to license data").build();
+			}
+		}
+		// TODO: set status based in current one and dates ? use custom actions ?
+		currentLicense.setCreatedBy(createdBy);
+		currentLicense.setCanceledBy(canceledBy);
+		// currentLicense.setPack(pack);
+		currentLicense.setCode(lic.getCode());
+		currentLicense.setFullName(lic.getFullName());
+		currentLicense.setEmail(lic.getEmail());
+		currentLicense.setRequestData(lic.getRequestData());
+		currentLicense.setModificationTimestamp(new Date());
+		em.persist(currentLicense);
 
-		lic.setCreatedBy(createdBy);
-		lic.setCanceledBy(canceledBy);
-		lic.setPack(pack);
-		em.persist(lic);
-
-		return Response.ok(lic).build();
+		return Response.ok(currentLicense).build();
 	}
 
 	@DELETE
 	@Path("/{licId}")
 	@Transactional
+	@Securable
 	@Produces(
 		{ MediaType.APPLICATION_JSON })
-	public Response delete(@PathParam("licId") String licId, @Context HttpServletRequest request) {
+	public Response delete(@PathParam("licId") String licId, @Context BasicSecurityContext bsc) {
 		log.info("Deleting license with id: {}", licId);
 		EntityManager em = emProvider.get();
-		License org = em.find(License.class, Integer.parseInt(licId));
-		if (org == null) {
+		License lic = em.find(License.class, Integer.parseInt(licId));
+		if (lic == null) {
 			log.error("License with id {} can not be deleted, It was not found in DB", licId);
 			return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License was not found, ID: " + licId).build();
 		}
 
-		em.remove(org);
+		if (!bsc.isUserInRole(BasicSecurityContext.ROL_ADMIN)) {
+			if (!bsc.getOrganizationsIds().contains(lic.getPack().getOrganization().getId())) {
+				log.error("License with id {} is not accesible by user {}", licId, bsc.getUserPrincipal());
+				return Response.status(Status.UNAUTHORIZED).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "Unathorized access to license data").build();
+			}
+		}
+
+		if (lic.getStatus() != License.Status.CANCELED || lic.getStatus() != License.Status.CREATED) {
+			log.error("License {} can not be deleted with status {}", lic.getCode(), lic.getStatus());
+			return Response.status(Status.FORBIDDEN).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License can not be deleted in current status").build();
+		}
+
+		em.remove(lic);
 		return Response.ok(Utils.createMap("success", true, "id", licId)).build();
 	}
 
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 76adfa1..f22649e 100644
--- a/securis/src/main/java/net/curisit/securis/services/PackResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/PackResource.java
@@ -101,7 +101,7 @@
 	@Securable
 	@Produces(
 		{ MediaType.APPLICATION_JSON })
-	public Response get(@PathParam("packId") String packId, @Context BasicSecurityContext bsc) {
+	public Response get(@PathParam("packId") Integer packId, @Context BasicSecurityContext bsc) {
 		log.info("Getting pack data for id: {}: ", packId);
 		if (packId == null || packId.equals("")) {
 			log.error("Pack ID is mandatory");
@@ -109,7 +109,7 @@
 		}
 
 		EntityManager em = emProvider.get();
-		Pack pack = em.find(Pack.class, Integer.parseInt(packId));
+		Pack pack = em.find(Pack.class, packId);
 		if (pack == null) {
 			log.error("Pack with id {} not found in DB", packId);
 			return Response.status(Status.NOT_FOUND).build();
@@ -171,10 +171,10 @@
 	@Consumes(MediaType.APPLICATION_JSON)
 	@Produces(
 		{ MediaType.APPLICATION_JSON })
-	public Response modify(Pack pack, @PathParam("packId") String packId) {
+	public Response modify(Pack pack, @PathParam("packId") Integer packId) {
 		log.info("Modifying pack with id: {}", packId);
 		EntityManager em = emProvider.get();
-		Pack currentPack = em.find(Pack.class, Integer.parseInt(packId));
+		Pack currentPack = em.find(Pack.class, packId);
 
 		Organization org = null;
 		if (pack.getOrgId() != null) {
diff --git a/securis/src/main/resources/static/css/securis.css b/securis/src/main/resources/static/css/securis.css
index 046cea7..8410ab5 100644
--- a/securis/src/main/resources/static/css/securis.css
+++ b/securis/src/main/resources/static/css/securis.css
@@ -15,6 +15,7 @@
 	}
 }
 
+
 a {
 	cursor: default !important;
 }
diff --git a/securis/src/main/resources/static/js/licenses.js b/securis/src/main/resources/static/js/licenses.js
index 50afef0..67bf7b4 100644
--- a/securis/src/main/resources/static/js/licenses.js
+++ b/securis/src/main/resources/static/js/licenses.js
@@ -60,7 +60,7 @@
         					if (!txt || txt.length <= len) return txt;
         					return txt.substring(0, len) + '...';
         				}
-                        $scope.currentPackId = $store.get('currentPackId');
+                        $scope.currentPack = $store.get('currentPack');
 
 	   			}]);
 	
@@ -153,11 +153,131 @@
                     $scope.showForm = false;
                 }
 
-				$scope.selectPack = function(packId) {
-					$scope.$parent.currentPackId = packId;
-					$store.put('currentPackId', packId);
+				$scope.selectPack = function(pack) {
+					$scope.$parent.currentPack = pack;
+					$store.put('currentPack', pack);
+					$scope.$parent.$broadcast('pack_changed', pack);
 				}
 				
 			} ]);
 
+	   app.controller('LicensesCtrl', [
+	                                   '$scope',
+	                                   '$http',
+	                                   '$resource',
+	                                   'toaster',
+	                                   '$store',
+	                                   '$L',
+	                                   function($scope, $http, $resource, toaster, $store, $L) {
+	                                       $scope.$on('pack_changed', function(evt, message) {
+                                               $scope.licenses = licenseResource.query({packId: $scope.currentPack.id});
+	                                           console.log('on pack_changed');
+	                                           if ($scope.showForm) {
+	                                               if ($scope.isNew) {
+	                                                   $scope.license.pack_id = $scope.currentPack.id
+	                                               } else {
+	                                                   $scope.showForm = false;    
+	                                               }
+	                                           }
+	                                       })
+	                                           
+	                                       var licenseResource = $resource('/license/:licenseId', {
+	                                           licenseId : '@id'
+	                                       });
+	                                       $scope.mandatory = {
+	                                               code: true
+	                                       }
+	                                       $scope.maxlength = {
+	                                               code: 50,
+	                                               comments: 1024
+	                                       }
+	                                       $scope.refs = {};
+
+	                                       // Used to create the form with the appropriate data
+	                                       $scope.isNew = undefined;
+
+	                                       // Selected license from listing
+	                                       // license is the edited license, in creation contains the data for the new license
+	                                       $scope.license = null;
+	                                       if ($scope.currentPack)
+	                                           $scope.licenses = licenseResource.query({packId: $scope.currentPack.id});
+	                                       
+	                                       $scope.save = function() {
+	                                           var _success = function() {
+	                                               if (!$scope.isNew) $scope.showForm = false;
+	                                               $scope.licenses = licenseResource.query({packId: $scope.currentPack.id});
+	                                           }
+	                                           licenseResource.save($scope.license, _success)
+	                                       }
+	                                       
+	                                       $scope.newLicense = function() {
+	                                           if (!$scope.currentPack) {
+	                                               BootstrapDialog.show({
+	                                                   title: $L.get('New license'),
+	                                                   type: BootstrapDialog.TYPE_WARNING,
+	                                                   message: $L.get('Please, select a pack before to create a new license'),
+	                                                   buttons: [{
+	                                                       label: 'OK',
+	                                                       action: function(dialog) {
+	                                                           dialog.close();
+	                                                       }
+	                                                   }]
+	                                               });
+	                                               return;
+	                                           }
+	                                               
+	                                           $scope.isNew = true;
+	                                           $scope.showForm = true;
+	                                           $scope.license = {
+	                                                   pack_id: $scope.currentPack.id
+	                                           }
+	                                          setTimeout(function() {
+	                                               $('#licenseForm * #code').focus();
+	                                           }, 0);
+	                                       }
+
+	                                       $scope.editLicense = function(selectedlicense) {
+	                                           $scope.isNew = false;
+	                                           $scope.showForm = true;
+	                                           $scope.license = selectedlicense;
+	                                          setTimeout(function() {
+	                                               $('#licenseForm * #code').focus();
+	                                           }, 0);
+	                                       }
+
+	                                       $scope.deletelicense = function(selectedlicense) {
+	                                           $scope.showForm = false;
+	                                           BootstrapDialog.confirm($L.get("The license '{0}' will be deleted, are you sure?", selectedlicense.code), function(result){
+	                                               if(result) {
+	                                                   var promise = licenseResource.remove({}, {id: selectedlicense.id}).$promise;
+	                                                   promise.then(function(data) {
+	                                                       $scope.selectlicense(null);
+	                                                       $scope.licenses = licenseResource.query({packId: $scope.currentPack.id});
+	                                                       toaster.pop('success', Catalogs.getName(), $L.get("License '{0}' deleted successfully", selectedlicense.code));
+	                                                   },function(error) {
+	                                                       console.log(error);
+	                                                       toaster.pop('error', Catalogs.getName(), $L.get("Error deleting license, 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.showStatus = function(lic) {
+                                               
+                                           }
+                                           $scope.showStatusComplete = function(license) {
+                                               
+                                           }
+                                           $scope.isActionVisible = function(actionMask, lic) {
+                                               
+                                           }
+	                                       
+	                                   } ]);
+
 })();
diff --git a/securis/src/main/resources/static/js/main.js b/securis/src/main/resources/static/js/main.js
index 957e197..0bf562d 100644
--- a/securis/src/main/resources/static/js/main.js
+++ b/securis/src/main/resources/static/js/main.js
@@ -21,26 +21,27 @@
 		}
 	});
 	
-	m.factory('securisHttpInterceptor', function($q, $location, $store) {
+	m.factory('securisHttpInterceptor', function($q, $location, $store, toaster) {
 		var isUnauthorizedAccess = function(rejection) {
-			console.log('rejection -----------------------');
-			console.log(rejection);
 			return rejection.status === 401 /* Unauthorized */;
 		} 
 		  return {
 		      'request': function(config) {
-		          var la = $store.get('last_access');
-		          var now = new Date().getTime();
-		          if (la !== null) {
-		              if (now > (la + 1800000)) { // Session timeout is 1/2 hour
-                          $store.clear();
-                          $location.path('/login');
-                          BootstrapDialog.alert('Session has expired');
-		              } else {
-		                  console.log('Last access recent');
-		              }
-		          }
-		          $store.set('last_access', now);
+                  var token = $store.get('token');
+                  if (token) {
+                      var la = $store.get('last_access');
+    		          var now = new Date().getTime();
+    		          if (la !== null) {
+    		              if (now > (la + 1800000)) { // Session timeout is 1/2 hour
+                              $store.clear();
+                              $location.path('/login');
+                              toaster.pop('warning', 'Session has expired', null, 4000);
+    		              } else {
+    		                  console.log('Last access recent');
+    		              }
+    		          }
+    		          $store.set('last_access', now);
+                  }
 		          return config || $q.when(config);
 		      },
 		   'responseError': function(rejection) {
diff --git a/securis/src/main/resources/static/licenses.html b/securis/src/main/resources/static/licenses.html
index 63b5b2a..79de58e 100644
--- a/securis/src/main/resources/static/licenses.html
+++ b/securis/src/main/resources/static/licenses.html
@@ -145,7 +145,7 @@
 						</tr>
 					</thead>
 					<tbody>
-						<tr ng-repeat="p in packs | filter:searchText" ng-dblclick="editPack(p)" ng-class="{success: currentPackId === p.id}" ng-click="selectPack(p.id)">
+						<tr ng-repeat="p in packs | filter:searchText" ng-dblclick="editPack(p)" ng-class="{success: currentPack.id === p.id}" ng-click="selectPack(p)">
 						    <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>
@@ -164,8 +164,8 @@
 			
 		</div>
 
-		<div id="licenses_section" class="col-md-6" >
-				<nav class="navbar navbar-default navbar-static-top" ng-disabled="currentPackId === null">
+		<div id="licenses_section" class="col-md-6"  ng-controller="LicensesCtrl">
+				<nav class="navbar navbar-default navbar-static-top" ng-disabled="!currentPack">
 					<!-- Brand and toggle get grouped for better mobile display -->
 					<div class="navbar-header success">
 						<a class="navbar-brand" i18n>Licenses</a>
@@ -175,9 +175,9 @@
 					<div class="collapse navbar-collapse"
 						id="bs-example-navbar-collapse-1">
 						<ul class="nav navbar-nav">
-							<li><a i18n ng-click="editNewLicense()"><span class="glyphicon glyphicon-plus"></span>
+							<li><a i18n ng-click="newLicense()"><span class="glyphicon glyphicon-plus"></span>
 									New</a></li>
-							<li><a i18n ng-click="cancelEditionLicense()"> <span
+							<li><a i18n ng-click="cancel()"> <span
 									class="glyphicon glyphicon-ban-circle"></span> Cancel
 							</a></li>
 						</ul>
@@ -191,12 +191,179 @@
 					</div>
 				</nav>
 				
-				<div ng-if="currentPackId === null" class="well well-lg">
+				<div ng-if="!currentPack" 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="currentPackId !== null">
+				<div ng-if="currentPack" class="panel panel-default animate-show ng-hide" ng-show="showForm">
+					<form role="form" class="form-horizontal " name="licenseForm" id="licenseForm" 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="license.id"></p>
+							</div>
+						</div>
+						<div class="form-group" >
+							<label class="col-md-3 control-label" for="pack_id" i18n>Pack</label>
+							<div class="col-md-8">
+								<p class="form-control-static" ng-bind="currentPack.code"></p>
+								<input type="hidden" id="pack_id" name="pack_id" ng-model="license.pack_id"  />
+							</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="license.code" ng-required="mandatory.code" ng-maxlength="{{maxlength.code}}" />
+							<div class="alert inline-alert alert-warning" ng-show="licenseForm.code.$invalid">
+							    <span class="glyphicon glyphicon-warning-sign"></span>
+							    <span ng-show="licenseForm.code.$error.maxlength" ng-bind="maxlengthErrorMsg('Code', maxlength.code)"></span>
+							    <span ng-show="licenseForm.code.$error.required" ng-bind="mandatoryFieldErrorMsg('Code')"></span>
+							</div>
+							</div>
+						</div>
+						<div class="form-group" ng-if="!isNew">
+							<label class="col-md-3 control-label" i18n>Status</label>
+							<div class="col-md-8">
+								<p class="form-control-static" ng-bind="showStatusComplete(license)"></p>
+							</div>
+						</div>
+
+						<div class="form-group" >
+							<label class="col-md-3 control-label" for="full_name" i18n>User full name</label>
+							<div class="col-md-8">
+									<input type="string" id="full_name" name="full_name" placeholder="" class="form-control" ng-model="license.full_name" ng-required="mandatory.full_name"  />
+							<div class="alert inline-alert alert-warning" ng-show="licenseForm.full_name.$invalid">
+							    <span class="glyphicon glyphicon-warning-sign"></span>
+							    <span ng-show="licenseForm.full_name.$error.maxlength" ng-bind="maxlengthErrorMsg('User full name', maxlength.full_name)"></span>
+							    <span ng-show="licenseForm.full_name.$error.required" ng-bind="mandatoryFieldErrorMsg('User full name')"></span>
+							</div>
+							</div>
+						</div>
+
+						<div class="form-group" >
+							<label class="col-md-3 control-label" for="email" i18n>User email</label>
+							<div class="col-md-8">
+									<input type="email" id="email" name="email" placeholder="" class="form-control" ng-model="license.email" ng-required="mandatory.email"  />
+							<div class="alert inline-alert alert-warning" ng-show="licenseForm.email.$invalid">
+							    <span class="glyphicon glyphicon-warning-sign"></span>
+							    <span ng-show="licenseForm.email.$error.email" ng-bind="'Please, write a valid email address'"></span>
+							    <span ng-show="licenseForm.email.$error.maxlength" ng-bind="maxlengthErrorMsg('User email', maxlength.email)"></span>
+							    <span ng-show="licenseForm.email.$error.required" ng-bind="mandatoryFieldErrorMsg('User email')"></span>
+							</div>
+							</div>
+						</div>
+
+						<div class="form-group" ng-if="isNew || !license.request_data" >
+							<label class="col-md-3 control-label" for="request_data" i18n>Request data</label>
+							<div class="col-md-8">
+								<textarea type="string" id="request_data" name="request_data" placeholder=""
+										class="form-control" ng-model="license.request_data" rows="2" ng-required="mandatory.request_data" ng-maxlength="{{maxlength.request_data}}"></textarea>
+							<div class="alert inline-alert alert-warning" ng-show="licenseForm.request_data.$invalid">
+							    <span class="glyphicon glyphicon-warning-sign"></span>
+							    <span ng-show="licenseForm.request_data.$error.maxlength" ng-bind="maxlengthErrorMsg('Request data', maxlength.request_data)"></span>
+							    <span ng-show="licenseForm.request_data.$error.required" ng-bind="mandatoryFieldErrorMsg('Request data')"></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="license.comments" rows="2" ng-required="mandatory.comments" ng-maxlength="{{maxlength.comments}}"></textarea>
+							<div class="alert inline-alert alert-warning" ng-show="licenseForm.comments.$invalid">
+							    <span class="glyphicon glyphicon-warning-sign"></span>
+							    <span ng-show="licenseForm.comments.$error.maxlength" ng-bind="maxlengthErrorMsg('Comments', maxlength.comments)"></span>
+							    <span ng-show="licenseForm.comments.$error.required" ng-bind="mandatoryFieldErrorMsg('comments')"></span>
+							</div>
+							</div>
+						</div>
+
+						<div class="form-group" ng-if="!isNew && license.request_data">
+							<label class="col-md-3 control-label" i18n>Request data</label>
+							<div class="col-md-8">
+								<pre class="form-control-static" ng-bind="license.request_data | json"></pre>
+							</div>
+						</div>
+
+						<div class="form-group" ng-if="!isNew && license.license_data">
+							<label class="col-md-3 control-label" i18n >License file</label>
+							<div class="col-md-8">
+								<p class="form-control-static" ng-bind="license.license_data"></p>
+								<button id="downloadLicense" class="btn btn-xs btn-link" ng-click="downloadLicense(license)">
+									<span i18n class="glyphicon glyphicon-download"></span>
+								</button>
+							</div>
+						</div>
+
+						<div class="form-group" ng-if="!isNew">
+							<label class="col-md-3 control-label" i18n>Created by</label>
+							<div class="col-md-8">
+								<p class="form-control-static" ng-bind="license.created_by_name"></p>
+							</div>
+						</div>
+
+						<div class="form-group" ng-if="!isNew && license.canceled_by_name">
+							<label class="col-md-3 control-label" >Canceled by</label>
+							<div class="col-md-8">
+								<p class="form-control-static" ng-bind="license.canceled_by_name"></p>
+							</div>
+						</div>
+
+						<div class="form-group" ng-if="!isNew">
+							<label class="col-md-3 control-label" i18n>Creation date</label>
+							<div class="col-md-8">
+								<p class="form-control-static" ng-bind="license.creationTimestamp | date:'medium'"></p>
+							</div>
+						</div>
+									
+						<div class="form-group" ng-if="!isNew">
+							<label class="col-md-3 control-label" i18n >Modification date</label>
+							<div class="col-md-8">
+								<p class="form-control-static" ng-bind="license.modificationTimestamp | date:'medium'"></p>
+							</div>
+						</div>
+									
+						<div class="form-group" ng-if="!isNew && license.activationTimestamp">
+							<label class="col-md-3 control-label" i18n >Activation date</label>
+							<div class="col-md-8">
+								<p class="form-control-static" ng-bind="license.activationTimestamp | date:'medium'"></p>
+							</div>
+						</div>
+									
+						<div class="form-group" ng-if="!isNew && license.sendTimestamp">
+							<label class="col-md-3 control-label" i18n >Send date</label>
+							<div class="col-md-8">
+								<p class="form-control-static" ng-bind="license.sendTimestamp | date:'medium'"></p>
+							</div>
+						</div>
+									
+						<div class="form-group" ng-if="!isNew && license.cancelationTimestamp">
+							<label class="col-md-3 control-label" i18n >Cancelation date</label>
+							<div class="col-md-8">
+								<p class="form-control-static" ng-bind="license.cancelationTimestamp | date:'medium'"></p>
+							</div>
+						</div>
+									
+						<div class="form-group" ng-if="!isNew && license.lastAccessTimestamp">
+							<label class="col-md-3 control-label"  i18n>Last access date</label>
+							<div class="col-md-8">
+								<p class="form-control-static" ng-bind="license.lastAccessTimestamp | 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" ng-if="currentPack">
 					<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>
@@ -217,19 +384,20 @@
 					<tbody>
 						<tr ng-repeat="lic in licenses | filter:searchLicenseText" ng-dblclick="editLicense(lic)" >
 						    <td style="white-space: nowrap;" ng-bind="lic.code"></td>
-						    <td ng-bind="ellipsis(lic.user_fullname, 20)" title="{{lic.user_fullname}}" ></td>
-						    <td ng-bind="ellipsis(lic.user_email, 30)" title="{{lic.user_email}}" ></td>
-						    <td ng-bind="lic.status"></td>
+						    <td ng-bind="ellipsis(lic.full_name, 20)" title="{{lic.full_name}}" ></td>
+						    <td ng-bind="ellipsis(lic.email, 30)" title="{{lic.email}}" ></td>
+						    <td ng-bind="showStatus(lic.status)"></td>
 							<td>
 							<div class="dropdown">
 							    <a class="dropdown-toggle" data-toggle="dropdown" >
 							      <span class="glyphicon glyphicon-align-justify"></span> <span class="caret"></span>
 							    </a>
 							    <ul class="dropdown-menu">
-							      <li><a ng-click="editLicense(lic)"><span class="glyphicon glyphicon-pencil"></span> <span i18n>Edit</span></a></li>
-							      <li><a ng-click="activateLicense(lic)"><span class="glyphicon glyphicon-check"></span> <span i18n>Activate</span></a></li>
-							      <li><a ng-click="sendEmail(lic)"><span class="glyphicon glyphicon-send"></span> <span i18n>Send email</span></a></li>
-							      <li><a ng-click="editLicense(lic)"><span class="glyphicon glyphicon-remove"></span> <span i18n>Remove</span></a></li>
+							      <li ng-if="isActionVisible(1, lic)"><a ng-click="downloadLicense(lic)"><span class="glyphicon glyphicon-download"></span> <span i18n>Download</span></a></li>
+							      <li ng-if="isActionVisible(2, lic)"><a ng-click="editLicense(lic)"><span class="glyphicon glyphicon-pencil"></span> <span i18n>Edit</span></a></li>
+							      <li ng-if="isActionVisible(4, lic)"><a ng-click="activateLicense(lic)"><span class="glyphicon glyphicon-check"></span> <span i18n>Activate</span></a></li>
+							      <li ng-if="isActionVisible(8, lic)"><a ng-click="sendEmail(lic)"><span class="glyphicon glyphicon-send"></span> <span i18n>Send email</span></a></li>
+							      <li ng-if="isActionVisible(16, lic)"><a ng-click="deleteLicense(lic)"><span class="glyphicon glyphicon-remove"></span> <span i18n>Remove</span></a></li>
 							    </ul>
 							  </div>
 							</td>

--
Gitblit v1.3.2