rsanchez
2014-10-28 1d9d7b5f03b3e7b6af5600574a0ae6053843b77b
#2021 feature - Fixing pack cacnellation and deletion actions
2 files added
7 files modified
changed files
securis/src/main/java/net/curisit/securis/db/Application.java patch | view | blame | history
securis/src/main/java/net/curisit/securis/db/LicenseType.java patch | view | blame | history
securis/src/main/java/net/curisit/securis/db/Pack.java patch | view | blame | history
securis/src/main/java/net/curisit/securis/services/LicenseResource.java patch | view | blame | history
securis/src/main/java/net/curisit/securis/services/PackResource.java patch | view | blame | history
securis/src/main/java/net/curisit/securis/services/helpers/LicenseHelper.java patch | view | blame | history
securis/src/main/java/net/curisit/securis/services/helpers/UserHelper.java patch | view | blame | history
securis/src/main/resources/static/js/licenses.js patch | view | blame | history
securis/src/main/resources/static/licenses.html patch | view | blame | history
securis/src/main/java/net/curisit/securis/db/Application.java
....@@ -4,6 +4,7 @@
44 import java.util.Date;
55 import java.util.Set;
66
7
+import javax.persistence.CascadeType;
78 import javax.persistence.Column;
89 import javax.persistence.Entity;
910 import javax.persistence.FetchType;
....@@ -56,7 +57,7 @@
5657 @OneToMany(fetch = FetchType.LAZY, mappedBy = "application")
5758 private Set<LicenseType> licenseTypes;
5859
59
- @OneToMany(fetch = FetchType.LAZY, mappedBy = "application")
60
+ @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "application")
6061 private Set<ApplicationMetadata> metadata;
6162
6263 public Integer getId() {
securis/src/main/java/net/curisit/securis/db/LicenseType.java
....@@ -4,6 +4,7 @@
44 import java.util.Date;
55 import java.util.Set;
66
7
+import javax.persistence.CascadeType;
78 import javax.persistence.Column;
89 import javax.persistence.Entity;
910 import javax.persistence.FetchType;
....@@ -62,7 +63,7 @@
6263 @JoinColumn(name = "application_id")
6364 private Application application;
6465
65
- @OneToMany(fetch = FetchType.LAZY, mappedBy = "licenseType")
66
+ @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "licenseType")
6667 private Set<LicenseTypeMetadata> metadata;
6768
6869 public Set<LicenseTypeMetadata> getMetadata() {
securis/src/main/java/net/curisit/securis/db/Pack.java
....@@ -99,7 +99,7 @@
9999 @JsonProperty("default_valid_period")
100100 private Integer defaultValidPeriod;
101101
102
- @OneToMany(fetch = FetchType.LAZY, mappedBy = "pack")
102
+ @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "pack")
103103 private Set<PackMetadata> metadata;
104104
105105 public Integer getId() {
....@@ -317,6 +317,14 @@
317317 this.endValidDate = endValidDate;
318318 }
319319
320
+ public Set<License> getLicenses() {
321
+ return licenses;
322
+ }
323
+
324
+ public void setLicenses(Set<License> licenses) {
325
+ this.licenses = licenses;
326
+ }
327
+
320328 @Override
321329 public boolean equals(Object obj) {
322330 if (!(obj instanceof Pack))
securis/src/main/java/net/curisit/securis/services/LicenseResource.java
....@@ -1,7 +1,6 @@
11 package net.curisit.securis.services;
22
33 import java.io.File;
4
-import java.io.FileWriter;
54 import java.io.IOException;
65 import java.nio.file.Files;
76 import java.text.MessageFormat;
....@@ -51,6 +50,8 @@
5150 import net.curisit.securis.security.Securable;
5251 import net.curisit.securis.services.exception.SeCurisServiceException;
5352 import net.curisit.securis.services.exception.SeCurisServiceException.ErrorCodes;
53
+import net.curisit.securis.services.helpers.LicenseHelper;
54
+import net.curisit.securis.services.helpers.UserHelper;
5455 import net.curisit.securis.utils.EmailManager;
5556 import net.curisit.securis.utils.JsonUtils;
5657 import net.curisit.securis.utils.Params;
....@@ -75,16 +76,22 @@
7576 private static final Logger LOG = LogManager.getLogger(LicenseResource.class);
7677
7778 @Inject
78
- TokenHelper tokenHelper;
79
+ private TokenHelper tokenHelper;
7980
8081 @Inject
81
- EmailManager emailManager;
82
+ private EmailManager emailManager;
8283
8384 @Inject
84
- Provider<EntityManager> emProvider;
85
+ private UserHelper userHelper;
8586
8687 @Inject
87
- LicenseGenerator licenseGenerator;
88
+ private LicenseHelper licenseHelper;
89
+
90
+ @Inject
91
+ private Provider<EntityManager> emProvider;
92
+
93
+ @Inject
94
+ private LicenseGenerator licenseGenerator;
8895
8996 /**
9097 *
....@@ -162,7 +169,7 @@
162169 LOG.error("License with id {} is not active, so It can not downloaded", licId, bsc.getUserPrincipal());
163170 throw new SeCurisServiceException(ErrorCodes.WRONG_STATUS, "License is not active, so It can not be downloaded");
164171 }
165
- em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.DOWNLOAD));
172
+ em.persist(licenseHelper.createLicenseHistoryAction(lic, userHelper.getUser(bsc, em), LicenseHistory.Actions.DOWNLOAD));
166173 return Response
167174 .ok(lic.getLicenseData())
168175 .header("Content-Disposition",
....@@ -210,8 +217,8 @@
210217 lic.setModificationTimestamp(new Date());
211218
212219 em.persist(lic);
213
- User user = getUser(bsc.getUserPrincipal().getName(), em);
214
- em.persist(createLicenseHistoryAction(lic, user, LicenseHistory.Actions.ACTIVATE));
220
+ User user = userHelper.getUser(bsc.getUserPrincipal().getName(), em);
221
+ em.persist(licenseHelper.createLicenseHistoryAction(lic, user, LicenseHistory.Actions.ACTIVATE));
215222 return Response.ok(lic).build();
216223 }
217224
....@@ -243,12 +250,12 @@
243250 throw new SeCurisServiceException(Status.NOT_FOUND.getStatusCode(), "There is no license file available");
244251 }
245252
246
- User user = getUser(bsc.getUserPrincipal().getName(), em);
253
+ User user = userHelper.getUser(bsc.getUserPrincipal().getName(), em);
247254 try {
248255 String subject = MessageFormat.format(Params.get(Params.KEYS.EMAIL_LIC_DEFAULT_SUBJECT), lic.getPack().getAppName());
249256 String email_tpl = IOUtils.toString(this.getClass().getResourceAsStream("/lic_email_template.en"));
250257 String body = MessageFormat.format(email_tpl, lic.getFullName(), app.getName());
251
- licFile = createTemporaryLicenseFile(lic, app.getLicenseFilename());
258
+ licFile = licenseHelper.createTemporaryLicenseFile(lic, app.getLicenseFilename());
252259
253260 emailManager.sendEmail(subject, body, lic.getEmail(), addCC ? user.getEmail() : null, licFile);
254261 } catch (IOException e) {
....@@ -262,7 +269,7 @@
262269
263270 lic.setModificationTimestamp(new Date());
264271 em.persist(lic);
265
- em.persist(createLicenseHistoryAction(lic, user, LicenseHistory.Actions.SEND, "Email sent to: " + lic.getEmail()));
272
+ em.persist(licenseHelper.createLicenseHistoryAction(lic, user, LicenseHistory.Actions.SEND, "Email sent to: " + lic.getEmail()));
266273 return Response.ok(lic).build();
267274 }
268275
....@@ -301,23 +308,8 @@
301308 + " can not be canceled without a reason");
302309 }
303310
304
- lic.setStatus(LicenseStatus.CANCELLED);
305
- lic.setCancelledById(bsc.getUserPrincipal().getName());
306
- lic.setModificationTimestamp(new Date());
307
- em.persist(lic);
308
-
309
- em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.CANCEL, "Cancellation reason: " + reason));
311
+ licenseHelper.cancelLicense(lic, reason, bsc, em);
310312 return Response.ok(lic).build();
311
- }
312
-
313
- /**
314
- * Cancel the license
315
- *
316
- * @param lic
317
- * @param em
318
- */
319
- public static void cancelLicense(License lic, EntityManager em) throws SeCurisServiceException {
320
-
321313 }
322314
323315 @POST
....@@ -349,7 +341,7 @@
349341 }
350342 }
351343
352
- User createdBy = getUser(bsc.getUserPrincipal().getName(), em);
344
+ User createdBy = userHelper.getUser(bsc.getUserPrincipal().getName(), em);
353345
354346 if (lic.getRequestData() != null) {
355347 License existingLicense = License.findLicenseByRequestData(lic.getRequestData(), em);
....@@ -380,9 +372,9 @@
380372 lic.setCreationTimestamp(new Date());
381373 lic.setModificationTimestamp(lic.getCreationTimestamp());
382374 em.persist(lic);
383
- em.persist(createLicenseHistoryAction(lic, createdBy, LicenseHistory.Actions.CREATE));
375
+ em.persist(licenseHelper.createLicenseHistoryAction(lic, createdBy, LicenseHistory.Actions.CREATE));
384376 if (lic.getStatus() == LicenseStatus.ACTIVE) {
385
- em.persist(createLicenseHistoryAction(lic, createdBy, LicenseHistory.Actions.CREATE, "Activated on creation"));
377
+ em.persist(licenseHelper.createLicenseHistoryAction(lic, createdBy, LicenseHistory.Actions.CREATE, "Activated on creation"));
386378 }
387379
388380 return Response.ok(lic).build();
....@@ -486,7 +478,7 @@
486478
487479 currentLicense.setModificationTimestamp(new Date());
488480 em.persist(currentLicense);
489
- em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.MODIFY));
481
+ em.persist(licenseHelper.createLicenseHistoryAction(lic, userHelper.getUser(bsc, em), LicenseHistory.Actions.MODIFY));
490482
491483 return Response.ok(currentLicense).build();
492484 }
....@@ -547,12 +539,12 @@
547539 }
548540 BlockedRequest blockedReq = new BlockedRequest();
549541 blockedReq.setCreationTimestamp(new Date());
550
- blockedReq.setBlockedBy(getUser(bsc, em));
542
+ blockedReq.setBlockedBy(userHelper.getUser(bsc, em));
551543 blockedReq.setRequestData(lic.getRequestData());
552544
553545 em.persist(blockedReq);
554546
555
- em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.BLOCK));
547
+ em.persist(licenseHelper.createLicenseHistoryAction(lic, userHelper.getUser(bsc, em), LicenseHistory.Actions.BLOCK));
556548 return Response.ok(Utils.createMap("success", true, "id", licId)).build();
557549 }
558550
....@@ -571,7 +563,7 @@
571563 if (BlockedRequest.isRequestBlocked(lic.getRequestData(), em)) {
572564 BlockedRequest blockedReq = em.find(BlockedRequest.class, lic.getReqDataHash());
573565 em.remove(blockedReq);
574
- em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.UNBLOCK));
566
+ em.persist(licenseHelper.createLicenseHistoryAction(lic, userHelper.getUser(bsc, em), LicenseHistory.Actions.UNBLOCK));
575567 } else {
576568 LOG.info("Request data for license {} is NOT blocked", licId);
577569 }
....@@ -595,43 +587,6 @@
595587 throw new SeCurisServiceException(Status.UNAUTHORIZED.getStatusCode(), "Unathorized access to license data");
596588 }
597589 return lic;
598
- }
599
-
600
- private User getUser(BasicSecurityContext bsc, EntityManager em) throws SeCurisServiceException {
601
- String username = bsc.getUserPrincipal().getName();
602
- return getUser(username, em);
603
- }
604
-
605
- private User getUser(String username, EntityManager em) throws SeCurisServiceException {
606
- User user = null;
607
- if (username != null) {
608
- user = em.find(User.class, username);
609
- if (user == null) {
610
- throw new SeCurisServiceException(Status.NOT_FOUND.getStatusCode(), "User not found with username: " + username);
611
- }
612
- }
613
- return user;
614
- }
615
-
616
- private File createTemporaryLicenseFile(License lic, String licFileName) throws IOException {
617
- File f = Files.createTempDirectory("securis-server").toFile();
618
- f = new File(f, licFileName);
619
- IOUtils.write(lic.getLicenseData(), new FileWriter(f));
620
- return f;
621
- }
622
-
623
- private LicenseHistory createLicenseHistoryAction(License lic, User user, String action, String comments) {
624
- LicenseHistory lh = new LicenseHistory();
625
- lh.setLicense(lic);
626
- lh.setUser(user);
627
- lh.setTimestamp(new Date());
628
- lh.setAction(action);
629
- lh.setComments(comments);
630
- return lh;
631
- }
632
-
633
- private LicenseHistory createLicenseHistoryAction(License lic, User user, String action) {
634
- return createLicenseHistoryAction(lic, user, action, null);
635590 }
636591
637592 public static void main(String[] args) throws IOException {
securis/src/main/java/net/curisit/securis/services/PackResource.java
....@@ -12,6 +12,7 @@
1212 import javax.persistence.TypedQuery;
1313 import javax.ws.rs.Consumes;
1414 import javax.ws.rs.DELETE;
15
+import javax.ws.rs.FormParam;
1516 import javax.ws.rs.GET;
1617 import javax.ws.rs.POST;
1718 import javax.ws.rs.PUT;
....@@ -26,6 +27,8 @@
2627 import net.curisit.integrity.commons.Utils;
2728 import net.curisit.securis.DefaultExceptionHandler;
2829 import net.curisit.securis.SeCurisException;
30
+import net.curisit.securis.db.License;
31
+import net.curisit.securis.db.LicenseStatus;
2932 import net.curisit.securis.db.LicenseType;
3033 import net.curisit.securis.db.Organization;
3134 import net.curisit.securis.db.Pack;
....@@ -36,6 +39,8 @@
3639 import net.curisit.securis.security.Securable;
3740 import net.curisit.securis.services.exception.SeCurisServiceException;
3841 import net.curisit.securis.services.exception.SeCurisServiceException.ErrorCodes;
42
+import net.curisit.securis.services.helpers.LicenseHelper;
43
+import net.curisit.securis.services.helpers.UserHelper;
3944 import net.curisit.securis.utils.TokenHelper;
4045
4146 import org.apache.logging.log4j.LogManager;
....@@ -60,8 +65,11 @@
6065 @Inject
6166 Provider<EntityManager> emProvider;
6267
63
- public PackResource() {
64
- }
68
+ @Inject
69
+ private UserHelper userHelper;
70
+
71
+ @Inject
72
+ private LicenseHelper licenseHelper;
6573
6674 /**
6775 *
....@@ -297,8 +305,9 @@
297305 @Produces({
298306 MediaType.APPLICATION_JSON
299307 })
300
- public Response cancel(@PathParam("packId") Integer packId) throws SeCurisServiceException {
301
- LOG.info("Putting On hold pack with id: {}", packId);
308
+ public Response cancel(@PathParam("packId") Integer packId, @FormParam("reason") String reason, @Context BasicSecurityContext bsc)
309
+ throws SeCurisServiceException {
310
+ LOG.info("Cancelling pack with id: {}", packId);
302311 EntityManager em = emProvider.get();
303312
304313 Pack currentPack = em.find(Pack.class, packId);
....@@ -308,6 +317,12 @@
308317 throw new SeCurisServiceException(ErrorCodes.WRONG_STATUS, "Pack cannot be cancelled in status: " + currentPack.getStatus().name());
309318 }
310319
320
+ Set<License> licenses = currentPack.getLicenses();
321
+ for (License license : licenses) {
322
+ if (license.getStatus() == LicenseStatus.ACTIVE || license.getStatus() == LicenseStatus.PRE_ACTIVE) {
323
+ licenseHelper.cancelLicense(license, "Pack cancellation. " + reason, bsc, em);
324
+ }
325
+ }
311326 currentPack.setStatus(PackStatus.CANCELLED);
312327 em.persist(currentPack);
313328
....@@ -334,7 +349,7 @@
334349 @Produces({
335350 MediaType.APPLICATION_JSON
336351 })
337
- public Response delete(@PathParam("packId") String packId) {
352
+ public Response delete(@PathParam("packId") String packId) throws SeCurisServiceException {
338353 LOG.info("Deleting pack with id: {}", packId);
339354 EntityManager em = emProvider.get();
340355 Pack pack = em.find(Pack.class, Integer.parseInt(packId));
....@@ -343,10 +358,14 @@
343358 return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "Pack was not found, ID: " + packId)
344359 .build();
345360 }
346
- if (pack.getMetadata() != null) {
347
- for (PackMetadata md : pack.getMetadata()) {
348
- em.remove(md);
361
+ // Pack metadata is removed in cascade automatically.
362
+
363
+ Set<License> licenses = pack.getLicenses();
364
+ for (License license : licenses) {
365
+ if (license.getStatus() == LicenseStatus.ACTIVE || license.getStatus() == LicenseStatus.PRE_ACTIVE) {
366
+ throw new SeCurisServiceException(ErrorCodes.WRONG_STATUS, "An active license cannot be deleted. License code: " + license.getCode());
349367 }
368
+ em.remove(license);
350369 }
351370
352371 em.remove(pack);
securis/src/main/java/net/curisit/securis/services/helpers/LicenseHelper.java
....@@ -0,0 +1,64 @@
1
+package net.curisit.securis.services.helpers;
2
+
3
+import java.io.File;
4
+import java.io.FileWriter;
5
+import java.io.IOException;
6
+import java.nio.file.Files;
7
+import java.util.Date;
8
+
9
+import javax.inject.Inject;
10
+import javax.inject.Singleton;
11
+import javax.persistence.EntityManager;
12
+
13
+import net.curisit.securis.db.License;
14
+import net.curisit.securis.db.LicenseHistory;
15
+import net.curisit.securis.db.LicenseStatus;
16
+import net.curisit.securis.db.User;
17
+import net.curisit.securis.security.BasicSecurityContext;
18
+import net.curisit.securis.services.exception.SeCurisServiceException;
19
+
20
+import org.apache.commons.io.IOUtils;
21
+
22
+@Singleton
23
+public class LicenseHelper {
24
+
25
+ @Inject
26
+ private UserHelper userHelper;
27
+
28
+ /**
29
+ * Cancel the license
30
+ *
31
+ * @param lic
32
+ * @param em
33
+ */
34
+ public void cancelLicense(License lic, String reason, BasicSecurityContext bsc, EntityManager em) throws SeCurisServiceException {
35
+ lic.setStatus(LicenseStatus.CANCELLED);
36
+ lic.setCancelledById(bsc.getUserPrincipal().getName());
37
+ lic.setModificationTimestamp(new Date());
38
+ em.persist(lic);
39
+
40
+ em.persist(createLicenseHistoryAction(lic, userHelper.getUser(bsc, em), LicenseHistory.Actions.CANCEL, "Cancellation reason: " + reason));
41
+
42
+ }
43
+
44
+ public LicenseHistory createLicenseHistoryAction(License lic, User user, String action, String comments) {
45
+ LicenseHistory lh = new LicenseHistory();
46
+ lh.setLicense(lic);
47
+ lh.setUser(user);
48
+ lh.setTimestamp(new Date());
49
+ lh.setAction(action);
50
+ lh.setComments(comments);
51
+ return lh;
52
+ }
53
+
54
+ public LicenseHistory createLicenseHistoryAction(License lic, User user, String action) {
55
+ return createLicenseHistoryAction(lic, user, action, null);
56
+ }
57
+
58
+ public File createTemporaryLicenseFile(License lic, String licFileName) throws IOException {
59
+ File f = Files.createTempDirectory("securis-server").toFile();
60
+ f = new File(f, licFileName);
61
+ IOUtils.write(lic.getLicenseData(), new FileWriter(f));
62
+ return f;
63
+ }
64
+}
securis/src/main/java/net/curisit/securis/services/helpers/UserHelper.java
....@@ -0,0 +1,29 @@
1
+package net.curisit.securis.services.helpers;
2
+
3
+import javax.inject.Singleton;
4
+import javax.persistence.EntityManager;
5
+import javax.ws.rs.core.Response.Status;
6
+
7
+import net.curisit.securis.db.User;
8
+import net.curisit.securis.security.BasicSecurityContext;
9
+import net.curisit.securis.services.exception.SeCurisServiceException;
10
+
11
+@Singleton
12
+public class UserHelper {
13
+
14
+ public User getUser(BasicSecurityContext bsc, EntityManager em) throws SeCurisServiceException {
15
+ String username = bsc.getUserPrincipal().getName();
16
+ return getUser(username, em);
17
+ }
18
+
19
+ public User getUser(String username, EntityManager em) throws SeCurisServiceException {
20
+ User user = null;
21
+ if (username != null) {
22
+ user = em.find(User.class, username);
23
+ if (user == null) {
24
+ throw new SeCurisServiceException(Status.NOT_FOUND.getStatusCode(), "User not found with username: " + username);
25
+ }
26
+ }
27
+ return user;
28
+ }
29
+}
securis/src/main/resources/static/js/licenses.js
....@@ -105,11 +105,12 @@
105105 var _error = _createErrorCallback(pack, $L.get('Put on hold'), _onerror);
106106 packResource.putonhold({id: pack.id}, _success, _error);
107107 }
108
- this.cancel = function(pack, _onsuccess, _onerror) {
108
+ this.cancel = function(pack, extra_data, _onsuccess, _onerror) {
109109 console.log('Cancellation on pack: ' + pack.id);
110110 var _success = _createSuccessCallback($L.get('Cancellation'), $L.get("Pack '{0}' {1} successfully", pack.code, $L.get("cancelled")), _onsuccess);
111111 var _error = _createErrorCallback(pack, $L.get('Cancellation'), _onerror);
112
- packResource.cancel({id: pack.id}, _success, _error);
112
+ var params = angular.extend({id: pack.id}, extra_data);
113
+ packResource.cancel(params, _success, _error);
113114 }
114115 this.delete = function(pack, _onsuccess, _onerror) {
115116 console.log('Delete on pack: ' + pack.id);
....@@ -334,10 +335,17 @@
334335 */
335336 $scope.execute = function(action, pack) {
336337 var _execute = function(extra_data) {
337
- Packs[action](pack || $scope.pack, extra_data, function() {
338
- if (!$scope.isNew) $scope.showForm = false;
339
- $scope.packs = Packs.getPacksList();
340
- });
338
+ if (extra_data) {
339
+ Packs[action](pack || $scope.pack, extra_data, function() {
340
+ if (!$scope.isNew) $scope.showForm = false;
341
+ $scope.packs = Packs.getPacksList();
342
+ });
343
+ } else {
344
+ Packs[action](pack || $scope.pack, function() {
345
+ if (!$scope.isNew) $scope.showForm = false;
346
+ $scope.packs = Packs.getPacksList();
347
+ });
348
+ }
341349 }
342350 if (action === 'delete') {
343351 BootstrapDialog.confirm($L.get("The pack '{0}' will be deleted, are you sure ?", $scope.pack.code), function(answer) {
securis/src/main/resources/static/licenses.html
....@@ -266,24 +266,6 @@
266266 </form>
267267 </div>
268268
269
-<div class="modal fade" id="cancellationReasonDialog" tabindex="-1" role="dialog" aria-labelledby="cancelDialogLabel" aria-hidden="true">
270
- <div class="modal-dialog">
271
- <div class="modal-content">
272
- <div class="modal-header">
273
- <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
274
- <h4 class="modal-title" id="cancelDialogLabel" i18n>Pack cancellation</h4>
275
- </div>
276
- <div class="modal-body">
277
-
278
- </div>
279
- <div class="modal-footer">
280
- <button type="button" class="btn btn-default" data-dismiss="modal" i18n>Close</button>
281
- <button type="button" class="btn btn-primary" i18n>Cancel pack</button>
282
- </div>
283
- </div>
284
- </div>
285
-</div>
286
-
287269 <div class="panel panel-default">
288270 <div class="panel-heading">
289271 Packs <span class="badge pull-right" ng-bind="packs.length || 0"></span>
....@@ -323,7 +305,6 @@
323305 </div>
324306
325307 </div>
326
- {{license | json}}
327308 <div id="licenses_section" class="col-md-6"
328309 ng-controller="LicensesCtrl">
329310 <nav class="navbar navbar-default navbar-static-top"