controllers.WidgetAdmin.java Source code

Java tutorial

Introduction

Here is the source code for controllers.WidgetAdmin.java

Source

/*
 * Copyright (c) 2013 GigaSpaces Technologies Ltd. All rights reserved
 *
 * 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 controllers;

import com.avaje.ebean.Ebean;
import data.validation.GsConstraints;
import models.*;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import play.data.Form;
import play.data.validation.Constraints;
import play.libs.Json;
import play.mvc.Controller;
import play.mvc.Http;
import play.mvc.Result;
import server.ApplicationContext;
import server.HeaderMessage;
import server.exceptions.ServerException;
import utils.CollectionUtils;
import utils.RestUtils;
import views.html.common.linkExpired;
import views.html.widgets.admin.newPassword;
import views.html.widgets.admin.resetPassword;
import views.html.widgets.admin.signin;
import views.html.widgets.admin.signup;
import views.html.widgets.dashboard.account;
import views.html.widgets.dashboard.angularjs_widget;
import views.html.widgets.dashboard.previewWidget;
import views.html.widgets.dashboard.widgets;
import views.html.widgets.widget;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import java.util.regex.Pattern;

import static utils.RestUtils.*;

/**
 * Widget Admin controller.
 * 
 * @author Igor Goldenberg
 */
public class WidgetAdmin extends Controller {

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

    public static Result getWidget(String apiKey) {
        Widget widgetItem = Widget.getWidget(apiKey);
        if (widgetItem == null || !widgetItem.isEnabled()) {
            return ok();
        }
        return ok(widget.render(ApplicationContext.get().conf().mixpanelApiKey, widgetItem));
    }

    public static Result icon(String apiKey) {
        WidgetIcon widgetItem = WidgetIcon.findByWidgetApiKey(apiKey);
        if (widgetItem == null) {
            return ok();
        }
        return ok(widgetItem.getData()).as(widgetItem.getContentType());
    }

    /*
     * Creates new account.
     */
    public static Result signUp(String email, String passwordConfirmation, String password, String firstname,
            String lastname) {
        try {
            Constraints.EmailValidator ev = new Constraints.EmailValidator();
            if (StringUtils.isEmpty(email) || !ev.isValid(email)) {
                new HeaderMessage().setError("Email is incorrect").apply(response().getHeaders());
                return internalServerError();
            }
            if (!validatePassword(password, passwordConfirmation, email)) {
                return internalServerError();
            }

            User.Session session = User.newUser(firstname, lastname, email, password).getSession();
            return RestUtils.resultAsJson(session);
        } catch (ServerException ex) {
            return resultErrorAsJson(ex.getMessage());
        }
    }

    public static Result logout() {
        session().clear();
        response().discardCookies("authToken");
        return redirect(routes.WidgetAdmin.index());
    }

    public static Result index() {
        // lets assume that if we have "authToken" we are already logged in
        // and we can redirect to widgets.html
        Http.Cookie authToken = request().cookies().get("authToken");
        if (authToken != null && User.validateAuthToken(authToken.value(), true) != null) {
            return redirect(routes.WidgetAdmin.newWidgetsPage());
        } else {
            return redirect(routes.WidgetAdmin.getSigninPage(null));
        }
    }

    /**
     *
     * this method will reset the user's password.
     * the parameters are cryptic on purpose.
     *
     * @param p - the hmac
     * @param pi - the user id
     * @return -
     */
    public static Result resetPasswordAction(String p, Long pi) {
        User user = User.findById(pi);
        // validate p
        if (!ApplicationContext.get().getHmac().compare(p, user.getEmail(), user.getId(), user.getPassword())) {
            return badRequest(linkExpired.render());
        }
        // if p is valid lets reset the password
        String newPasswordStr = StringUtils.substring(p, 0, 7);
        user.encryptAndSetPassword(newPasswordStr);
        user.save();
        return ok(newPassword.render(newPasswordStr));
    }

    public static Result postResetPassword(String email, String h) {
        logger.info("user {} requested password reset", email);
        if (!StringUtils.isEmpty(h)) {
            return badRequest(); // this is a bot.. lets block it.
        }

        if (StringUtils.isEmpty(email) || !(new Constraints.EmailValidator().isValid(email))) {
            new HeaderMessage().setError("Invalid email").apply(response().getHeaders());
            return badRequest();
        }

        User user = User.find.where().eq("email", email).findUnique();
        if (user == null) {
            return ok(); // do not notify if user does not exist. this is a security breach..
            // simply reply that an email was sent to the address.
        }

        ApplicationContext.get().getMailSender().resetPasswordMail(user);
        return ok();
    }

    public static Result getAccountPage() {
        return ok(account.render());
    }

    public static Result getWidgetsPage() {
        return ok(widgets.render());
    }

    public static Result getSigninPage(String message) {
        return ok(signin.render(message));
    }

    public static Result getSignupPage() {
        return ok(signup.render());
    }

    public static Result getResetPasswordPage() {
        return ok(resetPassword.render());
    }

    public static Result checkPasswordStrength(String password, String email) {
        if (!StringUtils.isEmpty(email) && new Constraints.EmailValidator().isValid(email)) {
            String result = isPasswordStrongEnough(password, email);
            if (result != null) {
                new HeaderMessage().setError(result).apply(response().getHeaders());
                return internalServerError();
            }
            return ok();
        }
        return ok();
    }

    private static String isPasswordStrongEnough(String password, String email) {
        if (StringUtils.length(password) < 8) {
            return "Password is too short";
        }
        if (!Pattern.matches("(?=^.{8,}$)((?=.*\\d)|(?=.*\\W+))(?![.\\n])(?=.*[A-Z])(?=.*[a-z]).*$", password)
                && !StringUtils.containsIgnoreCase(email, password)) {
            return "Password must match requirements";
        }

        Set<String> strSet = new HashSet<String>();
        for (String s : password.split("")) {
            if (StringUtils.length(s) > 0) {
                strSet.add(s.toLowerCase());
            }
        }

        if (CollectionUtils.size(strSet) < 3) {
            return "Too many repeating letters";
        }

        if (StringUtils.getLevenshteinDistance(password, email.split("@")[0]) < 5
                || StringUtils.getLevenshteinDistance(password, email.split("@")[1]) < 5) {
            return "Password similar to email";
        }

        return null;
    }

    public static Result getPasswordMatch(String authToken, String password) {
        User user = User.validateAuthToken(authToken);
        String passwordWeakReason = isPasswordStrongEnough(password, user.getEmail());
        if (passwordWeakReason == null) {
            return ok();
        }
        return ok(passwordWeakReason);
    }

    /**
     *
     * @param newPassword - the password user chose
     * @param confirmPassword - the confirmed password
     * @param email - user's email. used for checking similarity to password. passwords that are similar to email are considered weak.
     * @return true iff password is considered strong enough according to our policy.
     */
    private static boolean validatePassword(String newPassword, String confirmPassword, String email) {
        if (!StringUtils.equals(newPassword, confirmPassword)) {
            new HeaderMessage().setError("Passwords do not match").apply(response().getHeaders());
            return false;
        }

        String passwordWeakReason = isPasswordStrongEnough(newPassword, email);
        if (passwordWeakReason != null) {
            new HeaderMessage().setError(passwordWeakReason).apply(response().getHeaders());
            return false;
        }
        return true;
    }

    public static Result postChangePassword(String authToken, String oldPassword, String newPassword,
            String confirmPassword) {
        User user = User.validateAuthToken(authToken);
        if (!user.comparePassword(oldPassword)) {
            new HeaderMessage().setError("Wrong Password").apply(response().getHeaders());
            return internalServerError();
        }

        if (!validatePassword(newPassword, confirmPassword, user.getEmail())) {
            return internalServerError();
        }

        user.encryptAndSetPassword(newPassword);
        user.save();
        new HeaderMessage().setSuccess("Password Changed Successfully").apply(response().getHeaders());
        return ok();
    }

    /**
     * Login with existing account.
     * 
     * @param email
     * @param password
     * @return
     */
    public static Result signIn(String email, String password) {
        try {
            User.Session session = User.authenticate(email, password);

            return resultAsJson(session);
        } catch (ServerException ex) {
            return resultErrorAsJson(ex.getMessage());
        }
    }

    public static Result getAllUsers(String authToken) {
        User.validateAuthToken(authToken); // TODO : remove these validations and use "action interceptor"
                                           // there's no official documentation for interceptors. see code sample at : http://stackoverflow.com/questions/9629250/how-to-avoid-passing-parameters-everywhere-in-play2
        List<User> users = User.getAllUsers();

        return resultAsJson(users);
    }

    public static Result postWidget(String authToken) {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode jsonNode = request().body().asJson();

        User user = null;
        Widget w = null;
        if (jsonNode.has("id")) {
            String widgetApiKey = jsonNode.get("apiKey").asText();
            w = getWidgetSafely(authToken, widgetApiKey);

        } else {
            user = User.validateAuthToken(authToken);
        }

        String bodyRequest = jsonNode.toString();

        Form<Widget> validator = form(Widget.class).bind(jsonNode);
        if (validator.hasErrors()) {
            new HeaderMessage().populateFormErrors(validator).apply(response().getHeaders());
            return badRequest();
        }

        try {
            if (w == null) {
                w = mapper.treeToValue(jsonNode, Widget.class);
            } else {
                mapper.readerForUpdating(w).treeToValue(jsonNode, Widget.class);
            }
            logger.info("successfully turned json to widget [{}]", w);

            if (user != null) {
                user.addNewWidget(w);
            }

            w.save();
            w.refresh();

            return ok(Json.toJson(w));
        } catch (IOException e) {
            logger.error("unable to turn body to Json", e);
        }
        logger.info("saving widget [{}]", bodyRequest);
        return ok();
    }

    public static Result createNewWidget(String widgetId, String authToken, String productName,
            String productVersion, String title, String youtubeVideoUrl, String providerURL, String recipeURL,
            String consolename, String consoleurl, String rootpath, String recipeName, String consoleUrlService) {
        User user = User.validateAuthToken(authToken);
        Widget widget = null;
        if (!NumberUtils.isNumber(widgetId)) {
            widget = user.createNewWidget(productName, productVersion, title, youtubeVideoUrl, providerURL,
                    recipeURL, consolename, consoleurl, rootpath);
        } else {
            Long widgetIdLong = Long.parseLong(widgetId);
            widget = Widget.findByUserAndId(user, widgetIdLong);
            if (widget == null) {
                new HeaderMessage().setError("User is not allowed to edit this widget")
                        .apply(response().getHeaders());
                return badRequest();
            }
            widget.setProductName(productName);
            widget.setProductVersion(productVersion);
            widget.setTitle(title);
            widget.setYoutubeVideoUrl(youtubeVideoUrl);
            widget.setProviderURL(providerURL);
            widget.setRecipeURL(recipeURL);
            widget.setConsoleName(consolename);
            widget.setConsoleURL(consoleurl);
            widget.setRecipeRootPath(rootpath);
            widget.setRecipeName(recipeName);
            widget.setConsoleUrlService(consoleUrlService);
            widget.save();
        }

        logger.info("edited widget : " + widget.toString());
        return ok(Json.toJson(widget));
        //      return resultAsJson(widget);
    }

    public static Result getAllWidgets(String authToken) {
        User user = User.validateAuthToken(authToken);
        List<Widget> list = null;

        if (user.getSession().isAdmin()) {
            list = Widget.find.all(); // Utils.workaround( Widget.find.all() );
            //            list = Utils.workaround( Widget.find.all() );
        } else {
            list = user.getWidgets();
        }

        return ok(Json.toJson(list));
    }

    public static Result shutdownInstance(String authToken, String instanceId) {
        User.validateAuthToken(authToken);
        ApplicationContext.get().getWidgetServer().undeploy(ServerNode.getServerNode(instanceId)); // todo : link to user somehow
        return ok(OK_STATUS).as("application/json");
    }

    public static Result disableWidget(String authToken, String apiKey) {
        return enableDisableWidget(authToken, apiKey, false);
    }

    private static Result enableDisableWidget(String authToken, String apiKey, boolean enabled) {
        getWidgetSafely(authToken, apiKey).setEnabled(enabled).save();
        return ok(OK_STATUS).as("application/json");
    }

    public static Result enableWidget(String authToken, String apiKey) {
        return enableDisableWidget(authToken, apiKey, true);
    }

    private static Widget getWidgetSafely(String authToken, Long widgetId, boolean allowAdmin) {
        User user = User.validateAuthToken(authToken);
        if (allowAdmin && user.isAdmin()) {
            return Widget.find.byId(widgetId);
        } else {
            return Widget.findByUserAndId(user, widgetId);
        }
    }

    private static Widget getWidgetSafely(String authToken, String apiKey) {

        User user = User.validateAuthToken(authToken);
        if (user.isAdmin()) {
            return Widget.getWidget(apiKey);
        } else {
            return Widget.getWidgetByApiKey(user, apiKey);
        }
    }

    public static Result getUserWidgetTemplate() {
        return ok(views.html.widgets.userWidgets.render()); // we do this so we can get the embed code.. we cannot use angularJS as we might want to email it too..
    }

    public static Result deleteWidget(String authToken, String apiKey) {
        logger.info("got a request to delete widget [{}]", apiKey);
        Widget widget = getWidgetSafely(authToken, apiKey);
        widget.delete();
        return ok();
    }

    public static Result previewWidget(String apiKey) {
        String authToken = request().cookies().get("authToken").value();
        Widget widget = getWidgetSafely(authToken, apiKey);
        return ok(previewWidget.render(widget, request().host()));
    }

    public static Result regenerateWidgetApiKey(String authToken, String apiKey) {
        Widget w = getWidgetSafely(authToken, apiKey).regenerateApiKey();
        logger.info("regenerated api key to [{}]", w);
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("widget", w);
        return ok(Json.toJson(result));
    }

    public static Result headers() {
        Http.Request req = Http.Context.current().request();

        StringBuilder sb = new StringBuilder("HEADERS:");
        sb.append("\nRemote address: ").append(req.remoteAddress());

        Map<String, String[]> headerMap = req.headers();
        for (String headerKey : headerMap.keySet()) {
            for (String s : headerMap.get(headerKey))
                sb.append("\n").append(headerKey).append("=").append(s);
        }

        return ok(sb.toString());
    }

    public static Result postRequireLogin(String authToken, Long widgetId, boolean requireLogin,
            String loginVerificationUrl, String webServiceKey) {

        Widget widget = getWidgetSafely(authToken, widgetId, false);
        if (widget == null) {
            new HeaderMessage().setError(" User is not allowed to edit this widget ")
                    .apply(response().getHeaders());
            return badRequest();
        }
        GsConstraints.UrlValidator validator = new GsConstraints.UrlValidator();
        if (!validator.isValid(loginVerificationUrl)) {
            new HeaderMessage().addFormError("loginVerificationUrl", "invalid value")
                    .apply(response().getHeaders());
            return badRequest();
        }

        widget.setRequireLogin(requireLogin);
        widget.setLoginVerificationUrl(loginVerificationUrl);
        widget.setWebServiceKey(webServiceKey);
        widget.save();
        return ok();
    }

    public static Result postWidgetDescription(String authToken, Long widgetId, String description) {

        Widget widget = getWidgetSafely(authToken, widgetId, false);
        if (widget == null) {
            new HeaderMessage().setError(" User is not allowed to edit this widget ")
                    .apply(response().getHeaders());
            return badRequest();
        }

        widget.setDescription(description);
        widget.save();
        return ok();

    }

    public static Result newWidgetsPage() {
        return ok(angularjs_widget.render());
    }

    public static Result addIcon() {
        try {

            Http.MultipartFormData body = request().body().asMultipartFormData();

            Long widgetId = Long.parseLong(body.asFormUrlEncoded().get("widgetId")[0]);
            String authToken = body.asFormUrlEncoded().get("authToken")[0];

            Widget w = getWidgetSafely(authToken, widgetId, false);
            WidgetIcon icon = WidgetIcon.findByWidgetApiKey(w.getApiKey());

            if (icon == null) {
                icon = new WidgetIcon();
            }

            Http.MultipartFormData.FilePart picture = body.getFile("icon");
            if (picture != null) {
                String fileName = picture.getFilename();
                String contentType = picture.getContentType();

                File file = picture.getFile();
                byte[] iconData = IOUtils.toByteArray(new FileInputStream(file));

                icon.setName(fileName);
                icon.setContentType(contentType);
                icon.setData(iconData);
                Ebean.save(icon); // supports both save and update.
                w.setIcon(icon);
                w.save();
                return ok("Added icon successfully");
            } else {
                return ok("Error: no file");
            }
        } catch (Exception e) {
            return ok("Error: " + e.getMessage());
        }
    }

    public static Result removeIcon(String authToken, Long widgetId) {
        Widget w = getWidgetSafely(authToken, widgetId, false);
        WidgetIcon icon = WidgetIcon.findByWidgetApiKey(w.getApiKey());
        icon.delete();
        return ok();
    }
}