com.largecode.interview.rustem.controller.UsersController.java Source code

Java tutorial

Introduction

Here is the source code for com.largecode.interview.rustem.controller.UsersController.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.largecode.interview.rustem.controller;

import com.largecode.interview.rustem.domain.DomainUtils;
import com.largecode.interview.rustem.domain.SpringUser;
import com.largecode.interview.rustem.domain.User;
import com.largecode.interview.rustem.domain.UserDto;
import com.largecode.interview.rustem.service.UsersService;
import com.largecode.interview.rustem.service.validator.UserDtoValidator;
import io.swagger.annotations.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.NoSuchElementException;
import java.util.Optional;

import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;

/**
 *
 * @author Rustem.Zhunusov_at_gmail.com
 */
@RestController
@RequestMapping(value = "/users", produces = { APPLICATION_JSON_VALUE })
@Api(value = "/users", description = "All kind of operations under users")
public class UsersController {

    private static final Logger LOGGER = LoggerFactory.getLogger(UsersController.class);
    private final UsersService usersService;
    private final UserDtoValidator userDtoValidator;
    //   private Authentication authentication;
    static final String DEFAULT_PAGE_SIZE = "100";
    static final String DEFAULT_PAGE_NUM = "0";

    @Autowired
    public UsersController(UsersService userService, UserDtoValidator userCreateFormValidator) {
        this.usersService = userService;
        this.userDtoValidator = userCreateFormValidator;
        //     this.authentication= authentication;
    }

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.addValidators(userDtoValidator);
    }

    @PreAuthorize("hasAuthority('ADMIN')")
    @RequestMapping(value = "", method = RequestMethod.GET)
    @ApiOperation(value = "Get All Users.", notes = "Returns list of all existed Users by page.")
    @ApiResponses(value = { @ApiResponse(code = 401, message = "Only authenticated access allowed."),
            @ApiResponse(code = 403, message = "Only user of ADMIN role can have access to it.") })
    public Page<User> getAllUsers(
            @ApiParam(value = "Page number of User's list", required = false) @RequestParam(value = "page", required = true, defaultValue = DEFAULT_PAGE_NUM) Integer page,
            @ApiParam(value = "Size of Page of User's list. ", allowableValues = "range[1,1000]", required = false) @RequestParam(value = "size", required = true, defaultValue = DEFAULT_PAGE_SIZE) Integer size) {
        size = Math.min(1000, size);
        return usersService.getAllUsers(page, size);
    }

    @PreAuthorize("hasAuthority('ADMIN')")
    @RequestMapping(value = "", method = RequestMethod.POST)
    @ApiOperation(value = "Create new User.", notes = "Returns a new User and persisted it to DB.", response = User.class)
    @ApiResponses(value = { @ApiResponse(code = 401, message = "Only authenticated access allowed."),
            @ApiResponse(code = 403, message = "Only user of ADMIN role can have access to it."),
            @ApiResponse(code = 400, message = "Reasons:" + "\n1:Passwords not same or too short."
                    + "\n2:userDto.idUser set to other value than 0." + "\n3:userDto.email already exists."
                    + "\n4:Bad role name.") })
    public User createUser(@Valid @RequestBody UserDto userDto) {
        LOGGER.debug("Create new user {}", userDto);
        checkPasswordFilled(userDto);
        checkIdUserEmpty(userDto);
        checkEmailNotExists(userDto, "create new user");

        User user = usersService.createUser(userDto);
        return user;

    }

    private void checkIdUserEmpty(UserDto userDto) {
        if (!userDto.getIdUser().equals(DomainUtils.NO_ID)) {
            throw new ExceptionIdUserMustBeEmpty(
                    String.format("IdUser(%s) must be equal to %s when creating new User.", userDto.getIdUser(),
                            DomainUtils.NO_ID));
        }
    }

    private void checkPasswordFilled(UserDto userDto) {
        if (userDto.getPassword().equals(UserDto.NO_PASSWORD)) {
            throw new ExceptionUserWithoutPassword();
        }
    }

    @PreAuthorize("@userRightResolverServiceImpl.canAccessToUser(principal, #id)")
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    @ApiOperation(value = "Find User by ID.", notes = "Returns a User if found him.", response = User.class)
    @ApiResponses(value = { @ApiResponse(code = 401, message = "Only authenticated access allowed."),
            @ApiResponse(code = 403, message = "Only user of ADMIN role or User has authenticated with this Id can have access."),
            @ApiResponse(code = 404, message = "User with such Id not found.") })
    public User getUser(@ApiParam(value = "ID of User from DB", required = true) @PathVariable Long id)
            throws ExceptionUserNotFound {
        LOGGER.debug("Get user by id={}", id);
        return usersService.getUserById(id)
                .orElseThrow(() -> new ExceptionUserNotFound(String.format("User=%s not found", id)));
    }

    @PreAuthorize("@userRightResolverServiceImpl.canAccessToUser(principal, #id)")
    @ApiOperation(value = "Update User.", notes = "Returns NO_CONTENT if update was successful. Regular user can not change his Role.")
    @ApiResponses(value = { @ApiResponse(code = 401, message = "Only authenticated access allowed."),
            @ApiResponse(code = 403, message = "Only user of ADMIN role or User has authenticated with this Id can have access."),
            @ApiResponse(code = 404, message = "User with such Id not found."),
            @ApiResponse(code = 400, message = "Reasons:\n" + "1:Passwords not same or too short.\n"
                    + "2:Other userDto.email already exists.\n" + "3:Bad role name.\n"
                    + "3:value of ID different between Id in URL and userDto \n") })
    @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void updateUser(@ApiParam(value = "ID of User from DB", required = true) @PathVariable Long id,
            @ApiParam(value = "new properties for User by userDto", required = true) @Valid @RequestBody UserDto userDto,
            @ApiParam(value = "Authentication", hidden = true) Authentication authentication) {
        SpringUser springUser = (SpringUser) authentication.getPrincipal();
        LOGGER.debug("Update user {} by user '{}'", userDto, springUser.getUsername());
        checkUrlAndBodyForId(id, userDto);
        checkEmailNotExists(userDto, "update user");
        try {
            usersService.updateUser(id, userDto, springUser.getRole());
        } catch (NoSuchElementException exception) {
            throw new ExceptionUserNotFound(exception.getMessage());
        }
    }

    private void checkUrlAndBodyForId(Long id, UserDto userDto) {
        if (!id.equals(userDto.getIdUser())) {
            throw new ExceptionDifferentIdBetweenUrlAndBody(String.format(
                    "'idUser' in URL (%s) must be as same as in request body (%s)", id, userDto.getIdUser()));
        }
    }

    private void checkEmailNotExists(UserDto userDto, String operationName) {
        Optional<User> user = usersService.getUserByEmail(userDto.getEmail());
        if (user.isPresent()) {
            if (!user.get().getIdUser().equals(userDto.getIdUser())) {
                throw new ExceptionOtherUserWithSameEmail(
                        String.format("Can not %s because other User (%s) already exists with the same email '%s'.",
                                operationName, user.get().getIdUser(), userDto.getEmail()));
            }
        }
    }

    @PreAuthorize("@userRightResolverServiceImpl.canAccessToUser(principal, #id)")
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    @ApiOperation(value = "Delete User by ID.", notes = "Returns NO_CONTENT if deletion was successful.")
    @ApiResponses(value = { @ApiResponse(code = 401, message = "Only authenticated access allowed."),
            @ApiResponse(code = 403, message = "Only user of ADMIN role or User has authenticated with this Id can have access."),
            @ApiResponse(code = 404, message = "User with such Id not found."), })
    public void deleteUser(@PathVariable Long id) {
        LOGGER.debug("Delete user by id={}", id);
        try {
            usersService.deleteUser(id);
        } catch (NoSuchElementException exception) {
            throw new ExceptionUserNotFound(exception.getMessage());
        }
    }

    @ResponseStatus(HttpStatus.NOT_FOUND)
    static class ExceptionUserNotFound extends RuntimeException {
        public ExceptionUserNotFound(String message) {
            super(message);
        }
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    static class ExceptionDifferentIdBetweenUrlAndBody extends RuntimeException {
        public ExceptionDifferentIdBetweenUrlAndBody(String message) {
            super(message);
        }
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    static class ExceptionUserWithoutPassword extends RuntimeException {
        public ExceptionUserWithoutPassword() {
            super("Can not create new User without a password.");
        }
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    static class ExceptionOtherUserWithSameEmail extends RuntimeException {
        public ExceptionOtherUserWithSameEmail(String message) {
            super(message);
        }
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    static class ExceptionIdUserMustBeEmpty extends RuntimeException {
        public ExceptionIdUserMustBeEmpty(String message) {
            super(message);
        }
    }
}