minor fixes on getCatalogue method
git-svn-id: https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-catalogue/catalogue-ws@164565 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
parent
f83ce30d82
commit
8814c2efc5
|
@ -45,17 +45,11 @@ public class CatalogueUtils {
|
|||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static DataCatalogue getCatalogue(){
|
||||
public static DataCatalogue getCatalogue() throws Exception{
|
||||
|
||||
try{
|
||||
String context = ScopeProvider.instance.get();
|
||||
logger.debug("Discovering ckan instance into scope " + context);
|
||||
return DataCatalogueFactory.getFactory().getUtilsPerScope(context);
|
||||
}catch(Exception e){
|
||||
logger.error("Unable to lookup catalogue object here ", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
String context = ScopeProvider.instance.get();
|
||||
logger.debug("Discovering ckan instance into scope " + context);
|
||||
return DataCatalogueFactory.getFactory().getUtilsPerScope(context);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -216,13 +210,7 @@ public class CatalogueUtils {
|
|||
* @return
|
||||
*/
|
||||
public static String createJSONOnFailure(String errorMessage){
|
||||
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put(Constants.HELP_KEY, Constants.HELP_URL_GCUBE_CATALOGUE);
|
||||
obj.put(Constants.SUCCESS_KEY, false);
|
||||
obj.put(Constants.MESSAGE_ERROR_KEY, errorMessage);
|
||||
return obj.toJSONString();
|
||||
|
||||
return createJSONObjectMin(false, errorMessage).toJSONString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -291,19 +279,19 @@ public class CatalogueUtils {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetch the sysadmin key from the IS
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String fetchSysAPI(String context) throws Exception{
|
||||
|
||||
|
||||
DataCatalogueRunningCluster catalogueRunningInstance = new DataCatalogueRunningCluster(context);
|
||||
return catalogueRunningInstance.getSysAdminToken();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the token belongs to an application token
|
||||
* @param caller
|
||||
|
|
|
@ -52,61 +52,55 @@ public class Delegator {
|
|||
* @throws Exception
|
||||
*/
|
||||
public static String delegateGet(Caller caller, String context, String method, UriInfo uriInfo, boolean isAppRequest){
|
||||
|
||||
DataCatalogue catalogue = CatalogueUtils.getCatalogue();
|
||||
String username = caller.getClient().getId();
|
||||
|
||||
if(catalogue == null){
|
||||
String msg = "There is no catalogue instance in context " + context + " or a temporary problem arised.";
|
||||
logger.warn(msg);
|
||||
return CatalogueUtils.createJSONOnFailure(msg);
|
||||
}else{
|
||||
try(CloseableHttpClient client = HttpClientBuilder.create().build();){
|
||||
try(CloseableHttpClient client = HttpClientBuilder.create().build();){
|
||||
|
||||
String authorization = isAppRequest ? CatalogueUtils.fetchSysAPI(ScopeProvider.instance.get()) : catalogue.getApiKeyFromUsername(username);
|
||||
String requestPath = catalogue.getCatalogueUrl().endsWith("/") ? catalogue.getCatalogueUrl() : catalogue.getCatalogueUrl() + "/";
|
||||
requestPath += method;
|
||||
MultivaluedMap<String, String> undecodedParams = uriInfo.getQueryParameters(false);
|
||||
Iterator<Entry<String, List<String>>> iterator = undecodedParams.entrySet().iterator();
|
||||
DataCatalogue catalogue = CatalogueUtils.getCatalogue();
|
||||
String authorization = isAppRequest ? CatalogueUtils.fetchSysAPI(ScopeProvider.instance.get()) : catalogue.getApiKeyFromUsername(username);
|
||||
String requestPath = catalogue.getCatalogueUrl().endsWith("/") ? catalogue.getCatalogueUrl() : catalogue.getCatalogueUrl() + "/";
|
||||
requestPath += method;
|
||||
MultivaluedMap<String, String> undecodedParams = uriInfo.getQueryParameters(false);
|
||||
Iterator<Entry<String, List<String>>> iterator = undecodedParams.entrySet().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<java.lang.String, java.util.List<java.lang.String>> entry = (Map.Entry<java.lang.String, java.util.List<java.lang.String>>) iterator
|
||||
.next();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<java.lang.String, java.util.List<java.lang.String>> entry = (Map.Entry<java.lang.String, java.util.List<java.lang.String>>) iterator
|
||||
.next();
|
||||
|
||||
if(entry.getKey().equals(Constants.GCUBE_TOKEN_PARAMETER))
|
||||
continue;
|
||||
else{
|
||||
if(entry.getKey().equals(Constants.GCUBE_TOKEN_PARAMETER))
|
||||
continue;
|
||||
else{
|
||||
|
||||
List<String> values = entry.getValue();
|
||||
for (String value : values) {
|
||||
requestPath += entry.getKey() + "=" + value + "&";
|
||||
}
|
||||
List<String> values = entry.getValue();
|
||||
for (String value : values) {
|
||||
requestPath += entry.getKey() + "=" + value + "&";
|
||||
}
|
||||
}
|
||||
|
||||
if(requestPath.endsWith("&"))
|
||||
requestPath = requestPath.substring(0, requestPath.length() - 1);
|
||||
HttpGet request = new HttpGet(requestPath);
|
||||
if(authorization != null)
|
||||
request.addHeader(Constants.AUTH_CKAN_HEADER, authorization);
|
||||
|
||||
logger.debug("******* REQUEST URL IS " + requestPath);
|
||||
|
||||
HttpEntity entityRes = client.execute(request).getEntity();
|
||||
String json = EntityUtils.toString(entityRes);
|
||||
|
||||
// substitute "help" field
|
||||
JSONParser parser = new JSONParser();
|
||||
JSONObject obj = (JSONObject) parser.parse(json);
|
||||
obj.put(Constants.HELP_KEY, Constants.HELP_URL_GCUBE_CATALOGUE);
|
||||
return obj.toJSONString();
|
||||
|
||||
}catch(Exception e){
|
||||
logger.error("Failed to serve the request", e);
|
||||
return CatalogueUtils.createJSONOnFailure("Failed to serve the request: " + e);
|
||||
}
|
||||
|
||||
if(requestPath.endsWith("&"))
|
||||
requestPath = requestPath.substring(0, requestPath.length() - 1);
|
||||
HttpGet request = new HttpGet(requestPath);
|
||||
if(authorization != null)
|
||||
request.addHeader(Constants.AUTH_CKAN_HEADER, authorization);
|
||||
|
||||
logger.debug("******* REQUEST URL IS " + requestPath);
|
||||
|
||||
HttpEntity entityRes = client.execute(request).getEntity();
|
||||
String json = EntityUtils.toString(entityRes);
|
||||
|
||||
// substitute "help" field
|
||||
JSONParser parser = new JSONParser();
|
||||
JSONObject obj = (JSONObject) parser.parse(json);
|
||||
obj.put(Constants.HELP_KEY, Constants.HELP_URL_GCUBE_CATALOGUE);
|
||||
return obj.toJSONString();
|
||||
|
||||
}catch(Exception e){
|
||||
logger.error("Failed to serve the request", e);
|
||||
return CatalogueUtils.createJSONOnFailure("Failed to serve the request: " + e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -122,67 +116,62 @@ public class Delegator {
|
|||
String method, String json, UriInfo uriInfo, boolean isAppRequest){
|
||||
|
||||
String username = caller.getClient().getId();
|
||||
DataCatalogue catalogue = CatalogueUtils.getCatalogue();
|
||||
|
||||
if(catalogue == null){
|
||||
String msg = "There is no catalogue instance in context " + context + " or a temporary problem arised.";
|
||||
logger.warn(msg);
|
||||
return CatalogueUtils.createJSONOnFailure(msg);
|
||||
}else{
|
||||
try(CloseableHttpClient client = HttpClientBuilder.create().build();){
|
||||
|
||||
try(CloseableHttpClient client = HttpClientBuilder.create().build();){
|
||||
DataCatalogue catalogue = CatalogueUtils.getCatalogue();
|
||||
|
||||
String authorization = isAppRequest ? CatalogueUtils.fetchSysAPI(ScopeProvider.instance.get()) : catalogue.getApiKeyFromUsername(username);
|
||||
String requestPath = catalogue.getCatalogueUrl().endsWith("/") ? catalogue.getCatalogueUrl() : catalogue.getCatalogueUrl() + "/";
|
||||
requestPath += method + "?";
|
||||
String authorization = isAppRequest ? CatalogueUtils.fetchSysAPI(ScopeProvider.instance.get()) : catalogue.getApiKeyFromUsername(username);
|
||||
String requestPath = catalogue.getCatalogueUrl().endsWith("/") ? catalogue.getCatalogueUrl() : catalogue.getCatalogueUrl() + "/";
|
||||
requestPath += method + "?";
|
||||
|
||||
MultivaluedMap<String, String> undecodedParams = uriInfo.getQueryParameters(false);
|
||||
Iterator<Entry<String, List<String>>> iterator = undecodedParams.entrySet().iterator();
|
||||
MultivaluedMap<String, String> undecodedParams = uriInfo.getQueryParameters(false);
|
||||
Iterator<Entry<String, List<String>>> iterator = undecodedParams.entrySet().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<java.lang.String, java.util.List<java.lang.String>> entry = (Map.Entry<java.lang.String, java.util.List<java.lang.String>>) iterator
|
||||
.next();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<java.lang.String, java.util.List<java.lang.String>> entry = (Map.Entry<java.lang.String, java.util.List<java.lang.String>>) iterator
|
||||
.next();
|
||||
|
||||
if(entry.getKey().equals(Constants.GCUBE_TOKEN_PARAMETER))
|
||||
continue;
|
||||
else{
|
||||
if(entry.getKey().equals(Constants.GCUBE_TOKEN_PARAMETER))
|
||||
continue;
|
||||
else{
|
||||
|
||||
List<String> values = entry.getValue();
|
||||
for (String value : values) {
|
||||
requestPath += entry.getKey() + "=" + value + "&";
|
||||
}
|
||||
List<String> values = entry.getValue();
|
||||
for (String value : values) {
|
||||
requestPath += entry.getKey() + "=" + value + "&";
|
||||
}
|
||||
}
|
||||
|
||||
if(requestPath.endsWith("&"))
|
||||
requestPath = requestPath.substring(0, requestPath.length() - 1);
|
||||
|
||||
logger.debug("POST request url is going to be " + requestPath);
|
||||
|
||||
HttpPost request = new HttpPost(requestPath);
|
||||
request.addHeader(Constants.AUTH_CKAN_HEADER, authorization);
|
||||
logger.debug("Sending json to CKAN is " + json);
|
||||
StringEntity params = new StringEntity(json, ContentType.APPLICATION_JSON);
|
||||
request.setEntity(params);
|
||||
HttpEntity entityRes = client.execute(request).getEntity();
|
||||
String jsonRes = EntityUtils.toString(entityRes);
|
||||
|
||||
logger.debug("Result from CKAN is " + jsonRes);
|
||||
|
||||
// substitute "help" field
|
||||
JSONParser parser = new JSONParser();
|
||||
JSONObject obj = (JSONObject) parser.parse(jsonRes);
|
||||
obj.put(Constants.HELP_KEY, Constants.HELP_URL_GCUBE_CATALOGUE);
|
||||
|
||||
logger.debug("replaced information " + obj);
|
||||
return obj.toJSONString();
|
||||
|
||||
}catch(Exception e){
|
||||
logger.error("Failed to serve the request", e);
|
||||
return CatalogueUtils.createJSONOnFailure("Failed to serve the request: " + e);
|
||||
}
|
||||
|
||||
if(requestPath.endsWith("&"))
|
||||
requestPath = requestPath.substring(0, requestPath.length() - 1);
|
||||
|
||||
logger.debug("POST request url is going to be " + requestPath);
|
||||
|
||||
HttpPost request = new HttpPost(requestPath);
|
||||
request.addHeader(Constants.AUTH_CKAN_HEADER, authorization);
|
||||
logger.debug("Sending json to CKAN is " + json);
|
||||
StringEntity params = new StringEntity(json, ContentType.APPLICATION_JSON);
|
||||
request.setEntity(params);
|
||||
HttpEntity entityRes = client.execute(request).getEntity();
|
||||
String jsonRes = EntityUtils.toString(entityRes);
|
||||
|
||||
logger.debug("Result from CKAN is " + jsonRes);
|
||||
|
||||
// substitute "help" field
|
||||
JSONParser parser = new JSONParser();
|
||||
JSONObject obj = (JSONObject) parser.parse(jsonRes);
|
||||
obj.put(Constants.HELP_KEY, Constants.HELP_URL_GCUBE_CATALOGUE);
|
||||
|
||||
logger.debug("replaced information " + obj);
|
||||
return obj.toJSONString();
|
||||
|
||||
}catch(Exception e){
|
||||
logger.error("Failed to serve the request", e);
|
||||
return CatalogueUtils.createJSONOnFailure("Failed to serve the request: " + e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -198,80 +187,73 @@ public class Delegator {
|
|||
String method, FormDataMultiPart multiPart, UriInfo uriInfo, boolean isAppRequest) {
|
||||
|
||||
String username = caller.getClient().getId();
|
||||
DataCatalogue catalogue = CatalogueUtils.getCatalogue();
|
||||
|
||||
if(catalogue == null){
|
||||
String msg = "There is no catalogue instance in context " + context + " or a temporary problem arised.";
|
||||
logger.warn(msg);
|
||||
return CatalogueUtils.createJSONOnFailure(msg);
|
||||
}else{
|
||||
try{
|
||||
DataCatalogue catalogue = CatalogueUtils.getCatalogue();
|
||||
String authorization = isAppRequest ? CatalogueUtils.fetchSysAPI(ScopeProvider.instance.get()) : catalogue.getApiKeyFromUsername(username);
|
||||
String requestPath = catalogue.getCatalogueUrl().endsWith("/") ? catalogue.getCatalogueUrl() : catalogue.getCatalogueUrl() + "/";
|
||||
requestPath += method + "?";
|
||||
|
||||
try{
|
||||
MultivaluedMap<String, String> undecodedParams = uriInfo.getQueryParameters(false);
|
||||
Iterator<Entry<String, List<String>>> iterator = undecodedParams.entrySet().iterator();
|
||||
|
||||
String authorization = isAppRequest ? CatalogueUtils.fetchSysAPI(ScopeProvider.instance.get()) : catalogue.getApiKeyFromUsername(username);
|
||||
String requestPath = catalogue.getCatalogueUrl().endsWith("/") ? catalogue.getCatalogueUrl() : catalogue.getCatalogueUrl() + "/";
|
||||
requestPath += method + "?";
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<java.lang.String, java.util.List<java.lang.String>> entry = (Map.Entry<java.lang.String, java.util.List<java.lang.String>>) iterator
|
||||
.next();
|
||||
|
||||
MultivaluedMap<String, String> undecodedParams = uriInfo.getQueryParameters(false);
|
||||
Iterator<Entry<String, List<String>>> iterator = undecodedParams.entrySet().iterator();
|
||||
if(entry.getKey().equals("Constants.AUTH_CKAN_HEADER"))
|
||||
continue;
|
||||
else{
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<java.lang.String, java.util.List<java.lang.String>> entry = (Map.Entry<java.lang.String, java.util.List<java.lang.String>>) iterator
|
||||
.next();
|
||||
|
||||
if(entry.getKey().equals("Constants.AUTH_CKAN_HEADER"))
|
||||
continue;
|
||||
else{
|
||||
|
||||
List<String> values = entry.getValue();
|
||||
for (String value : values) {
|
||||
requestPath += entry.getKey() + "=" + value + "&";
|
||||
}
|
||||
List<String> values = entry.getValue();
|
||||
for (String value : values) {
|
||||
requestPath += entry.getKey() + "=" + value + "&";
|
||||
}
|
||||
}
|
||||
|
||||
if(requestPath.endsWith("&"))
|
||||
requestPath = requestPath.substring(0, requestPath.length() - 1);
|
||||
|
||||
logger.debug("POST request url is going to be " + requestPath);
|
||||
|
||||
// use jersey client
|
||||
logger.debug("Sending multipart to CKAN " + multiPart);
|
||||
|
||||
FormDataBodyPart upload = multiPart.getField("upload");
|
||||
if(upload != null){
|
||||
File file = upload.getValueAs(File.class);
|
||||
long fileLenghtBytes = file.length();
|
||||
long fileLenghtMegaByte = fileLenghtBytes >> 20;
|
||||
logger.debug("File lenght in MegaByte is " + fileLenghtMegaByte);
|
||||
|
||||
if(fileLenghtMegaByte > Constants.MAX_UPLOADABLE_FILE_SIZE_MB)
|
||||
throw new Exception("Exceeding maximum uploadable file size!");
|
||||
|
||||
}else
|
||||
throw new Exception("No 'upload' field has been provided!");
|
||||
|
||||
Client client = ClientBuilder.newClient();
|
||||
client.register(MultiPartFeature.class);
|
||||
WebTarget webResource = client.target(requestPath);
|
||||
JSONObject jsonRes =
|
||||
webResource
|
||||
.request(MediaType.APPLICATION_JSON)
|
||||
.header(Constants.AUTH_CKAN_HEADER, authorization)
|
||||
.post(Entity.entity(multiPart, multiPart.getMediaType()), JSONObject.class);
|
||||
|
||||
logger.debug("Result from CKAN is " + jsonRes);
|
||||
|
||||
// substitute "help" field
|
||||
jsonRes.put(Constants.HELP_KEY, Constants.HELP_URL_GCUBE_CATALOGUE);
|
||||
return jsonRes.toJSONString();
|
||||
|
||||
}catch(Exception e){
|
||||
logger.error("Failed to serve the request", e);
|
||||
return CatalogueUtils.createJSONOnFailure("Failed to serve the request: " + e);
|
||||
}
|
||||
|
||||
if(requestPath.endsWith("&"))
|
||||
requestPath = requestPath.substring(0, requestPath.length() - 1);
|
||||
|
||||
logger.debug("POST request url is going to be " + requestPath);
|
||||
|
||||
// use jersey client
|
||||
logger.debug("Sending multipart to CKAN " + multiPart);
|
||||
|
||||
FormDataBodyPart upload = multiPart.getField("upload");
|
||||
if(upload != null){
|
||||
File file = upload.getValueAs(File.class);
|
||||
long fileLenghtBytes = file.length();
|
||||
long fileLenghtMegaByte = fileLenghtBytes >> 20;
|
||||
logger.debug("File lenght in MegaByte is " + fileLenghtMegaByte);
|
||||
|
||||
if(fileLenghtMegaByte > Constants.MAX_UPLOADABLE_FILE_SIZE_MB)
|
||||
throw new Exception("Exceeding maximum uploadable file size!");
|
||||
|
||||
}else
|
||||
throw new Exception("No 'upload' field has been provided!");
|
||||
|
||||
Client client = ClientBuilder.newClient();
|
||||
client.register(MultiPartFeature.class);
|
||||
WebTarget webResource = client.target(requestPath);
|
||||
JSONObject jsonRes =
|
||||
webResource
|
||||
.request(MediaType.APPLICATION_JSON)
|
||||
.header(Constants.AUTH_CKAN_HEADER, authorization)
|
||||
.post(Entity.entity(multiPart, multiPart.getMediaType()), JSONObject.class);
|
||||
|
||||
logger.debug("Result from CKAN is " + jsonRes);
|
||||
|
||||
// substitute "help" field
|
||||
jsonRes.put(Constants.HELP_KEY, Constants.HELP_URL_GCUBE_CATALOGUE);
|
||||
return jsonRes.toJSONString();
|
||||
|
||||
}catch(Exception e){
|
||||
logger.error("Failed to serve the request", e);
|
||||
return CatalogueUtils.createJSONOnFailure("Failed to serve the request: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ public class Validator {
|
|||
dataset.put(Constants.OWNER_ORG_KEY, organization);
|
||||
}
|
||||
else
|
||||
throw new Exception("You must specify the field owner_org in which the item should be published!");
|
||||
throw new Exception("You must specify the field 'owner_org' in which the item should be published!");
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -213,11 +213,15 @@ public class Item {
|
|||
Caller caller = AuthorizationProvider.instance.get();
|
||||
String context = ScopeProvider.instance.get();
|
||||
String username = caller.getClient().getId();
|
||||
DataCatalogue utils = CatalogueUtils.getCatalogue();
|
||||
boolean isApplication = CatalogueUtils.isApplicationToken(caller);
|
||||
|
||||
if(isApplication){
|
||||
try {
|
||||
|
||||
try {
|
||||
|
||||
DataCatalogue utils = CatalogueUtils.getCatalogue();
|
||||
boolean isApplication = CatalogueUtils.isApplicationToken(caller);
|
||||
|
||||
if(isApplication){
|
||||
|
||||
// in this case we check the author has been filled with the same qualifier of this token: the same qualifier can be used in two different contexts
|
||||
String organization = CatalogueUtilMethods.getOrganizationNameFromScope(context);
|
||||
String datasetId = null;
|
||||
|
@ -236,23 +240,15 @@ public class Item {
|
|||
}else
|
||||
throw new Exception("You cannot purge this item");
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Something went wrong... ", e);
|
||||
if(e instanceof ParseException)
|
||||
return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!");
|
||||
else
|
||||
return CatalogueUtils.createJSONOnFailure(e.toString());
|
||||
}
|
||||
}else{
|
||||
|
||||
// if sysadmin, just invoke ckan
|
||||
if(utils.isSysAdmin(username)){
|
||||
logger.debug("User " + caller.getClient().getId() + " seems a sysadmin");
|
||||
return Delegator.delegatePost(caller, context, Constants.ITEM_PURGE, json, uriInfo, false);
|
||||
}
|
||||
else{
|
||||
try {
|
||||
|
||||
// if sysadmin, just invoke ckan
|
||||
if(utils.isSysAdmin(username)){
|
||||
logger.debug("User " + caller.getClient().getId() + " seems a sysadmin");
|
||||
return Delegator.delegatePost(caller, context, Constants.ITEM_PURGE, json, uriInfo, false);
|
||||
}
|
||||
else{
|
||||
String datasetId = null;
|
||||
String ownerId = null;
|
||||
String organization = null;
|
||||
|
@ -287,15 +283,17 @@ public class Item {
|
|||
}
|
||||
return CatalogueUtils.createJSONObjectMin(purged, null).toJSONString();
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Something went wrong... ", e);
|
||||
if(e instanceof ParseException)
|
||||
return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!");
|
||||
else
|
||||
return CatalogueUtils.createJSONOnFailure(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.error("Something went wrong... ", e);
|
||||
if(e instanceof ParseException)
|
||||
return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!");
|
||||
else
|
||||
return CatalogueUtils.createJSONOnFailure(e.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO PROFILE VALIDATION MUST BE PERFORMED HERE AS WELL
|
||||
|
|
Reference in New Issue