Package com.baasbox.commands

Source Code of com.baasbox.commands.DocumentsResource

/*
* Copyright (c) 2014.
*
* BaasBox - info@baasbox.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.baasbox.commands;

import com.baasbox.commands.exceptions.CommandException;
import com.baasbox.commands.exceptions.CommandExecutionException;
import com.baasbox.commands.exceptions.CommandParsingException;
import com.baasbox.controllers.actions.exceptions.RidNotFoundException;
import com.baasbox.dao.exception.*;
import com.baasbox.enumerations.Permissions;
import com.baasbox.exception.RoleNotFoundException;
import com.baasbox.exception.UserNotFoundException;
import com.baasbox.service.scripting.base.JsonCallback;
import com.baasbox.service.scripting.js.Json;
import com.baasbox.service.storage.BaasBoxPrivateFields;
import com.baasbox.service.storage.DocumentService;
import com.baasbox.util.JSONFormats;
import com.baasbox.util.QueryParams;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.BooleanNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableMap;
import com.orientechnologies.orient.core.exception.ODatabaseException;
import com.orientechnologies.orient.core.exception.OSecurityException;
import com.orientechnologies.orient.core.record.impl.ODocument;
import org.apache.commons.lang.exception.ExceptionUtils;
import play.Logger;

import java.io.IOException;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
* {resource: 'documents',
*  name: <'get'|'list'|'post'|'put'|'delete',
*  params; {
*      collection: <collection>,
*
*      query: <query>,*
*
*      id: <id>*,
*
*      grants: {}
*  }}
*
*
*  {resource: 'documents',
*   name: 'get',
*   params: {
*       collection: <collection>,
*       id: <uuid>,
*
*   }}
*
*
*  {resource: 'documents',
*   name: 'grant',
*   params: {
*       collection: <collection>,
*       id: <uuid>,
*       users: {read: [,,,],
*               update: [,,,,],
*               delete: [....],
*               all: [,,,,],
*               },
*       roles: {read: [,,,,],
*               update: [,,,,],
*               delete: [,,,,,],
*               all: [,,,,,]
*   }}
*
*
*
* Created by Andrea Tortorella on 30/06/14.
*/
class DocumentsResource extends BaseRestResource {
    private static final Predicate<BaasBoxPrivateFields> removeVisible = ((Predicate<BaasBoxPrivateFields>)BaasBoxPrivateFields::isVisibleByTheClient).negate();

    private static final Collection<String> TO_REMOVE = EnumSet.allOf(BaasBoxPrivateFields.class)
                                                               .stream().filter(removeVisible)
                                                                        .map(BaasBoxPrivateFields::toString)
                                                                        .collect(Collectors.toSet());


    public static final Resource INSTANCE = new DocumentsResource();

    private static final String RESOURCE_NAME = "documents";

    private static final String COLLECTION = "collection";
    private static final String QUERY = "query";
    private static final String DATA = "data";
    private static final String AUTHOR = "author";

    @Override
    protected ImmutableMap.Builder<String, ScriptCommand> baseCommands() {
        return super.baseCommands().put("grant", new ScriptCommand() {
            @Override
            public JsonNode execute(JsonNode command, JsonCallback callback) throws CommandException {
                return grant(command,true);
            }
        }).put("revoke", new ScriptCommand() {
            @Override
            public JsonNode execute(JsonNode command, JsonCallback callback) throws CommandException {
                return grant(command,false);
            }
        });
    }

    private JsonNode grant(JsonNode command, boolean grant) throws CommandException {
        validateHasParams(command);
        String coll = getCollectionName(command);
        String id = getDocumentId(command);

        try {
            try {
                String rid = DocumentService.getRidByString(id, true);
                alterGrants(command, coll, rid, true, grant);
                alterGrants(command, coll, rid, false, grant);
            } catch (Exception e){
                Logger.error("error",e);
                throw  e;
            }
        } catch (UserNotFoundException e) {

            throw new CommandExecutionException(command,"user not found exception");
        } catch (DocumentNotFoundException e) {
            throw new CommandExecutionException(command,"document not found exception");
        } catch (InvalidCollectionException e) {
            throw new CommandExecutionException(command,"invalid colleciton exception");
        } catch (InvalidModelException e) {
            throw new CommandExecutionException(command,"invalid model exception");
        } catch (RoleNotFoundException e) {
            throw new CommandExecutionException(command,"role not found exception");
        } catch (RidNotFoundException e) {
            throw new CommandExecutionException(command,"document "+id+" not found");
        }
        return BooleanNode.getTrue();
    }

    @Override
    protected JsonNode delete(JsonNode command) throws CommandException {
        validateHasParams(command);
        String coll = getCollectionName(command);
        String id = getDocumentId(command);
        String rid;
        try {
            rid = DocumentService.getRidByString(id,true);
        } catch (RidNotFoundException e) {
            return null;
        }
        try {
            DocumentService.delete(coll,rid);
        } catch (OSecurityException e) {
            throw new CommandExecutionException(command, "you don't have permissions to delete: "+id);
        } catch (ODatabaseException e){
            return null;
        } catch (Throwable e){
            throw new CommandExecutionException(command,"error executing delete command on "+id+ " message: "+e.getMessage());
        }
        return null;
    }


    private void validateHasParams(JsonNode commnand) throws CommandParsingException{
        if (!commnand.has(ScriptCommand.PARAMS)) {
            throw new CommandParsingException(commnand,"missing parameters");
        }
    }


    private String getCollectionName(JsonNode command) throws CommandParsingException {
        JsonNode params = command.get(ScriptCommand.PARAMS);
        JsonNode collNode = params.get(COLLECTION);
        if (collNode == null|| !collNode.isTextual()){
            throw new CommandParsingException(command,"invalid collection param: "+(collNode==null?"null":collNode.toString()));
        }
        return collNode.asText();
    }


    @Override
    protected JsonNode put(JsonNode command) throws CommandException{
        validateHasParams(command);
        String coll = getCollectionName(command);
        JsonNode data = getData(command);
        String id = getDocumentId(command);
        try {
            String rid = DocumentService.getRidByString(id, true);
            ODocument doc = DocumentService.update(coll, rid, data);
            String json = JSONFormats.prepareDocToJson(doc, JSONFormats.Formats.DOCUMENT_PUBLIC);
            ObjectNode node = (ObjectNode)Json.mapper().readTree(json);
            node.remove(TO_REMOVE);
            node.remove("@rid");
            return node;
        } catch (RidNotFoundException e) {
            throw new CommandExecutionException(command,"document: "+id+" does not exists");
        } catch (UpdateOldVersionException e) {
            throw new CommandExecutionException(command,"document: "+id+" has a more recent version");
        } catch (DocumentNotFoundException e) {
            throw new CommandExecutionException(command,"document: "+id+" does not exists");
        } catch (InvalidCollectionException e) {
            throw new CommandExecutionException(command,"invalid collection: "+coll);
        } catch (InvalidModelException e) {
            throw new CommandExecutionException(command,"error updating document: "+id+" message: "+e.getMessage());
        } catch (JsonProcessingException e) {
            throw new CommandExecutionException(command,"data do not represents a valid document, message: "+e.getMessage());
        } catch (IOException e) {
            throw new CommandExecutionException(command,"error updating document: "+id+" message:"+e.getMessage());
        }
    }

    @Override
    protected JsonNode post(JsonNode command) throws CommandException{
        validateHasParams(command);
        String collection = getCollectionName(command);
        JsonNode data = getData(command);
        String authorOverride = getAuthorOverride(command);

        try {
           ODocument doc =
                    DocumentService.create(collection, data);
//                    DocumentService.createOnBehalf(collection,authorOverride,data);
            if (doc == null){
                return null;
            }
            String fmt = JSONFormats.prepareDocToJson(doc, JSONFormats.Formats.DOCUMENT_PUBLIC);
            JsonNode node = Json.mapper().readTree(fmt);
            ObjectNode n =(ObjectNode)node;
            n.remove(TO_REMOVE).remove("@rid");
//            n.remove("@rid");
            return n;
        } catch (InvalidCollectionException throwable) {
            throw new CommandExecutionException(command,"invalid collection: "+collection);
        } catch (InvalidModelException e) {
            throw new CommandExecutionException(command,"error creating document: "+e.getMessage());
        } catch (Throwable e) {
            throw new CommandExecutionException(command,"error creating document: "+e.getMessage());
        }
    }

    private String getAuthorOverride(JsonNode command) throws CommandParsingException{
        JsonNode node = command.get(ScriptCommand.PARAMS).get(AUTHOR);
        if (node != null && !node.isTextual()){
            throw new CommandParsingException(command,"author must be a string");

        } else if (node != null){
            return node.asText();
        }
        return null;
    }

    private JsonNode getData(JsonNode command) throws CommandParsingException {
        JsonNode node = command.get(ScriptCommand.PARAMS).get(DATA);
        if (node == null||(!node.isObject())){
            throw new CommandParsingException(command,"missing required data parameter");
        }
        return node;
    }

    @Override
    protected JsonNode list(JsonNode command) throws CommandException {
        String collection= getCollectionName(command);
        QueryParams params = QueryParams.getParamsFromJson(command.get(ScriptCommand.PARAMS).get(QUERY));

        try {
            List<ODocument> docs = DocumentService.getDocuments(collection, params);

            String s = JSONFormats.prepareDocToJson(docs, JSONFormats.Formats.DOCUMENT_PUBLIC);
            ArrayNode lst = (ArrayNode)Json.mapper().readTree(s);
            lst.forEach((j)->((ObjectNode)j).remove(TO_REMOVE).remove("@rid"));
            return lst;
        } catch (SqlInjectionException | IOException e) {
            throw new CommandExecutionException(command,"error executing command: "+e.getMessage(),e);
        } catch (InvalidCollectionException e) {
            throw new CommandExecutionException(command,"invalid collection: "+collection,e);
        }
    }


    @Override
    protected JsonNode get(JsonNode command) throws CommandException{
        String collection = getCollectionName(command);
        String id = getDocumentId(command);
        try {
            String rid = DocumentService.getRidByString(id, true);
            ODocument document = DocumentService.get(collection, rid);
            if (document == null){
                return null;
            } else {
                String s = JSONFormats.prepareDocToJson(document, JSONFormats.Formats.DOCUMENT_PUBLIC);
                ObjectNode node = (ObjectNode)Json.mapper().readTree(s);
                node.remove(TO_REMOVE).remove("@rid");
                return node;
            }
        } catch (RidNotFoundException e) {
            return null;
        } catch (DocumentNotFoundException e) {
            return null;
        } catch (InvalidCollectionException e) {
            throw new CommandExecutionException(command,"invalid collection: "+collection);
        } catch (InvalidModelException e) {
            throw new CommandExecutionException(command,"error executing command: "+e.getMessage());
        } catch (JsonProcessingException e) {
            throw new CommandExecutionException(command,"error executing command: "+e.getMessage());
        } catch (IOException e) {
            throw new CommandExecutionException(command,"error executing command: "+e.getMessage());
        }
    }

    private void alterGrants(JsonNode command,String collection,String docId,boolean users,boolean grant ) throws CommandParsingException, UserNotFoundException, DocumentNotFoundException, InvalidCollectionException, InvalidModelException, RoleNotFoundException {
        JsonNode params = command.get(ScriptCommand.PARAMS);
        JsonNode node = users?params.get("users"):params.get("roles");
        if (node != null){
            JsonNode read = node.get("read");
            if (read!=null){
                alterGrantsTo(command, read, collection, docId, grant, users, Permissions.ALLOW_READ);
            }
            JsonNode write = node.get("write");
            if (write!=null){
                alterGrantsTo(command,write,collection,docId,grant,users,Permissions.ALLOW_UPDATE);
            }
            JsonNode delete = node.get("delete");
            if (delete!=null){
                alterGrantsTo(command,delete,collection,docId,grant,users,Permissions.ALLOW_DELETE);
            }
            JsonNode all= node.get("all");
            if (all!=null){
                alterGrantsTo(command,all,collection,docId,grant,users,Permissions.ALLOW);
            }

        }
    }

    private void alterGrantsTo(JsonNode command, JsonNode to, String collection, String docId, boolean isGrant,boolean users, Permissions permission) throws CommandParsingException, UserNotFoundException, DocumentNotFoundException, InvalidCollectionException, InvalidModelException, RoleNotFoundException {
        if (!to.isArray()) throw new CommandParsingException(command,"targets of permissions must be an array");
        if (isGrant){
           if (users){
               for (JsonNode u: to){
                   if (!u.isTextual()) throw new CommandParsingException(command,"invalid user name specified: "+u);
                   DocumentService.grantPermissionToUser(collection,docId,permission,u.asText());
               }
           } else {
               for (JsonNode r:to){
                    if (!r.isTextual()) throw new CommandParsingException(command,"invalid role name specified: "+r);
                    DocumentService.grantPermissionToRole(collection,docId,permission,r.asText());
               }
           }
        } else {
            if (users){
                for (JsonNode u: to){
                    if (!u.isTextual()) throw new CommandParsingException(command,"invalid user name specified: "+u);
                    DocumentService.revokePermissionToUser(collection, docId, permission, u.asText());
                }
            } else {
                for (JsonNode r:to){
                    if (!r.isTextual()) throw new CommandParsingException(command,"invalid role name specified: "+r);
                    DocumentService.revokePermissionToRole(collection, docId, permission, r.asText());
                }
            }
        }
    }

    private String getDocumentId(JsonNode command) throws CommandException{
        JsonNode params = command.get(ScriptCommand.PARAMS);
        JsonNode id = params.get("id");
        if (id==null||!id.isTextual()){
            throw new CommandParsingException(command,"missing document id");
        }
        String idString = id.asText();
        try{
            UUID.fromString(idString);
        } catch (IllegalArgumentException e){
            throw new CommandParsingException(command,"document id: "+id+" must be a valid uuid");
        }
        return idString;
    }

    @Override
    public String name() {
        return RESOURCE_NAME;
    }
}
TOP

Related Classes of com.baasbox.commands.DocumentsResource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.