From 59cdd2b7ebceae94fbecdb1eeb46a969666dc88f Mon Sep 17 00:00:00 2001
From: Roberto Sánchez <roberto.sanchez@curisit.net>
Date: Fri, 10 Jan 2014 12:25:27 +0000
Subject: [PATCH] #394 feature - Added all catalog resources with refereced fields

---
 securis/src/main/java/net/curisit/securis/db/User.java                       |   59 ++
 securis/src/main/resources/static/js/catalogs.json                           |   58 ++
 securis/src/main/java/net/curisit/securis/db/Application.java                |    4 
 securis/src/main/resources/static/js/catalogs.js                             |  188 ++++++++++
 securis/src/main/java/net/curisit/securis/services/ApplicationResource.java  |    7 
 securis/src/main/java/net/curisit/securis/SecurisErrorHandler.java           |    2 
 securis/src/main/resources/static/admin.html                                 |    7 
 securis/src/main/java/net/curisit/securis/services/LicenseTypeResource.java  |   49 ++
 securis/src/main/java/net/curisit/securis/db/Organization.java               |   57 +++
 securis/src/main/java/net/curisit/securis/services/UserResource.java         |  202 ++++++++---
 securis/src/main/java/net/curisit/securis/ioc/RequestsModule.java            |    2 
 securis/src/main/java/net/curisit/securis/db/LicenseType.java                |   21 +
 securis/src/main/java/net/curisit/securis/services/OrganizationResource.java |  204 +++++++++++
 securis/src/main/resources/static/js/admin.js                                |  172 ++-------
 securis/src/main/java/net/curisit/securis/dao/UserDao.java                   |    4 
 securis/src/main/resources/db/schema.sql                                     |   10 
 16 files changed, 803 insertions(+), 243 deletions(-)

diff --git a/securis/src/main/java/net/curisit/securis/SecurisErrorHandler.java b/securis/src/main/java/net/curisit/securis/SecurisErrorHandler.java
index 8994c44..7eb1393 100644
--- a/securis/src/main/java/net/curisit/securis/SecurisErrorHandler.java
+++ b/securis/src/main/java/net/curisit/securis/SecurisErrorHandler.java
@@ -9,6 +9,8 @@
 
 public class SecurisErrorHandler extends ErrorHandler {
 
+	public static String HEADER_ERROR_MESSAGE = "X-SECURIS_ERROR";
+
 	@Override
 	protected void writeErrorPageHead(HttpServletRequest request, Writer writer, int code, String message) throws IOException {
 		// TODO Auto-generated method stub
diff --git a/securis/src/main/java/net/curisit/securis/dao/UserDao.java b/securis/src/main/java/net/curisit/securis/dao/UserDao.java
index 037c12d..d7cfd9e 100644
--- a/securis/src/main/java/net/curisit/securis/dao/UserDao.java
+++ b/securis/src/main/java/net/curisit/securis/dao/UserDao.java
@@ -25,12 +25,12 @@
 		EntityManager em = emProvider.get();
 		User user = new User();
 		user.setUsername(username);
-		user.setFullName("Rob San");
+		user.setFirstName("Rob");
 		user.setPassword(Utils.sha256("rob"));
 		user.setLang("en");
 		user.setCreationTimestamp(new Date());
 		user.setRoles(User.Rol.ADMIN | User.Rol.ADVANCE);
-		user.setShortName("Rob");
+		user.setLastName("Sánchez");
 		em.persist(user);
 		User u2 = em.find(User.class, username);
 		return u2;
diff --git a/securis/src/main/java/net/curisit/securis/db/Application.java b/securis/src/main/java/net/curisit/securis/db/Application.java
index e0c487a..fac81a9 100644
--- a/securis/src/main/java/net/curisit/securis/db/Application.java
+++ b/securis/src/main/java/net/curisit/securis/db/Application.java
@@ -42,6 +42,10 @@
 		return id;
 	}
 
+	public void setId(int id) {
+		this.id = id;
+	}
+
 	public String getName() {
 		return name;
 	}
diff --git a/securis/src/main/java/net/curisit/securis/db/LicenseType.java b/securis/src/main/java/net/curisit/securis/db/LicenseType.java
index 675f108..a805a98 100644
--- a/securis/src/main/java/net/curisit/securis/db/LicenseType.java
+++ b/securis/src/main/java/net/curisit/securis/db/LicenseType.java
@@ -14,7 +14,11 @@
 import javax.persistence.Table;
 
 import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Entity implementation class for Entity: license_type
@@ -22,12 +26,14 @@
  */
 @JsonAutoDetect
 @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
 @Entity
 @Table(name = "license_type")
 @NamedQueries(
-	{ @NamedQuery(name = "list-license_types", query = "SELECT lt FROM LicenseType lt") })
+	{ @NamedQuery(name = "list-license_types", query = "SELECT new map(lt.id as id, lt.code as code, lt.name as name, lt.description as description, lt.creationTimestamp as creationTimestamp, ap.id as application_id, ap.name as application_name) FROM LicenseType lt inner join lt.application ap") })
 public class LicenseType implements Serializable {
 
+	private static final Logger log = LoggerFactory.getLogger(LicenseType.class);
 	private static final long serialVersionUID = 1L;
 
 	@Id
@@ -77,6 +83,19 @@
 		return application;
 	}
 
+	@JsonProperty("application_id")
+	public Integer getApplicationId() {
+		log.info("application  " + application);
+		return application == null ? null : application.getId();
+	}
+
+	@JsonProperty("application_id")
+	public void setApplicationId(Integer appId) {
+		log.info("setApplicationId(Integer appId)  " + appId);
+		application = new Application();
+		application.setId(appId);
+	}
+
 	public void setApplication(Application application) {
 		this.application = application;
 	}
diff --git a/securis/src/main/java/net/curisit/securis/db/Organization.java b/securis/src/main/java/net/curisit/securis/db/Organization.java
index 71a7ebc..04ac638 100644
--- a/securis/src/main/java/net/curisit/securis/db/Organization.java
+++ b/securis/src/main/java/net/curisit/securis/db/Organization.java
@@ -1,6 +1,7 @@
 package net.curisit.securis.db;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
@@ -17,7 +18,11 @@
 import javax.persistence.Table;
 
 import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Entity implementation class for Entity: organization
@@ -30,6 +35,9 @@
 @NamedQueries(
 	{ @NamedQuery(name = "list-organizations", query = "SELECT o FROM Organization o") })
 public class Organization implements Serializable {
+
+	@SuppressWarnings("unused")
+	private static final Logger log = LoggerFactory.getLogger(Organization.class);
 
 	private static final long serialVersionUID = 1L;
 
@@ -44,20 +52,28 @@
 	@Column(name = "creation_timestamp")
 	private Date creationTimestamp;
 
+	@JsonIgnore
+	// We don't include the users to limit the size of each row a the listing
 	@ManyToMany
 	@JoinTable(name = "user_organization", //
 	joinColumns =
 		{ @JoinColumn(name = "organization_id", referencedColumnName = "id") }, //
 	inverseJoinColumns =
-		{ @JoinColumn(name = "user_id", referencedColumnName = "username") })
+		{ @JoinColumn(name = "username", referencedColumnName = "username") })
 	private List<User> users;
 
+	@JsonIgnore
+	// We don't include the users to limit the size of each row a the listing
 	@ManyToOne
 	@JoinColumn(name = "org_parent_id")
 	private Organization parentOrganization;
 
 	public int getId() {
 		return id;
+	}
+
+	public void setId(int id) {
+		this.id = id;
 	}
 
 	public String getName() {
@@ -108,4 +124,43 @@
 		this.parentOrganization = parentOrganization;
 	}
 
+	// Roberto: Following methods are necessary to include in the REST list response
+	// information about the referenced entities.
+	@JsonProperty("org_parent_id")
+	public void setParentOrgId(Integer orgId) {
+		parentOrganization = new Organization();
+		parentOrganization.setId(orgId);
+	}
+
+	@JsonProperty("org_parent_id")
+	public Integer getParentOrgId() {
+		return parentOrganization == null ? null : parentOrganization.getId();
+	}
+
+	@JsonProperty("org_parent_name")
+	public String getParentOrgName() {
+		return parentOrganization == null ? null : parentOrganization.getName();
+	}
+
+	@JsonProperty("users_ids")
+	public void setUsersIds(List<String> usersIds) {
+		users = new ArrayList<>();
+		for (String userid : usersIds) {
+			User u = new User();
+			u.setUsername(userid);
+			users.add(u);
+		}
+	}
+
+	@JsonProperty("users_ids")
+	public List<String> getUsersIds() {
+		if (users == null)
+			return null;
+		List<String> ids = new ArrayList<>();
+		for (User user : users) {
+			ids.add(user.getUsername());
+		}
+		return ids;
+	}
+
 }
diff --git a/securis/src/main/java/net/curisit/securis/db/User.java b/securis/src/main/java/net/curisit/securis/db/User.java
index ba5890f..4846eb8 100644
--- a/securis/src/main/java/net/curisit/securis/db/User.java
+++ b/securis/src/main/java/net/curisit/securis/db/User.java
@@ -1,6 +1,7 @@
 package net.curisit.securis.db;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
@@ -15,6 +16,7 @@
 import javax.persistence.Table;
 
 import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
 
@@ -37,15 +39,16 @@
 	private String username;
 
 	private String password;
-	@JsonProperty(value = "short_name")
-	@Column(name = "short_name")
-	private String shortName;
+
+	@JsonProperty(value = "first_name")
+	@Column(name = "first_name")
+	private String firstName;
+
+	@JsonProperty(value = "last_name")
+	@Column(name = "last_name")
+	private String lastName;
 
 	private int roles;
-
-	@JsonProperty(value = "full_name")
-	@Column(name = "full_name")
-	private String fullName;
 
 	@JsonProperty(value = "last_login")
 	@Column(name = "last_login")
@@ -59,10 +62,11 @@
 
 	private String lang;
 
+	@JsonIgnore
 	@ManyToMany
 	@JoinTable(name = "user_organization", //
 	joinColumns =
-		{ @JoinColumn(name = "user_id", referencedColumnName = "username") }, //
+		{ @JoinColumn(name = "username", referencedColumnName = "username") }, //
 	inverseJoinColumns =
 		{ @JoinColumn(name = "organization_id", referencedColumnName = "id") } //
 	)
@@ -92,20 +96,20 @@
 		this.roles = roles;
 	}
 
-	public String getFullName() {
-		return fullName;
+	public String getFirstName() {
+		return firstName;
 	}
 
-	public void setFullName(String fullName) {
-		this.fullName = fullName;
+	public void setFirstName(String firstName) {
+		this.firstName = firstName;
 	}
 
-	public String getShortName() {
-		return shortName;
+	public String getLastName() {
+		return lastName;
 	}
 
-	public void setShortName(String shortName) {
-		this.shortName = shortName;
+	public void setLastName(String lastName) {
+		this.lastName = lastName;
 	}
 
 	public Date getLastLogin() {
@@ -134,7 +138,7 @@
 
 	@Override
 	public String toString() {
-		return "{User: " + username + " Full Name: " + fullName + ", last login: " + lastLogin + "}";
+		return "{User: " + username + " Name: " + firstName + " " + lastName + ", last login: " + lastLogin + "}";
 	}
 
 	public String getLang() {
@@ -153,6 +157,27 @@
 		this.organizations = organizations;
 	}
 
+	@JsonProperty("organizations_ids")
+	public void setOrgsIds(List<Integer> orgsIds) {
+		organizations = new ArrayList<>();
+		for (Integer orgid : orgsIds) {
+			Organization o = new Organization();
+			o.setId(orgid);
+			organizations.add(o);
+		}
+	}
+
+	@JsonProperty("organizations_ids")
+	public List<Integer> getOrgsIds() {
+		if (organizations == null)
+			return null;
+		List<Integer> ids = new ArrayList<>();
+		for (Organization org : organizations) {
+			ids.add(org.getId());
+		}
+		return ids;
+	}
+
 	static public class Rol {
 		static public final int ADVANCE = 0x01;
 		static public final int ADMIN = 0x02;
diff --git a/securis/src/main/java/net/curisit/securis/ioc/RequestsModule.java b/securis/src/main/java/net/curisit/securis/ioc/RequestsModule.java
index 2e2eacf..366b85d 100644
--- a/securis/src/main/java/net/curisit/securis/ioc/RequestsModule.java
+++ b/securis/src/main/java/net/curisit/securis/ioc/RequestsModule.java
@@ -4,6 +4,7 @@
 import net.curisit.securis.services.BasicServices;
 import net.curisit.securis.services.LicenseServices;
 import net.curisit.securis.services.LicenseTypeResource;
+import net.curisit.securis.services.OrganizationResource;
 import net.curisit.securis.services.SecurityInterceptor;
 import net.curisit.securis.services.UserResource;
 
@@ -27,6 +28,7 @@
 
 		bind(ApplicationResource.class);
 		bind(LicenseTypeResource.class);
+		bind(OrganizationResource.class);
 	}
 
 	@Provides
diff --git a/securis/src/main/java/net/curisit/securis/services/ApplicationResource.java b/securis/src/main/java/net/curisit/securis/services/ApplicationResource.java
index 1a59173..1452aed 100644
--- a/securis/src/main/java/net/curisit/securis/services/ApplicationResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/ApplicationResource.java
@@ -23,6 +23,7 @@
 import javax.ws.rs.core.Response.Status;
 
 import net.curisit.integrity.commons.Utils;
+import net.curisit.securis.SecurisErrorHandler;
 import net.curisit.securis.db.Application;
 import net.curisit.securis.utils.TokenHelper;
 
@@ -87,7 +88,7 @@
 		Application app = em.find(Application.class, Integer.parseInt(appid));
 		if (app == null) {
 			log.error("Application with id {} not found in DB", appid);
-			return Response.status(Status.NOT_FOUND).build();
+			return Response.status(Status.NOT_FOUND).header(SecurisErrorHandler.HEADER_ERROR_MESSAGE, "Application not found with ID: " + appid).build();
 		}
 		return Response.ok(app).build();
 	}
@@ -120,7 +121,7 @@
 		Application currentapp = em.find(Application.class, Integer.parseInt(appid));
 		if (currentapp == null) {
 			log.error("Application with id {} not found in DB", appid);
-			return Response.status(Status.NOT_FOUND).build();
+			return Response.status(Status.NOT_FOUND).header(SecurisErrorHandler.HEADER_ERROR_MESSAGE, "Application not found with ID: " + appid).build();
 		}
 		currentapp.setName(app.getName());
 		currentapp.setDescription(app.getDescription());
@@ -140,7 +141,7 @@
 		Application app = em.find(Application.class, Integer.parseInt(appid));
 		if (app == null) {
 			log.error("Application with id {} can not be deleted, It was not found in DB", appid);
-			return Response.status(Status.NOT_FOUND).build();
+			return Response.status(Status.NOT_FOUND).header(SecurisErrorHandler.HEADER_ERROR_MESSAGE, "Application not found with ID: " + appid).build();
 		}
 
 		em.remove(app);
diff --git a/securis/src/main/java/net/curisit/securis/services/LicenseTypeResource.java b/securis/src/main/java/net/curisit/securis/services/LicenseTypeResource.java
index 87b1c37..b229507 100644
--- a/securis/src/main/java/net/curisit/securis/services/LicenseTypeResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/LicenseTypeResource.java
@@ -6,7 +6,7 @@
 import javax.inject.Inject;
 import javax.inject.Provider;
 import javax.persistence.EntityManager;
-import javax.persistence.TypedQuery;
+import javax.persistence.Query;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -23,6 +23,8 @@
 import javax.ws.rs.core.Response.Status;
 
 import net.curisit.integrity.commons.Utils;
+import net.curisit.securis.SecurisErrorHandler;
+import net.curisit.securis.db.Application;
 import net.curisit.securis.db.LicenseType;
 import net.curisit.securis.utils.TokenHelper;
 
@@ -39,13 +41,13 @@
 @Path("/licensetype")
 public class LicenseTypeResource {
 
+	private static final Logger log = LoggerFactory.getLogger(LicenseTypeResource.class);
+
 	@Inject
 	TokenHelper tokenHelper;
 
 	@Inject
 	Provider<EntityManager> emProvider;
-
-	private static final Logger log = LoggerFactory.getLogger(LicenseTypeResource.class);
 
 	public LicenseTypeResource() {
 	}
@@ -62,8 +64,9 @@
 		log.info("Getting license types list ");
 
 		EntityManager em = emProvider.get();
-		TypedQuery<LicenseType> q = em.createNamedQuery("list-license_types", LicenseType.class);
-		List<LicenseType> list = q.getResultList();
+		Query q = em.createNamedQuery("list-license_types");
+		@SuppressWarnings("unchecked")
+		List<Object> list = q.getResultList();
 
 		return Response.ok(list).build();
 	}
@@ -98,13 +101,23 @@
 	@Produces(
 		{ MediaType.APPLICATION_JSON })
 	@Transactional
-	public Response create(LicenseType app, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
+	public Response create(LicenseType lt, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
 		log.info("Creating new license type");
 		EntityManager em = emProvider.get();
-		app.setCreationTimestamp(new Date());
-		em.persist(app);
+		Application app = null;
+		if (lt.getApplicationId() != null) {
+			app = em.find(Application.class, lt.getApplicationId());
+			if (app == null) {
+				log.error("LicenseType application with id {} not found in DB", lt.getApplicationId());
+				return Response.status(Status.NOT_FOUND).header(SecurisErrorHandler.HEADER_ERROR_MESSAGE, "License type's app not found with ID: " + lt.getApplicationId()).build();
+			}
+		}
 
-		return Response.ok(app).build();
+		lt.setApplication(app);
+		lt.setCreationTimestamp(new Date());
+		em.persist(lt);
+
+		return Response.ok(lt).build();
 	}
 
 	@PUT
@@ -114,16 +127,26 @@
 	@Consumes(MediaType.APPLICATION_JSON)
 	@Produces(
 		{ MediaType.APPLICATION_JSON })
-	public Response modify(LicenseType app, @PathParam("ltid") String ltid, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
+	public Response modify(LicenseType lt, @PathParam("ltid") String ltid, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
 		log.info("Modifying license type with id: {}", ltid);
 		EntityManager em = emProvider.get();
 		LicenseType currentlt = em.find(LicenseType.class, Integer.parseInt(ltid));
 		if (currentlt == null) {
 			log.error("LicenseType with id {} not found in DB", ltid);
-			return Response.status(Status.NOT_FOUND).build();
+			return Response.status(Status.NOT_FOUND).header(SecurisErrorHandler.HEADER_ERROR_MESSAGE, "License type not found with ID: " + ltid).build();
 		}
-		currentlt.setName(app.getName());
-		currentlt.setDescription(app.getDescription());
+		Application app = null;
+		if (lt.getApplicationId() != null) {
+			app = em.find(Application.class, lt.getApplicationId());
+			if (app == null) {
+				log.error("LicenseType application with id {} not found in DB", lt.getApplicationId());
+				return Response.status(Status.NOT_FOUND).header(SecurisErrorHandler.HEADER_ERROR_MESSAGE, "License type's app not found with ID: " + lt.getApplicationId()).build();
+			}
+		}
+		currentlt.setCode(lt.getCode());
+		currentlt.setName(lt.getName());
+		currentlt.setDescription(lt.getDescription());
+		currentlt.setApplication(app);
 		em.persist(currentlt);
 
 		return Response.ok(currentlt).build();
diff --git a/securis/src/main/java/net/curisit/securis/services/OrganizationResource.java b/securis/src/main/java/net/curisit/securis/services/OrganizationResource.java
new file mode 100644
index 0000000..feec7e5
--- /dev/null
+++ b/securis/src/main/java/net/curisit/securis/services/OrganizationResource.java
@@ -0,0 +1,204 @@
+package net.curisit.securis.services;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import javax.inject.Inject;
+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.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import net.curisit.integrity.commons.Utils;
+import net.curisit.securis.SecurisErrorHandler;
+import net.curisit.securis.db.Organization;
+import net.curisit.securis.db.User;
+import net.curisit.securis.utils.TokenHelper;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.persist.Transactional;
+
+/**
+ * Organization resource, this service will provide methods to create, modify and delete organizations
+ * 
+ * @author roberto <roberto.sanchez@curisit.net>
+ */
+@Path("/organization")
+public class OrganizationResource {
+
+	private static final Logger log = LoggerFactory.getLogger(OrganizationResource.class);
+
+	@Inject
+	TokenHelper tokenHelper;
+
+	@Inject
+	Provider<EntityManager> emProvider;
+
+	public OrganizationResource() {
+	}
+
+	/**
+	 * 
+	 * @return the server version in format majorVersion.minorVersion
+	 */
+	@GET
+	@Path("/")
+	@Produces(
+		{ MediaType.APPLICATION_JSON })
+	public Response index() {
+		log.info("Getting organizations list ");
+
+		EntityManager em = emProvider.get();
+		TypedQuery<Organization> q = em.createNamedQuery("list-organizations", Organization.class);
+
+		List<Organization> list = q.getResultList();
+
+		return Response.ok(list).build();
+	}
+
+	/**
+	 * 
+	 * @return the server version in format majorVersion.minorVersion
+	 */
+	@GET
+	@Path("/{orgid}")
+	@Produces(
+		{ MediaType.APPLICATION_JSON })
+	public Response get(@PathParam("orgid") String orgid, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
+		log.info("Getting organization data for id: {}: ", orgid);
+		if (orgid == null || orgid.equals("")) {
+			log.error("Organization ID is mandatory");
+			return Response.status(Status.NOT_FOUND).build();
+		}
+
+		EntityManager em = emProvider.get();
+		Organization lt = em.find(Organization.class, Integer.parseInt(orgid));
+		if (lt == null) {
+			log.error("Organization with id {} not found in DB", orgid);
+			return Response.status(Status.NOT_FOUND).build();
+		}
+		return Response.ok(lt).build();
+	}
+
+	@POST
+	@Path("/")
+	@Consumes(MediaType.APPLICATION_JSON)
+	@Produces(
+		{ MediaType.APPLICATION_JSON })
+	@Transactional
+	public Response create(Organization org, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
+		log.info("Creating new organization");
+		EntityManager em = emProvider.get();
+		Organization parentOrg = null;
+		if (org.getParentOrgId() != null) {
+			parentOrg = em.find(Organization.class, org.getParentOrgId());
+			if (parentOrg == null) {
+				log.error("Organization parent with id {} not found in DB", org.getParentOrgId());
+				return Response.status(Status.NOT_FOUND).header(SecurisErrorHandler.HEADER_ERROR_MESSAGE, "Organization's parent not found with ID: " + org.getParentOrgId()).build();
+			}
+		}
+		List<User> users = null;
+		List<String> usersIds = org.getUsersIds();
+		if (usersIds != null && usersIds.size() > 0) {
+			users = new ArrayList<>();
+			for (String username : usersIds) {
+				User user = em.find(User.class, username);
+				if (parentOrg == null) {
+					log.error("Organization user with id {} not found in DB", username);
+					return Response.status(Status.NOT_FOUND).header(SecurisErrorHandler.HEADER_ERROR_MESSAGE, "Organization's user not found with ID: " + username).build();
+				}
+				users.add(user);
+			}
+		}
+
+		org.setUsers(users);
+		org.setParentOrganization(parentOrg);
+		org.setCreationTimestamp(new Date());
+		em.persist(org);
+
+		return Response.ok(org).build();
+	}
+
+	@PUT
+	@POST
+	@Path("/{orgid}")
+	@Transactional
+	@Consumes(MediaType.APPLICATION_JSON)
+	@Produces(
+		{ MediaType.APPLICATION_JSON })
+	public Response modify(Organization org, @PathParam("orgid") String orgid, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
+		log.info("Modifying organization with id: {}", orgid);
+		EntityManager em = emProvider.get();
+		Organization currentOrg = em.find(Organization.class, Integer.parseInt(orgid));
+		if (currentOrg == null) {
+			log.error("Organization with id {} not found in DB", orgid);
+			return Response.status(Status.NOT_FOUND).header(SecurisErrorHandler.HEADER_ERROR_MESSAGE, "Organization not found with ID: " + orgid).build();
+		}
+		Organization parentOrg = null;
+		if (org.getParentOrgId() != null) {
+			parentOrg = em.find(Organization.class, org.getParentOrgId());
+			if (parentOrg == null) {
+				log.error("Organization parent with id {} not found in DB", org.getParentOrgId());
+				return Response.status(Status.NOT_FOUND).header(SecurisErrorHandler.HEADER_ERROR_MESSAGE, "Organization's parent not found with ID: " + org.getParentOrgId()).build();
+			}
+		}
+
+		List<User> users = null;
+		List<String> usersIds = org.getUsersIds();
+		if (usersIds != null && usersIds.size() > 0) {
+			users = new ArrayList<>();
+			for (String username : usersIds) {
+				User user = em.find(User.class, username);
+				if (parentOrg == null) {
+					log.error("Organization user with id {} not found in DB", username);
+					return Response.status(Status.NOT_FOUND).header(SecurisErrorHandler.HEADER_ERROR_MESSAGE, "Organization's user not found with ID: " + username).build();
+				}
+				users.add(user);
+			}
+		}
+
+		currentOrg.setUsers(users);
+		currentOrg.setParentOrganization(parentOrg);
+		currentOrg.setCode(org.getCode());
+		currentOrg.setName(org.getName());
+		currentOrg.setDescription(org.getDescription());
+		em.persist(currentOrg);
+
+		return Response.ok(currentOrg).build();
+	}
+
+	@DELETE
+	@Path("/{orgid}")
+	@Transactional
+	@Produces(
+		{ MediaType.APPLICATION_JSON })
+	public Response delete(@PathParam("orgid") String orgid, @Context HttpServletRequest request) {
+		log.info("Deleting app with id: {}", orgid);
+		EntityManager em = emProvider.get();
+		Organization app = em.find(Organization.class, Integer.parseInt(orgid));
+		if (app == null) {
+			log.error("Organization with id {} can not be deleted, It was not found in DB", orgid);
+			return Response.status(Status.NOT_FOUND).build();
+		}
+
+		em.remove(app);
+		return Response.ok(Utils.createMap("success", true, "id", orgid)).build();
+	}
+
+}
diff --git a/securis/src/main/java/net/curisit/securis/services/UserResource.java b/securis/src/main/java/net/curisit/securis/services/UserResource.java
index 8048e89..8788a02 100644
--- a/securis/src/main/java/net/curisit/securis/services/UserResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/UserResource.java
@@ -1,10 +1,21 @@
 package net.curisit.securis.services;
 
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
 import javax.inject.Inject;
+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.FormParam;
 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;
@@ -14,10 +25,14 @@
 import javax.ws.rs.core.Response.Status;
 
 import net.curisit.integrity.commons.Utils;
+import net.curisit.securis.db.Organization;
+import net.curisit.securis.db.User;
 import net.curisit.securis.utils.TokenHelper;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+
+import com.google.inject.persist.Transactional;
 
 /**
  * User resource
@@ -29,6 +44,9 @@
 
 	@Inject
 	TokenHelper tokenHelper;
+
+	@Inject
+	Provider<EntityManager> emProvider;
 
 	// private LicenseHelper licenseHelper = InjectorFactory.getInjector().getInstance(LicenseHelper.class);
 	private static final Logger log = LoggerFactory.getLogger(UserResource.class);
@@ -43,9 +61,134 @@
 	@GET
 	@Path("/")
 	@Produces(
-		{ MediaType.TEXT_PLAIN })
-	public Response index(@Context HttpServletRequest request) {
-		return Response.ok("User resource").build();
+		{ MediaType.APPLICATION_JSON })
+	public Response index() {
+		log.info("Getting users list ");
+
+		EntityManager em = emProvider.get();
+		TypedQuery<User> q = em.createNamedQuery("list-users", User.class);
+
+		List<User> list = q.getResultList();
+
+		return Response.ok(list).build();
+	}
+
+	/**
+	 * 
+	 * @return The user
+	 */
+	@GET
+	@Path("/{uid}")
+	@Produces(
+		{ MediaType.APPLICATION_JSON })
+	public Response get(@PathParam("uid") String uid, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
+		log.info("Getting user data for id: {}: ", uid);
+		if (uid == null || uid.equals("")) {
+			log.error("User ID is mandatory");
+			return Response.status(Status.NOT_FOUND).build();
+		}
+
+		EntityManager em = emProvider.get();
+		User lt = em.find(User.class, Integer.parseInt(uid));
+		if (lt == null) {
+			log.error("User with id {} not found in DB", uid);
+			return Response.status(Status.NOT_FOUND).build();
+		}
+		return Response.ok(lt).build();
+	}
+
+	@POST
+	@Path("/")
+	@Consumes(MediaType.APPLICATION_JSON)
+	@Produces(
+		{ MediaType.APPLICATION_JSON })
+	@Transactional
+	public Response create(User user, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
+		log.info("Creating new user");
+		EntityManager em = emProvider.get();
+		List<Organization> orgs = null;
+		List<Integer> orgsIds = user.getOrgsIds();
+		if (orgsIds != null && orgsIds.size() > 0) {
+			orgs = new ArrayList<>();
+			for (Integer orgId : orgsIds) {
+				Organization o = em.find(Organization.class, orgId);
+				if (o == null) {
+					log.error("User organization with id {} not found in DB", orgId);
+					return Response.status(Status.NOT_FOUND).header("SECURIS_ERROR", "User's organization not found with ID: " + orgId).build();
+				}
+				orgs.add(o);
+			}
+		}
+
+		user.setOrganizations(orgs);
+		user.setModificationTimestamp(new Date());
+		user.setLastLogin(null);
+		user.setCreationTimestamp(new Date());
+		em.persist(user);
+
+		return Response.ok(user).build();
+	}
+
+	@PUT
+	@POST
+	@Path("/{uid}")
+	@Transactional
+	@Consumes(MediaType.APPLICATION_JSON)
+	@Produces(
+		{ MediaType.APPLICATION_JSON })
+	public Response modify(User user, @PathParam("uid") String uid, @HeaderParam(TokenHelper.TOKEN_HEADER_PÀRAM) String token) {
+		log.info("Modifying user with id: {}", uid);
+		EntityManager em = emProvider.get();
+		User currentUser = em.find(User.class, Integer.parseInt(uid));
+		if (currentUser == null) {
+			log.error("User with id {} not found in DB", uid);
+			return Response.status(Status.NOT_FOUND).header("SECURIS_ERROR", "User not found with ID: " + uid).build();
+		}
+
+		List<Organization> orgs = null;
+		List<Integer> orgsIds = user.getOrgsIds();
+		if (orgsIds != null && orgsIds.size() > 0) {
+			orgs = new ArrayList<>();
+			for (Integer orgId : orgsIds) {
+				Organization o = em.find(Organization.class, orgId);
+				if (o == null) {
+					log.error("User organization with id {} not found in DB", orgId);
+					return Response.status(Status.NOT_FOUND).header("SECURIS_ERROR", "User's user not found with ID: " + orgId).build();
+				}
+				orgs.add(o);
+			}
+		}
+
+		currentUser.setOrganizations(orgs);
+		currentUser.setFirstName(user.getFirstName());
+		currentUser.setLastName(user.getLastName());
+		currentUser.setRoles(user.getRoles());
+		currentUser.setLang(user.getLang());
+		currentUser.setModificationTimestamp(new Date());
+		currentUser.setPassword(user.getPassword());
+		currentUser.setLastLogin(user.getLastLogin());
+
+		em.persist(currentUser);
+
+		return Response.ok(currentUser).build();
+	}
+
+	@DELETE
+	@Path("/{uid}")
+	@Transactional
+	@Produces(
+		{ MediaType.APPLICATION_JSON })
+	public Response delete(@PathParam("uid") String uid, @Context HttpServletRequest request) {
+		log.info("Deleting app with id: {}", uid);
+		EntityManager em = emProvider.get();
+		User app = em.find(User.class, Integer.parseInt(uid));
+		if (app == null) {
+			log.error("User with id {} can not be deleted, It was not found in DB", uid);
+			return Response.status(Status.NOT_FOUND).build();
+		}
+
+		em.remove(app);
+		return Response.ok(Utils.createMap("success", true, "id", uid)).build();
 	}
 
 	@POST
@@ -64,18 +207,6 @@
 		return Response.ok(Utils.createMap("success", true, "token", tokenAuth)).build();
 	}
 
-	/**
-	 * @return the version of the three entities that can be synchronized (Users, DataSet and Settings)
-	 */
-	@GET
-	@Path("/{username}")
-	@Produces(
-		{ MediaType.APPLICATION_JSON })
-	// @RolesAllowed("advance")
-	public Response main(@PathParam("username") String username) {
-		return Response.ok().entity(Utils.createMap("name", "Pepito", "username", username)).build();
-	}
-
 	@GET
 	@Path("/logout")
 	@Produces(
@@ -84,45 +215,4 @@
 		request.getSession().invalidate();
 		return Response.ok().build();
 	}
-
-	//
-	// private <T> ServiceResponse<T> buildErrorResponse(ServiceResponse<T> response, String msgErrorCode) {
-	// response.setSuccess(false);
-	// response.setErrorMessage(localManager.getString(msgErrorCode));
-	// response.setErrorMessageCode(msgErrorCode);
-	// return response;
-	// }
-	//
-	// private Date calculateCaducation() {
-	// Integer licenseExpiration = systemParams.getParamAsInt(SystemParams.Keys.CONFIG_SERVER_LICENSE_EXPIRATION);
-	// if (licenseExpiration == null)
-	// licenseExpiration = DEFAULT_LICENSE_EXPIRATION;
-	// return Utils.addDays(new Date(), licenseExpiration);
-	// }
-	//
-	// private boolean validateLicense(String license) {
-	// BasicApplication ba = basicApplicationDao.findByLicense(license);
-	// return (ba != null);
-	// }
-	//
-	// private boolean validateVersion(int minorVersion, int majorVersion) {
-	// return (versionManager.getMajorVersion() == majorVersion);
-	// }
-	//
-	// private BasicApplication findBasicApp(String license) {
-	// BasicApplication ba = basicApplicationDao.findByLicense(license);
-	// return ba;
-	// }
-	//
-	// private License generateLicense() {
-	// // TODO complete all field of the license
-	// License license = new License();
-	// license.setCustomerCode(systemParams.getParam(SystemParams.Keys.CONFIG_COMMON_CUSTOMER_CODE));
-	// license.setCSCode(systemParams.getParam(SystemParams.Keys.CONFIG_COMMON_CS_CODE));
-	// license.setCRCLogo("00000000");
-	// license.setExpirationDate(calculateCaducation());
-	// license.setInstallCode(codeGenerator.generateInstalationNumber());
-	// return license;
-	// }
-
 }
diff --git a/securis/src/main/resources/db/schema.sql b/securis/src/main/resources/db/schema.sql
index e26e417..e13879a 100644
--- a/securis/src/main/resources/db/schema.sql
+++ b/securis/src/main/resources/db/schema.sql
@@ -9,9 +9,9 @@
 CREATE  TABLE IF NOT EXISTS user (
   username VARCHAR(45) NOT NULL ,
   password VARCHAR(100) NULL ,
-  roles INT NULL ,
-  full_name VARCHAR(100) NULL ,
-  short_name VARCHAR(3) NULL ,
+  roles INT NOT NULL default 0,
+  first_name VARCHAR(100) NULL ,
+  last_name VARCHAR(100) NULL ,
   last_login DATETIME NULL ,
   lang VARCHAR(10) NULL ,
   creation_timestamp DATETIME NULL ,  
@@ -49,9 +49,9 @@
   
 drop table IF EXISTS user_organization;
 CREATE  TABLE IF NOT EXISTS user_organization (
-  user_id INT NOT NULL,
+  username VARCHAR(45) NOT NULL,
   organization_id INT NOT NULL,  
-  PRIMARY KEY (user_id, organization_id));
+  PRIMARY KEY (username, organization_id));
   
 drop table IF EXISTS pack;
 CREATE  TABLE IF NOT EXISTS pack (
diff --git a/securis/src/main/resources/static/admin.html b/securis/src/main/resources/static/admin.html
index 07a95a3..24ecf73 100644
--- a/securis/src/main/resources/static/admin.html
+++ b/securis/src/main/resources/static/admin.html
@@ -89,7 +89,7 @@
 		<div class="col-md-2">
 
 			<ul class="nav nav-pills nav-stacked">
-				<li ng-repeat="catalog in catalogs.data" ng-class="{active: $index === catalogIndex}"><a ng-click="selectCatalog($index, $event)" ng-bind="catalog.name"></a></li>
+				<li ng-repeat="catalog in catalogsList" ng-class="{active: $index === catalogIndex}"><a ng-click="selectCatalog($index)" ng-bind="catalog.name"></a></li>
 			</ul>
 
 		</div>
@@ -123,7 +123,7 @@
 				<div class="panel panel-default animate-show ng-hide" ng-show="showForm">
 					<form role="form" class="form-horizontal " name="catalogForm" id="catalogForm" ng-submit="saveCatalog()" >
 <!-- 					<pre>formu: {{formu | json}}</pre>-->
-						<div class="form-group" ng-repeat="field in catalogMetadata.fields" ng-if="!isNew || !field.readOnly">
+						<div class="form-group" ng-repeat="field in catalogMetadata.fields" ng-if="(!isNew || !field.readOnly) && !field.listingOnly">
 							<label class="col-md-3 control-label" for="{{field.name}}">{{field.display}}</label>
 							<div class="col-md-5">
 								<div ng-switch on="inputType(field)">
@@ -171,7 +171,7 @@
 					</thead>
 					<tbody>
 						<tr ng-repeat="row in list | filter:searchText" ng-dblclick="edit(row)">
-							<td ng-repeat="field in catalogMetadata.list_fields" ng-bind="print(field, row[field])"></td>
+							<td ng-repeat="field in catalogMetadata.list_fields" ng-bind="print(field, row)"></td>
 						
 							<td><span ng-click="edit(row)"
 								class="glyphicon glyphicon-pencil"></span>
@@ -228,6 +228,7 @@
 	<script type="text/javascript"
 		src="//code.angularjs.org/1.2.7/angular-animate.js"></script>
  -->
+ 	<script type="text/javascript" src="js/catalogs.js"></script>
  	<script type="text/javascript" src="js/admin.js"></script>
 
 	<!--  <script src="js/main.js"></script>  -->
diff --git a/securis/src/main/resources/static/js/admin.js b/securis/src/main/resources/static/js/admin.js
index 6b4ecec..39ba6b4 100644
--- a/securis/src/main/resources/static/js/admin.js
+++ b/securis/src/main/resources/static/js/admin.js
@@ -1,7 +1,7 @@
 (function() {
 	'use strict';
 
-	var app = angular.module('app', [ 'ngRoute', 'ngAnimate', 'ngResource', 'toaster' ]);
+	var app = angular.module('app', [ 'ngRoute', 'ngAnimate', 'ngResource', 'toaster', 'catalogs' ]);
 
 	app.directive(
 					'catalogField',
@@ -22,124 +22,34 @@
 						};
 					});
 
-	app.factory('Catalogs', function($http, $resource, toaster) {
-		var CatalogsService = {
-			resources : {
-				application : $resource('/application/:appId', {
-					appId : '@id'
-				}, {
-					update : {
-						method : "PUT"
-					}
-				}),
-				user : $resource('/user/:userId', {
-					userId : '@id'
-				}, {
-					update : {
-						method : "PUT"
-					}
-				}),
-				licensetype : $resource('/licensetype/:licenseTypeId', {
-					licenseTypeId : '@id'
-				}, {
-					update : {
-						method : "PUT"
-					}
-				})
-
-			},
-			list : function(initFn) {
-				$http.get('/js/catalogs.json').success(function(data) {
-					console.log(data);
-					CatalogsService.data = data;
-					initFn();
-				})
-				return CatalogsService;
-			},
-			getName : function(index) {
-				return CatalogsService.data ? CatalogsService.data[index].name
-						: '';
-			},
-			getResource : function(index) {
-				return CatalogsService.data ? CatalogsService.data[index].resource
-						: '';
-			},
-			getMetadata : function(index) {
-				return CatalogsService.data ? CatalogsService.data[index] : {};
-			},
-			save: function(catalog, data) {
-				var resource = CatalogsService.resources[catalog.toLowerCase()];
-				function success(data) {
-					console.log('success')
-					console.log(data)
-					toaster.pop('success', "Data saved sucessfully in " + catalog);
-				}
-				function fail(data, status) {
-					var errorMsg = {500: 'Server error', 404: 'Item to modify was not found'}[data.status]
-					toaster.pop('error', "Error saving data in " + catalog, errorMsg);
-					console.log('error')
-					console.error(data)
-					console.error(status)
-				}
-				if (data.id && data.id !== '')
-					return resource.update(data, success, fail)
-				else
-					return resource.save(data, success, fail)
-			},
-			remove: function(catalog, data) {
-				var resource = CatalogsService.resources[catalog.toLowerCase()];
-				function success(data) {
-					console.log('success')
-					console.log(data)
-				}
-				function fail(data, status) {
-					console.log('error')
-					console.error(data)
-					console.error(status)
-				}
-				return resource.remove({}, data, success, fail)
-			},
-			query: function(catalog) {
-				console.log('HI catalog ???? ' + catalog);
-				var resource = CatalogsService.resources[catalog];
-				function success(data) {
-					console.log('success')
-					console.log(data)
-				}
-				function fail(data, status) {
-					console.log('error')
-					console.error(data)
-					console.error(status)
-				}
-				return resource.query({}, success, fail);
-			}
-		}
-
-		return CatalogsService;
-
-	});
-
 	app.controller('CatalogsCtrl', [
 			'$scope',
 			'$http',
 			'Catalogs',
 			function($scope, $http, Catalogs) {
-				$scope.showForm = true;
+				$scope.showForm = false;
 				$scope.isNew = false;
 				$scope.formu = {};
 				$scope.catalogIndex = 0;
-				$scope.catalogs = Catalogs.list(function() {
-					$scope.catalogMetadata = Catalogs.getMetadata($scope.catalogIndex);
-					$scope.list = Catalogs.query(Catalogs.getResource($scope.catalogIndex));
-				}); 
-
 				$scope.catalogMetadata = {};
-				$scope.selectCatalog = function(index, $event) {
-					$scope.catalogIndex = index;
-					$scope.catalogMetadata = Catalogs.getMetadata($scope.catalogIndex);
-					$scope.list = Catalogs.query(Catalogs.getResource($scope.catalogIndex));
-					console.log($event);
+				$scope.catalogsList = null;
+				$scope.list = null;
+				
+				var _changeCatalog = function(index) {
+					if (!$scope.catalogsList) $scope.catalogsList = Catalogs.getList(); // catalog list is also in index.data
+					if (typeof index === 'number') $scope.catalogIndex = index;
+					Catalogs.setCurrent($scope.catalogIndex);
+					$scope.catalogMetadata = Catalogs.getMetadata();
+					$scope.list = Catalogs.query();
+					$scope.refs = {}
+					Catalogs.loadRefs($scope.refs)
+					console.log($scope.refs)
 				}
+				
+				Catalogs.init().then(_changeCatalog); 
+
+				$scope.selectCatalog = _changeCatalog;
+				
 				$scope.edit = function(data) {
 					$scope.showForm = true;
 					$scope.isNew = false;
@@ -149,15 +59,16 @@
 					}
 					console.log('$scope.edit')
 					console.log($scope.formu)
+					$('#'+ Catalogs.getFFF()).focus();
+
 					
 				}
 				$scope.delete = function(data) {
 					BootstrapDialog.confirm('The record will be deleted, are you sure?', function(result){
 			            if(result) {
-							var catalogName = Catalogs.getResource($scope.catalogIndex);
-							var promise = Catalogs.remove(catalogName, data).$promise;
+							var promise = Catalogs.remove(data).$promise;
 							promise.then(function(data) {
-								$scope.list = Catalogs.query(catalogName);
+								$scope.list = Catalogs.query();
 							});
 			            }
 			        });
@@ -190,7 +101,7 @@
 				}
 				
 				$scope.editNew = function() {
-					$('#name').focus();
+					$('#'+ Catalogs.getFFF()).focus();
 					$scope.$parent.showForm = true;
 					$scope.$parent.isNew = true;
 					$scope.$parent.formu = {};
@@ -203,20 +114,17 @@
 					if ($scope.catalogForm.$invalid) {
 						alert(JSON.stringify($scope.catalogForm))
 					} else {
-						var catalogName = Catalogs.getResource($scope.catalogIndex);
-						var promise = Catalogs.save(catalogName, $scope.formu).$promise;
+						var promise = Catalogs.save($scope.formu).$promise;
 						promise.then(function(data, otro) {
 							if ($scope.isNew) {
 								$scope.$parent.formu = {}
-								$('#name').focus();
+								$('#'+ Catalogs.getFFF()).focus();
 							} else {
 								$scope.cancel();
 							}
-							$scope.$parent.list = Catalogs.query(catalogName);
-						}, function(error, otro) {
-							console.log('then error');
+							$scope.$parent.list = Catalogs.query();
+						}, function(error) {
 							console.log(error);
-							console.log(otro);							
 						});
 						
 					}
@@ -225,24 +133,18 @@
 
 	app.controller('CatalogListCtrl', [ '$scope', '$http', '$filter', 'Catalogs', 
 			function($scope, $http, $filter, Catalogs) {
-				console.log('List: currentCatalog: ' + $scope.currentCatalog);
-				var _indexOfField = function(name) {
-					if (!$scope.catalogMetadata) return -1;
-					for (var i = $scope.catalogMetadata.fields.length - 1; i >= 0 && $scope.catalogMetadata.fields[i].name !== name; i--);
-					return i;
-				}
-				
-				$scope.print = function(name, value) {
-					var index = _indexOfField(name);
-					if (index === -1) return value;
-					var type = $scope.catalogMetadata.fields[index].type;
-					
-					return type === 'date' ? $filter('date')(value, 'yyyy-MM-dd') : value;
+
+				$scope.print = function(name, row) {
+					var value = row[name];
+					var type = Catalogs.getField(name).type;
+					var printedValue = type === 'date' ? $filter('date')(value, 'yyyy-MM-dd') : value;
+					if (printedValue !== value) // this line is a work around to allow search in formatted fields
+						row['_display_'+name] = printedValue;
+					return printedValue;
 				}
 				
 				$scope.display = function(name) {
-					var index = _indexOfField(name);
-					return index === -1 ? '' : $scope.catalogMetadata.fields[index].display;
+					return Catalogs.getField(name).display;
 				}
 
 			} ]);
diff --git a/securis/src/main/resources/static/js/catalogs.js b/securis/src/main/resources/static/js/catalogs.js
new file mode 100644
index 0000000..6b854fe
--- /dev/null
+++ b/securis/src/main/resources/static/js/catalogs.js
@@ -0,0 +1,188 @@
+(function() {
+	'use strict';
+
+	/*
+	 * Catalogs module
+	 */
+
+	angular.module('catalogs', ['ngResource'])
+
+	.service('Catalogs', ['$rootScope', '$http', '$resource', '$q', function ($rootScope, $http, $resource, $q) {
+		var resources = {
+				application : $resource('/application/:appId', {
+					appId : '@id'
+				}, {
+					update : {
+						method : "PUT"
+					}
+				}),
+				user : $resource('/user/:userId', {
+					userId : '@id'
+				}, {
+					update : {
+						method : "PUT"
+					}
+				}),
+				licensetype : $resource('/licensetype/:licenseTypeId', {
+					licenseTypeId : '@id'
+				}, {
+					update : {
+						method : "PUT"
+					}
+				})
+		}
+
+	var _metadata = null;
+	var _current = null;
+
+	var _list = function() {
+		return $http.get('/js/catalogs.json').success(function(data) {
+			_metadata = data;
+		})
+	}
+	this.init = function() {
+		return _list();
+	}
+	this.getList = function() {
+		return _metadata;
+	}
+	this.getName = function(index) {
+		if (index === undefined)
+			return _current ? _current.name : '';
+		return _metadata ? _metadata[index].name : '';
+	}
+	this.getResource = function(res) {
+		if (res === undefined)
+			return _current ? resources[_current.resource] : null;
+		return _current ? resources[res] : null;		
+	}
+	this.getPk = function(catalogMetadata) {
+		if (!catalogMetadata) catalogMetadata = _current;
+		
+		for(var i = 0; i < catalogMetadata.fields.length; i++)
+			if (catalogMetadata.fields[i].pk) return catalogMetadata.fields[i].name; 
+			
+		return null;		
+	}
+	/**
+	 * Returns catalog metadata
+	 * @param index: Return current catalog if undefined, if string It find the catalog by resoource name if number it find it by position
+	 */
+	this.getMetadata = function(index) {
+		if (!_metadata) throw new Error('There is no catalog metadata info');
+		if (index === undefined)
+			return _current;
+		if (typeof index === 'string') {
+			for (var i = _metadata.length - 1; i >= 0 && _metadata[i].resource !== index; i--);
+			index = i;
+		} 
+
+		return _metadata[index];
+	}
+	this.setCurrent = function(index) {
+		if (!_metadata) throw new Error('There is no catalog metadata info');
+		if (index === undefined)
+			_current = null;
+		else
+			_current = _metadata[index];
+	}
+	/********************************************
+	 * Catalog fields methods                   *
+	 ********************************************/
+
+	/**
+	 * Returns the first field in form that should get the focus. We find the first field that is not read only 
+	 */
+	this.getFFF = this.getFirstFocusableField = function() {
+		if (!_current) throw new Error('There is no current catalog selected');
+		
+		for(var i = i; i < _current.fields.length; i++)
+			if (f.readOnly) return f.name;
+		
+		return null;
+	}
+
+	/**
+	 * Find the field by name or position 
+	 */
+	this.getField = function(key) {
+		if (!_current) throw new Error('There is no current catalog selected');
+		var index = -1;
+		if (typeof key === 'string') {
+			for (var i = _current.fields.length - 1; i >= 0 && _current.fields[i].name !== key; i--);
+			index = i;
+		} else {
+			index = key; // In this case key === field position
+		}
+
+		return index === -1 ? {} : _current.fields[index];
+	}
+	
+	/********************************************
+	 * Catalog resource operations on server    *
+	 ********************************************/
+
+	function _success(response) {
+		console.log('$resource')
+		console.log(response)
+	}
+	function _fail(response) {
+		console.error('Error trying to get data, HTTP error code: ' + response.status)
+	}
+	
+	
+	this.save = function(data) {
+		if (!_current) throw new Error('There is no current catalog selected');
+
+		var resource = this.getResource();
+		if (data.id && data.id !== '')
+				return resource.update(data, _success, _fail);
+			else
+				return resource.save(data, _success, _fail);
+	}
+	this.remove = function(data) {
+		return this.getResource().remove({}, data, _success, _fail)
+	}
+	this.query = function() {
+		return this.getResource().query({}, _success, _fail);
+	}
+	this.loadRefs = function(refs) {
+		if (!_current) throw new Error('There is no current catalog selected');
+		var refsFields = [];
+		_current.fields.forEach(function(f) {
+			if (f.resource)
+				refsFields.push(f)
+		});
+		
+		var that = this;
+		var promises = []
+		refsFields.forEach(function(f) {
+			var resource = that.getResource(f.resource);
+			refs[f.name] = resource.query({}, _success, _fail);
+			promises.push(refs[f.name].$promise);
+		});
+		
+		console.log('promises: ' + promises.length + ' ')
+		console.log(promises)
+		$q.all(promises).then(function() {
+			console.log('ALL promises OK :::::::::::::::::::::::::::: ')
+			for (var k in refs) {
+				var pk = that.getPk(that.getMetadata(k))
+				console.log('PK for '+k+' is ' + pk);
+				var comboData = []
+				refs[k].forEach(function(row) {
+					comboData.push({
+						id: row[pk],
+						label: row.label || row.name || row.code
+					});
+				})
+				refs[k] = comboData;
+			}
+			
+		})
+		return refs;
+	} 
+	
+	}])
+
+})();
\ No newline at end of file
diff --git a/securis/src/main/resources/static/js/catalogs.json b/securis/src/main/resources/static/js/catalogs.json
index f123dac..a7facac 100644
--- a/securis/src/main/resources/static/js/catalogs.json
+++ b/securis/src/main/resources/static/js/catalogs.json
@@ -28,6 +28,7 @@
 	} ]
 }, {
 	"name" : "License types",
+	"list_fields" : [ "code", "name", "application_name", "creationTimestamp" ],
 	"resource" : "licensetype",
 	"fields" : [ {
 		"name" : "id",
@@ -54,23 +55,66 @@
 		"maxlength" : 500,
 		"multiline" : 2
 	}, {
-		"name" : "application",
+		"name" : "application_id",
 		"display" : "Application",
-		"type" : "select",
-		"readOnly" : true
+		"resource" : "application",
+		"type" : "select"
 	}, {
 		"name" : "creationTimestamp",
 		"display" : "Creation date",
 		"type" : "date",
 		"readOnly" : true
+	}, {
+		"name" : "application_name",
+		"display" : "Application",
+		"listingOnly" : true
+	} ]
+}, {
+	"name" : "Organizations",
+	"list_fields" : [ "code", "name", "application_name", "creationTimestamp" ],
+	"resource" : "organization",
+	"fields" : [ {
+		"name" : "id",
+		"display" : "ID",
+		"type" : "number",
+		"pk" : true,
+		"readOnly" : true
+	}, {
+		"name" : "code",
+		"display" : "Code",
+		"type" : "string",
+		"maxlength" : 10,
+		"mandatory" : true
+	}, {
+		"name" : "name",
+		"display" : "Name",
+		"type" : "string",
+		"maxlength" : 45,
+		"mandatory" : true
+	}, {
+		"name" : "description",
+		"display" : "Description",
+		"type" : "string",
+		"maxlength" : 500,
+		"multiline" : 2
+	}, {
+		"name" : "application_id",
+		"display" : "Application",
+		"resource" : "application",
+		"type" : "select"
+	}, {
+		"name" : "creationTimestamp",
+		"display" : "Creation date",
+		"type" : "date",
+		"readOnly" : true
+	}, {
+		"name" : "application_name",
+		"display" : "Application",
+		"listingOnly" : true
 	} ]
 }, {
 	"name" : "Users",
 	"resource" : "user",
-	"fields" : []
-}, {
-	"name" : "Organizations",
-	"resource" : "organization",
 	"fields" : []
 }, {
 	"name" : "System params",

--
Gitblit v1.3.2