From 1493d0f7be4ccf14631ba3e0b31cf63ca7fcf32c Mon Sep 17 00:00:00 2001
From: rsanchez <rsanchez@curisit.net>
Date: Tue, 02 Dec 2014 17:57:50 +0000
Subject: [PATCH] #396 fix - Many issues fixed: Block/Unblock commands, Upload request data, Send second email, ...

---
 securis/src/main/java/net/curisit/securis/db/License.java               |   10 ++
 securis/src/main/webapp/licenses.html                                   |   16 +----
 securis/src/main/java/net/curisit/securis/db/LicenseStatus.java         |    2 
 securis/src/main/java/net/curisit/securis/services/LicenseResource.java |   74 ++++++++++++++----------
 securis/src/main/webapp/js/licenses.js                                  |   22 +++++--
 securis/src/main/java/net/curisit/securis/utils/EmailManager.java       |   27 +++++----
 6 files changed, 86 insertions(+), 65 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 b8ce30f..ab7064c 100644
--- a/securis/src/main/java/net/curisit/securis/db/License.java
+++ b/securis/src/main/java/net/curisit/securis/db/License.java
@@ -115,6 +115,9 @@
 
     @Column(name = "license_data")
     @JsonProperty("license_data")
+    @JsonIgnore
+    // The license data is sent to user as a separate file, It doesn't need to
+    // be included as License attribute on browser
     private String licenseData;
 
     @Column(name = "creation_timestamp")
@@ -136,6 +139,7 @@
     private String comments;
 
     @OneToMany(fetch = FetchType.LAZY, mappedBy = "license")
+    @JsonIgnore
     private List<LicenseHistory> history;
 
     public int getId() {
@@ -334,17 +338,19 @@
         public static final int CANCEL = 6;
         public static final int DELETE = 7;
         public static final int BLOCK = 8;
+        public static final int UNBLOCK = 9;
     }
 
     public static class Status {
 
         private static final Map<Integer, List<LicenseStatus>> transitions = Utils.createMap( //
                 Action.REQUEST, Arrays.asList(LicenseStatus.CREATED, LicenseStatus.REQUESTED), //
-                Action.ACTIVATION, Arrays.asList(LicenseStatus.REQUESTED, LicenseStatus.PRE_ACTIVE, LicenseStatus.EXPIRED), //
+                Action.ACTIVATION, Arrays.asList(LicenseStatus.CREATED, LicenseStatus.REQUESTED, LicenseStatus.PRE_ACTIVE, LicenseStatus.EXPIRED), //
                 Action.SEND, Arrays.asList(LicenseStatus.ACTIVE, LicenseStatus.PRE_ACTIVE), //
                 Action.DOWNLOAD, Arrays.asList(LicenseStatus.ACTIVE, LicenseStatus.PRE_ACTIVE), //
                 Action.CANCEL, Arrays.asList(LicenseStatus.ACTIVE, LicenseStatus.PRE_ACTIVE, LicenseStatus.REQUESTED, LicenseStatus.EXPIRED), //
-                Action.DELETE, Arrays.asList(LicenseStatus.CANCELLED, LicenseStatus.CREATED), //
+                Action.DELETE, Arrays.asList(LicenseStatus.CANCELLED, LicenseStatus.CREATED, LicenseStatus.BLOCKED), //
+                Action.UNBLOCK, Arrays.asList(LicenseStatus.BLOCKED), //
                 Action.BLOCK, Arrays.asList(LicenseStatus.CANCELLED) //
                 );
 
diff --git a/securis/src/main/java/net/curisit/securis/db/LicenseStatus.java b/securis/src/main/java/net/curisit/securis/db/LicenseStatus.java
index 0127145..df94ccb 100644
--- a/securis/src/main/java/net/curisit/securis/db/LicenseStatus.java
+++ b/securis/src/main/java/net/curisit/securis/db/LicenseStatus.java
@@ -12,7 +12,7 @@
  * @author rob
  */
 public enum LicenseStatus implements CodedEnum {
-    CREATED("CR"), REQUESTED("RE"), ACTIVE("AC"), PRE_ACTIVE("PA"), EXPIRED("EX"), CANCELLED("CA");
+    CREATED("CR"), REQUESTED("RE"), ACTIVE("AC"), PRE_ACTIVE("PA"), EXPIRED("EX"), CANCELLED("CA"), BLOCKED("BL");
 
     private final String code;
 
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 d3165b4..f829f34 100644
--- a/securis/src/main/java/net/curisit/securis/services/LicenseResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/LicenseResource.java
@@ -55,7 +55,6 @@
 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;
 import org.apache.commons.lang3.ObjectUtils;
@@ -77,9 +76,6 @@
 public class LicenseResource {
 
     private static final Logger LOG = LogManager.getLogger(LicenseResource.class);
-
-    @Inject
-    private TokenHelper tokenHelper;
 
     @Inject
     private EmailManager emailManager;
@@ -206,6 +202,11 @@
             throw new SeCurisServiceException(Status.FORBIDDEN.getStatusCode(), "License with id " + licId
                     + " can not be activated from the current license status");
         }
+
+        if (lic.getPack().getNumAvailables() == 0) {
+            throw new SeCurisServiceException(Status.FORBIDDEN.getStatusCode(), "The pack has not available licenses");
+        }
+
         validateRequestData(lic.getPack(), lic.getRequestData());
 
         License existingLicense = License.findLicenseByRequestData(lic.getRequestData(), em);
@@ -250,11 +251,11 @@
         Application app = lic.getPack().getLicenseType().getApplication();
         File licFile = null;
         if (lic.getLicenseData() == null) {
-            throw new SeCurisServiceException(Status.NOT_FOUND.getStatusCode(), "There is no license file available");
+            throw new SeCurisServiceException(ErrorCodes.NOT_FOUND, "There is no license file available");
         }
 
         if (lic.getFullName() == null) {
-            throw new SeCurisServiceException(Status.NOT_FOUND.getStatusCode(), "Please add an user name in license data to send it the license file");
+            throw new SeCurisServiceException(ErrorCodes.NOT_FOUND, "Please add an user name in license data to send it the license file");
         }
 
         User user = userHelper.getUser(bsc.getUserPrincipal().getName(), em);
@@ -276,7 +277,7 @@
         }
 
         // lic.setModificationTimestamp(new Date());
-        em.merge(lic);
+        // em.merge(lic);
         em.persist(licenseHelper.createLicenseHistoryAction(lic, user, LicenseHistory.Actions.SEND, "Email sent to: " + lic.getEmail()));
         return Response.ok(lic).build();
     }
@@ -384,19 +385,23 @@
                         .header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "There is already an active license for current request data")
                         .type(MediaType.APPLICATION_JSON).entity(existingLicense).build();
             }
-            SignedLicenseBean signedLicense = generateLicense(lic, em);
-            // If user provide a request data the license status is passed
-            // directly to ACTIVE
-            lic.setStatus(LicenseStatus.ACTIVE);
-            try {
-                lic.setRequestData(JsonUtils.toJSON((RequestBean) signedLicense));
-                if (BlockedRequest.isRequestBlocked(lic.getRequestData(), em)) {
-                    throw new SeCurisServiceException(ErrorCodes.BLOCKED_REQUEST_DATA, "Given request data is blocked and cannot be activated");
+
+            if (pack.getNumAvailables() > 0) {
+
+                SignedLicenseBean signedLicense = generateLicense(lic, em);
+                // If user provide a request data the license status is passed
+                // directly to ACTIVE
+                lic.setStatus(LicenseStatus.ACTIVE);
+                try {
+                    lic.setRequestData(JsonUtils.toJSON(signedLicense, RequestBean.class));
+                    if (BlockedRequest.isRequestBlocked(lic.getRequestData(), em)) {
+                        throw new SeCurisServiceException(ErrorCodes.BLOCKED_REQUEST_DATA, "Given request data is blocked and cannot be activated");
+                    }
+                    lic.setLicenseData(JsonUtils.toJSON(signedLicense));
+                } catch (SeCurisException e) {
+                    LOG.error("Error generating license JSON", e);
+                    throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Error generating license JSON");
                 }
-                lic.setLicenseData(JsonUtils.toJSON(signedLicense));
-            } catch (SeCurisException e) {
-                LOG.error("Error generating license JSON", e);
-                throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Error generating license JSON");
             }
         } else {
             lic.setStatus(LicenseStatus.CREATED);
@@ -493,14 +498,15 @@
             if (lic.getRequestData() != null) {
                 SignedLicenseBean signedLicense = generateLicense(lic, em);
                 try {
-                    // Next line is necessary to normalize the String that
+                    // Next 2 lines are necessary to normalize the String that
                     // contains
                     // the request.
-                    lic.setRequestData(JsonUtils.toJSON((RequestBean) signedLicense));
-                    if (BlockedRequest.isRequestBlocked(lic.getRequestData(), em)) {
+                    currentLicense.setRequestData(JsonUtils.toJSON(signedLicense, RequestBean.class));
+                    LOG.info("JSON generated for request: \n{}", currentLicense.getRequestData());
+                    if (BlockedRequest.isRequestBlocked(currentLicense.getRequestData(), em)) {
                         throw new SeCurisServiceException(ErrorCodes.BLOCKED_REQUEST_DATA, "Given request data is blocked and cannot be used again");
                     }
-                    lic.setLicenseData(JsonUtils.toJSON(signedLicense));
+                    currentLicense.setLicenseData(JsonUtils.toJSON(signedLicense));
                 } catch (SeCurisException e) {
                     LOG.error("Error generaing license JSON", e);
                     throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Error generaing license JSON");
@@ -534,18 +540,15 @@
             LOG.error("License {} can not be deleted with status {}", lic.getCode(), lic.getStatus());
             throw new SeCurisServiceException(ErrorCodes.WRONG_STATUS, "License can not be deleted in current status: " + lic.getStatus().name());
         }
-        if (lic.getStatus() == LicenseStatus.CANCELLED) {
+        if (lic.getStatus() == LicenseStatus.BLOCKED) {
             // If license is removed and it's blocked then the blocked request
             // should be removed, that is,
             // the license deletion will unblock the request data
-            TypedQuery<License> query = em.createNamedQuery("list-licenses-by-req-data", License.class);
-            query.setParameter("hash", lic.getReqDataHash());
-            List<License> list = query.getResultList();
-            if (list == null || list.size() == 0) {
-                BlockedRequest br = em.find(BlockedRequest.class, lic.getReqDataHash());
-                if (br != null) {
-                    em.remove(br);
-                }
+            BlockedRequest blockedReq = em.find(BlockedRequest.class, lic.getReqDataHash());
+            if (blockedReq != null) {
+                // This if is to avoid some race condition or if the request has
+                // been already removed manually
+                em.remove(blockedReq);
             }
         }
 
@@ -578,6 +581,9 @@
         blockedReq.setRequestData(lic.getRequestData());
 
         em.persist(blockedReq);
+        lic.setStatus(LicenseStatus.BLOCKED);
+        lic.setModificationTimestamp(new Date());
+        em.merge(lic);
 
         em.persist(licenseHelper.createLicenseHistoryAction(lic, userHelper.getUser(bsc, em), LicenseHistory.Actions.BLOCK));
         return Response.ok(Utils.createMap("success", true, "id", licId)).build();
@@ -598,6 +604,10 @@
         if (BlockedRequest.isRequestBlocked(lic.getRequestData(), em)) {
             BlockedRequest blockedReq = em.find(BlockedRequest.class, lic.getReqDataHash());
             em.remove(blockedReq);
+
+            lic.setStatus(LicenseStatus.CANCELLED);
+            lic.setModificationTimestamp(new Date());
+            em.merge(lic);
             em.persist(licenseHelper.createLicenseHistoryAction(lic, userHelper.getUser(bsc, em), LicenseHistory.Actions.UNBLOCK));
         } else {
             LOG.info("Request data for license {} is NOT blocked", licId);
diff --git a/securis/src/main/java/net/curisit/securis/utils/EmailManager.java b/securis/src/main/java/net/curisit/securis/utils/EmailManager.java
index e6b686a..faf2389 100644
--- a/securis/src/main/java/net/curisit/securis/utils/EmailManager.java
+++ b/securis/src/main/java/net/curisit/securis/utils/EmailManager.java
@@ -17,12 +17,15 @@
 import javax.inject.Singleton;
 
 import net.curisit.securis.SeCurisException;
+import net.curisit.securis.services.exception.SeCurisServiceException;
+import net.curisit.securis.services.exception.SeCurisServiceException.ErrorCodes;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.http.HttpResponse;
 import org.apache.http.auth.AuthScope;
 import org.apache.http.auth.UsernamePasswordCredentials;
 import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 import org.apache.http.entity.ContentType;
@@ -30,7 +33,6 @@
 import org.apache.http.entity.mime.MultipartEntityBuilder;
 import org.apache.http.entity.mime.content.FileBody;
 import org.apache.http.impl.client.BasicCredentialsProvider;
-import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.ssl.SSLContextBuilder;
 import org.apache.http.ssl.TrustStrategy;
@@ -49,7 +51,7 @@
     private static final Logger LOG = LogManager.getLogger(EmailManager.class);
 
     private final String serverUrl;
-    private final CloseableHttpClient httpClient;
+    private final HttpClientBuilder httpClientBuilder;
 
     /**
      * 
@@ -61,11 +63,11 @@
             throw new SeCurisException("Please, add '" + Config.KEYS.MAILGUN_DOMAIN + "' parameter to config file");
         }
         serverUrl = String.format("https://api.mailgun.net/v2/%s/messages", domain);
-        httpClient = createHttpClient();
+        httpClientBuilder = createHttpClient();
 
     }
 
-    private CloseableHttpClient createHttpClient() throws SeCurisException {
+    private HttpClientBuilder createHttpClient() throws SeCurisException {
         SSLContextBuilder builder = new SSLContextBuilder();
         SSLConnectionSocketFactory sslsf = null;
         try {
@@ -84,7 +86,7 @@
         UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("api", Config.get(Config.KEYS.MAILGUN_API_KEY));
         provider.setCredentials(AuthScope.ANY, credentials);
 
-        return HttpClientBuilder.create().setDefaultCredentialsProvider(provider).setSSLSocketFactory(sslsf).build();
+        return HttpClientBuilder.create().setDefaultCredentialsProvider(provider).setSSLSocketFactory(sslsf);
     }
 
     /**
@@ -98,7 +100,7 @@
      * @throws SeCurisException
      * @throws UnsupportedEncodingException
      */
-    public void sendEmail(String subject, String body, String to, String cc, File file) throws SeCurisException, UnsupportedEncodingException {
+    public void sendEmail(String subject, String body, String to, String cc, File file) throws SeCurisServiceException, UnsupportedEncodingException {
         HttpPost postRequest = new HttpPost(serverUrl);
 
         MultipartEntityBuilder builder = MultipartEntityBuilder.create();
@@ -120,6 +122,7 @@
 
         postRequest.setEntity(builder.build());
         HttpResponse response;
+        HttpClient httpClient = httpClientBuilder.build();
         try {
             response = httpClient.execute(postRequest);
 
@@ -130,11 +133,11 @@
 
                 LOG.debug("Response mail read OK: {}", responseBean);
             } else {
-                throw new SeCurisException("Error sending email, response estatus: " + response.getStatusLine());
+                throw new SeCurisServiceException(ErrorCodes.UNEXPECTED_ERROR, "Error sending email, response estatus: " + response.getStatusLine());
             }
         } catch (IOException e) {
             LOG.error("Error sending email", e);
-            throw new SeCurisException("Error sending email");
+            throw new SeCurisServiceException(ErrorCodes.UNEXPECTED_ERROR, "Error sending email");
         }
     }
 
@@ -160,8 +163,8 @@
                     EmailManager.this.sendEmail(subject, body, to, cc, file);
                     callback.success();
                 } catch (UnsupportedEncodingException e) {
-                    callback.error(new SeCurisException("Error sending email", e));
-                } catch (SeCurisException e) {
+                    callback.error(new SeCurisServiceException("Error sending email: " + e));
+                } catch (SeCurisServiceException e) {
                     callback.error(e);
                 }
 
@@ -173,7 +176,7 @@
     public static interface EmailCallback {
         public void success();
 
-        public void error(SeCurisException e);
+        public void error(SeCurisServiceException e);
     }
 
     public static void main(String[] args) throws SeCurisException, UnsupportedEncodingException {
@@ -190,7 +193,7 @@
                     }
 
                     @Override
-                    public void error(SeCurisException e) {
+                    public void error(SeCurisServiceException e) {
                         LOG.error("Error: {} !!!", e);
                     }
                 });
diff --git a/securis/src/main/webapp/js/licenses.js b/securis/src/main/webapp/js/licenses.js
index 5e24c67..4d52d25 100644
--- a/securis/src/main/webapp/js/licenses.js
+++ b/securis/src/main/webapp/js/licenses.js
@@ -148,6 +148,7 @@
 				REQUESTED: 'RE',
 				PREACTIVE: 'PA',
 				EXPIRED: 'EX',
+				BLOCKED: 'BL',
 				CANCELLED: 'CA'
 		}
 
@@ -157,6 +158,7 @@
 				'PA': $L.get('Pre-active'),
 				'RE': $L.get('Requested'),
 				'EX': $L.get('Expired'),
+				'BL': $L.get('Blocked'),
 				'CA': $L.get('Cancelled')
 		};
 
@@ -165,13 +167,14 @@
 		 * we copy them for simplicity, this info won't change easily
 		 */
 		var LIC_ACTIONS_BY_STATUS = {
+				add_request: [LIC_STATUS.CREATED],
 				activate: [LIC_STATUS.CREATED, LIC_STATUS.REQUESTED, LIC_STATUS.PREACTIVE],
 				send: [LIC_STATUS.ACTIVE, LIC_STATUS.PREACTIVE],
 				download: [LIC_STATUS.ACTIVE, LIC_STATUS.PREACTIVE],
 				block: [LIC_STATUS.CANCELLED],
-				unblock: [LIC_STATUS.CANCELLED],
+				unblock: [LIC_STATUS.BLOCKED],
 				cancel: [LIC_STATUS.REQUESTED, LIC_STATUS.EXPIRED, LIC_STATUS.PREACTIVE, LIC_STATUS.ACTIVE],
-				'delete': [LIC_STATUS.CREATED, LIC_STATUS.CANCELLED]
+				'delete': [LIC_STATUS.CREATED, LIC_STATUS.CANCELLED, LIC_STATUS.BLOCKED]
 		}
 
 		var licenseResource = $resource('license/:licenseId/:action', {
@@ -217,6 +220,7 @@
 					'AC': '#329e5a',
 					'RE': '#2981d4',
 					'EX': '#ea7824',
+					'BL': '#ff0000',
 					'CA': '#a21717'
 			};
 
@@ -236,9 +240,11 @@
 				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);
+						if (license.code !== data) {
+							// Only if the new code is different we can think about an erro related with License CODE 
+							license.code = data;
+							toaster.pop('info', 'Licenses', $L.get("New license code, {0}, has been generated, please try again", license.code), 5000);
+						} 
 					});
 				}
 			}
@@ -348,7 +354,8 @@
 							scope.$apply();
 						}
 
-						reader.readAsText(fileList[0]);       
+						reader.readAsText(fileList[0]); 
+						element.val('');
 					} else {
 						setter(scope.$parent, '');
 						scope.$apply();
@@ -383,6 +390,9 @@
 	                                    		   return txt.substring(0, len) + '...';
 	                                    	   }
 	                                    	   $scope.currentPack = $store.get('currentPack');
+	                                    	   setTimeout(function() {
+	                                    		   $scope.$broadcast('pack_changed', $scope.currentPack);
+	                                    	   }, 0);
 
 	                                       }]);
 
diff --git a/securis/src/main/webapp/licenses.html b/securis/src/main/webapp/licenses.html
index ad76d33..f641478 100644
--- a/securis/src/main/webapp/licenses.html
+++ b/securis/src/main/webapp/licenses.html
@@ -445,7 +445,7 @@
 						</div>
 					</div>
 				</div>
-				<div class="form-group" ng-if="isNew || !license.request_data">
+				<div class="form-group" >
 					<label class="col-md-3 control-label" for="request_data" i18n>Request
 						data</label>
 					<div class="col-md-7">
@@ -455,9 +455,9 @@
 							ng-maxlength="{{maxlength.request_data}}"></textarea>
 						<div class="alert inline-alert alert-warning"
 							ng-show="licenseForm.request_data.$invalid">
-							Invalid ? {{licenseForm.request_data.$invalid}}
+							<!--  Invalid ? {{licenseForm.request_data.$invalid}}
 							Error ? {{licenseForm.request_data.$error | json}}
-							Error ? {{licenseForm.request_data.$error.maxlength}}
+							Error ? {{licenseForm.request_data.$error.maxlength}} -->
 							<span class="glyphicon glyphicon-warning-sign">
 								<span
 									ng-show="licenseForm.request_data.$error.maxlength"
@@ -467,7 +467,7 @@
 							</span> 
 						</div>
 					</div>
-						<span class="btn btn-file btn-default btn-xs"> 
+						<span class="btn btn-file btn-default btn-xs" ng-if="isNew || Licenses.isActionAvailable('add_request', license)"> 
 							<span class="glyphicon glyphicon-folder-open"></span> 
 							<input file-loader="license.request_data" type="file" />
 						</span>
@@ -489,14 +489,6 @@
 							<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>
 

--
Gitblit v1.3.2