From 85e2a65874fcd41771b30ebfff93f86edd4f32b3 Mon Sep 17 00:00:00 2001
From: rsanchez <rsanchez@curisit.net>
Date: Mon, 01 Dec 2014 14:59:34 +0000
Subject: [PATCH] #396 fix - Added automated license code generation and other minor fixes

---
 securis/src/main/java/net/curisit/securis/db/License.java                                 |   14 ++++
 securis/src/main/webapp/licenses.html                                                     |   18 +++---
 securis/src/main/webapp/login.html                                                        |    2 
 securis/src/main/java/net/curisit/securis/services/LicenseResource.java                   |   41 +++++++++----
 securis/src/main/webapp/js/licenses.js                                                    |   37 ++++++++----
 securis/src/main/java/net/curisit/securis/db/Pack.java                                    |    1 
 securis/src/main/java/net/curisit/securis/services/exception/SeCurisServiceException.java |    2 
 securis/src/main/resources/db/schema.sql                                                  |    1 
 securis/src/main/java/net/curisit/securis/services/PackResource.java                      |   56 ++++++++++++++++++
 9 files changed, 136 insertions(+), 36 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 de6973b..b8ce30f 100644
--- a/securis/src/main/java/net/curisit/securis/db/License.java
+++ b/securis/src/main/java/net/curisit/securis/db/License.java
@@ -55,6 +55,8 @@
 @Table(name = "license")
 @JsonIgnoreProperties(ignoreUnknown = true)
 @NamedQueries({
+        @NamedQuery(name = "license-by-code", query = "SELECT l FROM License l where l.code = :code"),
+        @NamedQuery(name = "last-code-suffix-used-in-pack", query = "SELECT max(l.codeSuffix) FROM License l where l.pack.id = :packId"),
         @NamedQuery(name = "list-licenses-by-pack", query = "SELECT l FROM License l where l.pack.id = :packId"),
         @NamedQuery(name = "list-licenses-by-req-data", query = "SELECT l FROM License l where l.reqDataHash = :hash"),
         @NamedQuery(name = "list-active-licenses-by-req-data", query = "SELECT l FROM License l where l.reqDataHash = :hash and l.status in ('AC', 'PA')")
@@ -70,6 +72,10 @@
     private int id;
 
     private String code;
+
+    @Column(name = "code_suffix")
+    @JsonProperty("code_suffix")
+    private Integer codeSuffix;
 
     @JsonIgnore
     @ManyToOne
@@ -372,4 +378,12 @@
         }
     }
 
+    public Integer getCodeSuffix() {
+        return codeSuffix;
+    }
+
+    public void setCodeSuffix(Integer codeSuffix) {
+        this.codeSuffix = codeSuffix;
+    }
+
 }
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 8406bff..5e44cac 100644
--- a/securis/src/main/java/net/curisit/securis/db/Pack.java
+++ b/securis/src/main/java/net/curisit/securis/db/Pack.java
@@ -42,6 +42,7 @@
 @JsonIgnoreProperties(ignoreUnknown = true)
 @NamedQueries({
         @NamedQuery(name = "list-packs", query = "SELECT pa FROM Pack pa"),//
+        @NamedQuery(name = "pack-by-code", query = "SELECT pa FROM Pack pa where pa.code = :code"),//
         @NamedQuery(name = "list-packs-by-orgs", query = "SELECT pa FROM Pack pa where pa.organization.id in :list_ids")
 })
 public class Pack implements Serializable {
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 927122e..d3165b4 100644
--- a/securis/src/main/java/net/curisit/securis/services/LicenseResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/LicenseResource.java
@@ -2,7 +2,6 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.nio.file.Files;
 import java.text.MessageFormat;
 import java.util.Date;
 import java.util.HashMap;
@@ -55,6 +54,7 @@
 import net.curisit.securis.utils.Config;
 import net.curisit.securis.utils.EmailManager;
 import net.curisit.securis.utils.JsonUtils;
+import net.curisit.securis.utils.LicUtils;
 import net.curisit.securis.utils.TokenHelper;
 
 import org.apache.commons.io.IOUtils;
@@ -320,6 +320,23 @@
         return Response.ok(lic).build();
     }
 
+    /**
+     * Check if there is some pack with the same code
+     * 
+     * @param code
+     *            Pack code
+     * @param em
+     *            DB session object
+     * @return <code>true</code> if code is already used, <code>false</code>
+     *         otherwise
+     */
+    private boolean checkIfCodeExists(String code, EntityManager em) {
+        TypedQuery<License> query = em.createNamedQuery("license-by-code", License.class);
+        query.setParameter("code", code);
+        int lics = query.getResultList().size();
+        return lics > 0;
+    }
+
     @POST
     @Path("/")
     @Consumes(MediaType.APPLICATION_JSON)
@@ -330,6 +347,14 @@
     @Transactional
     public Response create(License lic, @Context BasicSecurityContext bsc) throws SeCurisServiceException {
         EntityManager em = emProvider.get();
+
+        if (checkIfCodeExists(lic.getCode(), em)) {
+            throw new SeCurisServiceException(ErrorCodes.INVALID_DATA, "The license code is already used in an existing license");
+        }
+        if (!LicUtils.checkValidLicenseCodeCrc(lic.getCode())) {
+            throw new SeCurisServiceException(ErrorCodes.INVALID_DATA, "The license code is not valid");
+        }
+
         Pack pack = null;
         if (lic.getPackId() != null) {
             pack = em.find(Pack.class, lic.getPackId());
@@ -376,18 +401,16 @@
         } else {
             lic.setStatus(LicenseStatus.CREATED);
         }
+        lic.setCodeSuffix(LicUtils.getLicenseCodeSuffix(lic.getCode()));
         lic.setCreatedBy(createdBy);
         lic.setCreationTimestamp(new Date());
         lic.setModificationTimestamp(lic.getCreationTimestamp());
-        LOG.info("LICENSE: {}", lic);
+
         em.persist(lic);
-        LOG.info("LICENSE on HISTORY create");
         em.persist(licenseHelper.createLicenseHistoryAction(lic, createdBy, LicenseHistory.Actions.CREATE));
         if (lic.getStatus() == LicenseStatus.ACTIVE) {
-            LOG.info("LICENSE ACTIVATION on HISTORY create");
             em.persist(licenseHelper.createLicenseHistoryAction(lic, createdBy, LicenseHistory.Actions.CREATE, "Activated on creation"));
         }
-        LOG.info("LICENSE created oK ??");
 
         return Response.ok(lic).build();
     }
@@ -599,14 +622,6 @@
             throw new SeCurisServiceException(Status.UNAUTHORIZED.getStatusCode(), "Unathorized access to license data");
         }
         return lic;
-    }
-
-    public static void main(String[] args) throws IOException {
-        File f = Files.createTempDirectory("securis-server").toFile();
-
-        LOG.info("f: {}", f);
-        f = new File(f, "config-server.lic");
-        LOG.info("f: {}", f);
     }
 
     @JsonAutoDetect
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 8a29756..a584779 100644
--- a/securis/src/main/java/net/curisit/securis/services/PackResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/PackResource.java
@@ -41,6 +41,7 @@
 import net.curisit.securis.services.exception.SeCurisServiceException.ErrorCodes;
 import net.curisit.securis.services.helpers.LicenseHelper;
 import net.curisit.securis.services.helpers.UserHelper;
+import net.curisit.securis.utils.LicUtils;
 import net.curisit.securis.utils.TokenHelper;
 
 import org.apache.logging.log4j.LogManager;
@@ -147,9 +148,13 @@
         MediaType.APPLICATION_JSON
     })
     @Transactional
-    public Response create(Pack pack, @Context BasicSecurityContext bsc) {
+    public Response create(Pack pack, @Context BasicSecurityContext bsc) throws SeCurisServiceException {
         LOG.info("Creating new pack");
         EntityManager em = emProvider.get();
+
+        if (checkIfCodeExists(pack.getCode(), em)) {
+            throw new SeCurisServiceException(ErrorCodes.INVALID_DATA, "The pack code is already used in an existing pack");
+        }
 
         try {
             setPackOrganization(pack, pack.getOrgId(), em);
@@ -181,6 +186,55 @@
         return Response.ok(pack).build();
     }
 
+    /**
+     * Check if there is some pack with the same code
+     * 
+     * @param code
+     *            Pack code
+     * @param em
+     *            DB session object
+     * @return <code>true</code> if code is already used, <code>false</code>
+     *         otherwise
+     */
+    private boolean checkIfCodeExists(String code, EntityManager em) {
+        TypedQuery<Pack> query = em.createNamedQuery("pack-by-code", Pack.class);
+        query.setParameter("code", code);
+        int packs = query.getResultList().size();
+        return packs > 0;
+    }
+
+    private int getNextCodeSuffix(int packId, EntityManager em) {
+        TypedQuery<Integer> query = em.createNamedQuery("last-code-suffix-used-in-pack", Integer.class);
+        query.setParameter("packId", packId);
+        Integer lastCodeSuffix = query.getSingleResult();
+        return lastCodeSuffix == null ? 1 : lastCodeSuffix + 1;
+    }
+
+    /**
+     * 
+     * @return The next available code suffix in pack for license code
+     * @throws SeCurisServiceException
+     */
+    @GET
+    @Path("/{packId}/next_license_code")
+    @Securable
+    @Produces({
+        MediaType.TEXT_PLAIN
+    })
+    public Response getCodeSuffix(@PathParam("packId") Integer packId, @Context BasicSecurityContext bsc) throws SeCurisServiceException {
+        EntityManager em = emProvider.get();
+
+        if (packId == null) {
+            throw new SeCurisServiceException(ErrorCodes.INVALID_DATA, "The pack code is mandatory");
+        }
+        Integer codeSuffix = getNextCodeSuffix(packId, em);
+        Pack pack = em.find(Pack.class, packId);
+        ;
+
+        String licCode = LicUtils.getLicenseCode(pack.getCode(), codeSuffix);
+        return Response.ok(licCode).build();
+    }
+
     private void setPackLicenseType(Pack pack, Integer licTypeId, EntityManager em) throws SeCurisException {
         LicenseType lt = null;
         if (licTypeId != null) {
diff --git a/securis/src/main/java/net/curisit/securis/services/exception/SeCurisServiceException.java b/securis/src/main/java/net/curisit/securis/services/exception/SeCurisServiceException.java
index 9b71247..722ff47 100644
--- a/securis/src/main/java/net/curisit/securis/services/exception/SeCurisServiceException.java
+++ b/securis/src/main/java/net/curisit/securis/services/exception/SeCurisServiceException.java
@@ -40,5 +40,7 @@
         public static int INVALID_REQUEST_DATA_FORMAT = 1202;
         public static int BLOCKED_REQUEST_DATA = 1203;
         public static int DUPLICATED_REQUEST_DATA = 1204;
+
+        public static int INVALID_DATA = 1301;
     }
 }
diff --git a/securis/src/main/resources/db/schema.sql b/securis/src/main/resources/db/schema.sql
index 23d01ca..8a56b9d 100644
--- a/securis/src/main/resources/db/schema.sql
+++ b/securis/src/main/resources/db/schema.sql
@@ -104,6 +104,7 @@
 CREATE TABLE IF NOT EXISTS license (
   id INT NOT NULL auto_increment,
   code VARCHAR(100) NOT NULL ,
+  code_suffix INT NULL ,
   request_data VARCHAR(1024) NULL ,
   request_data_hash VARCHAR(64) NULL ,
   license_data VARCHAR(1024) NULL ,
diff --git a/securis/src/main/webapp/js/licenses.js b/securis/src/main/webapp/js/licenses.js
index 5df0f34..5e24c67 100644
--- a/securis/src/main/webapp/js/licenses.js
+++ b/securis/src/main/webapp/js/licenses.js
@@ -12,7 +12,7 @@
 	}
 
 	var app = angular.module('securis');
-	app.service('Packs', ['$L','$resource', 'toaster', function($L, $resource, toaster) {
+	app.service('Packs', ['$L','$resource', '$http', 'toaster', function($L, $resource, $http, toaster) {
 		var PACK_STATUS = {
 				CREATED: 'CR',
 				ACTIVE: 'AC',
@@ -117,6 +117,14 @@
 			var _error = _createErrorCallback(pack, $L.get('Put on hold'), _onerror);
 			packResource.putonhold({id: pack.id}, _success, _error);
 		}
+		this.nextliccode = function(packId, _onsuccess, _onerror) {
+			console.log('Get next code: ' + packId);
+			var _error = function(data, status, headers, config) {
+				console.log(headers);
+				toaster.pop('error', $L.get('Getting next code suffix'), $L.get("Error getting license code, pack ID: '{0}'. Reason: {1}",  packId, $L.get(headers('X-SECURIS-ERROR-MSG'))));
+			}
+			$http.get("/securis/pack/"+packId+"/next_license_code").success(_onsuccess).error(_error);
+		}
 		this.cancel = function(pack, extra_data, _onsuccess, _onerror) {
 			console.log('Cancellation on pack: ' + pack.id);
 			var _success = _createSuccessCallback($L.get('Cancellation'), $L.get("Pack '{0}' {1} successfully", pack.code, $L.get("cancelled")), _onsuccess);
@@ -133,7 +141,7 @@
 
 	}]);
 
-	app.service('Licenses', ['$L', '$resource', 'toaster', function($L, $resource, toaster) {
+	app.service('Licenses', ['$L', '$resource', 'toaster', 'Packs', function($L, $resource, toaster, Packs) {
 		var LIC_STATUS = {
 				CREATED: 'CR',
 				ACTIVE: 'AC',
@@ -225,7 +233,14 @@
 			}
 			var _error =  function(error) {
 				console.log(error);
-				toaster.pop('error', 'Licenses', $L.get("Error {0} license '{1}'. Reason: {2}", isNew ? $L.get("creating") : $L.get("updating"), license.code, $L.get(error.headers('X-SECURIS-ERROR-MSG'))));
+				toaster.pop('error', 'Licenses', $L.get("Error {0} license '{1}'. Reason: {2}", isNew ? $L.get("creating") : $L.get("updating"), license.code, $L.get(error.headers('X-SECURIS-ERROR-MSG'))), 5000);
+				if (error.headers('X-SECURIS-ERROR-CODE') === '1301') {
+					Packs.nextliccode(license.pack_id, function(data) {
+						console.log('New code: ' + data);
+						license.code = data;
+						toaster.pop('info', 'Licenses', $L.get("New license code, {0}, has been generated, please try again", license.code), 5000);
+					});
+				}
 			}
 			licenseResource.save(license, _success, _error);
 		} 
@@ -622,9 +637,10 @@
 	                                '$resource',
 	                                'toaster',
 	                                'Licenses',
+	                                'Packs',
 	                                '$store',
 	                                '$L',
-	                                function($scope, $http, $resource, toaster, Licenses, $store, $L) {
+	                                function($scope, $http, $resource, toaster, Licenses, Packs, $store, $L) {
 	                                	$scope.Licenses = Licenses;
 	                                	$scope.$on('pack_changed', function(evt, message) {
 	                                		$scope.licenses = Licenses.getLicensesList($scope.currentPack);
@@ -708,8 +724,12 @@
 	                                		$scope.license = {
 	                                				pack_id: $scope.currentPack.id
 	                                		}
+	                                		Packs.nextliccode($scope.currentPack.id, function(data) {
+	                    						console.log('New code: ' + data);
+	                    						$scope.license.code = data;
+	                    					});
 	                                		setTimeout(function() {
-	                                			$('#licenseForm * #code').focus();
+	                                			$('#licenseForm * #email').focus();
 	                                		}, 0);
 	                                	}
 
@@ -816,13 +836,6 @@
 
 	                                	$scope.cancel = function() {
 	                                		$scope.showForm = false;
-	                                	}
-
-	                                	$scope.showStatus = function(lic) {
-
-	                                	}
-	                                	$scope.showStatusLong = function(license) {
-
 	                                	}
 
 	                                } ]);
diff --git a/securis/src/main/webapp/licenses.html b/securis/src/main/webapp/licenses.html
index 425a85e..ad76d33 100644
--- a/securis/src/main/webapp/licenses.html
+++ b/securis/src/main/webapp/licenses.html
@@ -25,10 +25,10 @@
 							<div class="input-group-addon" style="width: 28px;">
 								<span class=" glyphicon glyphicon-search"></span>
 							</div> <input type="text" class="form-control" placeholder="Search"
-							ng-model="$searchPacksText">
+							ng-model="searchPackText">
 							<div class="input-group-addon" style="width: 20px;">
 								<span class=" glyphicon glyphicon-remove"
-									ng-click="$searchPacksText = '';"></span>
+									ng-click="searchPackText = '';"></span>
 							</div>
 						</span>
 					</div>
@@ -64,7 +64,7 @@
 				</div>
 
 				<div class="form-group">
-					<label class="col-md-3 control-label" for="code" i18n>Validity (from - to)</label>
+					<label class="col-md-3 control-label" for="init_valid_date" i18n>Validity (from - to)</label>
 					<div class="col-md-4">
 						<input type="date" id="init_valid_date" name="init_valid_date" placeholder=""
 							class="form-control" ng-model="pack.init_valid_date"
@@ -282,7 +282,7 @@
 					</tr>
 				</thead>
 				<tbody>
-					<tr ng-repeat="p in packs | filter:searchText"
+					<tr ng-repeat="p in packs | filter:searchPackText"
 						ng-dblclick="editPack(p)"
 						ng-class="{success: currentPack.id === p.id}"
 						ng-click="selectPack(p)">
@@ -351,10 +351,10 @@
 							<div class="input-group-addon" style="width: 28px;">
 								<span class=" glyphicon glyphicon-search"></span>
 							</div> <input type="text" class="form-control" placeholder="Search"
-							ng-model="$searchLicensesText">
+							ng-model="searchLicenseText">
 							<div class="input-group-addon" style="width: 20px;">
 								<span class=" glyphicon glyphicon-remove"
-									ng-click="$searchLicensesText = '';"></span>
+									ng-click="searchLicenseText = '';"></span>
 							</div>
 						</span>
 					</div>
@@ -389,7 +389,7 @@
 					<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"
+							class="form-control" ng-model="license.code" readonly
 							ng-required="mandatory.code" ng-maxlength="{{maxlength.code}}" />
 						<div class="alert inline-alert alert-warning"
 							ng-show="licenseForm.code.$invalid">
@@ -404,7 +404,7 @@
 				<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="showStatusLong(license)"></p>
+						<p class="form-control-static" ng-bind="license.status_name"></p>
 					</div>
 				</div>
 
@@ -625,7 +625,7 @@
 						<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 ng-bind="Licenses.getStatusName(lic.status)"></td>
 						<td>
 							<div class="dropdown">
 								<a class="dropdown-toggle" data-toggle="dropdown"> <span
diff --git a/securis/src/main/webapp/login.html b/securis/src/main/webapp/login.html
index 4b9ef09..04f6fea 100644
--- a/securis/src/main/webapp/login.html
+++ b/securis/src/main/webapp/login.html
@@ -22,7 +22,7 @@
 	<div class="jumbotron">
 		<div class="container">
 			<h2 i18n >SeCuris</h2>
-			<p i18n >Server License for CurisTEC products.</p>
+			<p i18n >Licenses Server for CurisTEC products.</p>
 		</div>
 	</div>
 

--
Gitblit v1.3.2