Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added view template support for get apis #209

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ public class Constants {
public static final String FILE_URL = "fileUrl";

public static final String CREDENTIAL_TEMPLATE = "credentialTemplate";
public static final String VIEW_TEMPLATE_ID = "viewTemplateId";
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
import dev.sunbirdrc.registry.transform.Configuration;
import dev.sunbirdrc.registry.transform.Data;
import dev.sunbirdrc.registry.transform.ITransformer;
import dev.sunbirdrc.registry.util.ViewTemplateManager;
import dev.sunbirdrc.validators.ValidationException;
import dev.sunbirdrc.views.ViewTemplate;
import org.agrona.Strings;
import org.apache.commons.lang3.StringUtils;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -62,6 +65,8 @@ public class RegistryEntityController extends AbstractController {
@Autowired
private AsyncRequest asyncRequest;

@Autowired
private ViewTemplateManager viewTemplateManager;


@Value("${authentication.enabled:true}") boolean securityEnabled;
Expand Down Expand Up @@ -434,7 +439,8 @@ private ArrayList<String> getConsentFields(HttpServletRequest request) {
{MediaType.APPLICATION_PDF_VALUE, MediaType.TEXT_HTML_VALUE, Constants.SVG_MEDIA_TYPE})
public ResponseEntity<Object> getEntityType(@PathVariable String entityName,
@PathVariable String entityId,
HttpServletRequest request) {
HttpServletRequest request,
@RequestHeader(required = false) String viewTemplateId) {
if (registryHelper.doesEntityOperationRequireAuthorization(entityName) && securityEnabled) {
try {
registryHelper.authorize(entityName, entityId, request);
Expand All @@ -448,7 +454,8 @@ public ResponseEntity<Object> getEntityType(@PathVariable String entityName,
}
try {
String readerUserId = getUserId(entityName, request);
JsonNode node = registryHelper.readEntity(readerUserId, entityName, entityId, false, null, false)
JsonNode node = registryHelper.readEntity(readerUserId, entityName, entityId, false,
viewTemplateManager.getViewTemplateById(viewTemplateId), false)
.get(entityName);
JsonNode signedNode = objectMapper.readTree(node.get(OSSystemFields._osSignedData.name()).asText());
return new ResponseEntity<>(certificateService.getCertificate(signedNode,
Expand Down Expand Up @@ -564,16 +571,17 @@ private JsonNode getEntityJsonNode(@PathVariable String entityName, @PathVariabl
}

@RequestMapping(value = "/api/v1/{entityName}", method = RequestMethod.GET)
public ResponseEntity<Object> getEntityByToken(@PathVariable String entityName, HttpServletRequest request) {
public ResponseEntity<Object> getEntityByToken(@PathVariable String entityName, HttpServletRequest request,
@RequestHeader(required = false) String viewTemplateId) {
ResponseParams responseParams = new ResponseParams();
Response response = new Response(Response.API_ID.SEARCH, "OK", responseParams);
try {
JsonNode result = registryHelper.getRequestedUserDetails(request, entityName);
if (result.get(entityName).size() > 0) {
ArrayNode responseFromDb = registryHelper.fetchFromDBUsingEsResponse(entityName, (ArrayNode) result.get(entityName));
return new ResponseEntity<>(responseFromDb, HttpStatus.OK);
String userId = registryHelper.getUserId(request, entityName);
if (!Strings.isEmpty(userId)) {
JsonNode responseFromDb = registryHelper.searchEntitiesByUserId(entityName, userId, viewTemplateId);
return new ResponseEntity<>(responseFromDb.get(entityName), HttpStatus.OK);
} else {
responseParams.setErrmsg("Entity not found");
responseParams.setErrmsg("User id is empty");
responseParams.setStatus(Response.Status.UNSUCCESSFUL);
return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import dev.sunbirdrc.views.ViewTransformer;
import io.minio.errors.*;
import lombok.Setter;
import org.agrona.Strings;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -108,6 +109,9 @@ public class RegistryHelper {
@Autowired
private ISearchService searchService;

@Autowired
private NativeSearchService nativeSearchService;

@Autowired
private ViewTemplateManager viewTemplateManager;

Expand Down Expand Up @@ -332,8 +336,12 @@ public JsonNode readEntity(JsonNode inputJson, String userId) throws Exception {
* @throws Exception
*/
public JsonNode searchEntity(JsonNode inputJson) throws Exception {
return searchEntity(inputJson, searchService);
}

private JsonNode searchEntity(JsonNode inputJson, ISearchService service) throws Exception {
logger.debug("searchEntity starts");
JsonNode resultNode = searchService.search(inputJson);
JsonNode resultNode = service.search(inputJson);
ViewTemplate viewTemplate = viewTemplateManager.getViewTemplate(inputJson);
if (viewTemplate != null) {
ViewTransformer vTransformer = new ViewTransformer();
Expand Down Expand Up @@ -776,11 +784,7 @@ private JsonNode getUserInfoFromKeyCloak(HttpServletRequest request, String enti
private JsonNode getUserInfoFromRegistry(HttpServletRequest request, String entityName) throws Exception {
String userId = getUserId(request,entityName);
if (userId != null) {
ObjectNode payload = JsonNodeFactory.instance.objectNode();
payload.set(ENTITY_TYPE, JsonNodeFactory.instance.arrayNode().add(entityName));
ObjectNode filters = JsonNodeFactory.instance.objectNode();
filters.set(OSSystemFields.osOwner.toString(), JsonNodeFactory.instance.objectNode().put("contains", userId));
payload.set(FILTERS, filters);
ObjectNode payload = getSearchByOwnerQuery(entityName, userId);

watch.start("RegistryController.searchEntity");
JsonNode result = searchEntity(payload);
Expand All @@ -790,6 +794,16 @@ private JsonNode getUserInfoFromRegistry(HttpServletRequest request, String enti
throw new Exception("Forbidden");
}

@NotNull
private ObjectNode getSearchByOwnerQuery(String entityName, String userId) {
ObjectNode payload = JsonNodeFactory.instance.objectNode();
payload.set(ENTITY_TYPE, JsonNodeFactory.instance.arrayNode().add(entityName));
ObjectNode filters = JsonNodeFactory.instance.objectNode();
filters.set(OSSystemFields.osOwner.toString(), JsonNodeFactory.instance.objectNode().put("contains", userId));
payload.set(FILTERS, filters);
return payload;
}

public String authorize(String entityName, String entityId, HttpServletRequest request) throws Exception {
String userIdFromRequest = getUserId(request, entityName);
if (getManageRoles(entityName).size() > 0) {
Expand Down Expand Up @@ -851,6 +865,13 @@ public ArrayNode fetchFromDBUsingEsResponse(String entity, ArrayNode esSearchRes
}
return result;
}
public JsonNode searchEntitiesByUserId(String entity, String userId, String viewTemplateId) throws Exception {
ObjectNode searchByOwnerQuery = getSearchByOwnerQuery(entity, userId);
if (!Strings.isEmpty(viewTemplateId)) {
searchByOwnerQuery.put(VIEW_TEMPLATE_ID, viewTemplateId);
}
return searchEntity(searchByOwnerQuery, nativeSearchService);
}

public void authorizeInviteEntity(HttpServletRequest request, String entityName) throws Exception {
List<String> inviteRoles = definitionsManager.getDefinition(entityName)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package dev.sunbirdrc.registry.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.*;

import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.Transaction;
Expand All @@ -27,7 +24,6 @@
import dev.sunbirdrc.registry.dao.IRegistryDao;
import dev.sunbirdrc.registry.dao.RegistryDaoImpl;
import dev.sunbirdrc.registry.dao.SearchDaoImpl;
import dev.sunbirdrc.registry.middleware.util.Constants;
import dev.sunbirdrc.registry.middleware.util.JSONUtil;
import dev.sunbirdrc.registry.model.DBConnectionInfo;
import dev.sunbirdrc.registry.model.DBConnectionInfoMgr;
Expand Down Expand Up @@ -66,22 +62,25 @@ public class NativeSearchService implements ISearchService {

@Value("${search.offset}")
private int offset;

@Value("${search.limit}")
private int limit;

@Value("${audit.enabled}")
private boolean auditEnabled;

@Value("${audit.frame.suffix}")
private String auditSuffix;

@Value("${search.expandInternal}")
private boolean expandInternal;

@Value("${search.removeNonPublicFieldsForNativeSearch:true}")
private boolean removeNonPublicFieldsForNativeSearch;

@Override
public JsonNode search(JsonNode inputQueryNode) throws IOException {

ArrayNode result = JsonNodeFactory.instance.arrayNode();
SearchQuery searchQuery = getSearchQuery(inputQueryNode, offset, limit);

Expand Down Expand Up @@ -120,8 +119,10 @@ public JsonNode search(JsonNode inputQueryNode) throws IOException {
String prefix = shard.getShardLabel() + RecordIdentifier.getSeparator();
JSONUtil.addPrefix((ObjectNode) shardResult, prefix, new ArrayList<>(Arrays.asList(uuidPropertyName)));
}
removeNonPublicFields(result, searchQuery, shardResult);
transaction.add(tx.hashCode());
result = removeNonPublicFields(searchQuery, shardResult);
if (tx != null) {
transaction.add(tx.hashCode());
}
}
} catch (Exception e) {
logger.error("search operation failed: {}", e);
Expand All @@ -140,21 +141,27 @@ public JsonNode search(JsonNode inputQueryNode) throws IOException {

}
}

return buildResultNode(searchQuery, result);
}

private void removeNonPublicFields(ArrayNode result, SearchQuery searchQuery, ObjectNode shardResult) throws Exception {
private ArrayNode removeNonPublicFields(SearchQuery searchQuery, ObjectNode shardResult) throws Exception {
ArrayNode result = JsonNodeFactory.instance.arrayNode();
for(String entityType: searchQuery.getEntityTypes()) {
ArrayNode arrayNode = (ArrayNode) shardResult.get(entityType);
for(JsonNode node : arrayNode) {
result.add(JSONUtil.removeNodesByPath(node, definitionsManager.getExcludingFieldsForEntity(entityType)));
if (removeNonPublicFieldsForNativeSearch) {
for(JsonNode node : arrayNode) {
result.add(JSONUtil.removeNodesByPath(node, definitionsManager.getExcludingFieldsForEntity(entityType)));
}
} else {
result = arrayNode;
}
}
return result;
}

/**
* Builds result node from given array of shard nodes
* Builds result node from given array of shard nodes
* @param searchQuery
* @param allShardResult
* @return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ public class DBProviderFactory {

@Autowired
DBConnectionInfoMgr dbConnectionInfoMgr;

public DatabaseProvider getInstance(DBConnectionInfo connectionInfo) {
DatabaseProvider provider = null;
String dbProvider = environment.getProperty(Constants.DATABASE_PROVIDER);
String uuidPropertyName = dbConnectionInfoMgr.getUuidPropertyName();

// In tests, we use TinkerGraph presently.
if (!dbProvider.equalsIgnoreCase(Constants.GraphDatabaseProvider.TINKERGRAPH.getName()) &&
dbProviderInstances.containsKey(connectionInfo.getShardId())) {
if (dbProvider == null) {
throw new RuntimeException("No Database Provider is configured. Please configure a Database Provider");
}
if (connectionInfo != null && dbProviderInstances.containsKey(connectionInfo.getShardId())) {
provider = dbProviderInstances.get(connectionInfo.getShardId());
} else {
if (dbProvider.equalsIgnoreCase(Constants.GraphDatabaseProvider.ORIENTDB.getName())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import javax.annotation.PostConstruct;

import org.agrona.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -23,18 +24,18 @@

@Component
public class ViewTemplateManager {

private static Logger logger = LoggerFactory.getLogger(ViewTemplateManager.class);


public static final String viewLocation = "classpath*:views/*.json";
private static final String viewTemplateId = "viewTemplateId";
private static final String viewTemplate = "viewTemplate";

private OSResourceLoader osResourceLoader;
private ObjectMapper mapper = new ObjectMapper();
private Map<String, ViewTemplate> templates = new HashMap<>();

@Autowired
private ResourceLoader resourceLoader;

Expand All @@ -58,10 +59,10 @@ public void loadTemplates() throws Exception {
}

}

/**
* Returns the view template based on the request parameter viewTemplateId, viewTemplate
*
* Returns the view template based on the request parameter viewTemplateId, viewTemplate
*
* @param requestNode
* @return
* @throws JsonParseException
Expand All @@ -76,7 +77,7 @@ public ViewTemplate getViewTemplate(JsonNode requestNode) {
if (requestNode.has(viewTemplateId)) {
name = requestNode.get(viewTemplateId).asText();
logger.info("Applying view template {}", name);
viewTemp = templates.get(name);
viewTemp = getViewTemplateById(name);
if(viewTemp == null)
logger.error("view template for {} not found!", name);
} else if (requestNode.has(viewTemplate)) {
Expand All @@ -88,7 +89,15 @@ public ViewTemplate getViewTemplate(JsonNode requestNode) {
}
return viewTemp;
}


public ViewTemplate getViewTemplateById(String name) {
if (Strings.isEmpty(name) || !templates.containsKey(name)) {
return null;
}
return templates.get(name);
}


private ViewTemplate getViewTemplateByContent(String templateContent)
throws IOException {
return mapper.readValue(templateContent, ViewTemplate.class);
Expand All @@ -108,5 +117,5 @@ public boolean isPrivateFieldEnabled(ViewTemplate viewTemplate, String entityTyp
}
return privateFieldEnabled;
}

}
1 change: 1 addition & 0 deletions java/registry/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ search:
# not offer high speed reads. This is the default search service, if this config is not provided.
# If ElasticSearchService, then Elastic search is used.
expandInternal: ${search_expandInternal:true}
removeNonPublicFieldsForNativeSearch: ${remove_non_public_fields_for_native_search:true}
providerName: ${search_providerName:dev.sunbirdrc.registry.service.NativeSearchService}

# This property is to be used for read request
Expand Down
Loading