de.hska.ld.core.controller.UserController.java Source code

Java tutorial

Introduction

Here is the source code for de.hska.ld.core.controller.UserController.java

Source

/*
 *  Code contributed to the Learning Layers project
 *  http://www.learning-layers.eu
 *  Development is partly funded by the FP7 Programme of the European
 *  Commission under Grant Agreement FP7-ICT-318209.
 *  Copyright (c) 2016, Karlsruhe University of Applied Sciences.
 *  For a list of contributors see the AUTHORS file at the top-level directory
 *  of this distribution.
 *
 *  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 de.hska.ld.core.controller;

import de.hska.ld.core.dto.UserRoleDto;
import de.hska.ld.core.exception.NotFoundException;
import de.hska.ld.core.exception.ValidationException;
import de.hska.ld.core.persistence.domain.User;
import de.hska.ld.core.service.UserService;
import de.hska.ld.core.util.AsyncExecutor;
import de.hska.ld.core.util.Core;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.bind.annotation.AuthenticationPrincipal;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

/**
 * <p><b>Resource:</b> {@value Core#RESOURCE_USER}
 */
@RestController
@RequestMapping(Core.RESOURCE_USER)
public class UserController {

    @Autowired
    private AsyncExecutor asyncExecutor;

    @Autowired
    private UserService userService;

    @RequestMapping(method = RequestMethod.GET, value = "/hello")
    public Callable helloWorld() {
        return () -> {
            String helloWorldString = "HelloWorld";
            return new ResponseEntity<>(helloWorldString, HttpStatus.OK);
        };
    }

    /**
     * <pre>
     * Gets a list with all users.
     *
     * <b>Required roles:</b> ROLE_ADMIN
     * <b>Path:</b> GET {@value Core#RESOURCE_USER}
     * </pre>
     *
     * @return <b>200 OK</b> and a list with all users or <br>
     * <b>403 Forbidden</b> if authorization failed or <br>
     * <b>404 Not Found</b> if no users are in the system
     */
    // TODO currently not working
    @Secured(Core.ROLE_USER)
    @RequestMapping(method = RequestMethod.GET, value = "/userlist")
    public Callable getAllUsers() {
        return () -> {
            List<User> userList = userService.findAll();
            if (userList != null) {
                return new ResponseEntity<>(userList, HttpStatus.OK);
            } else {
                return new ResponseEntity<>(HttpStatus.NOT_FOUND);
            }
        };
    }

    //TODO done with default parameters
    /**
     * <pre>
     * Gets a list with all users.
     *
     * <b>Required roles:</b> ROLE_ADMIN
     * <b>Path:</b> GET {@value Core#RESOURCE_USER}
     * </pre>
     *
     * @return <b>200 OK</b> and a list with all users or <br>
     * <b>403 Forbidden</b> if authorization failed or <br>
     * <b>404 Not Found</b> if no users are in the system
     */
    @Secured(Core.ROLE_ADMIN)
    @RequestMapping(method = RequestMethod.GET)
    public Callable getUsersPage(@RequestParam(value = "page-number", defaultValue = "0") Integer pageNumber,
            @RequestParam(value = "page-size", defaultValue = "10") Integer pageSize,
            @RequestParam(value = "sort-direction", defaultValue = "DESC") String sortDirection,
            @RequestParam(value = "sort-property", defaultValue = "createdAt") String sortProperty) {
        return () -> {
            Page<User> usersPage = userService.getUsersPage(pageNumber, pageSize, sortDirection, sortProperty);
            if (usersPage != null) {
                return new ResponseEntity<>(usersPage, HttpStatus.OK);
            } else {
                return new ResponseEntity<>(HttpStatus.NOT_FOUND);
            }
        };
    }

    /**
     * <pre>
     * Gets a list with all users.
     *
     * <b>Required roles:</b> ROLE_ADMIN
     * <b>Path:</b> GET {@value Core#RESOURCE_USER}
     * </pre>
     *
     * @return <b>200 OK</b> and a list with all users or <br>
     * <b>403 Forbidden</b> if authorization failed or <br>
     * <b>404 Not Found</b> if no users are in the system
     */
    @Secured(Core.ROLE_ADMIN)
    @RequestMapping(method = RequestMethod.GET, value = "/disabled")
    @Transactional(readOnly = true)
    public Callable getUsersDisabledPage(
            @RequestParam(value = "page-number", defaultValue = "0") Integer pageNumber,
            @RequestParam(value = "page-size", defaultValue = "10") Integer pageSize,
            @RequestParam(value = "sort-direction", defaultValue = "DESC") String sortDirection,
            @RequestParam(value = "sort-property", defaultValue = "createdAt") String sortProperty) {
        return () -> {
            Page<User> usersPage = userService.getUsersDisabledPage(pageNumber, pageSize, sortDirection,
                    sortProperty);
            if (usersPage != null) {
                return new ResponseEntity<>(usersPage, HttpStatus.OK);
            } else {
                return new ResponseEntity<>(HttpStatus.NOT_FOUND);
            }
        };
    }

    //TODO Description
    @Secured(Core.ROLE_ADMIN)
    @RequestMapping(method = RequestMethod.POST, value = "/activate/{userid}")
    public Callable activateUser(@PathVariable Long userid) {
        return () -> {
            User user = userService.activateUser(userid);
            if (user != null) {
                return new ResponseEntity<>(HttpStatus.OK);
            } else {
                return new ResponseEntity<>(HttpStatus.NOT_FOUND);
            }
        };
    }

    //TODO Description
    @Secured(Core.ROLE_ADMIN)
    @RequestMapping(method = RequestMethod.POST, value = "/deactivate/{userid}")
    public Callable deactivateUser(@PathVariable Long userid) {
        return () -> {
            User user = userService.deactivateUser(userid);
            if (user != null) {
                return new ResponseEntity<>(HttpStatus.OK);
            } else {
                return new ResponseEntity<>(HttpStatus.NOT_FOUND);
            }
        };
    }

    /**
     * <pre>
     * Authenticates the current user.
     *
     * <b>Required roles:</b> ROLE_USER
     * <b>Path:</b> GET {@value Core#RESOURCE_USER}/authenticate
     * </pre>
     *
     * @return <b>200 OK</b> and the current logged in user or <br>
     * <b>403 Forbidden</b> if authentication failed
     */
    @Secured(Core.ROLE_USER)
    @RequestMapping(method = RequestMethod.GET, value = "/authenticate")
    public Callable authenticate(@AuthenticationPrincipal User user) {
        final User user2 = Core.currentUser();
        return () -> new ResponseEntity<>(user2, HttpStatus.OK);
    }

    public boolean isAuthenticated() {
        SecurityContext securityContext = SecurityContextHolder.getContext();
        return securityContext != null && securityContext.getAuthentication() != null
                && securityContext.getAuthentication().isAuthenticated();
    }

    public User currentUser() {
        if (isAuthenticated()) {
            Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            if (principal instanceof User) {
                return (User) principal;
            } else {
                Map principalMap = (Map) principal;
                User user = userService.findBySubIdAndIssuer((String) principalMap.get("sub"),
                        (String) principalMap.get("iss"));
                return user;
            }
        }
        return null;
    }

    /**
     * <pre>
     * Gets a user by its username.
     *
     * <b>Required roles:</b> authorized user
     * <b>Path:</b> GET {@value Core#RESOURCE_USER}/{username}
     * </pre>
     *
     * @param username the unique username as path variable
     * @return <b>200 OK</b> and the user or <br>
     * <b>403 Forbidden</b> if authorization failed or <br>
     * <b>404 Not Found</b> if no user with the given username has been found
     */
    @PreAuthorize("hasRole('" + Core.ROLE_ADMIN + "') or (isAuthenticated() and principal.username == #username)")
    @RequestMapping(method = RequestMethod.GET, value = "/{username}")
    @Transactional(readOnly = true)
    public Callable getUserByUsername(@PathVariable String username) {
        return () -> {
            User user = userService.findByUsername(username);
            if (user == null) {
                return new ResponseEntity<>(HttpStatus.NOT_FOUND);
            }
            return new ResponseEntity<>(user, HttpStatus.OK);
        };
    }

    /**
     * <pre>
     * Saves a user. This means a new user will be created if no ID is specified or an old user will be
     * updated if ID is specified.
     *
     * <b>Required roles:</b> ROLE_ADMIN
     * <b>Path:</b> POST {@value Core#RESOURCE_USER}
     * </pre>
     *
     * @param user includes the user to be saved or updated. Example:<br>
     *             {username: 'jdoe', email: 'jdoe@jdoe.org', fullName: 'John Doe'}
     * @return <b>201 Created</b> and the user or <br>
     * <b>200 OK</b> and the user or <br>
     * <b>400 Bad Request</b> if at least one property was invalid or <br>
     * <b>403 Forbidden</b> if authorization failed
     */
    @Secured(Core.ROLE_ADMIN)
    @RequestMapping(method = RequestMethod.POST)
    public Callable saveUser(@RequestBody @Valid final User user) {
        return () -> {
            user.setLastupdatedAt(new Date());
            try {
                if (user.getId() == null) {
                    User savedUser = userService.save(user);
                    return new ResponseEntity<>(savedUser, HttpStatus.CREATED);
                } else {
                    User savedUser = userService.save(user);
                    return new ResponseEntity<>(savedUser, HttpStatus.OK);
                }
            } catch (ValidationException e) {
                return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
            }
        };
    }

    /**
     * <pre>
     * Saves a user. This means a new user will be created if no ID is specified or an old user will be
     * updated if ID is specified.
     *
     * <b>Required roles:</b> ROLE_ADMIN
     * <b>Path:</b> PUT {@value Core#RESOURCE_USER}
     * </pre>
     *
     * @param user includes the user to be saved or updated. Example:<br>
     *             {username: 'jdoe', email: 'jdoe@jdoe.org', fullName: 'John Doe'}
     * @return <b>201 Created</b> and the user or <br>
     * <b>200 OK</b> and the user or <br>
     * <b>400 Bad Request</b> if at least one property was invalid or <br>
     * <b>403 Forbidden</b> if authorization failed
     */
    @Secured(Core.ROLE_ADMIN)
    @RequestMapping(method = RequestMethod.PUT, value = "/{userId}")
    public Callable updateUser(@PathVariable Long userId, @RequestBody @Valid final User user) {
        return () -> {
            User dbUser = userService.findById(userId);
            if (dbUser != null) {
                user.setLastupdatedAt(new Date());
                User savedUser = userService.save(user);
                return new ResponseEntity<>(savedUser, HttpStatus.OK);
            } else {
                return new ResponseEntity<>(HttpStatus.NOT_FOUND);
            }
        };
    }

    /**
     * <pre>
     * Register a new user.
     *
     * <b>Required roles:</b> ROLE_ADMIN
     * <b>Path:</b> POST {@value Core#RESOURCE_USER}
     * </pre>
     *
     * @param user includes the user to be saved or updated. Example:<br>
     *             {username: 'jdoe', email: 'jdoe@jdoe.org', fullName: 'John Doe'}
     * @return <b>201 Created</b> and the user or <br>
     * <b>400 Bad Request</b> if at least one property was invalid
     */
    @RequestMapping(method = RequestMethod.POST, value = "/register")
    public Callable register(@RequestBody @Valid User user) {
        return () -> {
            userService.register(user);
            return new ResponseEntity<>(HttpStatus.CREATED);
        };
    }

    /**
     * <pre>
     * Enables the user.
     *
     * <b>Required roles:</b> no role required
     * <b>Path:</b> GET {@value Core#RESOURCE_USER}/confirmRegistration/{confirmationKey}
     * </pre>
     *
     * @param confirmationKey the confirmation key as path variable
     * @return <b>200 OK</b> if confirmation was successful or <br>
     * <b>400 Bad Request</b> if at least one property was invalid or <br>
     * <b>404 Not Found</b> if no user with the given confirmation key has been found
     */
    @SuppressWarnings("unchecked")
    @RequestMapping(method = RequestMethod.GET, value = "/confirmRegistration/{confirmationKey}")
    public Callable confirmRegistration(@PathVariable String confirmationKey) {
        return () -> {
            User user = userService.confirmRegistration(confirmationKey);
            return new ResponseEntity(user, HttpStatus.OK);
        };
    }

    /**
     * <pre>
     * Adds one or more roles to an existing user.
     *
     * <b>Required roles:</b> ROLE_ADMIN
     * <b>Path:</b> POST {@value Core#RESOURCE_USER}/roles/add
     * </pre>
     *
     * @param userRoleDto includes the username of the user to be updated. The transfer object also contains a role list.
     *                    Each role will be added to the user. Example: <br>
     *                    <code>{username: 'jdoe', roleList: [{id: 1, name: 'ROLE_NAME'}]}</code>
     * @return <b>200 OK</b> or <br>
     * <b>403 Forbidden</b> if authorization failed or <br>
     * <b>404 Not Found</b> if no user with the given username has been found
     */
    @Secured(Core.ROLE_ADMIN)
    @RequestMapping(method = RequestMethod.POST, value = "/roles/add")
    public Callable addRolesToUser(@RequestBody @Valid UserRoleDto userRoleDto) {
        return () -> {
            userService.addRoles(userRoleDto.getUsername(), userRoleDto.getRoleNames());
            return new ResponseEntity(HttpStatus.OK);
        };
    }

    /**
     * <pre>
     * Deletes a user.
     *
     * <b>Required roles:</b> ROLE_ADMIN
     * <b>Path:</b> DELETE {@value Core#RESOURCE_USER}/{id}
     * </pre>
     *
     * @param id the user ID as a path variable
     * @return <b>200 OK</b> if deletion was successful, <br>
     * <b>403 Forbidden</b> if authorization failed or <br>
     * <b>404 Not Found</b> if no user with the given ID has been found
     */
    @Secured(Core.ROLE_ADMIN)
    @RequestMapping(method = RequestMethod.DELETE, value = "/{id}")
    public Callable deleteUser(@PathVariable Long id) {
        return () -> {
            User user = userService.findById(id);
            if (user != null) {
                userService.delete(user);
                return new ResponseEntity<>(user.getId(), HttpStatus.OK);
            } else {
                return new ResponseEntity<>(HttpStatus.NOT_FOUND);
            }
        };
    }

    //TODO: describe functionality of Methode
    @Secured(Core.ROLE_USER)
    @RequestMapping(method = RequestMethod.GET, value = "/avatars")
    @Transactional(readOnly = true)
    public Callable loadAvatars(@RequestParam String userIdsString) {
        return () -> userService.getAvatars(userIdsString);
    }

    //TODO: describe functionality of Methode
    @Secured(Core.ROLE_USER)
    @RequestMapping(method = RequestMethod.GET, value = "/avatar")
    @Transactional(readOnly = true)
    public void loadAvatar(HttpServletResponse response) {
        try {
            User user = Core.currentUser();
            String userIdString = user.getId().toString();
            List<byte[]> avatars = userService.getAvatars(userIdString);
            if (avatars != null && avatars.size() > 0) {
                byte[] source = avatars.get(0);
                if (source != null) {
                    InputStream is = new ByteArrayInputStream(source);
                    //response.setContentType(attachment.getMimeType());
                    OutputStream outputStream = response.getOutputStream();
                    IOUtils.copy(is, outputStream);
                } else {
                    String fileName = "Portrait_placeholder.png";
                    InputStream is = null;
                    try {
                        is = UserController.class.getResourceAsStream("/" + fileName);
                        //response.setContentType(attachment.getMimeType());
                        OutputStream outputStream = response.getOutputStream();
                        IOUtils.copy(is, outputStream);
                    } finally {
                        IOUtils.closeQuietly(is);
                    }
                }
            } else {
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            }
        } catch (IOException e) {
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    //TODO: describe functionality of Methode
    @Secured(Core.ROLE_USER)
    @RequestMapping(method = RequestMethod.GET, value = "/avatar/{id}")
    @Transactional(readOnly = true)
    public void loadAvatarForUser(@PathVariable Long id, HttpServletResponse response) {
        try {
            String userIdString = id.toString();
            List<byte[]> avatars = userService.getAvatars(userIdString);
            if (avatars != null && avatars.size() > 0) {
                byte[] source = avatars.get(0);
                if (source != null) {
                    InputStream is = new ByteArrayInputStream(source);
                    //response.setContentType(attachment.getMimeType());
                    OutputStream outputStream = response.getOutputStream();
                    IOUtils.copy(is, outputStream);
                } else {
                    String fileName = "Portrait_placeholder.png";
                    InputStream is = null;
                    try {
                        is = UserController.class.getResourceAsStream("/" + fileName);
                        //response.setContentType(attachment.getMimeType());
                        OutputStream outputStream = response.getOutputStream();
                        IOUtils.copy(is, outputStream);
                    } finally {
                        IOUtils.closeQuietly(is);
                    }
                }
            } else {
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            }
        } catch (IOException e) {
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    //TODO: describe functionality of Methode
    @Secured(Core.ROLE_USER)
    @RequestMapping(method = RequestMethod.POST, value = "/avatar")
    public Callable uploadAvatar(@RequestParam MultipartFile file) {
        return () -> {
            String name = file.getOriginalFilename();
            if (!file.isEmpty()) {
                userService.uploadAvatar(file, name);
                return new ResponseEntity<>(HttpStatus.OK);
            } else {
                throw new ValidationException("file");
            }
        };
    }

    //TODO: describe functionality of method
    @Secured(Core.ROLE_USER)
    @RequestMapping(method = RequestMethod.GET, value = "/suggestions/list")
    @Transactional(readOnly = true)
    public Callable getMentionSuggestionsList(@RequestParam(required = false) String term) {
        return () -> {
            if (term != null && term.length() > 4) {
                if (!"".equals(term) || term.contains("%")) {
                    List<User> userSuggestionList = userService.getMentionSuggestions(term);
                    return new ResponseEntity<>(userSuggestionList, HttpStatus.OK);
                } else {
                    List<User> userSuggestionList = userService.getMentionSuggestions(term);
                    return new ResponseEntity<>(userSuggestionList, HttpStatus.BAD_REQUEST);
                }
            } else {
                List<User> userSuggestionList = new ArrayList<>();
                return new ResponseEntity<>(userSuggestionList, HttpStatus.BAD_REQUEST);
            }
        };
    }

    //TODO: describe functionality of method
    @Secured(Core.ROLE_USER)
    @RequestMapping(method = RequestMethod.GET, value = "/suggestions")
    @Transactional(readOnly = true)
    public Callable getMentionSuggestions(
            @RequestParam(value = "page-number", defaultValue = "0") Integer pageNumber,
            @RequestParam(value = "page-size", defaultValue = "10") Integer pageSize,
            @RequestParam(value = "sort-direction", defaultValue = "DESC") String sortDirection,
            @RequestParam(value = "sort-property", defaultValue = "username") String sortProperty,
            @RequestParam(value = "search-term", required = false) String searchTerm) {
        return () -> {
            if (searchTerm != null && searchTerm.length() > 4) {
                Page<User> usersPage = userService.getUsersPage(pageNumber, pageSize, sortDirection, sortProperty,
                        searchTerm);
                if (usersPage != null) {
                    return new ResponseEntity<>(usersPage, HttpStatus.OK);
                } else {
                    return new ResponseEntity<>(HttpStatus.NOT_FOUND);
                }
            } else {
                return new ResponseEntity<>(HttpStatus.NOT_FOUND);
            }
        };
    }

    //TODO: describe functionality of Methode
    @Secured(Core.ROLE_USER)
    @RequestMapping(method = RequestMethod.GET, value = "/username")
    @Transactional(readOnly = true)
    public Callable getUserByUserName(@RequestParam String term) {
        return () -> {
            User user = userService.findByUsername(term);
            if (user == null) {
                throw new NotFoundException();
            }
            return new ResponseEntity<>(user, HttpStatus.OK);
        };
    }

    //TODO: describe functionality of Methode
    @Secured(Core.ROLE_USER)
    @RequestMapping(method = RequestMethod.GET, value = "/id")
    @Transactional(readOnly = true)
    @SuppressWarnings("unchecked")
    public Callable getUser(@RequestParam Long id) {
        return () -> {
            User user = userService.findById(id);
            if (user == null) {
                throw new NotFoundException();
            }
            return new ResponseEntity(user, HttpStatus.OK);
        };
    }

    //TODO: describe functionality of Methode (Update password for current user)
    @Secured(Core.ROLE_USER)
    @RequestMapping(method = RequestMethod.PUT, value = "/password")
    public Callable updatePassword(@RequestBody User user) {
        return () -> {
            User dbUser = userService.updatePassword(user.getPassword());
            return new ResponseEntity<>(dbUser, HttpStatus.OK);
        };
    }

    //TODO: describe functionality of Methode
    @Secured(Core.ROLE_USER)
    @RequestMapping(method = RequestMethod.PUT, value = "/profile")
    public Callable updateProfile(@RequestBody User user) {
        return () -> {
            User dbUser = userService.updateProfile(user);
            return new ResponseEntity<>(dbUser, HttpStatus.OK);
        };
    }

    /**
     * <pre>
     * Forgot Password workflow (Step 1)
     *
     * <b>Required roles:</b> no role required
     * <b>Path:</b> POST {@value Core#RESOURCE_USER}/forgotPassword
     * </pre>
     *
     * @param userUsernameOrEmail username or the user's email address
     * @return always <b>200 OK</b>
     */
    @RequestMapping(method = RequestMethod.POST, value = "/forgotPassword")
    public ResponseEntity forgotPassword(@RequestBody String userUsernameOrEmail) {
        asyncExecutor.run(() -> userService.forgotPassword(userUsernameOrEmail));
        return new ResponseEntity(HttpStatus.OK);
    }

    /**
     * <pre>
     * Forgot Password workflow (Step 2)
     *
     * <b>Required roles:</b> no role required
     * <b>Path:</b> POST {@value Core#RESOURCE_USER}/forgotPasswordConfirm/{confirmationKey}
     * </pre>
     *
     * @param confirmationKey forgot password confirmation key
     * @param newPassword     the new password
     * @return <b>200 OK</b> if everything goes well or <br>
     * <b>500 Bad RequestInternal Server Error</b> if an error occurred
     */
    @RequestMapping(method = RequestMethod.POST, value = "/forgotPasswordConfirm/{confirmationKey}")
    public ResponseEntity forgotPasswordConfirm(@PathVariable String confirmationKey,
            @RequestBody String newPassword) {
        userService.forgotPasswordConfirm(confirmationKey, newPassword);
        return new ResponseEntity(HttpStatus.OK);
    }

    /**
     * <pre>
     * Change email workflow (Step 1)
     *
     * <b>Required roles:</b> ROLE_USER
     * <b>Path:</b> POST {@value Core#RESOURCE_USER}/changeEmail
     * </pre>
     *
     * @param emailToBeConfirmed the new email address to be confirmed
     * @return <b>200 OK</b> if everything goes well or <br>
     * <b>409 Conflict</b> if a user with the given username or email already exists
     */
    @Secured(Core.ROLE_USER)
    @RequestMapping(method = RequestMethod.POST, value = "/changeEmail")
    public ResponseEntity changeEmail(@AuthenticationPrincipal User user, @RequestBody String emailToBeConfirmed) {
        userService.changeEmail(user, emailToBeConfirmed);
        return new ResponseEntity(HttpStatus.OK);
    }

    /**
     * <pre>
     * Change email workflow (Step 2)
     *
     * <b>Required roles:</b> no role required
     * <b>Path:</b> GET {@value Core#RESOURCE_USER}/changeEmailConfirm/{confirmationKey}
     * </pre>
     *
     * @param confirmationKey change email confirmation key
     * @return <b>200 OK</b> if everything goes well or <br>
     * <b>409 Conflict</b> if a user with the given username or email already exists or <br>
     * <b>500 Bad RequestInternal Server Error</b> if an error occurred
     */
    @RequestMapping(method = RequestMethod.GET, value = "/changeEmailConfirm/{confirmationKey}")
    public ResponseEntity changeEmailConfirm(@PathVariable String confirmationKey) {
        userService.changeEmailConfirm(confirmationKey);
        return new ResponseEntity(HttpStatus.OK);
    }
}