com.baasbox.commands.UsersResource.java Source code

Java tutorial

Introduction

Here is the source code for com.baasbox.commands.UsersResource.java

Source

/*
 * 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 java.io.IOException;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;

import com.baasbox.commands.exceptions.CommandException;
import com.baasbox.commands.exceptions.CommandExecutionException;
import com.baasbox.commands.exceptions.CommandNotImplementedException;
import com.baasbox.commands.exceptions.CommandParsingException;
import com.baasbox.dao.UserDao;
import com.baasbox.dao.exception.EmailAlreadyUsedException;
import com.baasbox.dao.exception.SqlInjectionException;
import com.baasbox.dao.exception.UserAlreadyExistsException;
import com.baasbox.db.DbHelper;
import com.baasbox.enumerations.DefaultRoles;
import com.baasbox.exception.AlreadyFriendsException;
import com.baasbox.exception.InvalidJsonException;
import com.baasbox.exception.OpenTransactionException;
import com.baasbox.exception.UserNotFoundException;
import com.baasbox.service.push.PushService;
import com.baasbox.service.scripting.base.JsonCallback;
import com.baasbox.service.scripting.js.Json;
import com.baasbox.service.storage.BaasBoxPrivateFields;
import com.baasbox.service.user.FriendShipService;
import com.baasbox.service.user.RoleService;
import com.baasbox.service.user.UserService;
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.BooleanNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.google.common.collect.ImmutableMap;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.type.tree.OMVRBTreeRIDSet;

import scala.util.parsing.combinator.testing.Str;

/**
 * Created by Andrea Tortorella on 02/07/14.
 */
class UsersResource extends BaseRestResource {
    public static final Resource INSTANCE = new UsersResource();

    @Override
    protected ImmutableMap.Builder<String, ScriptCommand> baseCommands() {
        return super.baseCommands().put("suspend", new ScriptCommand() {
            @Override
            public JsonNode execute(JsonNode command, JsonCallback callback) throws CommandException {
                return suspend(command);
            }
        }).put("reactivate", new ScriptCommand() {
            @Override
            public JsonNode execute(JsonNode command, JsonCallback callback) throws CommandException {
                return reactivate(command);
            }
        }).put("follow", this::friendshipUpdate).put("followers", getFriends(false))
                .put("following", getFriends(true)).put("changeUsername", this::changeUsername)
                .put("changePassword", this::changePassword);
    }

    private ScriptCommand getFriends(boolean following) {
        return (command, unused) -> {
            JsonNode params = command.get(ScriptCommand.PARAMS);
            if (params == null)
                throw new CommandParsingException(command, "missing required parameters");
            JsonNode user = params.path("user");
            JsonNode query = params.get("query");
            if (!user.isTextual())
                throw new CommandParsingException(command, "missing required paramter user as string");
            if (query != null && !query.isObject())
                throw new CommandParsingException(command, "query must be a json object");
            QueryParams qparams = QueryParams.getParamsFromJson(query);
            try {

                List<ODocument> res = following ? FriendShipService.getFollowing(user.asText(), qparams)
                        : FriendShipService.getFriendsOf(user.asText(), qparams);
                String s = JSONFormats.prepareDocToJson(res, JSONFormats.Formats.USER);

                return Json.mapper().readTreeOrMissing(s);
            } catch (SqlInjectionException e) {
                throw new CommandExecutionException(command, ExceptionUtils.getMessage(e), e);
            }
        };
    }

    //    private JsonNode followers(JsonNode command, JsonCallback unused) throws CommandException{
    //        try {
    //            List<ODocument> friendsOf = FriendShipService.getFriendsOf(user.asText(), QueryParams.getParamsFromJson(query));
    //            String s = JSONFormats.prepareResponseToJson(friendsOf, JSONFormats.Formats.USER);
    //            return Json.mapper().readTreeOrMissing(s);
    //        } catch (SqlInjectionException | IOException e) {
    //            throw new CommandExecutionException(command,ExceptionUtils.getMessage(e),e);
    //        }
    //    }

    protected JsonNode friendshipUpdate(JsonNode command, JsonCallback unused) throws CommandException {
        JsonNode params = command.get(ScriptCommand.PARAMS);
        if (params == null)
            throw new CommandParsingException(command, "missing required parameters");
        JsonNode from = params.get("from");
        JsonNode to = params.get("to");
        JsonNode remove = params.get("remove");
        if (from == null || !from.isTextual() || to == null || !to.isTextual())
            throw new CommandParsingException(command, "missing required user");
        boolean unfollow;
        if (remove == null) {
            unfollow = false;
        } else if (remove.isBoolean()) {
            unfollow = remove.asBoolean();
        } else {
            throw new CommandParsingException(command, "wrong parameter remove");
        }
        if (unfollow) {
            return doUnfollow(command, from.asText(), to.asText());
        } else {
            return doFollow(command, from.asText(), to.asText());
        }
    }

    private JsonNode doUnfollow(JsonNode command, String from, String to) throws CommandExecutionException {
        try {
            return BooleanNode.valueOf(FriendShipService.unfollow(from, to));
        } catch (Exception e) {
            throw new CommandExecutionException(command, ExceptionUtils.getMessage(e), e);
        }
    }

    private JsonNode doFollow(JsonNode command, String from, String to) throws CommandExecutionException {
        try {
            ODocument followed = FriendShipService.follow(from, to);
            String s = JSONFormats.prepareDocToJson(followed, JSONFormats.Formats.USER);
            return Json.mapper().readTree(s);
        } catch (UserNotFoundException e) {
            throw new CommandExecutionException(command, ExceptionUtils.getMessage(e), e);
        } catch (AlreadyFriendsException e) {
            return NullNode.getInstance();
        } catch (SqlInjectionException e) {
            throw new CommandExecutionException(command, ExceptionUtils.getMessage(e), e);
        } catch (Exception e) {
            throw new CommandExecutionException(command, ExceptionUtils.getMessage(e), e);
        }
    }

    protected JsonNode suspend(JsonNode command) throws CommandException {
        String username = getUsername(command);

        try {
            boolean inTransaction = DbHelper.isInTransaction();
            if (inTransaction) {
                return BooleanNode.getFalse();
            }
            UserService.disableUser(username);
        } catch (UserNotFoundException e) {
            throw new CommandExecutionException(command, "User " + username + " does not exists");
        } catch (OpenTransactionException e) {
            return BooleanNode.getFalse();
            //throw new CommandExecutionException(command,"Transaction still open during suspend");
        }
        return BooleanNode.getTrue();
    }

    protected JsonNode changeUsername(JsonNode command, JsonCallback unused) throws CommandException {
        String username = getUsername(command);
        JsonNode newUsernameJson = getParamField(command, "newUsername");
        if (newUsernameJson == null || !newUsernameJson.isTextual())
            throw new CommandExecutionException(command, "invalid new username: " + newUsernameJson);
        String newUsername = newUsernameJson.asText();
        try {
            UserService.changeUsername(username, newUsername);
        } catch (UserNotFoundException | OpenTransactionException | SqlInjectionException e) {
            throw new CommandExecutionException(command, ExceptionUtils.getMessage(e), e);
        }
        return NullNode.getInstance();
    }

    protected JsonNode changePassword(JsonNode command, JsonCallback unused) throws CommandException {
        String username = getUsername(command);
        JsonNode newPasswordJson = getParamField(command, "newPassword");
        if (newPasswordJson == null || !newPasswordJson.isTextual())
            throw new CommandExecutionException(command, "invalid new password: " + newPasswordJson);
        String newPassword = newPasswordJson.asText();
        try {
            UserService.changePassword(username, newPassword);
        } catch (UserNotFoundException | OpenTransactionException | SqlInjectionException e) {
            throw new CommandExecutionException(command, ExceptionUtils.getMessage(e), e);
        }
        return NullNode.getInstance();
    }

    private String getUsername(JsonNode command) throws CommandException {
        JsonNode params = command.get(ScriptCommand.PARAMS);
        JsonNode id = params.get("username");
        if (id == null || !id.isTextual()) {
            throw new CommandParsingException(command, "missing user username");
        }

        String username = id.asText();
        boolean internalUsername = UserService.isInternalUsername(username);
        if (internalUsername) {
            throw new CommandExecutionException(command, "invalid user: " + username);
        }
        return username;
    }

    protected JsonNode reactivate(JsonNode command) throws CommandException {
        String username = getUsername(command);
        try {
            if (DbHelper.isInTransaction())
                return BooleanNode.getFalse();
            UserService.enableUser(username);

        } catch (UserNotFoundException e) {
            throw new CommandExecutionException(command, "user " + username + " does not exists");
        } catch (OpenTransactionException e) {
            return BooleanNode.getFalse();
            //throw new CommandExecutionException(command,"transaction still open while altering user status");
        }
        return BooleanNode.getTrue();
    }

    @Override
    protected JsonNode delete(JsonNode command) throws CommandException {
        throw new CommandNotImplementedException(command, "not implemented");
    }

    @Override
    protected JsonNode put(JsonNode command) throws CommandException {
        String username = getUsername(command);
        JsonNode params = command.get(ScriptCommand.PARAMS);
        String role = params.get("role") != null ? params.get("role").asText() : null;
        JsonNode userVisible = params.get(UserDao.ATTRIBUTES_VISIBLE_ONLY_BY_THE_USER);
        JsonNode friendsVisible = params.get(UserDao.ATTRIBUTES_VISIBLE_BY_FRIENDS_USER);
        JsonNode registeredVisible = params.get(UserDao.ATTRIBUTES_VISIBLE_BY_REGISTERED_USER);
        JsonNode anonymousVisible = params.get(UserDao.ATTRIBUTES_VISIBLE_BY_ANONYMOUS_USER);
        try {
            ODocument doc;
            if (!params.has("id")) {
                doc = UserService.updateProfile(username, role, anonymousVisible, userVisible, friendsVisible,
                        registeredVisible);
            } else {
                String id = params.get("id") != null ? params.get("id").asText() : null;
                doc = UserService.updateProfile(username, role, anonymousVisible, userVisible, friendsVisible,
                        registeredVisible, id);
            }
            String s = JSONFormats.prepareDocToJson(doc, JSONFormats.Formats.USER);
            return Json.mapper().readTree(s);
        } catch (Exception e) {
            throw new CommandExecutionException(command, "Error updating user: " + ExceptionUtils.getMessage(e));
        }
    }

    @Override
    protected JsonNode post(JsonNode command) throws CommandException {
        try {
            JsonNode params = command.get(ScriptCommand.PARAMS);
            if (params == null || !params.isObject())
                throw new CommandParsingException(command, "missing parameters");
            String username = getUsername(command);
            JsonNode password = params.get("password");
            if (password == null || !password.isTextual())
                throw new CommandParsingException(command, "missing required password");
            JsonNode id = params.get(BaasBoxPrivateFields.ID.toString());
            String idString = null;
            if (!(id instanceof NullNode) && id != null && !id.isTextual())
                throw new CommandParsingException(command, "ID must be a string");
            if (!(id instanceof NullNode) && id != null && id.isTextual() && StringUtils.isBlank(id.asText()))
                throw new CommandParsingException(command,
                        "ID cannot be empty or cannot contains only whitespaces");
            if (!(id instanceof NullNode) && id != null && id.isTextual())
                idString = id.asText();
            JsonNode roleNode = params.get("role");
            String role;
            if (roleNode == null) {
                role = DefaultRoles.REGISTERED_USER.getORole().getName();
            } else if (roleNode.isTextual()) {
                role = roleNode.asText();
            } else {
                throw new CommandParsingException(command, "role parameter is not valid");
            }
            if (!RoleService.exists(role)) {
                throw new CommandExecutionException(command, "required role does not exists: " + role);
            }
            JsonNode userVisible = params.get(UserDao.ATTRIBUTES_VISIBLE_ONLY_BY_THE_USER);
            JsonNode friendsVisible = params.get(UserDao.ATTRIBUTES_VISIBLE_BY_FRIENDS_USER);
            JsonNode registeredVisible = params.get(UserDao.ATTRIBUTES_VISIBLE_BY_REGISTERED_USER);
            JsonNode anonymousVisible = params.get(UserDao.ATTRIBUTES_VISIBLE_BY_ANONYMOUS_USER);

            ODocument user = UserService.signUp(username, password.asText(), new Date(), role, anonymousVisible,
                    userVisible, friendsVisible, registeredVisible, false, idString);
            String userNode = JSONFormats.prepareDocToJson(user, JSONFormats.Formats.USER);
            return Json.mapper().readTree(userNode);
        } catch (InvalidJsonException | IOException e) {
            throw new CommandExecutionException(command, "invalid json", e);
        } catch (UserAlreadyExistsException | EmailAlreadyUsedException e) {
            return NullNode.getInstance();
        }
    }

    @Override
    protected JsonNode list(JsonNode command) throws CommandException {
        JsonNode paramsNode = command.get(ScriptCommand.PARAMS);
        QueryParams qp = QueryParams.getParamsFromJson(paramsNode);
        try {
            List<ODocument> users = UserService.getUsers(qp, true);
            String response = prepareResponseToJson(users);
            return Json.mapper().readTree(response);
        } catch (SqlInjectionException e) {
            throw new CommandExecutionException(command,
                    "error executing command: " + ExceptionUtils.getMessage(e));
        } catch (IOException e) {
            throw new CommandExecutionException(command, "error parsing response: " + ExceptionUtils.getMessage(e));
        }
    }

    @Override
    protected JsonNode get(JsonNode command) throws CommandException {
        String user = getUsername(command);
        try {
            if (UserService.isInternalUsername(user))
                return NullNode.getInstance();
            ODocument doc = UserService.getUserProfilebyUsername(user);
            if (doc == null) {
                return NullNode.getInstance();
            }
            String resp = JSONFormats.prepareResponseToJson(doc, JSONFormats.Formats.USER);
            return Json.mapper().readTree(resp);
        } catch (SqlInjectionException e) {
            throw new CommandExecutionException(command,
                    "error executing command: " + ExceptionUtils.getMessage(e));
        } catch (IOException e) {
            throw new CommandExecutionException(command, "error parsing response: " + ExceptionUtils.getMessage(e));
        }
    }

    @Override
    public String name() {
        return "users";
    }

    private String prepareResponseToJson(List<ODocument> listOfDoc) {
        try {
            for (ODocument doc : listOfDoc) {
                doc.detach();
                if (doc.field("user") instanceof ODocument) {
                    OMVRBTreeRIDSet roles = ((ODocument) doc.field("user")).field("roles");
                    if (roles.size() > 1) {
                        Iterator<OIdentifiable> it = roles.iterator();
                        while (it.hasNext()) {
                            if (((ODocument) it.next().getRecord()).field("name").toString()
                                    .startsWith(FriendShipService.FRIEND_ROLE_NAME)) {
                                it.remove();
                            }
                        }
                    }
                }
            }
            return JSONFormats.prepareResponseToJson(listOfDoc, JSONFormats.Formats.USER);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}