securis/src/main/java/net/curisit/securis/db/Pack.java
.. .. @@ -73,6 +73,16 @@ 73 73 @Column(name = "num_licenses") 74 74 @JsonProperty("num_licenses") 75 75 private int numLicenses; 76 +77 + @Column(name = "init_valid_date")78 + @JsonProperty("init_valid_date")79 + private Date initValidDate;80 +81 + @Column(name = "end_valid_date")82 + @JsonProperty("end_valid_date")83 + private Date endValidDate;84 +85 + private String status;76 86 77 87 @Column(name = "license_preactivation") 78 88 @JsonProperty("license_preactivation") .. .. @@ -239,7 +249,7 @@ 239 249 240 250 @JsonProperty("created_by_name") 241 251 public String getCreatedByname() { 242 - return createdBy == null ? null : String.format("%s %s (%s)", createdBy.getFirstName(), createdBy.getLastName(), createdBy.getUsername());252 + return createdBy == null ? null : String.format("%s %s (%s)", createdBy.getFirstName(), createdBy.getLastName() != null ? createdBy.getLastName() : "", createdBy.getUsername());243 253 } 244 254 245 255 @JsonProperty("licensetype_code") .. .. @@ -271,6 +281,30 @@ 271 281 this.metadata = metadata; 272 282 } 273 283 284 + public String getStatus() {285 + return status;286 + }287 +288 + public void setStatus(String status) {289 + this.status = status;290 + }291 +292 + public Date getInitValidDate() {293 + return initValidDate;294 + }295 +296 + public void setInitValidDate(Date initValidDate) {297 + this.initValidDate = initValidDate;298 + }299 +300 + public Date getEndValidDate() {301 + return endValidDate;302 + }303 +304 + public void setEndValidDate(Date endValidDate) {305 + this.endValidDate = endValidDate;306 + }307 +274 308 @Override 275 309 public boolean equals(Object obj) { 276 310 if (!(obj instanceof Pack)) securis/src/main/resources/db/schema.sql
.. .. @@ -75,6 +75,9 @@ 75 75 id INT NOT NULL auto_increment, 76 76 code VARCHAR(50) NOT NULL , 77 77 num_licenses INT NOT NULL , 78 + init_valid_date DATE NOT NULL default today(),79 + end_valid_date DATE NOT NULL default today(),80 + status VARCHAR(2) NOT NULL default 'PE',78 81 comments VARCHAR(1024) NULL , 79 82 license_type_id INT NOT NULL, 80 83 organization_id INT NOT NULL, securis/src/main/resources/static/admin.html
.. .. @@ -77,7 +77,7 @@ 77 77 </td> 78 78 <td> 79 79 <input type="text" id="md_value" name="md_value" placeholder="" 80 - class="form-control" ng-model="row_md['value']" ng-required="row_md['mandatory']" ng-maxlength="150" />80 + class="form-control" ng-model="row_md['value']" ng-required="false" ng-maxlength="150" />81 81 </td> 82 82 <td> 83 83 <input type="checkbox" id="md_mandatory" name="md_mandatory" ng-disabled="!field.allow_creation" securis/src/main/resources/static/js/admin.js
.. .. @@ -38,7 +38,9 @@ 38 38 '$store', 39 39 '$L', 40 40 function($scope, $http, toaster, Catalogs, $store, $L) { 41 - $scope.showForm = false;41 + $store.set('location', '/admin');42 +43 + $scope.showForm = false;42 44 $scope.isNew = false; 43 45 $scope.formu = {}; 44 46 $scope.catalogIndex = 0; .. .. @@ -145,8 +147,6 @@ 145 147 $('select').val(null); 146 148 $scope.$parent.formu = {}; 147 149 148 - console.log("Refs for new form:");149 - console.log($scope.refs);150 150 var fields = Catalogs.getMetadata().fields; 151 151 fields.forEach(function(field) { 152 152 if (!field.listingOnly) $scope.$parent.formu[field.name] = null; securis/src/main/resources/static/js/licenses.js
.. .. @@ -74,7 +74,8 @@ 74 74 '$store', 75 75 '$L', 76 76 function($scope, $http, toaster, $store, $L) { 77 -77 + $store.set('location', '/licenses');78 +78 79 $scope.maxLengthErrorMsg = function(displayname, fieldMaxlength) { 79 80 return $L.get("{0} length is too long (max: {1}).", $L.get(displayname), fieldMaxlength); 80 81 } .. .. @@ -101,6 +102,13 @@ 101 102 var packResource = $resource('/pack/:packId', { 102 103 packId : '@id' 103 104 }); 105 + var PACK_STATUS = [106 + {id: 'PE', label: $L.get('Pending')},107 + {id: 'AC', label: $L.get('Active')},108 + {id: 'OH', label: $L.get('On Hold')},109 + {id: 'EX', label: $L.get('Expired')},110 + {id: 'CA', label: $L.get('Cancelled')}111 + ];104 112 $scope.mandatory = { 105 113 code: true, 106 114 num_licenses: true, .. .. @@ -116,6 +124,7 @@ 116 124 var refFields = [{resource: 'organization', name: 'organization_id'},{resource: 'licensetype', name: 'license_type_id'}]; 117 125 Catalogs.loadRefs(function(refs) { 118 126 $scope.refs = refs; 127 + $scope.refs['pack_status'] = PACK_STATUS;119 128 }, refFields); 120 129 }); 121 130 .. .. @@ -128,12 +137,28 @@ 128 137 129 138 $scope.packs = packResource.query(); 130 139 131 - $scope.save = function() {140 + var _savePackData = function() {132 141 var _success = function() { 133 142 if (!$scope.isNew) $scope.showForm = false; 134 143 $scope.packs = packResource.query(); 144 + toaster.pop('success', Catalogs.getName(), $L.get("Pack '{0}' {1} successfully", $scope.pack.code, $scope.isNew ? $L.get("created") : $L.get("updated")));135 145 } 136 - packResource.save($scope.pack, _success)146 + var _error = function(error) {147 + console.log(error);148 + toaster.pop('error', Catalogs.getName(), $L.get("Error {0} pack '{1}'. Reason: {2}", $scope.isNew ? $L.get("creating") : $L.get("updating"), $scope.pack.code, $L.get(error.headers('X-SECURIS-ERROR'))));149 + }150 + packResource.save($scope.pack, _success, _error);151 + }152 + $scope.save = function() {153 + if ($scope.pack.num_activations > 0) {154 + BootstrapDialog.confirm($L.get("The pack '{0}' has active licenses, Do you want to modify it ?", $scope.pack.code), function(answer){155 + if (answer) {156 + _savePackData();157 + }158 + });159 + } else {160 + _savePackData();161 + }137 162 } 138 163 139 164 $scope.newPack = function() { .. .. @@ -141,9 +166,10 @@ 141 166 $scope.showForm = true; 142 167 $scope.pack = { 143 168 license_preactivation: true, 169 + status: 'PE',144 170 num_licenses: 1, 145 - license_type_id: !$scope.refs.license_type_id || !$scope.refs.license_type_id.length ? null : $scope.refs.license_type_id[0].id,146 - organization_id: !$scope.refs.organization_id || !$scope.refs.organization_id.length ? null : $scope.refs.organization_id[0].id171 + license_type_id: null,172 + organization_id: null //!$scope.refs.organization_id || !$scope.refs.organization_id.length ? null : $scope.refs.organization_id[0].id147 173 } 148 174 setTimeout(function() { 149 175 $('#code').focus(); .. .. @@ -188,6 +214,33 @@ 188 214 $scope.$parent.$broadcast('pack_changed', pack); 189 215 } 190 216 217 + $scope.createMetadataRow = function() {218 + if (!$scope.formu.metadata) {219 + $scope.formu.metadata = [];220 + }221 + $scope.formu.metadata.push({key: '', value: '', mandatory: true});222 + }223 + $scope.removeMetadataKey = function(row_md) {224 + $scope.formu.metadata.splice( $scope.formu.metadata.indexOf(row_md), 1 );225 + }226 + $scope.updateMetadata = function() {227 + // Called when Application ID change in current field228 + var newLTId = $scope.pack['license_type_id'];229 + if (newLTId) {230 + // Only if there is a "valid" value selected we should update the metadata231 + Catalogs.getResource('licensetype').get({licenseTypeId: newLTId}).$promise.then(function(lt) {232 + $scope.pack.metadata = [];233 + lt.metadata.forEach(function(md) {234 + $scope.pack.metadata.push({235 + key: md.key,236 + value: md.value,237 + readonly: !!md.value,238 + mandatory: md.mandatory239 + });240 + });241 + });242 + }243 + }191 244 } ]); 192 245 193 246 app.controller('LicensesCtrl', [ securis/src/main/resources/static/js/login.js
.. .. @@ -23,14 +23,18 @@ 23 23 }). 24 24 success(function(data, status, headers, config) { 25 25 toaster.pop('success', $L.get('Login successful'), $L.get('User {0} has logged in application', $scope.username), 1500); 26 - $location.path('/licenses');26 + var location = $store.get('location') || '/licenses';27 +28 + $location.path(location);27 29 $store.put('username', $scope.username); 28 30 $store.put('token', data.token); 29 31 $http.defaults.headers.common['X-SECURIS-TOKEN'] = data.token; 30 32 }). 31 33 error(function(data, status, headers, config) { 32 - if (status === 403 /* forbidden */) {33 - toaster.pop('error', $L.get('Login error'), $L.get('Invalid credentials'), 3000);34 + if (status === 403 /* forbidden */ || status === 401 /* unauthorized */) {35 + toaster.pop('error', $L.get('Login error'), $L.get('Invalid credentials'), 2000);36 + } else if (status === 418 /* Teapot */) {37 + toaster.pop('error', $L.get('Login error'), $L.get(headers['X-SECURIS-ERROR-MSG']), 2000);34 38 } else { 35 39 console.error(data + " status: "+ status); 36 40 toaster.pop('error', $L.get('Unexpected Login error'), $L.get('Unexpected error HTTP ({0}) accessing to server. Contact with the administrator.', status), 5000); securis/src/main/resources/static/js/main.js
.. .. @@ -78,10 +78,14 @@ 78 78 // configure html5 to get links working on jsfiddle 79 79 $locationProvider.html5Mode(true); 80 80 $httpProvider.interceptors.push('securisHttpInterceptor'); 81 - });81 + });82 +82 83 m.controller('MainCtrl', ['$scope', '$http', '$location', '$L', '$store', 83 84 function($scope, $http, $location, $L, $store) { 84 85 86 + $scope.currentRoute = null;87 + console.log('Current location: ' + $location);88 + console.log($location);85 89 $location.path('/login'); 86 90 if ($store.get('token') != null) { 87 91 .. .. @@ -91,8 +95,10 @@ 91 95 } 92 96 }).success(function(data) { 93 97 if (data.valid) { 94 - $http.defaults.headers.common['X-SECURIS-TOKEN'] = $store.get('token');95 - $location.path('/licenses');98 + $http.defaults.headers.common['X-SECURIS-TOKEN'] = $store.get('token');99 + var location = $store.get('location') || '/licenses';100 +101 + $location.path(location);96 102 $store.set('user', data.user); 97 103 } 98 104 }); securis/src/main/resources/static/licenses.html
.. .. @@ -21,15 +21,16 @@ 21 21 </a></li> 22 22 </ul> 23 23 <div class="navbar-form navbar-right form-group"> 24 - <span class="input-group input-group-sm">25 - <div class="input-group-addon" style="width: 28px;" >24 + <span class="input-group input-group-sm">25 + <div class="input-group-addon" style="width: 28px;">26 26 <span class=" glyphicon glyphicon-search"></span> 27 + </div> <input type="text" class="form-control" placeholder="Search"28 + ng-model="$searchPacksText">29 + <div class="input-group-addon" style="width: 20px;">30 + <span class=" glyphicon glyphicon-remove"31 + ng-click="$searchPacksText = '';"></span>27 32 </div> 28 - <input type="text" class="form-control" placeholder="Search" ng-model="$searchPacksText">29 - <div class="input-group-addon" style="width: 20px;" >30 - <span class=" glyphicon glyphicon-remove" ng-click="$searchPacksText = '';"></span>31 - </div>32 - </span>33 + </span>33 34 </div> 34 35 </div> 35 36 </div> .. .. @@ -63,6 +64,32 @@ 63 64 </div> 64 65 65 66 <div class="form-group"> 67 + <label class="col-md-3 control-label" for="code" i18n>Validity (from - to)</label>68 + <div class="col-md-4">69 + <input type="date" id="init_valid_date" name="init_valid_date" placeholder=""70 + class="form-control" ng-model="pack.init_valid_date"71 + ng-required="mandatory.init_valid_date" />72 + <div class="alert inline-alert alert-warning"73 + ng-show="packForm.initValidDate.$invalid">74 + <span class="glyphicon glyphicon-warning-sign"></span>75 + <span ng-show="packForm.init_valid_date.$error.required"76 + ng-bind="mandatoryFieldErrorMsg('Init valid date')"></span>77 + </div>78 + </div>79 + <div class="col-md-4">80 + <input type="date" id="end_valid_date" name="end_valid_date" placeholder=""81 + class="form-control" ng-model="pack.end_valid_date"82 + ng-required="mandatory.end_valid_date" />83 + <div class="alert inline-alert alert-warning"84 + ng-show="packForm.initValidDate.$invalid">85 + <span class="glyphicon glyphicon-warning-sign"></span>86 + <span ng-show="packForm.end_valid_date.$error.required"87 + ng-bind="mandatoryFieldErrorMsg('End valid date')"></span>88 + </div>89 + </div>90 + </div>91 +92 + <div class="form-group">66 93 <label class="col-md-3 control-label" for="num_licenses" i18n>Num. 67 94 Licenses</label> 68 95 <div class="col-md-8"> .. .. @@ -80,15 +107,33 @@ 80 107 </div> 81 108 </div> 82 109 110 + <div class="form-group" ng-if="!isNew">111 + <label class="col-md-3 control-label" for="status" i18n>Status</label>112 + <div class="col-md-8">113 + <select class="form-control" id="status"114 + ng-required="mandatory.status"115 + ng-model="pack.status"116 + ng-options="o.id as o.label for o in refs.pack_status">117 + </select>118 + <div class="alert inline-alert alert-warning"119 + ng-show="packForm.status.$invalid">120 + <span class="glyphicon glyphicon-warning-sign"></span> <span121 + ng-show="packForm.status.$error.required"122 + ng-bind="mandatoryFieldErrorMsg('Status')"></span>123 + </div>124 + </div>125 + </div>126 +83 127 <div class="form-group"> 84 128 <label class="col-md-3 control-label" for="license_type_id" i18n>License 85 129 type</label> 86 130 <div class="col-md-8"> 87 - <select class="form-control"131 + <select class="form-control" id="license_type_id"132 + ng-change="updateMetadata()"88 133 ng-required="mandatory.license_type_id" 89 134 ng-model="pack.license_type_id" 90 135 ng-options="o.id as o.label for o in refs.license_type_id"> 91 -136 +92 137 </select> 93 138 <div class="alert inline-alert alert-warning" 94 139 ng-show="packForm.license_type_id.$invalid"> .. .. @@ -143,17 +188,42 @@ 143 188 </div> 144 189 145 190 <div class="form-group" ng-if="!isNew"> 146 - <label class="col-md-3 control-label">Created by</label>191 + <label i18n class="col-md-3 control-label">Created by</label>147 192 <div class="col-md-8"> 148 193 <p class="form-control-static" ng-bind="pack.created_by_name"></p> 149 194 </div> 150 195 </div> 151 196 152 197 <div class="form-group" ng-if="!isNew"> 153 - <label class="col-md-3 control-label">Creation date</label>198 + <label i18n class="col-md-3 control-label">Creation date</label>154 199 <div class="col-md-8"> 155 200 <p class="form-control-static" 156 201 ng-bind="pack.creationTimestamp | date:'medium'"></p> 202 + </div>203 + </div>204 +205 + <div class="form-group">206 + <label class="col-md-3 control-label" i18n>Metadata</label>207 + <div class="col-md-8">208 + <table class="table table-hover table-condensed">209 + <thead>210 + <tr>211 + <th i18n>Key</th>212 + <th i18n>Value</th>213 + </tr>214 + </thead>215 + <tbody>216 + <tr ng-repeat="row_md in pack.metadata">217 + <td><input type="text" id="md_key" name="md_key"218 + placeholder="" ng-readonly="true"219 + class="form-control" ng-model="row_md['key']"220 + ng-required="true" /></td>221 + <td><input type="text" id="md_value" name="md_value" ng-readonly="row_md['readonly']"222 + placeholder="" class="form-control" ng-model="row_md['value']"223 + ng-required="row_md['mandatory']" ng-maxlength="150" /></td>224 + </tr>225 + </tbody>226 + </table>157 227 </div> 158 228 </div> 159 229 .. .. @@ -213,33 +283,34 @@ 213 283 <nav class="navbar navbar-default navbar-static-top" 214 284 ng-disabled="!currentPack"> 215 285 <div class="container-fluid"> 216 - <!-- Brand and toggle get grouped for better mobile display -->217 - <div class="navbar-header success">218 - <a class="navbar-brand" i18n>Licenses</a>219 - </div>286 + <!-- Brand and toggle get grouped for better mobile display -->287 + <div class="navbar-header success">288 + <a class="navbar-brand" i18n>Licenses</a>289 + </div>220 290 221 - <!-- Collect the nav links, forms, and other content for toggling -->222 - <div class="collapse navbar-collapse"223 - id="bs-example-navbar-collapse-1">224 - <ul class="nav navbar-nav">225 - <li><a i18n ng-click="newLicense()"><span226 - class="glyphicon glyphicon-plus"></span> New</a></li>227 - <li><a i18n ng-click="cancel()"> <span228 - class="glyphicon glyphicon-ban-circle"></span> Cancel229 - </a></li>230 - </ul>231 - <div class="navbar-form navbar-right form-group">232 - <span class="input-group input-group-sm">233 - <div class="input-group-addon" style="width: 28px;" >291 + <!-- Collect the nav links, forms, and other content for toggling -->292 + <div class="collapse navbar-collapse"293 + id="bs-example-navbar-collapse-1">294 + <ul class="nav navbar-nav">295 + <li><a i18n ng-click="newLicense()"><span296 + class="glyphicon glyphicon-plus"></span> New</a></li>297 + <li><a i18n ng-click="cancel()"> <span298 + class="glyphicon glyphicon-ban-circle"></span> Cancel299 + </a></li>300 + </ul>301 + <div class="navbar-form navbar-right form-group">302 + <span class="input-group input-group-sm">303 + <div class="input-group-addon" style="width: 28px;">234 304 <span class=" glyphicon glyphicon-search"></span> 305 + </div> <input type="text" class="form-control" placeholder="Search"306 + ng-model="$searchLicensesText">307 + <div class="input-group-addon" style="width: 20px;">308 + <span class=" glyphicon glyphicon-remove"309 + ng-click="$searchLicensesText = '';"></span>235 310 </div> 236 - <input type="text" class="form-control" placeholder="Search" ng-model="$searchLicensesText">237 - <div class="input-group-addon" style="width: 20px;" >238 - <span class=" glyphicon glyphicon-remove" ng-click="$searchLicensesText = '';"></span>239 - </div>240 - </span>311 + </span>241 312 </div> 242 - </div>313 + </div>243 314 </div> 244 315 </nav> 245 316