edu.zipcloud.cloudstreetmarket.api.controllers.UsersController.java Source code

Java tutorial

Introduction

Here is the source code for edu.zipcloud.cloudstreetmarket.api.controllers.UsersController.java

Source

/***
 *  Cloudstreetmarket.com is a Spring MVC showcase application developed 
 *  with the book Spring MVC Cookbook [PACKT] (2015). 
 *    Copyright (C) 2015  Alex Bretet
 *  
 *  This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 * 
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 **/
package edu.zipcloud.cloudstreetmarket.api.controllers;

import static edu.zipcloud.cloudstreetmarket.api.controllers.UsersController.USERS_PATH;
import static edu.zipcloud.cloudstreetmarket.core.enums.Role.ROLE_BASIC;
import static edu.zipcloud.cloudstreetmarket.core.enums.Role.ROLE_OAUTH2;
import static edu.zipcloud.cloudstreetmarket.core.i18n.I18nKeys.I18N_USER_GUID_UNKNOWN_TO_PROVIDER;
import static edu.zipcloud.cloudstreetmarket.core.util.Constants.FALSE;
import static edu.zipcloud.cloudstreetmarket.core.util.Constants.LOCATION_HEADER;
import static edu.zipcloud.cloudstreetmarket.core.util.Constants.MUST_REGISTER_HEADER;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;

import java.math.BigDecimal;
import java.util.Set;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import net.kaczmarzyk.spring.data.jpa.domain.LikeIgnoreCase;
import net.kaczmarzyk.spring.data.jpa.web.annotation.Or;
import net.kaczmarzyk.spring.data.jpa.web.annotation.Spec;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.social.connect.ConnectionRepository;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import com.mangofactory.swagger.annotations.ApiIgnore;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;

import edu.zipcloud.cloudstreetmarket.api.services.CurrencyExchangeServiceOnline;
import edu.zipcloud.cloudstreetmarket.core.dtos.UserActivityDTO;
import edu.zipcloud.cloudstreetmarket.core.dtos.UserDTO;
import edu.zipcloud.cloudstreetmarket.core.entities.CurrencyExchange;
import edu.zipcloud.cloudstreetmarket.core.entities.User;
import edu.zipcloud.cloudstreetmarket.core.enums.Role;
import edu.zipcloud.cloudstreetmarket.core.enums.SupportedCurrency;
import edu.zipcloud.cloudstreetmarket.core.services.CommunityService;
import edu.zipcloud.cloudstreetmarket.core.util.Constants;
import edu.zipcloud.cloudstreetmarket.core.util.ValidatorUtil;
import edu.zipcloud.cloudstreetmarket.core.validators.UserValidator;

@Api(value = "users", description = "Cloudstreet Market users") // Swagger annotation
@RestController
@RequestMapping(value = USERS_PATH, produces = { "application/xml", "application/json" })
public class UsersController extends CloudstreetApiWCI {

    public static final String USERS_PATH = "/users";

    @Autowired
    private CommunityService communityService;

    @Autowired
    private ConnectionRepository connectionRepository;

    @Autowired
    private CurrencyExchangeServiceOnline currencyExchangeService;

    @RequestMapping(method = POST)
    @ResponseStatus(HttpStatus.CREATED)
    @ApiOperation(value = "Creates a user account")
    public void create(@Valid @RequestBody User user, @RequestHeader(value = "Spi", required = false) String guid,
            @RequestHeader(value = "OAuthProvider", required = false) String provider, HttpServletResponse response)
            throws IllegalAccessException {
        if (isNotBlank(guid)) {
            if (isGuidUnknownToProvider(guid, provider)
                    || usersConnectionRepository.isSocialUserAlreadyRegistered(guid)) {
                throw new AccessDeniedException(guid + " @ " + provider);
            }

            user = communityService.createUserWithBalance(user, new Role[] { ROLE_BASIC, ROLE_OAUTH2 },
                    BigDecimal.valueOf(20000L));

            messagingTemplate.convertAndSend(Constants.WS_TOPIC_ACTIVITY_FEED_PATH,
                    new UserActivityDTO(user.getActions().iterator().next()));

            usersConnectionRepository.bindSocialUserToUser(guid, user, provider);
            communityService.signInUser(user);

            if (!SupportedCurrency.USD.equals(user.getCurrency())) {
                CurrencyExchange currencyExchange = currencyExchangeService
                        .gather("USD" + user.getCurrency().name() + "=X");
                user.setBalance(currencyExchange.getDailyLatestValue().multiply(BigDecimal.valueOf(20000L)));
            }

            communityService.save(user);
        } else {
            user = communityService.createUser(user, ROLE_BASIC);
            messagingTemplate.convertAndSend(Constants.AMQP_USER_ACTIVITY_QUEUE,
                    new UserActivityDTO(user.getActions().iterator().next()));
            communityService.signInUser(user);
        }

        response.setHeader(MUST_REGISTER_HEADER, FALSE);
        response.setHeader(LOCATION_HEADER, USERS_PATH + "/" + user.getId());
    }

    @RequestMapping(value = "/{username}", method = PUT)
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "Updates a user account")
    public void update(@Valid @RequestBody User user, BindingResult result) {
        ValidatorUtil.raiseFirstError(result);
        prepareUserForUpdate(user);
        communityService.updateUser(user);
    }

    @RequestMapping(method = GET)
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "List user accounts", notes = "")
    public Page<UserDTO> search(@Or({
            @Spec(params = "cn", path = "id", spec = LikeIgnoreCase.class) }) @ApiIgnore Specification<User> spec,
            @ApiParam(value = "Contains filter") @RequestParam(value = "cn", defaultValue = "", required = false) String contain,
            @ApiIgnore @PageableDefault(size = 10, page = 0, sort = {
                    "balance" }, direction = Direction.DESC) Pageable pageable) {
        return communityService.search(spec, pageable);
    }

    @RequestMapping(value = "/leaderboard", method = GET)
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "Leaderboard", notes = "")
    public Page<UserDTO> getLeaders(@ApiIgnore @PageableDefault(size = 9, page = 0, sort = {
            "balanceUSD" }, direction = Direction.DESC) Pageable pageable) {
        return communityService.getLeaders(pageable);
    }

    @RequestMapping(value = "/{username}", method = GET)
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "Details one account", notes = "")
    public UserDTO get(@PathVariable String username) {
        return communityService.getUser(username);
    }

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.setValidator(new UserValidator());
    }

    private boolean isGuidUnknownToProvider(String guid, String providerId) {
        Preconditions.checkArgument(isNotBlank(providerId), bundle.get(I18N_USER_GUID_UNKNOWN_TO_PROVIDER));

        Set<String> results = usersConnectionRepository.findUserIdsConnectedTo(providerId, Sets.newHashSet(guid));
        if (results == null || results.isEmpty()) {
            return true;
        }
        return false;
    }

    private void prepareUserForUpdate(User user) {
        User existingUser = communityService.findOne(user.getId());
        if (!existingUser.getCurrency().equals(user.getCurrency())) {
            CurrencyExchange currencyExchange = currencyExchangeService
                    .gather(existingUser.getCurrency().name() + user.getCurrency().name() + "=X");
            BigDecimal change = BigDecimal.valueOf(1L);
            if (currencyExchange != null && currencyExchange.getAsk() != null
                    && currencyExchange.getAsk().compareTo(BigDecimal.ZERO) > 0) {
                change = currencyExchange.getAsk();
            }
            //Let's say 2.5% virtual charge applied for now 
            user.setBalance(change.multiply(existingUser.getBalance()).multiply(BigDecimal.valueOf(0.975)));
        } else {
            user.setBalance(existingUser.getBalance());
        }
    }
}