nu.yona.server.subscriptions.service.UserService.java Source code

Java tutorial

Introduction

Here is the source code for nu.yona.server.subscriptions.service.UserService.java

Source

/*******************************************************************************
 * Copyright (c) 2015 Stichting Yona Foundation This Source Code Form is subject to the terms of the Mozilla Public License, v.
 * 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
 *******************************************************************************/
package nu.yona.server.subscriptions.service;

import java.util.Optional;
import java.util.UUID;
import java.util.regex.Pattern;

import javax.transaction.Transactional;

import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import nu.yona.server.crypto.Constants;
import nu.yona.server.crypto.CryptoSession;
import nu.yona.server.exceptions.InvalidDataException;
import nu.yona.server.exceptions.YonaException;
import nu.yona.server.messaging.entities.MessageSource;
import nu.yona.server.subscriptions.entities.Buddy;
import nu.yona.server.subscriptions.entities.NewDeviceRequest;
import nu.yona.server.subscriptions.entities.User;

@Service
public class UserService {
    /** Holds the regex to validate a valid phone number. Start with a '+' sign followed by only numbers */
    private static Pattern REGEX_PHONE = Pattern.compile("^\\+[1-9][0-9]+$");

    // TODO: Do we need this? Currently unused.
    @Transactional
    public UserDTO getUser(String mobileNumber) {
        if (mobileNumber == null) {
            throw new IllegalArgumentException("mobileNumber cannot be null");
        }

        User userEntity = findUserByMobileNumber(mobileNumber);
        return UserDTO.createInstanceWithPrivateData(userEntity);
    }

    @Transactional
    public boolean canAccessPrivateData(UUID id) {
        return getEntityByID(id).canAccessPrivateData();
    }

    @Transactional
    public UserDTO getPublicUser(UUID id) {
        return UserDTO.createInstance(getEntityByID(id));
    }

    @Transactional
    public UserDTO getPrivateUser(UUID id) {
        return UserDTO.createInstanceWithPrivateData(getEntityByID(id));
    }

    @Transactional
    public UserDTO addUser(UserDTO userResource) {
        validateUserFields(userResource);

        User userEntity = userResource.createUserEntity();
        userEntity = User.getRepository().save(userEntity);

        return UserDTO.createInstanceWithPrivateData(userEntity);
    }

    @Transactional
    public UserDTO updateUser(UUID id, UserDTO userResource) {
        User originalUserEntity = getEntityByID(id);
        UserDTO savedUser;
        if (originalUserEntity.isCreatedOnBuddyRequest()) {
            // TODO: the password needs to come from the URL, not from the
            // payload
            savedUser = handleUserSignupUponBuddyRequest("TODO", userResource, originalUserEntity);
        } else {
            savedUser = handleUserUpdate(userResource, originalUserEntity);
        }
        return savedUser;
    }

    static User findUserByMobileNumber(String mobileNumber) {
        User userEntity;
        userEntity = User.getRepository().findByMobileNumber(mobileNumber);
        if (userEntity == null) {
            throw UserNotFoundException.notFoundByMobileNumber(mobileNumber);
        }
        return userEntity;
    }

    private UserDTO handleUserSignupUponBuddyRequest(String password, UserDTO userResource,
            User originalUserEntity) {
        UpdatedEntities updatedEntities = updateUserWithTempPassword(userResource, originalUserEntity);
        return saveUserWithDevicePassword(password, updatedEntities);
    }

    static class UpdatedEntities {
        final User userEntity;
        final MessageSource namedMessageSource;
        final MessageSource anonymousMessageSource;

        UpdatedEntities(User userEntity, MessageSource namedMessageSource, MessageSource anonymousMessageSource) {
            this.userEntity = userEntity;
            this.namedMessageSource = namedMessageSource;
            this.anonymousMessageSource = anonymousMessageSource;
        }
    }

    private UpdatedEntities updateUserWithTempPassword(UserDTO userDTO, User originalUserEntity) {
        // TODO: the password needs to come from the URL, not from the
        // payload
        return CryptoSession.execute(Optional.of("TODO"), () -> canAccessPrivateData(userDTO.getID()), () -> {
            User updatedUserEntity = userDTO.updateUser(originalUserEntity);
            MessageSource touchedNameMessageSource = touchMessageSource(updatedUserEntity.getNamedMessageSource());
            MessageSource touchedAnonymousMessageSource = touchMessageSource(
                    updatedUserEntity.getAnonymousMessageSource());
            return new UpdatedEntities(updatedUserEntity, touchedNameMessageSource, touchedAnonymousMessageSource);
        });
    }

    private MessageSource touchMessageSource(MessageSource messageSource) {
        messageSource.touch();
        return messageSource;
    }

    private UserDTO saveUserWithDevicePassword(String password, UpdatedEntities updatedEntities) {
        return CryptoSession.execute(Optional.of(password),
                () -> canAccessPrivateData(updatedEntities.userEntity.getID()), () -> {
                    UserDTO savedUser;
                    MessageSource.getRepository().save(updatedEntities.namedMessageSource);
                    MessageSource.getRepository().save(updatedEntities.anonymousMessageSource);
                    savedUser = UserDTO
                            .createInstanceWithPrivateData(User.getRepository().save(updatedEntities.userEntity));
                    return savedUser;
                });
    }

    private UserDTO handleUserUpdate(UserDTO userResource, User originalUserEntity) {
        return UserDTO.createInstanceWithPrivateData(
                User.getRepository().save(userResource.updateUser(originalUserEntity)));
    }

    public void deleteUser(Optional<String> password, UUID id) {

        User.getRepository().delete(id);
    }

    private User getEntityByID(UUID id) {
        User entity = User.getRepository().findOne(id);
        if (entity == null) {
            throw UserNotFoundException.notFoundByID(id);
        }
        return entity;
    }

    private void validateUserFields(UserDTO userResource) {
        if (StringUtils.isBlank(userResource.getFirstName())) {
            throw new InvalidDataException("error.user.firstname");
        }

        if (StringUtils.isBlank(userResource.getLastName())) {
            throw new InvalidDataException("error.user.lastname");
        }

        if (StringUtils.isBlank(userResource.getMobileNumber())) {
            throw new InvalidDataException("error.user.mobile.number");
        }

        if (!REGEX_PHONE.matcher(userResource.getMobileNumber()).matches()) {
            throw new InvalidDataException("error.user.mobile.number.invalid");
        }
    }

    public static String getPassword(Optional<String> password) {
        return password.orElseThrow(() -> new YonaException("Missing '" + Constants.PASSWORD_HEADER + "' header"));
    }

    public void addBuddy(UserDTO user, BuddyDTO buddy) {
        User userEntity = getEntityByID(user.getID());
        Buddy buddyEntity = Buddy.getRepository().findOne(buddy.getID());
        userEntity.addBuddy(buddyEntity);
        User.getRepository().save(userEntity);
    }

    @Transactional
    public NewDeviceRequestDTO setNewDeviceRequestForUser(UUID userID, String userPassword, String userSecret) {
        User userEntity = getEntityByID(userID);
        NewDeviceRequest newDeviceRequestEntity = NewDeviceRequest.createInstance(userPassword);
        newDeviceRequestEntity.encryptUserPassword(userSecret);
        boolean isUpdatingExistingRequest = userEntity.getNewDeviceRequest() != null;
        userEntity.setNewDeviceRequest(newDeviceRequestEntity);
        return NewDeviceRequestDTO.createInstance(User.getRepository().save(userEntity).getNewDeviceRequest(),
                isUpdatingExistingRequest);
    }

    @Transactional
    public NewDeviceRequestDTO getNewDeviceRequestForUser(UUID userID, String userSecret) {
        User userEntity = getEntityByID(userID);
        NewDeviceRequest newDeviceRequestEntity = userEntity.getNewDeviceRequest();
        if (newDeviceRequestEntity == null) {
            throw new NewDeviceRequestNotPresentException(userID);
        }

        if (StringUtils.isBlank(userSecret)) {
            return NewDeviceRequestDTO.createInstance(userEntity.getNewDeviceRequest());
        } else {
            newDeviceRequestEntity.decryptUserPassword(userSecret);
            return NewDeviceRequestDTO.createInstanceWithPassword(newDeviceRequestEntity);
        }
    }

    @Transactional
    public void clearNewDeviceRequestForUser(UUID userID) {
        User userEntity = getEntityByID(userID);
        NewDeviceRequest existingNewDeviceRequestEntity = userEntity.getNewDeviceRequest();
        if (existingNewDeviceRequestEntity != null) {
            userEntity.setNewDeviceRequest(null);
            User.getRepository().save(userEntity);
        }
    }
}